using NUnit.Framework; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.ContentPublishing; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services; namespace Umbraco.Cms.Tests.Integration.Umbraco.PublishedCache.HybridCache; [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] internal sealed class DocumentHybridCacheTests : UmbracoIntegrationTestWithContentEditing { protected override void CustomTestSetup(IUmbracoBuilder builder) { builder.AddNotificationHandler(); builder.Services.AddUnique(); } private IPublishedContentCache PublishedContentHybridCache => GetRequiredService(); private IContentPublishingService ContentPublishingService => GetRequiredService(); private IDocumentCacheService DocumentCacheService => GetRequiredService(); private const string NewName = "New Name"; private const string NewTitle = "New Title"; [Test] public async Task Can_Get_Draft_Content_By_Id() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(TextpageId, true); // Assert AssertTextPage(textPage); } [Test] public async Task Can_Get_Draft_Content_By_Key() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(Textpage.Key.Value, true); // Assert AssertTextPage(textPage); } [Test] public async Task Can_Get_Published_Content_By_Id() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId); // Assert AssertPublishedTextPage(textPage); } [Test] public async Task Can_Get_Published_Content_By_Key() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value); // Assert AssertPublishedTextPage(textPage); } [Test] public async Task Can_Get_Draft_Of_Published_Content_By_Id() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, true); // Assert AssertPublishedTextPage(textPage); Assert.IsFalse(textPage.IsPublished()); } [TestCase(true)] [TestCase(false)] public async Task Can_Get_Unpublished_Content_By_Key(bool preview) { // Arrange var unpublishAttempt = await ContentPublishingService.UnpublishAsync(PublishedTextPage.Key.Value, null, Constants.Security.SuperUserKey); Assert.IsTrue(unpublishAttempt.Success); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, preview); // Assert if (preview) { Assert.IsNotNull(textPage); Assert.IsFalse(textPage.IsPublished()); } else { Assert.IsNull(textPage); } } [TestCase(true)] [TestCase(false)] public async Task Can_Get_Unpublished_Content_By_Id(bool preview) { // Arrange var unpublishAttempt = await ContentPublishingService.UnpublishAsync(PublishedTextPage.Key.Value, null, Constants.Security.SuperUserKey); Assert.IsTrue(unpublishAttempt.Success); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, preview); // Assert if (preview) { Assert.IsNotNull(textPage); Assert.IsFalse(textPage.IsPublished()); } else { Assert.IsNull(textPage); } } [Test] public async Task Can_Get_Draft_Of_Published_Content_By_Key() { // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, true); // Assert AssertPublishedTextPage(textPage); Assert.IsFalse(textPage.IsPublished()); } [Test] public async Task Can_Get_Updated_Draft_Content_By_Id() { // Arrange Textpage.Variants = [new() { Name = NewName }]; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = Textpage.Properties, Variants = Textpage.Variants, TemplateKey = Textpage.TemplateKey, }; await ContentEditingService.UpdateAsync(Textpage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var updatedPage = await PublishedContentHybridCache.GetByIdAsync(TextpageId, true); // Assert Assert.AreEqual(NewName, updatedPage.Name); } [Test] public async Task Can_Get_Updated_Draft_Content_By_Key() { // Arrange Textpage.Variants = [new() { Name = NewName }]; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = Textpage.Properties, Variants = Textpage.Variants, TemplateKey = Textpage.TemplateKey, }; await ContentEditingService.UpdateAsync(Textpage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var updatedPage = await PublishedContentHybridCache.GetByIdAsync(Textpage.Key.Value, true); // Assert Assert.AreEqual(NewName, updatedPage.Name); } [Test] [TestCase(true, true)] [TestCase(false, false)] // BETTER NAMING, CURRENTLY THIS IS TESTING BOTH THE PUBLISHED AND THE DRAFT OF THE PUBLISHED. public async Task Can_Get_Updated_Draft_Published_Content_By_Id(bool preview, bool result) { // Arrange PublishedTextPage.Variants = [new() { Name = NewName }]; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, preview); // Assert Assert.AreEqual(result, NewName.Equals(textPage.Name)); } [Test] [TestCase(true, true)] [TestCase(false, false)] // BETTER NAMING, CURRENTLY THIS IS TESTING BOTH THE PUBLISHED AND THE DRAFT OF THE PUBLISHED. public async Task Can_Get_Updated_Draft_Published_Content_By_Key(bool preview, bool result) { // Arrange PublishedTextPage.Variants = [new() { Name = NewName }];; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, preview); // Assert Assert.AreEqual(result, NewName.Equals(textPage.Name)); } [Test] public async Task Can_Get_Draft_Content_Property_By_Id() { // Arrange var titleValue = Textpage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(TextpageId, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Draft_Content_Property_By_Key() { // Arrange var titleValue = Textpage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(Textpage.Key.Value, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Published_Content_Property_By_Id() { // Arrange var titleValue = PublishedTextPage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Published_Content_Property_By_Key() { // Arrange var titleValue = PublishedTextPage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Draft_Of_Published_Content_Property_By_Id() { // Arrange var titleValue = PublishedTextPage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Draft_Of_Published_Content_Property_By_Key() { // Arrange var titleValue = PublishedTextPage.Properties.First(x => x.Alias == "title").Value; // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, true); // Assert Assert.AreEqual(titleValue, textPage.Value("title")); } [Test] public async Task Can_Get_Updated_Draft_Content_Property_By_Id() { // Arrange Textpage.Properties.First(x => x.Alias == "title").Value = NewTitle; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = Textpage.Properties, Variants = Textpage.Variants, TemplateKey = Textpage.TemplateKey, }; await ContentEditingService.UpdateAsync(Textpage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(TextpageId, true); // Assert Assert.AreEqual(NewTitle, textPage.Value("title")); } [Test] public async Task Can_Get_Updated_Draft_Content_Property_By_Key() { // Arrange Textpage.Properties.First(x => x.Alias == "title").Value = NewTitle; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = Textpage.Properties, Variants = Textpage.Variants, TemplateKey = Textpage.TemplateKey, }; await ContentEditingService.UpdateAsync(Textpage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(Textpage.Key.Value, true); // Assert Assert.AreEqual(NewTitle, textPage.Value("title")); } [Test] public async Task Can_Get_Updated_Published_Content_Property_By_Id() { // Arrange PublishedTextPage.Properties.First(x => x.Alias == "title").Value = NewTitle; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); await ContentPublishingService.PublishAsync( PublishedTextPage.Key.Value, [new CulturePublishScheduleModel { Culture = "*" }], Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, true); // Assert Assert.AreEqual(NewTitle, textPage.Value("title")); } [Test] public async Task Can_Get_Updated_Published_Content_Property_By_Key() { // Arrange PublishedTextPage.Properties.First(x => x.Alias == "title").Value = NewTitle; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); await ContentPublishingService.PublishAsync( PublishedTextPage.Key.Value, [new CulturePublishScheduleModel { Culture = "*" }], Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value); // Assert Assert.AreEqual(NewTitle, textPage.Value("title")); } [Test] [TestCase(true, "New Title")] [TestCase(false, "Welcome to our Home page")] public async Task Can_Get_Updated_Draft_Of_Published_Content_Property_By_Id(bool preview, string titleName) { // Arrange PublishedTextPage.Properties.First(x => x.Alias == "title").Value = NewTitle; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, preview); // Assert Assert.AreEqual(titleName, textPage.Value("title")); } [Test] [TestCase(true, "New Name")] [TestCase(false, "Welcome to our Home page")] public async Task Can_Get_Updated_Draft_Of_Published_Content_Property_By_Key(bool preview, string titleName) { // Arrange PublishedTextPage.Properties.First(x => x.Alias == "title").Value = titleName; ContentUpdateModel updateModel = new ContentUpdateModel { Properties = PublishedTextPage.Properties, Variants = PublishedTextPage.Variants, TemplateKey = PublishedTextPage.TemplateKey, }; await ContentEditingService.UpdateAsync(PublishedTextPage.Key.Value, updateModel, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, true); // Assert Assert.AreEqual(titleName, textPage.Value("title")); } [Test] public async Task Can_Not_Get_Deleted_Content_By_Id() { // Arrange var content = await PublishedContentHybridCache.GetByIdAsync(Subpage1Id, true); Assert.IsNotNull(content); await ContentEditingService.DeleteAsync(Subpage1.Key.Value, Constants.Security.SuperUserKey); // Act var textPagePublishedContent = await PublishedContentHybridCache.GetByIdAsync(Subpage1Id, false); var textPage = await PublishedContentHybridCache.GetByIdAsync(Subpage1Id, true); // Assert Assert.IsNull(textPage); } [Test] public async Task Can_Not_Get_Deleted_Content_By_Key() { // Arrange await PublishedContentHybridCache.GetByIdAsync(Subpage1.Key.Value, true); var hasContent = await PublishedContentHybridCache.GetByIdAsync(Subpage1Id, true); Assert.IsNotNull(hasContent); await ContentEditingService.DeleteAsync(Subpage1.Key.Value, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(Subpage1.Key.Value, true); // Assert Assert.IsNull(textPage); } [Test] [TestCase(true)] [TestCase(false)] public async Task Can_Not_Get_Deleted_Published_Content_By_Id(bool preview) { // Arrange await ContentEditingService.DeleteAsync(PublishedTextPage.Key.Value, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId, preview); // Assert Assert.IsNull(textPage); } [Test] [TestCase(true)] [TestCase(false)] public async Task Can_Not_Get_Deleted_Published_Content_By_Key(bool preview) { // Arrange await ContentEditingService.DeleteAsync(PublishedTextPage.Key.Value, Constants.Security.SuperUserKey); // Act var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPage.Key.Value, preview); // Assert Assert.IsNull(textPage); } [Test] public async Task Can_Get_Published_Content_By_Id_After_Previous_Check_Where_Not_Found() { // Arrange var testPageKey = Guid.NewGuid(); // Act & Assert // - assert we cannot get the content that doesn't yet exist from the cache var testPage = await PublishedContentHybridCache.GetByIdAsync(testPageKey); Assert.IsNull(testPage); testPage = await PublishedContentHybridCache.GetByIdAsync(testPageKey); Assert.IsNull(testPage); // - create and publish the content var testPageContent = ContentEditingBuilder.CreateBasicContent(ContentType.Key, testPageKey); var createResult = await ContentEditingService.CreateAsync(testPageContent, Constants.Security.SuperUserKey); Assert.IsTrue(createResult.Success); var publishResult = await ContentPublishingService.PublishAsync(testPageKey, CultureAndSchedule, Constants.Security.SuperUserKey); Assert.IsTrue(publishResult.Success); // - assert we can now get the content from the cache testPage = await PublishedContentHybridCache.GetByIdAsync(testPageKey); Assert.IsNotNull(testPage); } [Test] public async Task Can_Get_Published_Content_By_Id_After_Previous_Exists_Check() { // Act var hasContentForTextPageCached = await DocumentCacheService.HasContentByIdAsync(PublishedTextPageId); Assert.IsTrue(hasContentForTextPageCached); var textPage = await PublishedContentHybridCache.GetByIdAsync(PublishedTextPageId); // Assert AssertPublishedTextPage(textPage); } [Test] public async Task Can_Do_Exists_Check_On_Created_Published_Content() { var testPageKey = Guid.NewGuid(); var testPageContent = ContentEditingBuilder.CreateBasicContent(ContentType.Key, testPageKey); var createResult = await ContentEditingService.CreateAsync(testPageContent, Constants.Security.SuperUserKey); Assert.IsTrue(createResult.Success); var publishResult = await ContentPublishingService.PublishAsync(testPageKey, CultureAndSchedule, Constants.Security.SuperUserKey); Assert.IsTrue(publishResult.Success); var testPage = await PublishedContentHybridCache.GetByIdAsync(testPageKey); Assert.IsNotNull(testPage); var hasContentForTextPageCached = await DocumentCacheService.HasContentByIdAsync(testPage.Id); Assert.IsTrue(hasContentForTextPageCached); } private void AssertTextPage(IPublishedContent textPage) { Assert.Multiple(() => { Assert.IsNotNull(textPage); Assert.AreEqual(Textpage.Key, textPage.Key); Assert.AreEqual(Textpage.ContentTypeKey, textPage.ContentType.Key); Assert.AreEqual(Textpage.Variants.Single().Name, textPage.Name); }); AssertProperties(Textpage.Properties, textPage.Properties); } private void AssertPublishedTextPage(IPublishedContent textPage) { Assert.Multiple(() => { Assert.IsNotNull(textPage); Assert.AreEqual(PublishedTextPage.Key, textPage.Key); Assert.AreEqual(PublishedTextPage.ContentTypeKey, textPage.ContentType.Key); Assert.AreEqual(PublishedTextPage.Variants.Single().Name, textPage.Name); }); AssertProperties(PublishedTextPage.Properties, textPage.Properties); } private void AssertProperties(IEnumerable propertyCollection, IEnumerable publishedProperties) { foreach (var prop in propertyCollection) { AssertProperty(prop, publishedProperties.First(x => x.Alias == prop.Alias)); } } private void AssertProperty(PropertyValueModel property, IPublishedProperty publishedProperty) { Assert.Multiple(() => { Assert.AreEqual(property.Alias, publishedProperty.Alias); Assert.AreEqual(property.Value, publishedProperty.GetSourceValue()); }); } }