diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 85c0aaeb2a..405152917d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1378,6 +1378,11 @@ public class DocumentRepository : ContentRepositoryBase(entity.Key)); + // troubleshooting //if (Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.DocumentVersion} JOIN {Constants.DatabaseSchema.Tables.ContentVersion} ON {Constants.DatabaseSchema.Tables.DocumentVersion}.id={Constants.DatabaseSchema.Tables.ContentVersion}.id WHERE published=1 AND nodeId=" + content.Id) > 1) //{ diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index 654ea8bb54..52657a21e0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -541,6 +541,11 @@ public class MediaRepository : ContentRepositoryBase(entity.Key)); } protected override void PersistDeletedItem(IMedia entity) diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceNotificationWithCacheTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceNotificationWithCacheTests.cs new file mode 100644 index 0000000000..8bfe6859e7 --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceNotificationWithCacheTests.cs @@ -0,0 +1,148 @@ +using Microsoft.Extensions.DependencyInjection; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services; + +[TestFixture] +[UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] +internal sealed class ContentServiceNotificationWithCacheTests : UmbracoIntegrationTest +{ + private IContentType _contentType; + + private IContentTypeService ContentTypeService => GetRequiredService(); + + private IContentService ContentService => GetRequiredService(); + + private IContentEditingService ContentEditingService => GetRequiredService(); + + protected override void ConfigureTestServices(IServiceCollection services) + => services.AddSingleton(AppCaches.Create(Mock.Of())); + + [SetUp] + public async Task SetupTest() + { + ContentRepositoryBase.ThrowOnWarning = true; + + _contentType = ContentTypeBuilder.CreateBasicContentType(); + _contentType.AllowedAsRoot = true; + await ContentTypeService.CreateAsync(_contentType, Constants.Security.SuperUserKey); + } + + [TearDown] + public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false; + + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder + .AddNotificationHandler() + .AddNotificationHandler(); + + [Test] + public async Task Saving_Saved_Get_Value() + { + var createAttempt = await ContentEditingService.CreateAsync( + new ContentCreateModel + { + ContentTypeKey = _contentType.Key, + Variants = [ + new() { Name = "Initial name" } + ], + }, + Constants.Security.SuperUserKey); + + Assert.Multiple(() => + { + Assert.IsTrue(createAttempt.Success); + Assert.IsNotNull(createAttempt.Result.Content); + }); + + var savingWasCalled = false; + var savedWasCalled = false; + + ContentNotificationHandler.SavingContent = notification => + { + savingWasCalled = true; + + var saved = notification.SavedEntities.First(); + var documentById = ContentService.GetById(saved.Id)!; + var documentByKey = ContentService.GetById(saved.Key)!; + + Assert.Multiple(() => + { + Assert.AreEqual("Updated name", saved.Name); + Assert.AreEqual("Initial name", documentById.Name); + Assert.AreEqual("Initial name", documentByKey.Name); + }); + }; + + ContentNotificationHandler.SavedContent = notification => + { + savedWasCalled = true; + + var saved = notification.SavedEntities.First(); + var documentById = ContentService.GetById(saved.Id)!; + var documentByKey = ContentService.GetById(saved.Key)!; + + Assert.Multiple(() => + { + Assert.AreEqual("Updated name", saved.Name); + Assert.AreEqual("Updated name", documentById.Name); + Assert.AreEqual("Updated name", documentByKey.Name); + }); + }; + + try + { + var updateAttempt = await ContentEditingService.UpdateAsync( + createAttempt.Result.Content!.Key, + new ContentUpdateModel + { + Variants = [ + new() { Name = "Updated name" } + ], + }, + Constants.Security.SuperUserKey); + + Assert.Multiple(() => + { + Assert.IsTrue(updateAttempt.Success); + Assert.IsNotNull(updateAttempt.Result.Content); + }); + + Assert.IsTrue(savingWasCalled); + Assert.IsTrue(savedWasCalled); + } + finally + { + ContentNotificationHandler.SavingContent = null; + ContentNotificationHandler.SavedContent = null; + } + } + + internal sealed class ContentNotificationHandler : + INotificationHandler, + INotificationHandler + { + public static Action? SavingContent { get; set; } + + public static Action? SavedContent { get; set; } + + public void Handle(ContentSavedNotification notification) => SavedContent?.Invoke(notification); + + public void Handle(ContentSavingNotification notification) => SavingContent?.Invoke(notification); + } +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceNotificationWithCacheTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceNotificationWithCacheTests.cs new file mode 100644 index 0000000000..d4de99daba --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceNotificationWithCacheTests.cs @@ -0,0 +1,146 @@ +using Microsoft.Extensions.DependencyInjection; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services; + +[TestFixture] +[UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] +internal sealed class MediaServiceNotificationWithCacheTests : UmbracoIntegrationTest +{ + private IMediaType _mediaType; + + private IMediaTypeService MediaTypeService => GetRequiredService(); + + private IMediaService MediaService => GetRequiredService(); + + private IMediaEditingService MediaEditingService => GetRequiredService(); + + protected override void ConfigureTestServices(IServiceCollection services) + => services.AddSingleton(AppCaches.Create(Mock.Of())); + + [SetUp] + public void SetupTest() + { + ContentRepositoryBase.ThrowOnWarning = true; + + _mediaType = MediaTypeService.Get("folder") + ?? throw new ApplicationException("Could not find the \"folder\" media type"); + } + + [TearDown] + public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false; + + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder + .AddNotificationHandler() + .AddNotificationHandler(); + + [Test] + public async Task Saving_Saved_Get_Value() + { + var createAttempt = await MediaEditingService.CreateAsync( + new MediaCreateModel + { + ContentTypeKey = _mediaType.Key, + Variants = [ + new() { Name = "Initial name" } + ], + }, + Constants.Security.SuperUserKey); + + Assert.Multiple(() => + { + Assert.IsTrue(createAttempt.Success); + Assert.IsNotNull(createAttempt.Result.Content); + }); + + var savingWasCalled = false; + var savedWasCalled = false; + + MediaNotificationHandler.SavingMedia = notification => + { + savingWasCalled = true; + + var saved = notification.SavedEntities.First(); + var documentById = MediaService.GetById(saved.Id)!; + var documentByKey = MediaService.GetById(saved.Key)!; + + Assert.Multiple(() => + { + Assert.AreEqual("Updated name", saved.Name); + Assert.AreEqual("Initial name", documentById.Name); + Assert.AreEqual("Initial name", documentByKey.Name); + }); + }; + + MediaNotificationHandler.SavedMedia = notification => + { + savedWasCalled = true; + + var saved = notification.SavedEntities.First(); + var documentById = MediaService.GetById(saved.Id)!; + var documentByKey = MediaService.GetById(saved.Key)!; + + Assert.Multiple(() => + { + Assert.AreEqual("Updated name", saved.Name); + Assert.AreEqual("Updated name", documentById.Name); + Assert.AreEqual("Updated name", documentByKey.Name); + }); + }; + + try + { + var updateAttempt = await MediaEditingService.UpdateAsync( + createAttempt.Result.Content!.Key, + new MediaUpdateModel + { + Variants = [ + new() { Name = "Updated name" } + ], + }, + Constants.Security.SuperUserKey); + + Assert.Multiple(() => + { + Assert.IsTrue(updateAttempt.Success); + Assert.IsNotNull(updateAttempt.Result.Content); + }); + + Assert.IsTrue(savingWasCalled); + Assert.IsTrue(savedWasCalled); + } + finally + { + MediaNotificationHandler.SavingMedia = null; + MediaNotificationHandler.SavedMedia = null; + } + } + + internal sealed class MediaNotificationHandler : + INotificationHandler, + INotificationHandler + { + public static Action? SavingMedia { get; set; } + + public static Action? SavedMedia { get; set; } + + public void Handle(MediaSavedNotification notification) => SavedMedia?.Invoke(notification); + + public void Handle(MediaSavingNotification notification) => SavingMedia?.Invoke(notification); + } +}