|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 |
|
4 | 4 | using System.Collections;
|
| 5 | +using System.Collections.Generic; |
5 | 6 | using System.Runtime.Caching;
|
6 | 7 | using System.Threading.Tasks;
|
7 | 8 | using AutoFixture;
|
| 9 | +using Microsoft.AspNetCore.SystemWebAdapters; |
8 | 10 | using Moq;
|
9 | 11 | using Xunit;
|
10 | 12 |
|
@@ -292,4 +294,135 @@ public void InsertItem()
|
292 | 294 | }
|
293 | 295 |
|
294 | 296 | private sealed record Removal(string Key, object Item, CacheItemRemovedReason Reason);
|
| 297 | + |
| 298 | + [Fact] |
| 299 | + public void InsertNoAbsoluteSlidingExpiration() |
| 300 | + { |
| 301 | + // Arrange |
| 302 | + var memCache = new Mock<MemoryCache>(_fixture.Create<string>(), null); |
| 303 | + var cache = new Cache(memCache.Object); |
| 304 | + var key = _fixture.Create<string>(); |
| 305 | + var item = new object(); |
| 306 | + |
| 307 | + // Act |
| 308 | + cache.Insert(key, item); |
| 309 | + |
| 310 | + // Assert |
| 311 | + memCache.Verify(m => m.Set(key, item, It.Is<CacheItemPolicy>(e => e.AbsoluteExpiration.Equals(Cache.NoAbsoluteExpiration) && e.SlidingExpiration.Equals(Cache.NoSlidingExpiration)), null), Times.Once); |
| 312 | + } |
| 313 | + |
| 314 | + [Fact] |
| 315 | + public void InsertWithDependency() |
| 316 | + { |
| 317 | + // Arrange |
| 318 | + var memCache = new Mock<MemoryCache>(_fixture.Create<string>(), null); |
| 319 | + var cache = new Cache(memCache.Object); |
| 320 | + var key = _fixture.Create<string>(); |
| 321 | + var item = new object(); |
| 322 | + var cacheDependency = new Mock<CacheDependency>(); |
| 323 | + |
| 324 | + // Act |
| 325 | + cache.Insert(key, item, cacheDependency.Object); |
| 326 | + |
| 327 | + // Assert |
| 328 | + memCache.Verify(m => m.Set(key, item, It.Is<CacheItemPolicy>(e => e.AbsoluteExpiration.Equals(Cache.NoAbsoluteExpiration) && e.SlidingExpiration.Equals(Cache.NoSlidingExpiration)), null), Times.Once); |
| 329 | + } |
| 330 | + |
| 331 | + [Fact] |
| 332 | + public async Task DependentFileCallback() |
| 333 | + { |
| 334 | + // Arrange |
| 335 | + using var memCache = new MemoryCache(_fixture.Create<string>()); |
| 336 | + var cache = new Cache(memCache); |
| 337 | + var item = new object(); |
| 338 | + var key = _fixture.Create<string>(); |
| 339 | + var updated = false; |
| 340 | + var slidingExpiration = TimeSpan.FromMilliseconds(1); |
| 341 | + CacheItemUpdateReason? updateReason = default; |
| 342 | + |
| 343 | + void Callback(string key, CacheItemUpdateReason reason, out object? expensiveObject, out CacheDependency? dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration) |
| 344 | + { |
| 345 | + expensiveObject = null; |
| 346 | + dependency = null; |
| 347 | + absoluteExpiration = Cache.NoAbsoluteExpiration; |
| 348 | + slidingExpiration = TimeSpan.FromMilliseconds(5); |
| 349 | + |
| 350 | + updated = true; |
| 351 | + updateReason = reason; |
| 352 | + } |
| 353 | + |
| 354 | + var file = System.IO.Path.GetTempFileName(); |
| 355 | + await System.IO.File.WriteAllTextAsync(file, key); |
| 356 | + |
| 357 | + using var cd = new CacheDependency(file); |
| 358 | + // Act |
| 359 | + cache.Insert(key, item, cd, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, Callback); |
| 360 | + |
| 361 | + // Ensure file is updated |
| 362 | + await System.IO.File.WriteAllTextAsync(file, DateTime.UtcNow.ToString("O")); |
| 363 | + |
| 364 | + // Small delay here to ensure that the file change notification happens (may fail tests if too fast) |
| 365 | + await Task.Delay(10); |
| 366 | + |
| 367 | + // Force cleanup to initiate callbacks on current thread |
| 368 | + memCache.Trim(100); |
| 369 | + |
| 370 | + // Assert |
| 371 | + Assert.True(updated); |
| 372 | + Assert.Null(cache[key]); |
| 373 | + Assert.Equal(CacheItemUpdateReason.DependencyChanged, updateReason); |
| 374 | + } |
| 375 | + |
| 376 | + [Fact] |
| 377 | + public async Task DependentItemCallback() |
| 378 | + { |
| 379 | + // Arrange |
| 380 | + using var memCache = new MemoryCache(_fixture.Create<string>()); |
| 381 | + |
| 382 | + var cache = new Cache(memCache); |
| 383 | + var httpRuntime = new Mock<IHttpRuntime>(); |
| 384 | + httpRuntime.Setup(s => s.Cache).Returns(cache); |
| 385 | + HttpRuntime.Current = httpRuntime.Object; |
| 386 | + |
| 387 | + var item1 = new object(); |
| 388 | + var item2 = new object(); |
| 389 | + var key1 = _fixture.Create<string>(); |
| 390 | + var key2 = _fixture.Create<string>(); |
| 391 | + var updateReason = new Dictionary<string, CacheItemUpdateReason>(); |
| 392 | + var slidingExpiration = TimeSpan.FromMilliseconds(1); |
| 393 | + |
| 394 | + void Callback(string key, CacheItemUpdateReason reason, out object? expensiveObject, out CacheDependency? dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration) |
| 395 | + { |
| 396 | + expensiveObject = null; |
| 397 | + dependency = null; |
| 398 | + absoluteExpiration = Cache.NoAbsoluteExpiration; |
| 399 | + slidingExpiration = Cache.NoSlidingExpiration; |
| 400 | + |
| 401 | + updateReason[key] = reason; |
| 402 | + } |
| 403 | + |
| 404 | + // Act |
| 405 | + cache.Insert(key1, item1, null, Cache.NoAbsoluteExpiration, slidingExpiration, Callback); |
| 406 | + |
| 407 | + using var cd = new CacheDependency(null, new[] { key1 }); |
| 408 | + cache.Insert(key2, item2, cd, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, Callback); |
| 409 | + |
| 410 | + Assert.Empty(updateReason); |
| 411 | + |
| 412 | + // Ensure sliding expiration has hit |
| 413 | + await Task.Delay(slidingExpiration); |
| 414 | + |
| 415 | + // Force cleanup to initiate callbacks on current thread |
| 416 | + memCache.Trim(100); |
| 417 | + |
| 418 | + // Assert |
| 419 | + Assert.Contains(key1, updateReason.Keys); |
| 420 | + Assert.Contains(key2, updateReason.Keys); |
| 421 | + |
| 422 | + Assert.Null(cache[key1]); |
| 423 | + Assert.Null(cache[key2]); |
| 424 | + |
| 425 | + Assert.Equal(CacheItemUpdateReason.Expired, updateReason[key1]); |
| 426 | + Assert.Equal(CacheItemUpdateReason.DependencyChanged, updateReason[key2]); |
| 427 | + } |
295 | 428 | }
|
0 commit comments