@@ -269,20 +269,21 @@ describe("key vault reference deduplication", function () {
269269 } ) ;
270270
271271 it ( "should re-fetch once per unique secret on a key-value change reload" , async ( ) => {
272- const sentinelEtag = "sentinel-etag" ;
273- const kvs = [
274- ...[ "TestKey1" , "TestKey2" , "TestKey3" , "TestKey4" , "TestKey5" ] . map ( ( key ) => createMockedKeyVaultReference ( key , sameSecretUri ) ) ,
275- createMockedKeyValue ( { key : "sentinel" , value : "v1" , etag : sentinelEtag } )
272+ const secretKeys = [ "TestKey1" , "TestKey2" , "TestKey3" , "TestKey4" , "TestKey5" ] ;
273+ // Mutable page so the sentinel can change without re-stubbing (which would tear down the fake clock).
274+ const kvPage = [
275+ ...secretKeys . map ( ( key ) => createMockedKeyVaultReference ( key , sameSecretUri ) ) ,
276+ createMockedKeyValue ( { key : "sentinel" , value : "v1" , etag : "sentinel-etag-1" } )
276277 ] ;
277- mockAppConfigurationClientListConfigurationSettings ( [ kvs ] ) ;
278- mockAppConfigurationClientGetConfigurationSetting ( kvs ) ;
278+ mockAppConfigurationClientListConfigurationSettings ( [ kvPage ] ) ;
279+ mockAppConfigurationClientGetConfigurationSetting ( kvPage ) ;
279280
280281 const client = new SecretClient ( "https://fake-vault-name.vault.azure.net" , createMockedTokenCredential ( ) ) ;
282+ let secretValue = "SecretValue-initial" ;
281283 let callCount = 0 ;
282284 sinon . stub ( client , "getSecret" ) . callsFake ( async ( ) => {
283285 callCount ++ ;
284- await sleepInMs ( 100 ) ;
285- return { value : `SecretValue-${ callCount } ` } as KeyVaultSecret ;
286+ return { value : secretValue } as KeyVaultSecret ;
286287 } ) ;
287288
288289 const settings = await load ( createMockedConnectionString ( ) , {
@@ -299,30 +300,26 @@ describe("key vault reference deduplication", function () {
299300 // Initial load resolves the duplicates with a single request.
300301 expect ( callCount ) . eq ( 1 ) ;
301302
302- // Wait past the min secret refresh interval so the key-value change reload re-fetches secrets.
303- await sleepInMs ( 60_000 + 100 ) ;
303+ // Install the fake clock seeded with the current time so the refresh timers (created during load) stay consistent.
304+ const clock = sinon . useFakeTimers ( { now : Date . now ( ) } ) ;
305+ try {
306+ // Advance past the min secret refresh interval so the key-value change reload clears the cache.
307+ await clock . tickAsync ( 60_000 + 100 ) ;
304308
305- // Trigger a key-value change reload by changing the sentinel.
306- const updatedKvs = [
307- ...[ "TestKey1" , "TestKey2" , "TestKey3" , "TestKey4" , "TestKey5" ] . map ( ( key ) => createMockedKeyVaultReference ( key , sameSecretUri ) ) ,
308- createMockedKeyValue ( { key : "sentinel" , value : "v2" , etag : "sentinel-etag-2" } )
309- ] ;
310- restoreMocks ( ) ;
311- mockAppConfigurationClientListConfigurationSettings ( [ updatedKvs ] ) ;
312- mockAppConfigurationClientGetConfigurationSetting ( updatedKvs ) ;
313- let reloadCallCount = 0 ;
314- sinon . stub ( client , "getSecret" ) . callsFake ( async ( ) => {
315- reloadCallCount ++ ;
316- await sleepInMs ( 100 ) ;
317- return { value : "SecretValue-reloaded" } as KeyVaultSecret ;
318- } ) ;
309+ // Change the watched sentinel (new etag) and the secret value in place to trigger a reload.
310+ kvPage [ kvPage . length - 1 ] = createMockedKeyValue ( { key : "sentinel" , value : "v2" , etag : "sentinel-etag-2" } ) ;
311+ secretValue = "SecretValue-reloaded" ;
312+ const callCountBeforeReload = callCount ;
319313
320- await settings . refresh ( ) ;
314+ await settings . refresh ( ) ;
321315
322- // The key-value change reload clears the cache and re-fetches, but only once for the unique secret.
323- expect ( reloadCallCount ) . eq ( 1 ) ;
324- for ( const key of [ "TestKey1" , "TestKey2" , "TestKey3" , "TestKey4" , "TestKey5" ] ) {
325- expect ( settings . get ( key ) ) . eq ( "SecretValue-reloaded" ) ;
316+ // The key-value change reload clears the cache and re-fetches, but only once for the unique secret.
317+ expect ( callCount - callCountBeforeReload ) . eq ( 1 ) ;
318+ for ( const key of secretKeys ) {
319+ expect ( settings . get ( key ) ) . eq ( "SecretValue-reloaded" ) ;
320+ }
321+ } finally {
322+ clock . restore ( ) ;
326323 }
327324 } ) ;
328325
@@ -332,7 +329,6 @@ describe("key vault reference deduplication", function () {
332329 let callCount = 0 ;
333330 sinon . stub ( client , "getSecret" ) . callsFake ( async ( ) => {
334331 callCount ++ ;
335- await sleepInMs ( 100 ) ;
336332 return { value : `SecretValue-${ callCount } ` } as KeyVaultSecret ;
337333 } ) ;
338334
@@ -347,9 +343,14 @@ describe("key vault reference deduplication", function () {
347343 expect ( callCount ) . eq ( 1 ) ;
348344 expect ( settings . get ( "TestKey1" ) ) . eq ( "SecretValue-1" ) ;
349345
350- // After the secret refresh interval elapses, the refresh round re-fetches once.
351- await sleepInMs ( 60_000 + 100 ) ;
352- await settings . refresh ( ) ;
346+ // Advance past the secret refresh interval using a fake clock so the refresh round re-fetches once.
347+ const clock = sinon . useFakeTimers ( { now : Date . now ( ) } ) ;
348+ try {
349+ await clock . tickAsync ( 60_000 + 100 ) ;
350+ await settings . refresh ( ) ;
351+ } finally {
352+ clock . restore ( ) ;
353+ }
353354 expect ( callCount ) . eq ( 2 ) ;
354355 expect ( settings . get ( "TestKey1" ) ) . eq ( "SecretValue-2" ) ;
355356 } ) ;
0 commit comments