using ZB.MOM.WW.CBDD.Bson; using ZB.MOM.WW.CBDD.Core.Collections; using ZB.MOM.WW.CBDD.Core.Indexing; using ZB.MOM.WW.CBDD.Core.Storage; using ZB.MOM.WW.CBDD.Core.Transactions; using ZB.MOM.WW.CBDD.Shared; using ZB.MOM.WW.CBDD.Shared.TestDbContext_TestDbContext_Mappers; using Xunit; namespace ZB.MOM.WW.CBDD.Tests; public class MetadataPersistenceTests : IDisposable { private readonly string _dbPath; private readonly string _walPath; /// /// Initializes a new instance of the class. /// public MetadataPersistenceTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"docdb_meta_{Guid.NewGuid()}.db"); _walPath = Path.ChangeExtension(_dbPath, ".wal"); } /// /// Tests index definitions are persisted and reloaded. /// [Fact] public void IndexDefinitions_ArePersisted_AndReloaded() { // 1. Create index in first session using (var storage = new StorageEngine(_dbPath, PageFileConfig.Default)) { // Disable auto-checkpoint to ensure cleaner test tracing, though not strictly required var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper(); var indexManager = new CollectionIndexManager(storage, mapper, nameof(User)); // Create 2 indexes indexManager.CreateIndex(u => u.Age, "idx_age"); indexManager.CreateIndex(u => u.Name, unique: true); // name auto-generated } // 2. Re-open storage and verify indexes exist using (var storage = new StorageEngine(_dbPath, PageFileConfig.Default)) { var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper(); // Assuming Page 1 was allocated above in clean DB var indexManager = new CollectionIndexManager(storage, mapper, nameof(User)); var indexes = indexManager.GetAllIndexes().ToList(); indexes.Count.ShouldBe(2); var ageIdx = indexManager.GetIndex("idx_age"); ageIdx.ShouldNotBeNull(); ageIdx.Definition.IsUnique.ShouldBeFalse(); ageIdx.Definition.PropertyPaths.Count().ShouldBe(1); ageIdx.Definition.PropertyPaths[0].ShouldBe("Age"); // Check auto-generated name index var nameIdx = indexes.FirstOrDefault(i => i.Definition.PropertyPaths[0] == "Name"); nameIdx.ShouldNotBeNull(); nameIdx.Definition.IsUnique.ShouldBeTrue(); } } /// /// Tests ensure index does not recreate if index exists. /// [Fact] public void EnsureIndex_DoesNotRecreate_IfIndexExists() { // 1. Create index using (var context = new Shared.TestDbContext(_dbPath)) { context.Users.EnsureIndex(u => u.Age); } // 2. Re-open and EnsureIndex again - should be fast/no-op using (var context = new Shared.TestDbContext(_dbPath)) { var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper(); // Use reflection or diagnostic to check if it triggered rebuild? // Currently hard to verify "no rebuild" without logs or mocking. // But we can verify it doesn't throw and index is still valid. var idx = context.Users.EnsureIndex(u => u.Age); idx.ShouldNotBeNull(); // Verify functioning using var txn = context.BeginTransaction(); context.Users.Insert(new User { Name = "Bob", Age = 50 }); txn.Commit(); // Should find it via index var results = context.Users.Find(u => u.Age == 50).ToList(); results.Count().ShouldBe(1); } } /// /// Disposes the resources used by this instance. /// public void Dispose() { if (File.Exists(_dbPath)) File.Delete(_dbPath); if (File.Exists(_walPath)) File.Delete(_walPath); } }