Files
jellyfin-multilang/tests/Jellyfin.Plugin.Multilang.Tests/ItemsProxyCacheTests.cs
T
ajp_anton e36775f1a3 Release 0.2.5: harden proxy and streamline metadata fetching
Remove obsolete rule formats, batch SQLite work, preserve artwork source URLs, and coordinate refresh workers with maintenance. Add regression coverage and document backup format changes.
2026-09-09 01:18:43 +00:00

133 lines
4.7 KiB
C#

using Jellyfin.Plugin.Multilang.Services;
namespace Jellyfin.Plugin.Multilang.Tests;
public sealed class ItemsProxyCacheTests
{
[Fact]
public void PolicyChangesInvalidateCachedDataAndOldInFlightWrites()
{
var cache = new ItemsProxyCache();
var generation = cache.ObserveUserPolicy("user", "all libraries");
Store(cache, "key");
Assert.Equal(generation, cache.ObserveUserPolicy("user", "all libraries"));
Assert.True(cache.TryGet("key", TimeSpan.FromMinutes(1), out _));
Assert.True(cache.ObserveUserPolicy("user", "no libraries") > generation);
Assert.False(cache.TryGet("key", TimeSpan.FromMinutes(1), out _));
Assert.False(cache.Store("key", "user", "/Items", 1, "body", "application/json", 1, 100, TimeSpan.FromMinutes(1), generation));
}
[Fact]
public void StoreRetrievesAndClearsCachedResponses()
{
var cache = new ItemsProxyCache();
Assert.True(Store(cache, "key"));
Assert.True(cache.TryGet("key", TimeSpan.FromMinutes(1), out var response));
Assert.Equal("body-key", response.Body);
Assert.Equal(1, response.ItemCount);
cache.ClearAll();
Assert.False(cache.TryGet("key", TimeSpan.FromMinutes(1), out _));
}
[Fact]
public void MicroCacheServesFastResponsesAndIsInvalidatedWithTheMainCache()
{
var cache = new ItemsProxyCache();
Assert.True(cache.StoreMicro("key", "user", "/Items", 1, "micro", "application/json", 1, 1024));
Assert.True(cache.TryGet("key", TimeSpan.FromMinutes(1), out var response));
Assert.Equal("micro", response.Body);
cache.ClearAll();
Assert.False(cache.TryGet("key", TimeSpan.FromMinutes(1), out _));
}
[Fact]
public void StoreEvictsTheOldestEntryWhenCapacityIsExceeded()
{
var cache = new ItemsProxyCache();
Assert.True(Store(cache, "first", body: "1111", maxBytes: 6));
Thread.Sleep(10);
Assert.True(Store(cache, "second", body: "2222", maxBytes: 6));
Assert.False(cache.TryGet("first", TimeSpan.FromMinutes(1), out _));
Assert.True(cache.TryGet("second", TimeSpan.FromMinutes(1), out _));
}
[Fact]
public void StoreEntriesExpireAtTheConfiguredTtl()
{
var cache = new ItemsProxyCache();
Assert.True(Store(cache, "key", ttl: TimeSpan.FromMilliseconds(1)));
Thread.Sleep(20);
Assert.False(cache.TryGet("key", TimeSpan.FromMilliseconds(1), out _));
}
[Fact]
public void StoreRejectsResponsesLargerThanTheConfiguredLimit()
{
var cache = new ItemsProxyCache();
Assert.False(Store(cache, "key", body: "12345", maxBytes: 4));
Assert.False(cache.TryGet("key", TimeSpan.FromMinutes(1), out _));
}
private static bool Store(
ItemsProxyCache cache,
string key,
int itemCount = 1,
string? body = null,
long maxBytes = 1024,
TimeSpan? ttl = null)
=> cache.Store(
key,
"user",
"/Items",
itemCount,
body ?? "body-" + key,
"application/json",
100,
maxBytes,
ttl ?? TimeSpan.FromMinutes(1));
[Fact]
public void MicroAndMainEntriesShareOneBudget()
{
var cache = new ItemsProxyCache();
Assert.True(Store(cache, "main", body: "1111", maxBytes: 6));
Assert.True(cache.StoreMicro("micro1", "user", "/Items", 1, "2222", "application/json", 1, 6));
Assert.False(cache.TryGet("main", TimeSpan.FromMinutes(1), out _));
Assert.True(cache.StoreMicro("micro2", "user", "/Items", 1, "3333", "application/json", 1, 6));
Assert.False(cache.TryGet("micro1", TimeSpan.FromMinutes(1), out _));
Assert.True(cache.TryGet("micro2", TimeSpan.FromMinutes(1), out _));
}
[Fact]
public void InvalidationRejectsStaleInFlightWrites()
{
var cache = new ItemsProxyCache();
var generation = cache.Generation;
cache.ClearAll();
Assert.False(cache.Store("key", "user", "/Items", 1, "body", "application/json", 1, 100, TimeSpan.FromMinutes(1), generation));
Assert.False(cache.StoreMicro("key", "user", "/Items", 1, "body", "application/json", 1, 100, generation));
}
[Fact]
public void ClearingOneUserPreservesOtherUsersCachedResponses()
{
var cache = new ItemsProxyCache();
Store(cache, "one");
cache.Store("two", "other", "/Items", 1, "body", "application/json", 1, 100, TimeSpan.FromMinutes(1));
cache.ClearUser("user");
Assert.False(cache.TryGet("one", TimeSpan.FromMinutes(1), out _));
Assert.True(cache.TryGet("two", TimeSpan.FromMinutes(1), out _));
}
}