1
1
// Copyright Finbuckle LLC, Andrew White, and Contributors.
2
2
// Refer to the solution LICENSE file for more information.
3
3
4
+ using System . Text ;
5
+ using System . Text . Json ;
4
6
using Finbuckle . MultiTenant . Abstractions ;
5
7
using Finbuckle . MultiTenant . Internal ;
6
8
using Finbuckle . MultiTenant . Stores . DistributedCacheStore ;
7
9
using Microsoft . Extensions . Caching . Distributed ;
8
10
using Microsoft . Extensions . DependencyInjection ;
11
+ using Moq ;
9
12
using Xunit ;
10
13
11
14
namespace Finbuckle . MultiTenant . Test . Stores ;
12
15
13
16
public class DistributedCacheStoreShould : MultiTenantStoreTestBase
14
17
{
15
18
[ Fact ]
16
- public void ThrownOnGetAllTenantsFromStoreAsync ( )
19
+ public async Task ThrowOnGetAllTenantsFromStoreAsync ( )
17
20
{
18
21
var store = CreateTestStore ( ) ;
19
- Assert . Throws < NotImplementedException > ( ( ) => store . GetAllAsync ( ) . Wait ( ) ) ;
22
+ await Assert . ThrowsAsync < NotImplementedException > ( async ( ) => await store . GetAllAsync ( ) ) ;
20
23
}
21
24
22
25
[ Fact ]
@@ -45,7 +48,7 @@ public async Task RemoveReturnsFalseWhenNoMatchingIdentifierFound()
45
48
}
46
49
47
50
[ Fact ]
48
- public async Task AddDualEntriesOnAddOrUpdate ( )
51
+ public async Task AddDualEntriesOnAdd ( )
49
52
{
50
53
var store = CreateTestStore ( ) ;
51
54
@@ -61,34 +64,69 @@ public async Task AddDualEntriesOnAddOrUpdate()
61
64
}
62
65
63
66
[ Fact ]
64
- public async Task RefreshDualEntriesOnAddOrUpdate ( )
67
+ public async Task RefreshDualEntriesOnTryGet ( )
65
68
{
66
- var store = CreateTestStore ( ) ;
67
- await Task . Delay ( 1500 ) ;
69
+ var cache = new Mock < IDistributedCache > ( ) ;
70
+ cache . Setup ( c => c . GetAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
71
+ . ReturnsAsync ( Encoding . UTF8 . GetBytes ( JsonSerializer . Serialize ( new TenantInfo
72
+ { Id = "lol-id" , Identifier = "lol" } ) ) ) ;
73
+
74
+ var store = new DistributedCacheStore < TenantInfo > ( cache . Object , Constants . TenantToken , TimeSpan . FromSeconds ( 1 ) ) ;
75
+
68
76
var t1 = await store . TryGetAsync ( "lol-id" ) ;
69
- await Task . Delay ( 1500 ) ;
70
- var t2 = await store . TryGetByIdentifierAsync ( "lol" ) ;
71
- await Task . Delay ( 1500 ) ;
72
- var t3 = await store . TryGetAsync ( "lol-id" ) ;
77
+ cache . Verify ( c => c . RefreshAsync ( It . IsAny < string > ( ) , CancellationToken . None ) , Times . Once ) ;
78
+ }
73
79
74
- Assert . NotNull ( t1 ) ;
75
- Assert . NotNull ( t2 ) ;
76
- Assert . NotNull ( t3 ) ;
77
- Assert . Equal ( "lol-id" , t1 . Id ) ;
78
- Assert . Equal ( "lol-id" , t2 . Id ) ;
79
- Assert . Equal ( "lol-id" , t3 . Id ) ;
80
+ [ Fact ]
81
+ public async Task RefreshDualEntriesOnTryGetByIdentifier ( )
82
+ {
83
+ var cache = new Mock < IDistributedCache > ( ) ;
84
+ cache . Setup ( c => c . GetAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
85
+ . ReturnsAsync ( Encoding . UTF8 . GetBytes ( JsonSerializer . Serialize ( new TenantInfo
86
+ { Id = "lol-id" , Identifier = "lol" } ) ) ) ;
87
+
88
+ var store = new DistributedCacheStore < TenantInfo > ( cache . Object , Constants . TenantToken , TimeSpan . FromSeconds ( 1 ) ) ;
89
+
90
+ var t1 = await store . TryGetByIdentifierAsync ( "lol-id" ) ;
91
+ cache . Verify ( c => c . RefreshAsync ( It . IsAny < string > ( ) , CancellationToken . None ) , Times . Once ) ;
80
92
}
93
+
94
+ [ Fact ]
95
+ public async Task SetSlidingExpirationOnAdd ( )
96
+ {
97
+ var cache = new Mock < IDistributedCache > ( ) ;
98
+ var options = new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan . FromSeconds ( 1 ) } ;
99
+
100
+ cache . Setup ( c => c . SetAsync ( It . IsAny < string > ( ) , It . IsAny < byte [ ] > ( ) ,
101
+ It . IsAny < DistributedCacheEntryOptions > ( ) , It . IsAny < CancellationToken > ( ) ) )
102
+ . Callback < string , byte [ ] , DistributedCacheEntryOptions , CancellationToken > ( ( key , value , opts , token ) =>
103
+ {
104
+ Assert . Equal ( options . SlidingExpiration , opts . SlidingExpiration ) ;
105
+ } )
106
+ . Returns ( Task . CompletedTask ) ;
107
+
108
+ var store = new DistributedCacheStore < TenantInfo > ( cache . Object , Constants . TenantToken , TimeSpan . FromSeconds ( 1 ) ) ;
81
109
110
+ await store . TryAddAsync ( new TenantInfo { Id = "test-id" , Identifier = "test" , Name = "Test Tenant" } ) ;
111
+ }
112
+
82
113
[ Fact ]
83
- public async Task ExpireDualEntriesAfterTimespan ( )
114
+ public async Task SetSlidingExpirationOnUpdate ( )
84
115
{
85
- var store = CreateTestStore ( ) ;
86
- await Task . Delay ( 2100 ) ;
87
- var t1 = await store . TryGetAsync ( "lol-id" ) ;
88
- var t2 = await store . TryGetByIdentifierAsync ( "lol" ) ;
116
+ var cache = new Mock < IDistributedCache > ( ) ;
117
+ var options = new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan . FromSeconds ( 1 ) } ;
89
118
90
- Assert . Null ( t1 ) ;
91
- Assert . Null ( t2 ) ;
119
+ cache . Setup ( c => c . SetAsync ( It . IsAny < string > ( ) , It . IsAny < byte [ ] > ( ) ,
120
+ It . IsAny < DistributedCacheEntryOptions > ( ) , It . IsAny < CancellationToken > ( ) ) )
121
+ . Callback < string , byte [ ] , DistributedCacheEntryOptions , CancellationToken > ( ( key , value , opts , token ) =>
122
+ {
123
+ Assert . Equal ( options . SlidingExpiration , opts . SlidingExpiration ) ;
124
+ } )
125
+ . Returns ( Task . CompletedTask ) ;
126
+
127
+ var store = new DistributedCacheStore < TenantInfo > ( cache . Object , Constants . TenantToken , TimeSpan . FromSeconds ( 1 ) ) ;
128
+
129
+ await store . TryAddAsync ( new TenantInfo { Id = "test-id" , Identifier = "test" , Name = "Test Tenant" } ) ;
92
130
}
93
131
94
132
// Basic store functionality tested in MultiTenantStoresShould.cs
@@ -99,7 +137,8 @@ protected override IMultiTenantStore<TenantInfo> CreateTestStore()
99
137
services . AddOptions ( ) . AddDistributedMemoryCache ( ) ;
100
138
var sp = services . BuildServiceProvider ( ) ;
101
139
102
- var store = new DistributedCacheStore < TenantInfo > ( sp . GetRequiredService < IDistributedCache > ( ) , Constants . TenantToken , TimeSpan . FromMilliseconds ( 2000 ) ) ;
140
+ var store = new DistributedCacheStore < TenantInfo > ( sp . GetRequiredService < IDistributedCache > ( ) ,
141
+ Constants . TenantToken , TimeSpan . MaxValue ) ;
103
142
104
143
return PopulateTestStore ( store ) ;
105
144
}
0 commit comments