Skip to content

Commit 3ceb688

Browse files
Make MemoryCache test deterministic
1 parent 00b0d4f commit 3ceb688

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Utilities/MemoryCacheTest.cs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -379,51 +379,75 @@ public async Task LRUEviction_WithConcurrentAccess_BehavesReasonably()
379379
var cache = new MemoryCache<string, IReadOnlyList<int>>(SizeLimit);
380380
var cacheAccessor = cache.GetTestAccessor();
381381

382-
using var cancellationSource = new CancellationTokenSource();
382+
var hotAccessEstablished = new TaskCompletionSource<bool>();
383+
var coldEntryAdded = false;
383384

384385
// Add initial entries
385-
var initialKeys = new List<string>();
386+
var initialKeys = new string[SizeLimit];
387+
386388
for (var i = 0; i < SizeLimit; i++)
387389
{
388390
var key = $"initial-{i}";
389-
initialKeys.Add(key);
391+
initialKeys[i] = key;
390392
cache.Set(key, [i]);
391393
}
392394

393-
// Continuously access first few entries to make them "hot"
394-
var hotKeys = initialKeys.Take(2).ToList();
395+
// Continuously access first couple entries to make them "hot"
396+
var hotKeys = initialKeys.Take(2).ToArray();
395397
var keepHotTask = Task.Run(async () =>
396398
{
397399
try
398400
{
399-
while (!cancellationSource.IsCancellationRequested)
401+
// Establish hot key access
402+
for (var i = 0; i < 10; i++)
400403
{
401-
foreach (var key in hotKeys)
402-
{
403-
_ = cache.TryGetValue(key, out _);
404-
}
404+
await AccessHotKeysAsync(hotKeys, cache);
405+
}
405406

406-
await Task.Delay(1, cancellationSource.Token);
407+
hotAccessEstablished.TrySetResult(true);
408+
409+
// Continue accessing hot keys while waiting for cold entry to be added
410+
while (!coldEntryAdded)
411+
{
412+
await AccessHotKeysAsync(hotKeys, cache);
413+
}
414+
415+
// Continue accessing hot keys until finished.
416+
for (var i = 0; i < 100; i++)
417+
{
418+
await AccessHotKeysAsync(hotKeys, cache);
407419
}
408420
}
409421
catch (OperationCanceledException)
410422
{
411423
// Expected when cancellation token is canceled
412424
}
425+
426+
async Task AccessHotKeysAsync(string[] hotKeys, MemoryCache<string, IReadOnlyList<int>> cache)
427+
{
428+
foreach (var key in hotKeys)
429+
{
430+
_ = cache.TryGetValue(key, out _);
431+
}
432+
433+
await Task.Delay(1, DisposalToken);
434+
}
413435
});
414436

415437
// Trigger compaction
416-
await Task.Delay(10); // Let hot access pattern establish
438+
await hotAccessEstablished.Task;
417439
cache.Set("trigger-compaction", [999]);
418440

419-
cancellationSource.Cancel();
441+
// Signal that the cold entry was added
442+
coldEntryAdded = true;
443+
420444
await keepHotTask;
421445

422446
// Verify hot entries are more likely to survive
423447
var hotSurvivalCount = hotKeys.Count(key => cache.TryGetValue(key, out _));
424448
var coldSurvivalCount = initialKeys.Skip(2).Count(key => cache.TryGetValue(key, out _));
425449

426-
// Hot entries should have better survival rate (though this is probabilistic)
450+
// Hot entries should have better survival rate
427451
Assert.True(hotSurvivalCount >= coldSurvivalCount,
428452
$"Hot entries ({hotSurvivalCount}) should survive at least as well as cold entries ({coldSurvivalCount})");
429453
}

0 commit comments

Comments
 (0)