@@ -23,9 +23,16 @@ public ClientPersistenceTests(MongoDatabaseFixture mongoFixture)
2323 public async Task WhenInsertingAClient_ThenItMustPersistInTheDatabase ( )
2424 {
2525 /* arrange: create client and matching filter */
26+ var realm = _fixture . Create < Realm > ( ) ;
27+
28+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
29+ . Returns ( realm ) ;
30+
2631 var client = _fixture . Build < Client > ( )
2732 . With ( client => client . Name , "federation-admin" )
33+ . With ( client => client . ClientId , "federation-admin-id" )
2834 . With ( client => client . IsDeleted , false )
35+ . With ( client => client . RealmId , realm . Id )
2936 . Create ( ) ;
3037
3138 var filters = ClientFilters . WithSpecifications ( )
@@ -45,9 +52,344 @@ public async Task WhenInsertingAClient_ThenItMustPersistInTheDatabase()
4552 Assert . Equal ( client . Name , retrievedClient . Name ) ;
4653 }
4754
55+ [ Fact ( DisplayName = "[infrastructure] - when updating a client, then updated fields must persist" ) ]
56+ public async Task WhenUpdatingAClient_ThenUpdatedFieldsMustPersist ( )
57+ {
58+ /* arrange: create and insert client */
59+ var realm = _fixture . Create < Realm > ( ) ;
60+
61+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
62+ . Returns ( realm ) ;
63+
64+ var client = _fixture . Build < Client > ( )
65+ . With ( client => client . Name , "update.test" )
66+ . With ( client => client . ClientId , "update.test.client" )
67+ . With ( client => client . IsDeleted , false )
68+ . With ( client => client . RealmId , realm . Id )
69+ . Create ( ) ;
70+
71+ await _clientCollection . InsertAsync ( client ) ;
72+
73+ /* act: update name and save */
74+ var newName = "updated.client" ;
75+
76+ client . Name = newName ;
77+
78+ await _clientCollection . UpdateAsync ( client ) ;
79+
80+ var filters = ClientFilters . WithSpecifications ( )
81+ . WithName ( newName )
82+ . Build ( ) ;
83+
84+ var result = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
85+ var updatedClient = result . FirstOrDefault ( ) ;
86+
87+ /* assert: updated client must be found with new name */
88+ Assert . NotNull ( updatedClient ) ;
89+
90+ Assert . Equal ( client . Id , updatedClient . Id ) ;
91+ Assert . Equal ( newName , updatedClient . Name ) ;
92+ }
93+
94+ [ Fact ( DisplayName = "[infrastructure] - when deleting a client, then it must be marked as deleted and not returned by filters" ) ]
95+ public async Task WhenDeletingAClient_ThenItMustBeMarkedDeletedAndExcludedFromResults ( )
96+ {
97+ /* arrange: create and insert client */
98+ var realm = _fixture . Create < Realm > ( ) ;
99+
100+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
101+ . Returns ( realm ) ;
102+
103+ var client = _fixture . Build < Client > ( )
104+ . With ( client => client . Name , "delete.test" )
105+ . With ( client => client . ClientId , "delete.test.client" )
106+ . With ( client => client . IsDeleted , false )
107+ . With ( client => client . RealmId , realm . Id )
108+ . Create ( ) ;
109+
110+ await _clientCollection . InsertAsync ( client ) ;
111+
112+ var filters = ClientFilters . WithSpecifications ( )
113+ . WithName ( client . Name )
114+ . Build ( ) ;
115+
116+ /* act: delete client and query by name */
117+ var deleted = await _clientCollection . DeleteAsync ( client ) ;
118+
119+ var resultAfterDelete = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
120+
121+ /* assert: no clients should be returned after delete */
122+ Assert . DoesNotContain ( resultAfterDelete , current => current . Id == client . Id ) ;
123+
124+ /* arrange: prepare filters including deleted clients */
125+ var filtersWithDeleted = ClientFilters . WithSpecifications ( )
126+ . WithName ( client . Name )
127+ . WithIsDeleted ( true )
128+ . Build ( ) ;
129+
130+ /* act: refetch clients including deleted */
131+ var resultWithDeleted = await _clientCollection . GetClientsAsync ( filtersWithDeleted , CancellationToken . None ) ;
132+
133+ /* assert: client should be returned when including deleted clients */
134+ Assert . Contains ( resultWithDeleted , current => current . Id == client . Id ) ;
135+
136+ Assert . True ( client . IsDeleted ) ;
137+ Assert . True ( deleted ) ;
138+ }
139+
140+ [ Fact ( DisplayName = "[infrastructure] - when filtering clients by id, then it must return matching client" ) ]
141+ public async Task WhenFilteringClientsById_ThenItMustReturnMatchingClient ( )
142+ {
143+ /* arrange: insert two clients */
144+ var realm = _fixture . Create < Realm > ( ) ;
145+
146+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
147+ . Returns ( realm ) ;
148+
149+ var client1 = _fixture . Build < Client > ( )
150+ . With ( client => client . IsDeleted , false )
151+ . With ( client => client . RealmId , realm . Id )
152+ . Create ( ) ;
153+
154+ var client2 = _fixture . Build < Client > ( )
155+ . With ( client => client . IsDeleted , false )
156+ . With ( client => client . RealmId , realm . Id )
157+ . Create ( ) ;
158+
159+ await _clientCollection . InsertAsync ( client1 ) ;
160+ await _clientCollection . InsertAsync ( client2 ) ;
161+
162+ var filters = ClientFilters . WithSpecifications ( )
163+ . WithIdentifier ( client1 . Id )
164+ . Build ( ) ;
165+
166+ /* act: query clients filtered by id */
167+ var filteredClients = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
168+
169+ /* assert: only client1 should be returned */
170+ Assert . Single ( filteredClients ) ;
171+ Assert . Equal ( client1 . Id , filteredClients . First ( ) . Id ) ;
172+ }
173+
174+ [ Fact ( DisplayName = "[infrastructure] - when filtering clients by current realm, then it must return matching clients" ) ]
175+ public async Task WhenFilteringClientsByCurrentRealm_ThenItMustReturnMatchingClients ( )
176+ {
177+ /* arrange: insert two clients with different realm ids */
178+ var realm = _fixture . Create < Realm > ( ) ;
179+ var anotherRealm = _fixture . Create < Realm > ( ) ;
180+
181+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
182+ . Returns ( realm ) ;
183+
184+ var client1 = _fixture . Build < Client > ( )
185+ . With ( client => client . RealmId , realm . Id )
186+ . With ( client => client . IsDeleted , false )
187+ . Create ( ) ;
188+
189+ var client2 = _fixture . Build < Client > ( )
190+ . With ( client => client . RealmId , anotherRealm . Id )
191+ . With ( client => client . IsDeleted , false )
192+ . Create ( ) ;
193+
194+ await _clientCollection . InsertAsync ( client1 ) ;
195+ await _clientCollection . InsertAsync ( client2 ) ;
196+
197+ var filters = ClientFilters . WithSpecifications ( )
198+ . Build ( ) ;
199+
200+ /* act: query clients filtered by current realm */
201+ var filteredClients = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
202+
203+ /* assert: only client1 should be returned */
204+ Assert . Single ( filteredClients ) ;
205+ Assert . Equal ( client1 . Id , filteredClients . First ( ) . Id ) ;
206+ }
207+
208+ [ Fact ( DisplayName = "[infrastructure] - when filtering clients by name, then it must return matching clients" ) ]
209+ public async Task WhenFilteringClientsByName_ThenItMustReturnMatchingClients ( )
210+ {
211+ /* arrange: insert two clients with different names */
212+ var realm = _fixture . Create < Realm > ( ) ;
213+
214+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
215+ . Returns ( realm ) ;
216+
217+ var client1 = _fixture . Build < Client > ( )
218+ . With ( client => client . Name , "filter1" )
219+ . With ( client => client . IsDeleted , false )
220+ . With ( client => client . RealmId , realm . Id )
221+ . Create ( ) ;
222+
223+ var client2 = _fixture . Build < Client > ( )
224+ . With ( client => client . Name , "filter2" )
225+ . With ( client => client . IsDeleted , false )
226+ . With ( client => client . RealmId , realm . Id )
227+ . Create ( ) ;
228+
229+ await _clientCollection . InsertAsync ( client1 ) ;
230+ await _clientCollection . InsertAsync ( client2 ) ;
231+
232+ var filters = ClientFilters . WithSpecifications ( )
233+ . WithName ( "filter1" )
234+ . Build ( ) ;
235+
236+ /* act: query clients filtered by name */
237+ var filteredClients = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
238+
239+ /* assert: only client1 should be returned */
240+ Assert . Single ( filteredClients ) ;
241+ Assert . Equal ( client1 . Id , filteredClients . First ( ) . Id ) ;
242+ }
243+
244+ [ Fact ( DisplayName = "[infrastructure] - when filtering clients by client id, then it must return matching clients" ) ]
245+ public async Task WhenFilteringClientsByClientId_ThenItMustReturnMatchingClients ( )
246+ {
247+ /* arrange: insert two clients with different client ids */
248+ var realm = _fixture . Create < Realm > ( ) ;
249+
250+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
251+ . Returns ( realm ) ;
252+
253+ var client1 = _fixture . Build < Client > ( )
254+ . With ( client => client . ClientId , "client.filter.1" )
255+ . With ( client => client . IsDeleted , false )
256+ . With ( client => client . RealmId , realm . Id )
257+ . Create ( ) ;
258+
259+ var client2 = _fixture . Build < Client > ( )
260+ . With ( client => client . ClientId , "client.filter.2" )
261+ . With ( client => client . IsDeleted , false )
262+ . With ( client => client . RealmId , realm . Id )
263+ . Create ( ) ;
264+
265+ await _clientCollection . InsertAsync ( client1 ) ;
266+ await _clientCollection . InsertAsync ( client2 ) ;
267+
268+ var filters = ClientFilters . WithSpecifications ( )
269+ . WithClientId ( "client.filter.1" )
270+ . Build ( ) ;
271+
272+ /* act: query clients filtered by client id */
273+ var filteredClients = await _clientCollection . GetClientsAsync ( filters , CancellationToken . None ) ;
274+
275+ /* assert: only client1 should be returned */
276+ Assert . Single ( filteredClients ) ;
277+ Assert . Equal ( client1 . Id , filteredClients . First ( ) . Id ) ;
278+ }
279+
280+ [ Fact ( DisplayName = "[infrastructure] - when paginating 10 clients with page size 5, then it must return 5 clients per page" ) ]
281+ public async Task WhenPaginatingTenClients_ThenItMustReturnFiveClientsPerPage ( )
282+ {
283+ /* arrange: create and insert 10 clients, all not deleted */
284+ var realm = _fixture . Create < Realm > ( ) ;
285+
286+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
287+ . Returns ( realm ) ;
288+
289+ var clients = Enumerable . Range ( 1 , 10 )
290+ . Select ( index => _fixture . Build < Client > ( )
291+ . With ( client => client . Name , $ "client.{ index } ")
292+ . With ( client => client . ClientId , $ "client-id.{ index } ")
293+ . With ( client => client . IsDeleted , false )
294+ . With ( client => client . RealmId , realm . Id )
295+ . Create ( ) )
296+ . ToList ( ) ;
297+
298+ foreach ( var client in clients )
299+ {
300+ await _clientCollection . InsertAsync ( client ) ;
301+ }
302+
303+ /* arrange: prepare filters for page 1 with page size 5 */
304+ var filtersPage1 = ClientFilters . WithSpecifications ( )
305+ . WithPagination ( PaginationFilters . From ( pageNumber : 1 , pageSize : 5 ) )
306+ . Build ( ) ;
307+
308+ /* act: get first page */
309+ var page1Results = await _clientCollection . GetClientsAsync ( filtersPage1 , CancellationToken . None ) ;
310+
311+ /* assert: page 1 should return exactly 5 clients */
312+ Assert . Equal ( 5 , page1Results . Count ) ;
313+
314+ /* arrange: prepare filters for page 2 with page size 5 */
315+ var filtersPage2 = ClientFilters . WithSpecifications ( )
316+ . WithPagination ( PaginationFilters . From ( pageNumber : 2 , pageSize : 5 ) )
317+ . Build ( ) ;
318+
319+ /* act: get second page */
320+ var page2Results = await _clientCollection . GetClientsAsync ( filtersPage2 , CancellationToken . None ) ;
321+
322+ /* assert: page 2 should return exactly 5 clients */
323+ Assert . Equal ( 5 , page2Results . Count ) ;
324+ }
325+
326+ [ Fact ( DisplayName = "[infrastructure] - when counting 10 clients with isDeleted = false, then it must return 10" ) ]
327+ public async Task WhenCountingTenClientsWithIsDeletedFalse_ThenItMustReturnTen ( )
328+ {
329+ /* arrange: create and insert 10 clients, all not deleted */
330+ var realm = _fixture . Create < Realm > ( ) ;
331+
332+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
333+ . Returns ( realm ) ;
334+
335+ var clients = Enumerable . Range ( 1 , 10 )
336+ . Select ( index => _fixture . Build < Client > ( )
337+ . With ( client => client . Name , $ "client.{ index } ")
338+ . With ( client => client . ClientId , $ "client-id.{ index } ")
339+ . With ( client => client . IsDeleted , false )
340+ . With ( client => client . RealmId , realm . Id )
341+ . Create ( ) )
342+ . ToList ( ) ;
343+
344+ await _clientCollection . InsertManyAsync ( clients ) ;
345+
346+ /* arrange: prepare filters with IsDeleted = false */
347+ var filters = ClientFilters . WithSpecifications ( )
348+ . WithIsDeleted ( false )
349+ . Build ( ) ;
350+
351+ /* act: count clients matching filters */
352+ var total = await _clientCollection . CountClientsAsync ( filters ) ;
353+
354+ /* assert: should return 10 */
355+ Assert . Equal ( 10 , ( int ) total ) ;
356+ }
357+
358+ [ Fact ( DisplayName = "[infrastructure] - when counting 10 clients with isDeleted = true, then it must return 0" ) ]
359+ public async Task WhenCountingTenClientsWithIsDeletedTrue_ThenItMustReturnZero ( )
360+ {
361+ /* arrange: create and insert 10 clients, all not deleted */
362+ var realm = _fixture . Create < Realm > ( ) ;
363+
364+ _realmProvider . Setup ( provider => provider . GetCurrentRealm ( ) )
365+ . Returns ( realm ) ;
366+
367+ var clients = Enumerable . Range ( 1 , 10 )
368+ . Select ( index => _fixture . Build < Client > ( )
369+ . With ( client => client . Name , $ "client.{ index } ")
370+ . With ( client => client . ClientId , $ "client-id.{ index } ")
371+ . With ( client => client . IsDeleted , false )
372+ . With ( client => client . RealmId , realm . Id )
373+ . Create ( ) )
374+ . ToList ( ) ;
375+
376+ await _clientCollection . InsertManyAsync ( clients ) ;
377+
378+ /* arrange: prepare filters with IsDeleted = true */
379+ var filters = ClientFilters . WithSpecifications ( )
380+ . WithIsDeleted ( true )
381+ . Build ( ) ;
382+
383+ /* act: count clients matching filters */
384+ var total = await _clientCollection . CountClientsAsync ( filters ) ;
385+
386+ /* assert: should return 0 */
387+ Assert . Equal ( 0 , ( int ) total ) ;
388+ }
389+
48390 public async Task DisposeAsync ( ) => await Task . CompletedTask ;
49391 public async Task InitializeAsync ( )
50392 {
51393 await _mongoFixture . CleanDatabaseAsync ( ) ;
52394 }
53- }
395+ }
0 commit comments