Skip to content

Commit 6f644d1

Browse files
authored
Use hosted environment for CacheDependency tests (#464)
The implementation of this requires HttpRuntime.Cache to be set in some code paths and so we need to use the SelfHostedTests collection to ensure this is setup correctly and doesn't stomp on other tests.
1 parent f71eb39 commit 6f644d1

File tree

3 files changed

+188
-198
lines changed

3 files changed

+188
-198
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Runtime.Caching;
8+
using System.Threading.Tasks;
9+
using System.Web;
10+
using System.Web.Caching;
11+
using AutoFixture;
12+
using Microsoft.AspNetCore.Hosting;
13+
using Microsoft.AspNetCore.TestHost;
14+
using Microsoft.Extensions.DependencyInjection;
15+
using Microsoft.Extensions.Hosting;
16+
using Moq;
17+
using Xunit;
18+
19+
namespace Microsoft.AspNetCore.SystemWebAdapters.Tests;
20+
21+
/// <summary>
22+
/// Tests for <see cref="CacheDependency"/>. These use <see cref="HttpRuntime.Cache"/> in some cases and must be tested within a host if cache keys are used
23+
/// </summary>
24+
[Collection(nameof(SelfHostedTests))]
25+
public class CacheDependencyTests
26+
{
27+
private readonly Fixture _fixture;
28+
29+
public CacheDependencyTests()
30+
{
31+
_fixture = new Fixture();
32+
}
33+
34+
[Fact]
35+
public void InsertWithDependency()
36+
{
37+
// Arrange
38+
var memCache = new Mock<MemoryCache>(_fixture.Create<string>(), null);
39+
var cache = new Cache(memCache.Object);
40+
var key = _fixture.Create<string>();
41+
var item = new object();
42+
var cacheDependency = new Mock<CacheDependency>();
43+
44+
// Act
45+
cache.Insert(key, item, cacheDependency.Object);
46+
47+
// Assert
48+
memCache.Verify(m => m.Set(key, item, It.Is<CacheItemPolicy>(e => e.AbsoluteExpiration.DateTime.Equals(Cache.NoAbsoluteExpiration) && e.SlidingExpiration.Equals(Cache.NoSlidingExpiration)), null), Times.Once);
49+
}
50+
51+
[Fact]
52+
public async Task DependentFileCallback()
53+
{
54+
// Arrange
55+
using var memCache = new MemoryCache(_fixture.Create<string>());
56+
var cache = new Cache(memCache);
57+
var item = new object();
58+
var key = _fixture.Create<string>();
59+
var updated = false;
60+
var slidingExpiration = TimeSpan.FromMilliseconds(1);
61+
CacheItemUpdateReason? updateReason = default;
62+
63+
var tcs = new TaskCompletionSource();
64+
65+
void Callback(string key, CacheItemUpdateReason reason, out object? expensiveObject, out CacheDependency? dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration)
66+
{
67+
expensiveObject = null;
68+
dependency = null;
69+
absoluteExpiration = Cache.NoAbsoluteExpiration;
70+
slidingExpiration = TimeSpan.FromMilliseconds(5);
71+
72+
updated = true;
73+
updateReason = reason;
74+
75+
tcs.SetResult();
76+
}
77+
78+
var file = Path.GetTempFileName();
79+
await File.WriteAllTextAsync(file, key);
80+
81+
using var cd = new CacheDependency(file);
82+
// Act
83+
cache.Insert(key, item, cd, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, Callback);
84+
85+
// Ensure file is updated
86+
await File.WriteAllTextAsync(file, DateTime.UtcNow.ToString("O"));
87+
88+
// Wait for callback to be called
89+
await tcs.Task;
90+
91+
// Wait for callback to be finalized
92+
await Task.Delay(100);
93+
94+
// Assert
95+
Assert.True(updated);
96+
Assert.Null(cache[key]);
97+
Assert.Equal(CacheItemUpdateReason.DependencyChanged, updateReason);
98+
}
99+
100+
[Fact]
101+
public async Task DependentItemCallback()
102+
{
103+
// Arrange
104+
using var memCache = new MemoryCache(_fixture.Create<string>());
105+
var cache = new Cache(memCache);
106+
using var host = StartHost(cache);
107+
108+
var item1 = new object();
109+
var item2 = new object();
110+
var key1 = _fixture.Create<string>();
111+
var key2 = _fixture.Create<string>();
112+
var updateReason = new Dictionary<string, CacheItemUpdateReason>();
113+
var slidingExpiration = TimeSpan.FromMilliseconds(1);
114+
115+
void Callback(string key, CacheItemUpdateReason reason, out object? expensiveObject, out CacheDependency? dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration)
116+
{
117+
expensiveObject = null;
118+
dependency = null;
119+
absoluteExpiration = Cache.NoAbsoluteExpiration;
120+
slidingExpiration = Cache.NoSlidingExpiration;
121+
122+
updateReason[key] = reason;
123+
}
124+
125+
// Act
126+
cache.Insert(key1, item1, null, Cache.NoAbsoluteExpiration, slidingExpiration, Callback);
127+
128+
using var cd = new CacheDependency(null, new[] { key1 });
129+
cache.Insert(key2, item2, cd, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, Callback);
130+
131+
Assert.Empty(updateReason);
132+
133+
// Ensure sliding expiration has hit
134+
await Task.Delay(slidingExpiration);
135+
136+
// Force cleanup to initiate callbacks on current thread
137+
memCache.Trim(100);
138+
139+
// Assert
140+
Assert.Contains(key1, updateReason.Keys);
141+
Assert.Contains(key2, updateReason.Keys);
142+
143+
Assert.Null(cache[key1]);
144+
Assert.Null(cache[key2]);
145+
146+
Assert.Equal(CacheItemUpdateReason.Expired, updateReason[key1]);
147+
Assert.Equal(CacheItemUpdateReason.DependencyChanged, updateReason[key2]);
148+
}
149+
150+
private static IDisposable StartHost(Cache cache) => Host.CreateDefaultBuilder()
151+
.ConfigureWebHost(app =>
152+
{
153+
app.UseTestServer();
154+
app.Configure(app => { });
155+
app.ConfigureServices(services =>
156+
{
157+
services.AddSystemWebAdapters();
158+
services.AddSingleton(cache);
159+
});
160+
})
161+
.Start();
162+
}

test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/CacheTests.cs

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)