Files
2026-03-13 09:11:35 -05:00

201 lines
7.4 KiB
C#

using LCU.API.Internal.DocumentLib.Containers;
using MongoDB.Driver;
using OwnerNumberMigration;
using OwnerNumberMigrationTest.TestDataFactories;
using OwnerNumberMigrationTest.TestDoubles;
namespace OwnerNumberMigrationTest;
public class AttributeMigrationTest : IDisposable
{
private readonly IAttributeMigration _migration;
private readonly string _attributeName = Guid.NewGuid().ToString();
private const string DestinationProperty = nameof(DocumentInformation.PersonNumbers);
private string[] GetDestinationProperty(DocumentInformation document) => (string[])typeof(DocumentInformation).GetProperty(DestinationProperty)!.GetValue(document)!;
private readonly FakeMongoCollectionFactory _collectionFactory = new();
private readonly FakeParsingStrategy<string[]> _parsingStrategy = new(Array.Empty<string>);
private readonly FakeMigrationObserver _observer = new();
private readonly FakeDocumentFilterFactory _filterFactory = new();
public AttributeMigrationTest()
{
_migration = new AttributeMigration<string[]>
(
_collectionFactory,
_attributeName,
_parsingStrategy,
DestinationProperty,
_observer,
_filterFactory
);
}
[Test]
public async Task Migrate_AlreadyCancelled_ReturnsImmediately()
{
var cancellation = new CancellationTokenSource();
cancellation.Cancel();
var document = await MigrateableDocumentFactory();
await _migration.Migrate(cancellation.Token);
var documentRecord = (await _collectionFactory
.GetCollection<DocumentInformation>()
.FindAsync(Builders<DocumentInformation>.Filter.Eq(d => d.DocumentId, document.DocumentId)))
.Single();
var unmigratedDestinationProperty = GetDestinationProperty(document);
var migratedDestinationProperty = GetDestinationProperty(documentRecord);
CollectionAssert.AreEquivalent(unmigratedDestinationProperty, migratedDestinationProperty);
}
[Test]
public void Migrate_DocumentInformationMissingDestination_ThrowsException()
{
var migration = new AttributeMigration<string[]>
(
_collectionFactory,
_attributeName,
_parsingStrategy,
Guid.NewGuid().ToString(),
_observer,
_filterFactory
);
Assert.ThrowsAsync<InvalidOperationException>(() => migration.Migrate(new CancellationToken()));
}
[Test]
public void Migrate_DocumentInformationMissingDestination_NotifiesObserver()
{
var migration = new AttributeMigration<string[]>
(
_collectionFactory,
_attributeName,
_parsingStrategy,
Guid.NewGuid().ToString(),
_observer,
_filterFactory
);
var thrown = Assert.ThrowsAsync<InvalidOperationException>(() => migration.Migrate(new CancellationToken()));
Assert.Contains(thrown, _observer.Errors);
}
[Test]
public async Task Migrate_DocumentInformationMissingDestination_DoesNotMigrate()
{
var document = await MigrateableDocumentFactory();
var migration = new AttributeMigration<string[]>
(
_collectionFactory,
_attributeName,
_parsingStrategy,
Guid.NewGuid().ToString(),
_observer,
_filterFactory
);
Assert.ThrowsAsync<InvalidOperationException>(() => migration.Migrate(new CancellationToken()));
var documentRecord = (await _collectionFactory
.GetCollection<DocumentInformation>()
.FindAsync(Builders<DocumentInformation>.Filter.Eq(d => d.DocumentId, document.DocumentId)))
.Single();
var unmigratedDestinationProperty = GetDestinationProperty(document);
var migratedDestinationProperty = GetDestinationProperty(documentRecord);
CollectionAssert.AreEquivalent(unmigratedDestinationProperty, migratedDestinationProperty);
}
[Test]
public async Task Migrate_NotCancelled_NotifiesObserverOfDocument()
{
var document = await MigrateableDocumentFactory();
await _migration.Migrate(new CancellationToken());
var documentsStartedMigrating = _observer.Documents.Select(d => d.doc.DocumentId);
CollectionAssert.Contains(documentsStartedMigrating, document.DocumentId);
}
[Test]
public async Task Migrate_NotCancelled_MovesValueFromParseStrategyIntoDestinationAndSaves()
{
var document = await MigrateableDocumentFactory();
var parsedOwners = _parsingStrategy.Values[document.Attributes[_attributeName]] =
new[]
{
Guid.NewGuid().ToString(),
Guid.NewGuid().ToString()
};
await _migration.Migrate(new CancellationToken());
var documentRecord = (await _collectionFactory
.GetCollection<DocumentInformation>()
.FindAsync(Builders<DocumentInformation>.Filter.Eq(d => d.DocumentId, document.DocumentId)))
.Single();
var migratedDestinationProperty = GetDestinationProperty(documentRecord);
CollectionAssert.AreEquivalent(parsedOwners, migratedDestinationProperty);
}
[Test]
public async Task Migrate_AfterDocumentMigrates_NotifiesObserver()
{
var document = await MigrateableDocumentFactory();
await _migration.Migrate(new CancellationToken());
var ended = DateTime.Now;
var migrationStart = _observer.Documents
.Where(d => d.doc.DocumentId == document.DocumentId)
.Select(d => d.started)
.Single();
Assert.AreEqual(1, _observer.Completions.Count);
var migrationCompleted = _observer.Completions.Single();
Assert.That(migrationCompleted, Is.InRange(migrationStart, ended));
}
[Test]
public async Task Migrate_TooManyRequests_SleepsForIndicatedTimeThenResumes()
{
var document = await MigrateableDocumentFactory();
var parsedOwners = _parsingStrategy.Values[document.Attributes[_attributeName]] =
new[]
{
Guid.NewGuid().ToString(),
Guid.NewGuid().ToString()
};
_collectionFactory.TooManyRequestsOnWriteFor = TimeSpan.FromMilliseconds(25);
await _migration.Migrate(new CancellationToken());
_collectionFactory.TooManyRequestsOnWriteFor = null;
var documentRecord = (await _collectionFactory
.GetCollection<DocumentInformation>()
.FindAsync(Builders<DocumentInformation>.Filter.Eq(d => d.DocumentId, document.DocumentId)))
.Single();
var migratedDestinationProperty = GetDestinationProperty(documentRecord);
CollectionAssert.AreEquivalent(parsedOwners, migratedDestinationProperty);
}
private async Task<DocumentInformation> MigrateableDocumentFactory()
{
var document = DocumentInformationFactory.CreateDocumentInformation();
document.Attributes[_attributeName] = Guid.NewGuid().ToString();
_filterFactory.ApplicableDocuments[(_attributeName, DestinationProperty)] = new[] { document };
await _collectionFactory
.GetCollection<DocumentInformation>()
.InsertOneAsync(document);
return document;
}
public void Dispose()
{
_collectionFactory.Dispose();
}
}