From 5c871da8d8da959f55563f5059616d4a4a47f6e2 Mon Sep 17 00:00:00 2001 From: Shyam Namboodiripad Date: Wed, 7 May 2025 19:06:17 -0700 Subject: [PATCH] Remove CacheOptions from DiskBasedResponseCache Fixes #6387 --- .../Storage/AzureStorageResponseCache.cs | 2 +- .../CSharp/Defaults.cs | 6 +- .../CSharp/JsonSerialization/JsonUtilities.cs | 4 - .../DiskBasedResponseCache.CacheMode.cs | 31 ----- .../DiskBasedResponseCache.CacheOptions.cs | 90 -------------- .../CSharp/Storage/DiskBasedResponseCache.cs | 111 +++++------------- .../Storage/DiskBasedResponseCacheProvider.cs | 16 ++- .../CacheOptionsTests.cs | 73 ------------ .../ResponseCacheTester.cs | 5 +- 9 files changed, 49 insertions(+), 289 deletions(-) delete mode 100644 src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheMode.cs delete mode 100644 src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheOptions.cs delete mode 100644 test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/CacheOptionsTests.cs diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Storage/AzureStorageResponseCache.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Storage/AzureStorageResponseCache.cs index f7115a37024..5e83b456a0b 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Storage/AzureStorageResponseCache.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Storage/AzureStorageResponseCache.cs @@ -40,9 +40,9 @@ internal sealed partial class AzureStorageResponseCache( private const string EntryAndContentsFilesNotFound = "Cache entry file {0} and contents file {1} were not found."; private readonly string _iterationPath = $"cache/{scenarioName}/{iterationName}"; + private readonly Func _provideDateTime = provideDateTime; private readonly TimeSpan _timeToLiveForCacheEntries = timeToLiveForCacheEntries ?? Defaults.DefaultTimeToLiveForCacheEntries; - private readonly Func _provideDateTime = provideDateTime; public byte[]? Get(string key) { diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Defaults.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Defaults.cs index e5cd6b26ec3..095bdee575c 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Defaults.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Defaults.cs @@ -31,9 +31,7 @@ public static class Defaults /// public static TimeSpan DefaultTimeToLiveForCacheEntries { get; } = TimeSpan.FromDays(14); - /// - /// Defines the version number for the reporting format. If and when the serialized format undergoes - /// breaking changes, this number will be incremented. - /// + // Defines the version number for the reporting format. If and when the serialized format undergoes + // breaking changes, this number should be incremented. internal const int ReportingFormatVersion = 1; } diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/JsonSerialization/JsonUtilities.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/JsonSerialization/JsonUtilities.cs index e372b7e8434..9ba74009433 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/JsonSerialization/JsonUtilities.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/JsonSerialization/JsonUtilities.cs @@ -19,7 +19,6 @@ internal static class Default internal static JsonSerializerOptions Options => _options ??= CreateJsonSerializerOptions(writeIndented: true); internal static JsonTypeInfo DatasetTypeInfo => Options.GetTypeInfo(); internal static JsonTypeInfo CacheEntryTypeInfo => Options.GetTypeInfo(); - internal static JsonTypeInfo CacheOptionsTypeInfo => Options.GetTypeInfo(); internal static JsonTypeInfo ScenarioRunResultTypeInfo => Options.GetTypeInfo(); } @@ -29,7 +28,6 @@ internal static class Compact internal static JsonSerializerOptions Options => _options ??= CreateJsonSerializerOptions(writeIndented: false); internal static JsonTypeInfo DatasetTypeInfo => Options.GetTypeInfo(); internal static JsonTypeInfo CacheEntryTypeInfo => Options.GetTypeInfo(); - internal static JsonTypeInfo CacheOptionsTypeInfo => Options.GetTypeInfo(); internal static JsonTypeInfo ScenarioRunResultTypeInfo => Options.GetTypeInfo(); } @@ -50,12 +48,10 @@ private static JsonSerializerOptions CreateJsonSerializerOptions(bool writeInden [JsonSerializable(typeof(EvaluationResult))] [JsonSerializable(typeof(Dataset))] [JsonSerializable(typeof(CacheEntry))] - [JsonSerializable(typeof(CacheOptions))] [JsonSourceGenerationOptions( Converters = [ typeof(CamelCaseEnumConverter), typeof(CamelCaseEnumConverter), - typeof(CamelCaseEnumConverter), typeof(TimeSpanConverter), typeof(EvaluationContextConverter) ], diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheMode.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheMode.cs deleted file mode 100644 index cbc8ca2f151..00000000000 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheMode.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage; - -internal partial class DiskBasedResponseCache -{ - /// - /// An enum representing the mode in which the cache is operating. - /// - internal enum CacheMode - { - /// - /// In this mode, the cache is disabled. All requests bypass the cache and are forwarded online. - /// - Disabled, - - /// - /// In this mode, the cache is enabled. Requests are handled by the cache first. If a cached response is not - /// available, then the request is forwarded online. - /// - Enabled, - - /// - /// In this mode, the cache is enabled. However, requests are never forwarded online. Instead if a cached response - /// is not available, then an exception is thrown. Additionally in this mode, the cache is considered frozen (or - /// read only) which means that all the cache artifacts (including expired entries) are preserved as is on disk. - /// - EnabledOfflineOnly - } -} diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheOptions.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheOptions.cs deleted file mode 100644 index 1e21c59828b..00000000000 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.CacheOptions.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Globalization; -using System.IO; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.AI.Evaluation.Reporting.JsonSerialization; - -namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage; - -internal partial class DiskBasedResponseCache -{ - internal sealed class CacheOptions - { - public static CacheOptions Default { get; } = new CacheOptions(); - - private const string DeserializationFailedMessage = "Unable to deserialize the cache options file at {0}."; - - public CacheOptions(CacheMode mode = CacheMode.Enabled, TimeSpan? timeToLiveForCacheEntries = null) - { - Mode = mode; - TimeToLiveForCacheEntries = timeToLiveForCacheEntries ?? Defaults.DefaultTimeToLiveForCacheEntries; - } - - [JsonConstructor] - public CacheOptions(CacheMode mode, TimeSpan timeToLiveForCacheEntries) - { - Mode = mode; - TimeToLiveForCacheEntries = timeToLiveForCacheEntries; - } - - public CacheMode Mode { get; } - - [JsonPropertyName("timeToLiveInSecondsForCacheEntries")] - public TimeSpan TimeToLiveForCacheEntries { get; } - - public static CacheOptions Read(string cacheOptionsFilePath) - { - using FileStream cacheOptionsFile = File.OpenRead(cacheOptionsFilePath); - - CacheOptions cacheOptions = - JsonSerializer.Deserialize( - cacheOptionsFile, - JsonUtilities.Default.CacheOptionsTypeInfo) ?? - throw new JsonException( - string.Format(CultureInfo.CurrentCulture, DeserializationFailedMessage, cacheOptionsFilePath)); - - return cacheOptions; - } - - public static async Task ReadAsync( - string cacheOptionsFilePath, - CancellationToken cancellationToken = default) - { - using FileStream cacheOptionsFile = File.OpenRead(cacheOptionsFilePath); - - CacheOptions cacheOptions = - await JsonSerializer.DeserializeAsync( - cacheOptionsFile, - JsonUtilities.Default.CacheOptionsTypeInfo, - cancellationToken).ConfigureAwait(false) ?? - throw new JsonException( - string.Format(CultureInfo.CurrentCulture, DeserializationFailedMessage, cacheOptionsFilePath)); - - return cacheOptions; - } - - public void Write(string cacheOptionsFilePath) - { - using FileStream cacheOptionsFile = File.Create(cacheOptionsFilePath); - JsonSerializer.Serialize(cacheOptionsFile, this, JsonUtilities.Default.CacheOptionsTypeInfo); - } - - public async Task WriteAsync( - string cacheOptionsFilePath, - CancellationToken cancellationToken = default) - { - using FileStream cacheOptionsFile = File.Create(cacheOptionsFilePath); - await JsonSerializer.SerializeAsync( - cacheOptionsFile, - this, - JsonUtilities.Default.CacheOptionsTypeInfo, - cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.cs index 51b96739964..d0a107d8710 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCache.cs @@ -1,6 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#pragma warning disable S3604 +// S3604: Member initializer values should not be redundant. +// We disable this warning because it is a false positive arising from the analyzer's lack of support for C#'s primary +// constructor syntax. + #pragma warning disable CA1725 // CA1725: Parameter names should match base declaration. // All functions on 'IDistributedCache' use the parameter name 'token' in place of 'cancellationToken'. However, @@ -26,55 +31,42 @@ internal sealed partial class DiskBasedResponseCache : IDistributedCache private readonly string _scenarioName; private readonly string _iterationName; - private readonly CacheOptions _options; private readonly string _iterationPath; private readonly Func _provideDateTime; + private readonly TimeSpan _timeToLiveForCacheEntries; - public DiskBasedResponseCache( + internal DiskBasedResponseCache( string storageRootPath, string scenarioName, string iterationName, - Func provideDateTime) + Func provideDateTime, + TimeSpan? timeToLiveForCacheEntries = null) { _scenarioName = scenarioName; _iterationName = iterationName; storageRootPath = Path.GetFullPath(storageRootPath); string cacheRootPath = GetCacheRootPath(storageRootPath); - string optionsFilePath = GetOptionsFilePath(cacheRootPath); - _options = File.Exists(optionsFilePath) ? CacheOptions.Read(optionsFilePath) : CacheOptions.Default; + _iterationPath = Path.Combine(cacheRootPath, scenarioName, iterationName); _provideDateTime = provideDateTime; + _timeToLiveForCacheEntries = timeToLiveForCacheEntries ?? Defaults.DefaultTimeToLiveForCacheEntries; } public byte[]? Get(string key) { - if (_options.Mode is CacheMode.Disabled) - { - return null; - } - (_, string entryFilePath, string contentsFilePath, bool filesExist) = GetPaths(key); + if (!filesExist) { - return _options.Mode is CacheMode.EnabledOfflineOnly - ? throw new FileNotFoundException( - string.Format( - CultureInfo.CurrentCulture, - EntryAndContentsFilesNotFound, - entryFilePath, - contentsFilePath)) - : null; + return null; } - if (_options.Mode is not CacheMode.EnabledOfflineOnly) + CacheEntry entry = CacheEntry.Read(entryFilePath); + if (entry.Expiration <= _provideDateTime()) { - CacheEntry entry = CacheEntry.Read(entryFilePath); - if (entry.Expiration <= _provideDateTime()) - { - Remove(key); - return null; - } + Remove(key); + return null; } return File.ReadAllBytes(contentsFilePath); @@ -82,34 +74,20 @@ public DiskBasedResponseCache( public async Task GetAsync(string key, CancellationToken cancellationToken = default) { - if (_options.Mode is CacheMode.Disabled) - { - return null; - } - (string _, string entryFilePath, string contentsFilePath, bool filesExist) = GetPaths(key); + if (!filesExist) { - return _options.Mode is CacheMode.EnabledOfflineOnly - ? throw new FileNotFoundException( - string.Format( - CultureInfo.CurrentCulture, - EntryAndContentsFilesNotFound, - entryFilePath, - contentsFilePath)) - : null; + return null; } - if (_options.Mode is not CacheMode.EnabledOfflineOnly) - { - CacheEntry entry = - await CacheEntry.ReadAsync(entryFilePath, cancellationToken: cancellationToken).ConfigureAwait(false); + CacheEntry entry = + await CacheEntry.ReadAsync(entryFilePath, cancellationToken: cancellationToken).ConfigureAwait(false); - if (entry.Expiration <= _provideDateTime()) - { - await RemoveAsync(key, cancellationToken).ConfigureAwait(false); - return null; - } + if (entry.Expiration <= _provideDateTime()) + { + await RemoveAsync(key, cancellationToken).ConfigureAwait(false); + return null; } #if NET @@ -162,12 +140,8 @@ await stream.ReadAsync( public void Refresh(string key) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return; - } - (_, string entryFilePath, string contentsFilePath, bool filesExist) = GetPaths(key); + if (!filesExist) { throw new FileNotFoundException( @@ -184,12 +158,8 @@ public void Refresh(string key) public async Task RefreshAsync(string key, CancellationToken cancellationToken = default) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return; - } - (_, string entryFilePath, string contentsFilePath, bool filesExist) = GetPaths(key); + if (!filesExist) { throw new FileNotFoundException( @@ -206,33 +176,20 @@ public async Task RefreshAsync(string key, CancellationToken cancellationToken = public void Remove(string key) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return; - } - (string keyPath, _, _, _) = GetPaths(key); + Directory.Delete(keyPath, recursive: true); } public Task RemoveAsync(string key, CancellationToken cancellationToken = default) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return Task.CompletedTask; - } - Remove(key); + return Task.CompletedTask; } public void Set(string key, byte[] value, DistributedCacheEntryOptions options) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return; - } - (string keyPath, string entryFilePath, string contentsFilePath, _) = GetPaths(key); _ = Directory.CreateDirectory(keyPath); @@ -249,11 +206,6 @@ public async Task SetAsync( DistributedCacheEntryOptions options, CancellationToken cancellationToken = default) { - if (_options.Mode is CacheMode.Disabled or CacheMode.EnabledOfflineOnly) - { - return; - } - (string keyPath, string entryFilePath, string contentsFilePath, _) = GetPaths(key); Directory.CreateDirectory(keyPath); @@ -334,9 +286,6 @@ await CacheEntry.ReadAsync( private static string GetCacheRootPath(string storageRootPath) => Path.Combine(storageRootPath, "cache"); - private static string GetOptionsFilePath(string cacheRootPath) - => Path.Combine(cacheRootPath, "options.json"); - private static string GetEntryFilePath(string keyPath) => Path.Combine(keyPath, "entry.json"); @@ -368,7 +317,7 @@ private static string GetContentsFilePath(string keyPath) private CacheEntry CreateEntry() { DateTime creation = _provideDateTime(); - DateTime expiration = creation.Add(_options.TimeToLiveForCacheEntries); + DateTime expiration = creation.Add(_timeToLiveForCacheEntries); return new CacheEntry(_scenarioName, _iterationName, creation, expiration); } diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCacheProvider.cs b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCacheProvider.cs index d3fce0e5aff..feb75df1dba 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCacheProvider.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Storage/DiskBasedResponseCacheProvider.cs @@ -20,7 +20,13 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage; /// /// The path to a directory on disk under which the cached AI responses should be stored. /// -public sealed class DiskBasedResponseCacheProvider(string storageRootPath) : IResponseCacheProvider +/// +/// An optional that specifies the maximum amount of time that cached AI responses should +/// survive in the cache before they are considered expired and evicted. +/// +public sealed class DiskBasedResponseCacheProvider( + string storageRootPath, + TimeSpan? timeToLiveForCacheEntries = null) : IResponseCacheProvider { private readonly Func _provideDateTime = () => DateTime.UtcNow; @@ -39,7 +45,13 @@ public ValueTask GetCacheAsync( string iterationName, CancellationToken cancellationToken = default) { - var cache = new DiskBasedResponseCache(storageRootPath, scenarioName, iterationName, _provideDateTime); + var cache = + new DiskBasedResponseCache( + storageRootPath, + scenarioName, + iterationName, + _provideDateTime, + timeToLiveForCacheEntries); return new ValueTask(cache); } diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/CacheOptionsTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/CacheOptionsTests.cs deleted file mode 100644 index b8351f45695..00000000000 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/CacheOptionsTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Text.Json; -using System.Threading.Tasks; -using Microsoft.Extensions.AI.Evaluation.Reporting.JsonSerialization; -using Xunit; -using CacheMode = Microsoft.Extensions.AI.Evaluation.Reporting.Storage.DiskBasedResponseCache.CacheMode; -using CacheOptions = Microsoft.Extensions.AI.Evaluation.Reporting.Storage.DiskBasedResponseCache.CacheOptions; - -namespace Microsoft.Extensions.AI.Evaluation.Reporting.Tests; - -public class CacheOptionsTests -{ - [Fact] - public void SerializeCacheOptions() - { - var options = new CacheOptions(CacheMode.Disabled, TimeSpan.FromDays(300)); - - string json = JsonSerializer.Serialize(options, JsonUtilities.Default.CacheOptionsTypeInfo); - CacheOptions? deserialized = JsonSerializer.Deserialize(json, JsonUtilities.Default.CacheOptionsTypeInfo); - - Assert.NotNull(deserialized); - Assert.Equal(options.Mode, deserialized!.Mode); - Assert.Equal(options.TimeToLiveForCacheEntries, deserialized.TimeToLiveForCacheEntries); - - } - - [Fact] - public void SerializeCacheOptionsCompact() - { - var options = new CacheOptions(CacheMode.Disabled, TimeSpan.FromDays(300)); - - string json = JsonSerializer.Serialize(options, JsonUtilities.Compact.CacheOptionsTypeInfo); - CacheOptions? deserialized = JsonSerializer.Deserialize(json, JsonUtilities.Default.CacheOptionsTypeInfo); - - Assert.NotNull(deserialized); - Assert.Equal(options.Mode, deserialized!.Mode); - Assert.Equal(options.TimeToLiveForCacheEntries, deserialized.TimeToLiveForCacheEntries); - - } - - [Fact] - public void SerializeCacheOptionsToFile() - { - var options = new CacheOptions(CacheMode.Enabled, TimeSpan.FromSeconds(10)); - - string tempFilePath = Path.GetTempFileName(); - options.Write(tempFilePath); - CacheOptions deserialized = CacheOptions.Read(tempFilePath); - - Assert.NotNull(deserialized); - Assert.Equal(options.Mode, deserialized.Mode); - Assert.Equal(options.TimeToLiveForCacheEntries, deserialized.TimeToLiveForCacheEntries); - } - - [Fact] - public async Task SerializeCacheOptionsToFileAsync() - { - var options = new CacheOptions(CacheMode.Enabled, TimeSpan.FromSeconds(10)); - - string tempFilePath = Path.GetTempFileName(); - await options.WriteAsync(tempFilePath); - CacheOptions deserialized = await CacheOptions.ReadAsync(tempFilePath); - - Assert.NotNull(deserialized); - Assert.Equal(options.Mode, deserialized.Mode); - Assert.Equal(options.TimeToLiveForCacheEntries, deserialized.TimeToLiveForCacheEntries); - } - -} diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs index 60e4e6f21ed..76e50244b92 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Extensions.AI.Evaluation.Reporting.Storage; using Microsoft.Extensions.Caching.Distributed; using Microsoft.TestUtilities; using Xunit; @@ -96,7 +95,7 @@ public async Task CacheEntryExpiration() cache.Set(_keyB, _responseB); Assert.True(_responseB.SequenceEqual(cache.Get(_keyB) ?? [])); - now = DateTime.UtcNow + DiskBasedResponseCache.CacheOptions.Default.TimeToLiveForCacheEntries; + now = DateTime.UtcNow + Defaults.DefaultTimeToLiveForCacheEntries; Assert.Null(await cache.GetAsync(_keyA)); Assert.Null(cache.Get(_keyB)); @@ -144,7 +143,7 @@ public async Task DeleteExpiredEntries() cache.Set(_keyB, _responseB); Assert.True(_responseB.SequenceEqual(cache.Get(_keyB) ?? [])); - now = DateTime.UtcNow + DiskBasedResponseCache.CacheOptions.Default.TimeToLiveForCacheEntries; + now = DateTime.UtcNow + Defaults.DefaultTimeToLiveForCacheEntries; await provider.DeleteExpiredCacheEntriesAsync();