@@ -498,6 +498,140 @@ public void Constructor_WithCreateHostSecretsIfMissingSet_CreatesHostSecret()
498498 }
499499 }
500500
501+ [ Fact ]
502+ public async Task GetHostSecretsAsync_WaitsForNewSecrets ( )
503+ {
504+ using ( var directory = new TempDirectory ( ) )
505+ {
506+ string hostSecretsJson = @"{
507+ 'masterKey': {
508+ 'name': 'master',
509+ 'value': '1234',
510+ 'encrypted': false
511+ },
512+ 'functionKeys': [],
513+ 'systemKeys': []
514+ }" ;
515+ string filePath = Path . Combine ( directory . Path , ScriptConstants . HostMetadataFileName ) ;
516+ File . WriteAllText ( filePath , hostSecretsJson ) ;
517+
518+ HostSecretsInfo hostSecrets = null ;
519+ var traceWriter = new TestTraceWriter ( TraceLevel . Verbose ) ;
520+ ISecretsRepository repository = new FileSystemSecretsRepository ( directory . Path ) ;
521+
522+ using ( var secretManager = new SecretManager ( _settingsManager , repository , traceWriter , null ) )
523+ {
524+ await Task . WhenAll (
525+ Task . Run ( async ( ) =>
526+ {
527+ // Lock the file
528+ using ( FileStream fs = new FileStream ( filePath , FileMode . Open , FileAccess . Write ) )
529+ {
530+ await Task . Delay ( 500 ) ;
531+ }
532+ } ) ,
533+ Task . Run ( async ( ) =>
534+ {
535+ await Task . Delay ( 100 ) ;
536+ hostSecrets = await secretManager . GetHostSecretsAsync ( ) ;
537+ } ) ) ;
538+
539+ Assert . Equal ( hostSecrets . MasterKey , "1234" ) ;
540+ }
541+
542+ using ( var secretManager = new SecretManager ( _settingsManager , repository , traceWriter , null ) )
543+ {
544+ await Assert . ThrowsAsync < IOException > ( async ( ) =>
545+ {
546+ await Task . WhenAll (
547+ Task . Run ( async ( ) =>
548+ {
549+ // Lock the file
550+ using ( FileStream fs = new FileStream ( filePath , FileMode . Open , FileAccess . Write ) )
551+ {
552+ await Task . Delay ( 3000 ) ;
553+ }
554+ } ) ,
555+ Task . Run ( async ( ) =>
556+ {
557+ await Task . Delay ( 100 ) ;
558+ hostSecrets = await secretManager . GetHostSecretsAsync ( ) ;
559+ } ) ) ;
560+ } ) ;
561+ }
562+ }
563+ }
564+
565+ [ Fact ]
566+ public async Task GetFunctionSecretsAsync_WaitsForNewSecrets ( )
567+ {
568+ using ( var directory = new TempDirectory ( ) )
569+ {
570+ string functionName = "testfunction" ;
571+ string functionSecretsJson =
572+ @"{
573+ 'keys': [
574+ {
575+ 'name': 'Key1',
576+ 'value': 'FunctionValue1',
577+ 'encrypted': false
578+ },
579+ {
580+ 'name': 'Key2',
581+ 'value': 'FunctionValue2',
582+ 'encrypted': false
583+ }
584+ ]
585+ }" ;
586+ string filePath = Path . Combine ( directory . Path , functionName + ".json" ) ;
587+ File . WriteAllText ( filePath , functionSecretsJson ) ;
588+
589+ IDictionary < string , string > functionSecrets = null ;
590+ var traceWriter = new TestTraceWriter ( TraceLevel . Verbose ) ;
591+ ISecretsRepository repository = new FileSystemSecretsRepository ( directory . Path ) ;
592+ using ( var secretManager = new SecretManager ( _settingsManager , repository , traceWriter , null ) )
593+ {
594+ await Task . WhenAll (
595+ Task . Run ( async ( ) =>
596+ {
597+ // Lock the file
598+ using ( FileStream fs = new FileStream ( filePath , FileMode . Open , FileAccess . Write ) )
599+ {
600+ await Task . Delay ( 500 ) ;
601+ }
602+ } ) ,
603+ Task . Run ( async ( ) =>
604+ {
605+ await Task . Delay ( 100 ) ;
606+ functionSecrets = await secretManager . GetFunctionSecretsAsync ( functionName ) ;
607+ } ) ) ;
608+
609+ Assert . Equal ( functionSecrets [ "Key1" ] , "FunctionValue1" ) ;
610+ }
611+
612+ using ( var secretManager = new SecretManager ( _settingsManager , repository , traceWriter , null ) )
613+ {
614+ await Assert . ThrowsAsync < IOException > ( async ( ) =>
615+ {
616+ await Task . WhenAll (
617+ Task . Run ( async ( ) =>
618+ {
619+ // Lock the file
620+ using ( FileStream fs = new FileStream ( filePath , FileMode . Open , FileAccess . Write ) )
621+ {
622+ await Task . Delay ( 3000 ) ;
623+ }
624+ } ) ,
625+ Task . Run ( async ( ) =>
626+ {
627+ await Task . Delay ( 100 ) ;
628+ functionSecrets = await secretManager . GetFunctionSecretsAsync ( functionName ) ;
629+ } ) ) ;
630+ } ) ;
631+ }
632+ }
633+ }
634+
501635 private Mock < IKeyValueConverterFactory > GetConverterFactoryMock ( bool simulateWriteConversion = true , bool setStaleValue = true )
502636 {
503637 var mockValueReader = new Mock < IKeyValueReader > ( ) ;
0 commit comments