@@ -267,6 +267,8 @@ await service.ApplyAsync(
267267 Snapshot ( members : [ Member ( 111UL ) , Member ( 222UL ) ] ) ) ,
268268 CancellationToken . None ) ;
269269
270+ // 111 is missing from the cache, so the socket call must happen and its answer recorded.
271+ await _query . Received ( 1 ) . GetTeamInfoAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) ;
270272 await _store . Received ( 1 ) . RecordNameAsync ( Guild , Server , 111UL , "Alice" , Arg . Any < CancellationToken > ( ) ) ;
271273
272274 // 222 is already cached, and 333 is on the team but not in the clan.
@@ -276,18 +278,46 @@ await _store.DidNotReceive()
276278 . RecordNameAsync ( Guild , Server , 333UL , Arg . Any < string > ( ) , Arg . Any < CancellationToken > ( ) ) ;
277279 }
278280
281+ [ Fact ]
282+ public async Task Skips_the_team_query_when_every_roster_member_already_has_a_cached_name ( )
283+ {
284+ // OnClanChanged fires on any clan edit, including score changes, and score moves on every
285+ // kill: once the whole roster's names are cached this must cost zero companion-API RPCs.
286+ _store . GetAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) . Returns ( ( ClanSnapshot ? ) null ) ;
287+ _store . GetNamesAsync ( Guild , Server , Arg . Any < IReadOnlyCollection < ulong > > ( ) , Arg . Any < CancellationToken > ( ) )
288+ . Returns ( new Dictionary < ulong , string >
289+ {
290+ [ 111UL ] = "Alice" , [ 222UL ] = "Bob"
291+ } ) ;
292+ var service = Build ( ) ;
293+
294+ await service . ApplyAsync (
295+ new ClanStateChangedEvent ( Guild , Server , ClanProbeStatus . HasClan ,
296+ Snapshot ( members : [ Member ( 111UL ) , Member ( 222UL ) ] ) ) ,
297+ CancellationToken . None ) ;
298+
299+ await _query . DidNotReceive ( )
300+ . GetTeamInfoAsync ( Arg . Any < ulong > ( ) , Arg . Any < Guid > ( ) , Arg . Any < CancellationToken > ( ) ) ;
301+ await _store . DidNotReceive ( ) . RecordNameAsync ( Arg . Any < ulong > ( ) , Arg . Any < Guid > ( ) , Arg . Any < ulong > ( ) ,
302+ Arg . Any < string > ( ) , Arg . Any < CancellationToken > ( ) ) ;
303+ }
304+
279305 [ Fact ]
280306 public async Task A_null_team_snapshot_records_nothing_and_changes_nothing_else ( )
281307 {
282308 _query . GetTeamInfoAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) )
283309 . Returns ( ( TeamInfoSnapshot ? ) null ) ;
284- _store . GetAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) . Returns ( Snapshot ( ) ) ;
285- var renamed = Snapshot ( "Bears" ) ;
310+ // A non-empty, uncached roster so the harvest actually reaches the socket call whose
311+ // null answer this test is meant to prove is harmless.
312+ _store . GetAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) )
313+ . Returns ( Snapshot ( members : [ Member ( 111UL ) ] ) ) ;
314+ var renamed = Snapshot ( "Bears" , members : [ Member ( 111UL ) ] ) ;
286315 var service = Build ( ) ;
287316
288317 await service . ApplyAsync ( new ClanStateChangedEvent ( Guild , Server , ClanProbeStatus . HasClan , renamed ) ,
289318 CancellationToken . None ) ;
290319
320+ await _query . Received ( 1 ) . GetTeamInfoAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) ;
291321 await _store . DidNotReceive ( ) . RecordNameAsync ( Arg . Any < ulong > ( ) , Arg . Any < Guid > ( ) , Arg . Any < ulong > ( ) ,
292322 Arg . Any < string > ( ) , Arg . Any < CancellationToken > ( ) ) ;
293323 await _store . Received ( 1 ) . SaveAsync ( Guild , Server , renamed , Arg . Any < CancellationToken > ( ) ) ;
@@ -299,13 +329,16 @@ public async Task A_failing_team_query_still_persists_the_clan_and_posts_the_fee
299329 {
300330 _query . GetTeamInfoAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) )
301331 . Returns < TeamInfoSnapshot ? > ( _ => throw new InvalidOperationException ( "socket gone" ) ) ;
302- _store . GetAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) . Returns ( Snapshot ( ) ) ;
303- var renamed = Snapshot ( "Bears" ) ;
332+ // A non-empty, uncached roster so the harvest actually reaches the socket call that throws.
333+ _store . GetAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) )
334+ . Returns ( Snapshot ( members : [ Member ( 111UL ) ] ) ) ;
335+ var renamed = Snapshot ( "Bears" , members : [ Member ( 111UL ) ] ) ;
304336 var service = Build ( ) ;
305337
306338 await service . ApplyAsync ( new ClanStateChangedEvent ( Guild , Server , ClanProbeStatus . HasClan , renamed ) ,
307339 CancellationToken . None ) ;
308340
341+ await _query . Received ( 1 ) . GetTeamInfoAsync ( Guild , Server , Arg . Any < CancellationToken > ( ) ) ;
309342 await _store . Received ( 1 ) . SaveAsync ( Guild , Server , renamed , Arg . Any < CancellationToken > ( ) ) ;
310343 await _poster . Received ( 1 ) . PostAsync ( Channel , "clan.event.renamed" , Arg . Any < CancellationToken > ( ) ) ;
311344 }
0 commit comments