using adas_core.Domain.Enums; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.MongoModels; using adas_core.Infrastructure.Migrations.MongoMigrations; using adas_core.Infrastructure.Repositories; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using MongoMigrations.Core; using Options = Microsoft.Extensions.Options.Options; namespace adas_core.Test.Repositories; /// /// Integration test fixture that verifies MongoDB migration behavior. /// /// /// Marked with and using the "Integration" category to group it with other integration-level tests. /// /// [TestFixture] [Category("Integration")] public class MongodbMigrationTest { private PatientRepository _repository; private IOptions _optionsApiSettings; private readonly ApiSettings _apiSettings = new() { ArchivePatientsDiagnosis = "patients" }; private static readonly DateTime Now = DateTime.Now; private static readonly ObjectId PatientId = ObjectId.GenerateNewId(); /// /// Performs one-time initialization for the test fixture by dropping and recreating the "patients" collection, instantiating the PatientRepository, and seeding it with three test Patient records (one of which has a discharge time set to the current time) to verify they are persisted. /// [OneTimeSetUp] public async Task Init() { _optionsApiSettings = Options.Create(_apiSettings); await IntegrationDb.Database.DropCollectionAsync("patients"); await IntegrationDb.Database.CreateCollectionAsync("patients"); _repository = new PatientRepository(_optionsApiSettings, IntegrationDb.Database); var patients = new List { new () { Id = PatientId, PatientId = "patientId1", PointOfCareId = ObjectId.GenerateNewId(), Bed = "bed1", PatientNumber = "patientNumber1", Person = new Person { FirstName = "firstName1", LastName = "lastName1", BirthDate = new DateTime(), Gender = PatientEnum.Gender.Male }, DisTime = Now }, new () { PatientId = "patientId2", PointOfCareId = ObjectId.GenerateNewId(), Bed = "bed2", PatientNumber = "patientNumber2", Person = new Person { FirstName = "firstName2", LastName = "lastName2", BirthDate = new DateTime(), Gender = PatientEnum.Gender.Male } }, new () { PatientId = "patientId3", PointOfCareId = ObjectId.GenerateNewId(), Bed = "bed3", PatientNumber = "patientNumber3", Person = new Person { FirstName = "firstName3", LastName = "lastName3", BirthDate = new DateTime(), Gender = PatientEnum.Gender.Male } } }; await _repository.InsertManyAsync(patients); Assert.That(await _repository.Collection.CountDocumentsAsync(_ => true), Is.EqualTo(3)); } /// /// Performs one-time cleanup after integration tests by dropping the patients and __migrations collections from the integration database, ensuring a clean state for subsequent test runs. /// [OneTimeTearDown] public void Teardown() { IntegrationDb.Database.DropCollection("patients"); IntegrationDb.Database.DropCollection("__migrations"); } /// /// Verifies that the database is detected as outdated by creating a runner and asserting that IsDatabaseUpToDate returns false when using the primary read preference. /// [Test] [Order(1)] public void IsDatabaseOutdated_ShouldReturnTrue() { var runner = CreateRunner(); var isUpToDate = runner.IsDatabaseUpToDate(ReadPreference.Primary); Assert.That(isUpToDate, Is.False); } /// /// Verifies that after running the migration update to the latest version, the migration with ID 10 (version 0.1.0) is present among the applied migrations. /// [Test] [Order(2)] public void AfterUpdateToLatest_MigrationShouldBeApplied() { var runner = CreateRunner(); runner.UpdateToLatest(); var ids = GetAppliedMigrationIds(); Assert.That(ids, Does.Contain(10)); // 0.1.0 } /// /// Verifies that running migrations twice via the runner is idempotent and does not fail, and that the migration identified by id 10 remains present in the applied set returned by GetAppliedMigrationIds after the second UpdateToLatest execution. /// /// [Test] public void RunningMigrationsTwice_ShouldNotFail() { var runner = CreateRunner(); runner.UpdateToLatest(); runner.UpdateToLatest(); // segunda ejecución var ids = GetAppliedMigrationIds(); Assert.That(ids, Does.Contain(10)); } // Helpers /// /// Creates and configures a for executing database migrations, using a locator that scans the assembly containing the patient data update migration. /// /// A configured bound to the integration database and the migrations collection. private MigrationRunner CreateRunner() { var locator = new MigrationLocator(); locator.LookForMigrationsInAssembly(typeof(U_0_1_0_UpdateDataPatien).Assembly); return new MigrationRunner( IntegrationDb.Database, collectionName: "__migrations", migrationLocator: locator ); } /// /// Retrieves the identifiers of all applied migrations from the "__migrations" collection in the integration database. /// /// A list of migration identifiers extracted from the "_id" field of each migration document. private List GetAppliedMigrationIds() { var collection = IntegrationDb.Database.GetCollection("__migrations"); return collection .Find(FilterDefinition.Empty) .ToList() .Select(d => d["_id"].AsInt32) .ToList(); } }