@@ -264,15 +264,39 @@ mod tests {
264264 assert_eq ! ( cache. len( ) . await , 2 ) ;
265265 }
266266
267+ async fn backdate_entry ( cache : & IssuerKeyCache , pubkey : & str , age : Duration ) -> Instant {
268+ let inserted_at = Instant :: now ( ) . checked_sub ( age) . unwrap ( ) ;
269+ cache
270+ . entries
271+ . lock ( )
272+ . await
273+ . peek_mut ( pubkey)
274+ . unwrap ( )
275+ . inserted_at = inserted_at;
276+ inserted_at
277+ }
278+
279+ async fn entry_inserted_at ( cache : & IssuerKeyCache , pubkey : & str ) -> Instant {
280+ cache. entries . lock ( ) . await . peek ( pubkey) . unwrap ( ) . inserted_at
281+ }
282+
267283 #[ tokio:: test]
268284 async fn issuer_key_cache_refreshes_expired_entries ( ) {
269- let cache = IssuerKeyCache :: with_capacity_and_ttl ( 4 , Duration :: ZERO ) ;
285+ let ttl = Duration :: from_secs ( 3600 ) ;
286+ let cache = IssuerKeyCache :: with_capacity_and_ttl ( 4 , ttl) ;
270287 let key = SigningKey :: generate ( & mut jsonwebtoken:: signature:: rand_core:: OsRng ) ;
271288 let pubkey = pubkey_b64 ( & key) ;
272289 cache. get_or_insert ( & pubkey) . await . unwrap ( ) ;
273- assert_eq ! ( cache. len( ) . await , 1 ) ;
274- // A zero TTL forces every lookup to expire and refresh instead of accumulating.
290+
291+ // Just inside the TTL: served from cache, entry untouched.
292+ let inside = backdate_entry ( & cache, & pubkey, ttl - Duration :: from_secs ( 60 ) ) . await ;
293+ cache. get_or_insert ( & pubkey) . await . unwrap ( ) ;
294+ assert_eq ! ( entry_inserted_at( & cache, & pubkey) . await , inside) ;
295+
296+ // Just past the TTL: refreshed in place without accumulating.
297+ let expired = backdate_entry ( & cache, & pubkey, ttl + Duration :: from_secs ( 1 ) ) . await ;
275298 cache. get_or_insert ( & pubkey) . await . unwrap ( ) ;
299+ assert ! ( entry_inserted_at( & cache, & pubkey) . await > expired) ;
276300 assert_eq ! ( cache. len( ) . await , 1 ) ;
277301 }
278302
0 commit comments