using System.Text.Json.Nodes; using Eis.Infrastructure.Caching; namespace Eis.Infrastructure.Tests.Caching; public sealed class ApplicationCacheTests { [Fact] public async Task RememberJsonAsync_CoalescesConcurrentLocalLoads() { using var cache = new ApplicationCache(redisUrl: null); var calls = 0; var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); async Task Load() { Interlocked.Increment(ref calls); await release.Task; return new JsonObject { ["value"] = 42 }; } var first = cache.RememberJsonAsync("public", "home", Load); var second = cache.RememberJsonAsync("public", "home", Load); release.SetResult(); var values = await Task.WhenAll(first, second); Assert.Equal(1, calls); Assert.All(values, value => Assert.Equal(42, value["value"]!.GetValue())); } [Fact] public async Task InvalidateAsync_DropsLocalNamespaceWithoutAffectingOthers() { using var cache = new ApplicationCache(redisUrl: null); var publicCalls = 0; var resultCalls = 0; Task PublicLoader() => Task.FromResult(new JsonObject { ["generation"] = ++publicCalls }); Task ResultLoader() => Task.FromResult(new JsonObject { ["generation"] = ++resultCalls }); _ = await cache.RememberJsonAsync("public", "home", PublicLoader); _ = await cache.RememberJsonAsync("results", "candidate:1", ResultLoader); Assert.False(await cache.InvalidateAsync("public")); var publicValue = await cache.RememberJsonAsync("public", "home", PublicLoader); var resultValue = await cache.RememberJsonAsync("results", "candidate:1", ResultLoader); Assert.Equal(2, publicValue["generation"]!.GetValue()); Assert.Equal(1, resultValue["generation"]!.GetValue()); } [Fact] public async Task InvalidateAsync_PreventsInFlightLoadFromRepopulatingOldGeneration() { using var cache = new ApplicationCache(redisUrl: null); var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var calls = 0; async Task SlowLoader() { var value = Interlocked.Increment(ref calls); await release.Task; return new JsonObject { ["generation"] = value }; } var staleLoad = cache.RememberJsonAsync("public", "home", SlowLoader); _ = await cache.InvalidateAsync("public"); var refreshed = await cache.RememberJsonAsync( "public", "home", () => Task.FromResult(new JsonObject { ["generation"] = Interlocked.Increment(ref calls) })); release.SetResult(); _ = await staleLoad; Assert.Equal(2, refreshed["generation"]!.GetValue()); } }