using System.Text.Json; using ZB.MOM.WW.CBDDC.Core.Cache; using ZB.MOM.WW.CBDDC.Core.Network; namespace ZB.MOM.WW.CBDDC.Core.Tests; public class DocumentCacheTests { /// /// Verifies cache hit/miss statistics after get and set operations. /// [Fact] public async Task GetAndSet_ShouldTrackCacheHitsAndMisses() { var cache = new DocumentCache(CreateConfigProvider(maxDocumentCacheSize: 2)); Document? missing = await cache.Get("users", "1"); missing.ShouldBeNull(); var document = CreateDocument("users", "1"); await cache.Set("users", "1", document); Document? hit = await cache.Get("users", "1"); hit.ShouldNotBeNull(); hit.Key.ShouldBe("1"); var stats = cache.GetStatistics(); stats.Hits.ShouldBe(1); stats.Misses.ShouldBe(1); stats.Size.ShouldBe(1); stats.HitRate.ShouldBe(0.5d); } /// /// Verifies least-recently-used eviction when cache capacity is reached. /// [Fact] public async Task Set_WhenCacheIsFull_EvictsLeastRecentlyUsedEntry() { var cache = new DocumentCache(CreateConfigProvider(maxDocumentCacheSize: 2)); await cache.Set("users", "1", CreateDocument("users", "1")); await cache.Set("users", "2", CreateDocument("users", "2")); // Touch key 1 so key 2 becomes the LRU entry. (await cache.Get("users", "1")).ShouldNotBeNull(); await cache.Set("users", "3", CreateDocument("users", "3")); (await cache.Get("users", "2")).ShouldBeNull(); (await cache.Get("users", "1")).ShouldNotBeNull(); (await cache.Get("users", "3")).ShouldNotBeNull(); } /// /// Verifies remove and clear operations delete entries from the cache. /// [Fact] public async Task RemoveAndClear_ShouldDeleteEntriesFromCache() { var cache = new DocumentCache(CreateConfigProvider(maxDocumentCacheSize: 3)); await cache.Set("users", "1", CreateDocument("users", "1")); await cache.Set("users", "2", CreateDocument("users", "2")); cache.GetStatistics().Size.ShouldBe(2); cache.Remove("users", "1"); (await cache.Get("users", "1")).ShouldBeNull(); cache.GetStatistics().Size.ShouldBe(1); cache.Clear(); cache.GetStatistics().Size.ShouldBe(0); } private static Document CreateDocument(string collection, string key) { using var json = JsonDocument.Parse("""{"name":"test"}"""); return new Document(collection, key, json.RootElement.Clone(), new HlcTimestamp(1, 0, "node-a"), false); } private static IPeerNodeConfigurationProvider CreateConfigProvider(int maxDocumentCacheSize) { var configProvider = Substitute.For(); configProvider.GetConfiguration().Returns(new PeerNodeConfiguration { MaxDocumentCacheSize = maxDocumentCacheSize }); return configProvider; } }