private Task AssertExpirationInRangeAsync(Context context, string cacheNamespace, StrongFingerprint strongFingerprint, DateTime expectedLow, DateTime expectedHigh) { // Create a bare BuildCache client so that the value read is not thwarted by some intermediate cache layer (like Redis) Func <DisposableDirectory, ICache> createCheckerCacheFunc = dir => CreateBareBuildCache(dir, cacheNamespace, FileSystem, Logger, BackingOption.WriteThrough, ItemStorageOption); Func <ICacheSession, Task> checkFunc = async(ICacheSession checkSession) => { // Bare BuildCache clients should only produce BuildCacheSessions BuildCacheSession buildCacheSession = checkSession as BuildCacheSession; Assert.NotNull(buildCacheSession); // Raw expiration is only visible to the adapter, not through the ICacheSession APIs. // This also has the nice (non-)side-effect of not updating the expiration as part of *this* read. IContentHashListAdapter buildCacheHttpClientAdapter = buildCacheSession.ContentHashListAdapter; ObjectResult <ContentHashListWithCacheMetadata> getResult = await buildCacheHttpClientAdapter.GetContentHashListAsync(context, cacheNamespace, strongFingerprint); Assert.True(getResult.Succeeded); Assert.NotNull(getResult.Data); DateTime?rawExpiration = getResult.Data.GetRawExpirationTimeUtc(); Assert.NotNull(rawExpiration); // Verify that the raw expiration (i.e. the value's TTL w/o consideration for content existence or whether the value might be replaced) is visible and correct TimeSpan assertionTolerance = TimeSpan.FromHours(1); // The test time + the simulator's clock skew hopefully won't exceed 1 hour. Assert.InRange(rawExpiration.Value, expectedLow - assertionTolerance, expectedHigh + assertionTolerance); }; return(RunTestAsync(context, checkFunc, createCheckerCacheFunc)); }
/// <inheritdoc /> public Task <GetContentHashListResult> GetContentHashListAsync( Context context, StrongFingerprint strongFingerprint, CancellationToken cts, UrgencyHint urgencyHint) { return(GetContentHashListCall.RunAsync(Tracer.MemoizationStoreTracer, context, strongFingerprint, async() => { // Check for pre-fetched data ContentHashListWithDeterminism contentHashListWithDeterminism; if (ContentHashListWithDeterminismCache.Instance.TryGetValue( CacheNamespace, strongFingerprint, out contentHashListWithDeterminism)) { Tracer.RecordUseOfPrefetchedContentHashList(); FingerprintTracker.Track( strongFingerprint, contentHashListWithDeterminism.Determinism.ExpirationUtc); return new GetContentHashListResult(contentHashListWithDeterminism); } // No pre-fetched data. Need to query the server. ObjectResult <ContentHashListWithCacheMetadata> responseObject = await ContentHashListAdapter.GetContentHashListAsync(context, CacheNamespace, strongFingerprint).ConfigureAwait(false); if (!responseObject.Succeeded) { return new GetContentHashListResult(responseObject); } ContentHashListWithCacheMetadata response = responseObject.Data; if (response.ContentHashListWithDeterminism.ContentHashList == null) { // Miss return new GetContentHashListResult(new ContentHashListWithDeterminism(null, CacheDeterminism.None)); } GetContentHashListResult unpackResult = UnpackContentHashListWithDeterminismAfterGet(response, CacheId); if (!unpackResult.Succeeded) { return unpackResult; } SealIfNecessaryAfterGet(context, strongFingerprint, response); FingerprintTracker.Track(strongFingerprint, response.GetRawExpirationTimeUtc()); return new GetContentHashListResult(unpackResult.ContentHashListWithDeterminism); })); }