diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs new file mode 100644 index 0000000000..3e20c00eae --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs @@ -0,0 +1,157 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +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; + +/// +/// Integration tests specifically for validating ContentService refactoring. +/// These tests establish behavioral baselines that must pass throughout the refactoring phases. +/// +[TestFixture] +[NonParallelizable] // Required: static notification handler state is shared across tests +[Category("Refactoring")] // v1.2: Added for easier test filtering during refactoring +[UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] +internal sealed class ContentServiceRefactoringTests : UmbracoIntegrationTestWithContent +{ + private IContentTypeService ContentTypeService => GetRequiredService(); + private IUserService UserService => GetRequiredService(); + + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler(); + + [SetUp] + public override void Setup() + { + base.Setup(); + RefactoringTestNotificationHandler.Reset(); + } + + [TearDown] + public void Teardown() + { + RefactoringTestNotificationHandler.Reset(); + } + + #region Notification Ordering Tests + + // Tests 1-2 will be added in Task 2 + + #endregion + + #region Sort Operation Tests + + // Tests 3-5 will be added in Task 3 + + #endregion + + #region DeleteOfType Tests + + // Tests 6-8 will be added in Task 4 + + #endregion + + #region Permission Tests + + // Tests 9-12 will be added in Task 5 + + #endregion + + #region Transaction Boundary Tests + + // Tests 13-15 will be added in Task 6 + + #endregion + + /// + /// Notification handler that tracks the order of notifications for test verification. + /// + internal sealed class RefactoringTestNotificationHandler : + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler, + INotificationHandler + { + private static readonly List _notificationOrder = new(); + private static readonly object _lock = new(); + + public static IReadOnlyList NotificationOrder + { + get + { + lock (_lock) + { + return _notificationOrder.ToList(); + } + } + } + + public static void Reset() + { + lock (_lock) + { + _notificationOrder.Clear(); + } + } + + private static void Record(string notificationType) + { + lock (_lock) + { + _notificationOrder.Add(notificationType); + } + } + + public void Handle(ContentSavingNotification notification) => Record(nameof(ContentSavingNotification)); + public void Handle(ContentSavedNotification notification) => Record(nameof(ContentSavedNotification)); + public void Handle(ContentPublishingNotification notification) => Record(nameof(ContentPublishingNotification)); + public void Handle(ContentPublishedNotification notification) => Record(nameof(ContentPublishedNotification)); + public void Handle(ContentUnpublishingNotification notification) => Record(nameof(ContentUnpublishingNotification)); + public void Handle(ContentUnpublishedNotification notification) => Record(nameof(ContentUnpublishedNotification)); + public void Handle(ContentMovingNotification notification) => Record(nameof(ContentMovingNotification)); + public void Handle(ContentMovedNotification notification) => Record(nameof(ContentMovedNotification)); + public void Handle(ContentMovingToRecycleBinNotification notification) => Record(nameof(ContentMovingToRecycleBinNotification)); + public void Handle(ContentMovedToRecycleBinNotification notification) => Record(nameof(ContentMovedToRecycleBinNotification)); + public void Handle(ContentSortingNotification notification) => Record(nameof(ContentSortingNotification)); + public void Handle(ContentSortedNotification notification) => Record(nameof(ContentSortedNotification)); + public void Handle(ContentDeletingNotification notification) => Record(nameof(ContentDeletingNotification)); + public void Handle(ContentDeletedNotification notification) => Record(nameof(ContentDeletedNotification)); + } +}