using Microsoft.Extensions.Hosting; using Moq; using OwnerNumberMigration; using OwnerNumberMigration.Migrations; using OwnerNumberMigration.ValueParsing; using OwnerNumberMigrationTest.TestDoubles; namespace OwnerNumberMigrationTest.Migrations; public abstract class AttributeMigrationTaskTest { protected abstract IHostedService MigrationTaskFactory ( AttributeMigrationFactory factory, IParsingStrategyFactory strategyFactory, IMigrationManager manager ); private IHostedService MigrationServiceFactory() => MigrationTaskFactory ( (_, _, _) => _migration.Object, StrategyFactory.Object, _manager.Object ); protected abstract string SourceAttribute { get; } protected abstract string DestinationAttribute { get; } protected readonly Mock StrategyFactory = new(); private readonly FakeParsingStrategy _parsingStrategy; private readonly Mock _migration = new(); private readonly Mock _manager = new(); protected AttributeMigrationTaskTest(Func newT) { _parsingStrategy = new FakeParsingStrategy(newT); } [SetUp] public void SetUp() { StrategyFactory .Setup(f => f.CreateParsingStrategy(SourceAttribute)) .Returns((IValueParsingStrategy)_parsingStrategy); _migration.Reset(); } [Test] public void Constructor_AllCases_CreatesMigrationWithJobTypeAttributes() { string? sourceAttribute = null; string? destinationAttribute = null; IValueParsingStrategy? parsingStrategy = null; MigrationTaskFactory ( (source, strategy, destination) => { sourceAttribute = source; parsingStrategy = strategy; destinationAttribute = destination; return _migration.Object; }, StrategyFactory.Object, _manager.Object ); Assert.AreEqual(SourceAttribute, sourceAttribute); Assert.AreSame(_parsingStrategy, parsingStrategy); Assert.AreEqual(DestinationAttribute, destinationAttribute); } [Test] public async Task StartAsync_TokenCancelled_DoesNotStartMigration() { var cancellation = new CancellationToken(true); var migration = MigrationServiceFactory(); await migration.StartAsync(cancellation); _migration.Verify(m => m.Migrate(It.IsAny()), Times.Never); } [Test] public async Task StartAsync_NotCanceled_StartsMigrationTaskAndReturns() { var cancellation = new CancellationToken(); _migration .Setup(m => m.Migrate(It.IsAny())) .Returns(async token => { await Task.Delay(TimeSpan.MaxValue, token); } ); var migration = MigrationServiceFactory(); await migration.StartAsync(cancellation); _migration.Verify(m => m.Migrate(It.IsAny()), Times.Once); } [Test] public async Task StartAsync_NotCanceled_RegistersMigrationTaskWithManager() { var cancellation = new CancellationToken(); var migrationTask = Task.Run(() => { }); _migration .Setup(m => m.Migrate(It.IsAny())) .Returns(migrationTask); var migration = MigrationServiceFactory(); await migration.StartAsync(cancellation); _manager.Verify(m => m.Start(migrationTask), Times.Once); } [Test] public async Task StopAsync_NotStarted_ReturnsWithoutError() { var cancellation = new CancellationToken(); var migration = MigrationServiceFactory(); Assert.DoesNotThrowAsync(() => migration.StopAsync(cancellation)); } [Test] public async Task StopAsync_AlreadyCompleted_CleansUpMigrationTask() { var cancellation = new CancellationToken(); Task? migrationTask = null; _migration .Setup(m => m.Migrate(It.IsAny())) .Returns(token => migrationTask = Task.Run ( () => { }, token )); var migration = MigrationServiceFactory(); await migration.StartAsync(cancellation); await migrationTask; await migration.StopAsync(cancellation); Assert.AreEqual(TaskStatus.RanToCompletion, migrationTask.Status); } [Test] public async Task StopAsync_NotCompleted_CancelsMigrationTaskThenCleansUp() { var cancellation = new CancellationToken(); Task? migrationTask = null; _migration .Setup(m => m.Migrate(It.IsAny())) .Returns(token => migrationTask = Task.Run ( async () => { await Task.Delay(-1, token); }, token )); var migration = MigrationServiceFactory(); await migration.StartAsync(cancellation); await migration.StopAsync(cancellation); Assert.AreEqual(TaskStatus.Canceled, migrationTask.Status); } }