3
3
4
4
using Microsoft . AspNetCore . Components . Server . Circuits ;
5
5
using Microsoft . Extensions . Caching . Hybrid ;
6
+ using Microsoft . Extensions . DependencyInjection ;
6
7
using Microsoft . Extensions . Logging . Abstractions ;
7
8
using Microsoft . Extensions . Options ;
8
9
using Moq ;
@@ -15,43 +16,38 @@ public class HybridCacheCircuitPersistenceProviderTest
15
16
public async Task PersistCircuitAsync_StoresCircuitState ( )
16
17
{
17
18
// Arrange
18
- var mockHybridCache = new Mock < HybridCache > ( ) ;
19
+ var hybridCache = CreateHybridCache ( ) ;
19
20
var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
20
- var persistedState = new PersistedCircuitState ( ) ;
21
- var provider = CreateProvider ( mockHybridCache . Object ) ;
21
+ var persistedState = new PersistedCircuitState ( ) {
22
+ RootComponents = [ 1 , 2 , 3 ] ,
23
+ ApplicationState = new Dictionary < string , byte [ ] > {
24
+ { "key1" , new byte [ ] { 4 , 5 , 6 } } ,
25
+ { "key2" , new byte [ ] { 7 , 8 , 9 } }
26
+ }
27
+ } ;
28
+ var provider = CreateProvider ( hybridCache ) ;
22
29
23
30
// Act
24
31
await provider . PersistCircuitAsync ( circuitId , persistedState ) ;
25
32
26
33
// Assert
27
- mockHybridCache . Verify (
28
- c => c . SetAsync (
29
- $ "blazor-circuit:{ circuitId . Secret } ",
30
- persistedState ,
31
- It . IsAny < HybridCacheEntryOptions > ( ) ,
32
- It . IsAny < IEnumerable < string > > ( ) ,
33
- It . IsAny < CancellationToken > ( ) ) ,
34
- Times . Once ) ;
34
+ var result = await provider . RestoreCircuitAsync ( circuitId ) ;
35
+ Assert . NotNull ( result ) ;
36
+ Assert . Equal ( persistedState . RootComponents , result . RootComponents ) ;
37
+ Assert . Equal ( persistedState . ApplicationState , result . ApplicationState ) ;
35
38
}
36
39
37
40
[ Fact ]
38
41
public async Task RestoreCircuitAsync_ReturnsPersistedState_WhenCircuitExists ( )
39
42
{
40
43
// Arrange
41
- var mockHybridCache = new Mock < HybridCache > ( ) ;
44
+ var hybridCache = CreateHybridCache ( ) ;
42
45
var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
43
46
var persistedState = new PersistedCircuitState ( ) ;
44
- var provider = CreateProvider ( mockHybridCache . Object ) ;
45
- var cacheKey = $ "blazor-circuit:{ circuitId . Secret } ";
46
- mockHybridCache
47
- . Setup ( c => c . GetOrCreateAsync (
48
- cacheKey ,
49
- It . IsAny < Func < CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
50
- It . IsAny < Func < Func < CancellationToken , ValueTask < PersistedCircuitState > > , CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
51
- It . IsAny < HybridCacheEntryOptions > ( ) ,
52
- It . IsAny < IEnumerable < string > > ( ) ,
53
- It . IsAny < CancellationToken > ( ) ) )
54
- . ReturnsAsync ( persistedState ) ;
47
+ var provider = CreateProvider ( hybridCache ) ;
48
+ var cacheKey = circuitId . Secret ;
49
+
50
+ await provider . PersistCircuitAsync ( circuitId , persistedState ) ;
55
51
56
52
// Act
57
53
var result = await provider . RestoreCircuitAsync ( circuitId ) ;
@@ -64,19 +60,10 @@ public async Task RestoreCircuitAsync_ReturnsPersistedState_WhenCircuitExists()
64
60
public async Task RestoreCircuitAsync_ReturnsNull_WhenCircuitDoesNotExist ( )
65
61
{
66
62
// Arrange
67
- var mockHybridCache = new Mock < HybridCache > ( ) ;
63
+ var hybridCache = CreateHybridCache ( ) ;
68
64
var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
69
- var provider = CreateProvider ( mockHybridCache . Object ) ;
70
- var cacheKey = $ "blazor-circuit:{ circuitId . Secret } ";
71
- mockHybridCache
72
- . Setup ( c => c . GetOrCreateAsync (
73
- cacheKey ,
74
- It . IsAny < Func < CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
75
- It . IsAny < Func < Func < CancellationToken , ValueTask < PersistedCircuitState > > , CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
76
- It . IsAny < HybridCacheEntryOptions > ( ) ,
77
- It . IsAny < IEnumerable < string > > ( ) ,
78
- It . IsAny < CancellationToken > ( ) ) )
79
- . ReturnsAsync ( ( PersistedCircuitState ) null ) ;
65
+ var provider = CreateProvider ( hybridCache ) ;
66
+ var cacheKey = circuitId . Secret ;
80
67
81
68
// Act
82
69
var result = await provider . RestoreCircuitAsync ( circuitId ) ;
@@ -89,133 +76,29 @@ public async Task RestoreCircuitAsync_ReturnsNull_WhenCircuitDoesNotExist()
89
76
public async Task RestoreCircuitAsync_RemovesCircuitFromCache ( )
90
77
{
91
78
// Arrange
92
- var mockHybridCache = new Mock < HybridCache > ( ) ;
79
+ var hybridCache = CreateHybridCache ( ) ;
93
80
var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
94
81
var persistedState = new PersistedCircuitState ( ) ;
95
- var provider = CreateProvider ( mockHybridCache . Object ) ;
96
- var cacheKey = $ "blazor-circuit:{ circuitId . Secret } ";
97
-
98
- mockHybridCache
99
- . Setup ( c => c . GetOrCreateAsync (
100
- cacheKey ,
101
- It . IsAny < Func < CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
102
- It . IsAny < Func < Func < CancellationToken , ValueTask < PersistedCircuitState > > , CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
103
- It . IsAny < HybridCacheEntryOptions > ( ) ,
104
- It . IsAny < IEnumerable < string > > ( ) ,
105
- It . IsAny < CancellationToken > ( ) ) )
106
- . ReturnsAsync ( persistedState ) ;
107
-
108
- // Act
109
- var result = await provider . RestoreCircuitAsync ( circuitId ) ;
110
-
111
- // Assert
112
- Assert . Same ( persistedState , result ) ;
113
- mockHybridCache . Verify (
114
- c => c . RemoveAsync ( $ "blazor-circuit:{ circuitId . Secret } ", It . IsAny < CancellationToken > ( ) ) ,
115
- Times . Once ) ;
116
- }
82
+ var provider = CreateProvider ( hybridCache ) ;
83
+ var cacheKey = circuitId . Secret ;
117
84
118
- [ Fact ]
119
- public async Task PersistCircuitAsync_HandlesExceptions_GracefullyWithLogging ( )
120
- {
121
- // Arrange
122
- var mockHybridCache = new Mock < HybridCache > ( ) ;
123
- var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
124
- var persistedState = new PersistedCircuitState ( ) ;
125
- var provider = CreateProvider ( mockHybridCache . Object ) ;
126
-
127
- mockHybridCache
128
- . Setup ( c => c . SetAsync (
129
- It . IsAny < string > ( ) ,
130
- It . IsAny < PersistedCircuitState > ( ) ,
131
- It . IsAny < HybridCacheEntryOptions > ( ) ,
132
- It . IsAny < IEnumerable < string > > ( ) ,
133
- It . IsAny < CancellationToken > ( ) ) )
134
- . Throws ( new InvalidOperationException ( "Test exception" ) ) ;
135
-
136
- // Act & Assert - should not throw
137
85
await provider . PersistCircuitAsync ( circuitId , persistedState ) ;
138
- }
139
-
140
- [ Fact ]
141
- public async Task RestoreCircuitAsync_HandlesExceptions_GracefullyWithLogging ( )
142
- {
143
- // Arrange
144
- var mockHybridCache = new Mock < HybridCache > ( ) ;
145
- var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
146
- var provider = CreateProvider ( mockHybridCache . Object ) ;
147
-
148
- mockHybridCache
149
- . Setup ( c => c . GetOrCreateAsync (
150
- It . IsAny < string > ( ) ,
151
- It . IsAny < Func < CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
152
- It . IsAny < Func < Func < CancellationToken , ValueTask < PersistedCircuitState > > , CancellationToken , ValueTask < PersistedCircuitState > > > ( ) ,
153
- It . IsAny < HybridCacheEntryOptions > ( ) ,
154
- It . IsAny < IEnumerable < string > > ( ) ,
155
- It . IsAny < CancellationToken > ( ) ) )
156
- . ThrowsAsync ( new InvalidOperationException ( "Test exception" ) ) ;
157
86
158
87
// Act
159
- var result = await provider . RestoreCircuitAsync ( circuitId ) ;
160
-
161
- // Assert - should return null when exception occurs
162
- Assert . Null ( result ) ;
163
- }
164
-
165
- [ Fact ]
166
- public async Task PersistCircuitAsync_UsesCorrectCacheKey ( )
167
- {
168
- // Arrange
169
- var mockHybridCache = new Mock < HybridCache > ( ) ;
170
- var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
171
- var persistedState = new PersistedCircuitState ( ) ;
172
- var provider = CreateProvider ( mockHybridCache . Object ) ;
173
-
174
- // Act
175
- await provider . PersistCircuitAsync ( circuitId , persistedState ) ;
88
+ var result1 = await provider . RestoreCircuitAsync ( circuitId ) ;
89
+ var result2 = await provider . RestoreCircuitAsync ( circuitId ) ;
176
90
177
91
// Assert
178
- mockHybridCache . Verify (
179
- c => c . SetAsync (
180
- $ "blazor-circuit:{ circuitId . Secret } ",
181
- persistedState ,
182
- It . IsAny < HybridCacheEntryOptions > ( ) ,
183
- It . IsAny < IEnumerable < string > > ( ) ,
184
- It . IsAny < CancellationToken > ( ) ) ,
185
- Times . Once ) ;
92
+ Assert . Same ( persistedState , result1 ) ;
93
+ Assert . Null ( result2 ) ; // Circuit should be removed after first restore
186
94
}
187
95
188
- [ Fact ]
189
- public async Task PersistCircuitAsync_UsesCorrectExpirationTime ( )
96
+ private HybridCache CreateHybridCache ( )
190
97
{
191
- // Arrange
192
- var mockHybridCache = new Mock < HybridCache > ( ) ;
193
- var circuitId = TestCircuitIdFactory . CreateTestFactory ( ) . CreateCircuitId ( ) ;
194
- var persistedState = new PersistedCircuitState ( ) ;
195
- var customOptions = new CircuitOptions
196
- {
197
- PersistedCircuitInMemoryRetentionPeriod = TimeSpan . FromMinutes ( 5 )
198
- } ;
199
- var provider = CreateProvider ( mockHybridCache . Object , customOptions ) ;
200
-
201
- HybridCacheEntryOptions capturedOptions = null ;
202
- mockHybridCache
203
- . Setup ( c => c . SetAsync (
204
- It . IsAny < string > ( ) ,
205
- It . IsAny < PersistedCircuitState > ( ) ,
206
- It . IsAny < HybridCacheEntryOptions > ( ) ,
207
- It . IsAny < IEnumerable < string > > ( ) ,
208
- It . IsAny < CancellationToken > ( ) ) )
209
- . Callback < string , PersistedCircuitState , HybridCacheEntryOptions , IEnumerable < string > , CancellationToken > (
210
- ( key , state , options , tags , ct ) => capturedOptions = options ) ;
211
-
212
- // Act
213
- await provider . PersistCircuitAsync ( circuitId , persistedState ) ;
214
-
215
- // Assert
216
- Assert . NotNull ( capturedOptions ) ;
217
- Assert . Equal ( TimeSpan . FromMinutes ( 5 ) , capturedOptions . Expiration ) ;
218
- Assert . Equal ( TimeSpan . FromMinutes ( 5 ) , capturedOptions . LocalCacheExpiration ) ;
98
+ return new ServiceCollection ( )
99
+ . AddHybridCache ( ) . Services
100
+ . BuildServiceProvider ( )
101
+ . GetRequiredService < HybridCache > ( ) ;
219
102
}
220
103
221
104
private static HybridCacheCircuitPersistenceProvider CreateProvider (
0 commit comments