mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 23:52:50 -05:00
[PM-5518] Sql-backed IDistributedCache (#3791)
* Sql-backed IDistributedCache * sqlserver cache table * remove unused using * setup EF entity * cache indexes * add back cipher * revert SetupEntityFramework change * ef cache * EntityFrameworkCache * IServiceScopeFactory for db context * implement EntityFrameworkCache * move to _serviceScopeFactory * move to config file * ef migrations * fixes * datetime and error codes * revert migrations * migrations * format * static and namespace fix * use time provider * Move SQL migration and remove EF one for the moment * Add clean migration of just the new table * Formatting * Test Custom `IDistributedCache` Implementation * Add Back Logging * Remove Double Logging * Skip Test When Not EntityFrameworkCache * Format --------- Co-authored-by: Matt Bishop <mbishop@bitwarden.com> Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
This commit is contained in:
71
test/Infrastructure.IntegrationTest/DistributedCacheTests.cs
Normal file
71
test/Infrastructure.IntegrationTest/DistributedCacheTests.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using Bit.Infrastructure.EntityFramework;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Infrastructure.IntegrationTest;
|
||||
|
||||
public class DistributedCacheTests
|
||||
{
|
||||
[DatabaseTheory, DatabaseData(UseFakeTimeProvider = true)]
|
||||
public async Task Simple_NotExpiredItem_StartsScan(IDistributedCache cache, TimeProvider timeProvider)
|
||||
{
|
||||
if (cache is not EntityFrameworkCache efCache)
|
||||
{
|
||||
// We don't write the SqlServer cache implementation so we don't need to test it
|
||||
// also it doesn't use TimeProvider under the hood so we'd have to delay the test
|
||||
// for 30 minutes to get it to work. So just skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
var fakeTimeProvider = (FakeTimeProvider)timeProvider;
|
||||
|
||||
cache.Set("test-key", "some-value"u8.ToArray(), new DistributedCacheEntryOptions
|
||||
{
|
||||
SlidingExpiration = TimeSpan.FromMinutes(20),
|
||||
});
|
||||
|
||||
// Should have expired and not be returned
|
||||
var firstValue = cache.Get("test-key");
|
||||
|
||||
// Scan for expired items is supposed to run every 30 minutes
|
||||
fakeTimeProvider.Advance(TimeSpan.FromMinutes(31));
|
||||
|
||||
var secondValue = cache.Get("test-key");
|
||||
|
||||
// This should have forced the EF cache to start a scan task
|
||||
Assert.NotNull(efCache.scanTask);
|
||||
// We don't want the scan task to throw an exception, unwrap it.
|
||||
await efCache.scanTask;
|
||||
|
||||
Assert.NotNull(firstValue);
|
||||
Assert.Null(secondValue);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData(UseFakeTimeProvider = true)]
|
||||
public async Task ParallelReadsAndWrites_Work(IDistributedCache cache, TimeProvider timeProvider)
|
||||
{
|
||||
var fakeTimeProvider = (FakeTimeProvider)timeProvider;
|
||||
|
||||
await Parallel.ForEachAsync(Enumerable.Range(1, 100), async (index, _) =>
|
||||
{
|
||||
await cache.SetAsync($"test-{index}", "some-value"u8.ToArray(), new DistributedCacheEntryOptions
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(index),
|
||||
});
|
||||
});
|
||||
|
||||
await Parallel.ForEachAsync(Enumerable.Range(1, 100), async (index, _) =>
|
||||
{
|
||||
var value = await cache.GetAsync($"test-{index}");
|
||||
Assert.NotNull(value);
|
||||
});
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task MultipleWritesOnSameKey_ShouldNotThrow(IDistributedCache cache)
|
||||
{
|
||||
await cache.SetAsync("test-duplicate", "some-value"u8.ToArray());
|
||||
await cache.SetAsync("test-duplicate", "some-value"u8.ToArray());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user