@@ -18,9 +18,9 @@ public sealed class ConfigureCertificateOptionsTest
1818{
1919 private const string CertificateName = "test" ;
2020
21+ [ Theory ]
2122 [ InlineData ( "" ) ]
2223 [ InlineData ( CertificateName ) ]
23- [ Theory ]
2424 public void ConfigureCertificateOptions_NoPath_NoCertificate ( string certificateName )
2525 {
2626 var configureOptions = new ConfigureCertificateOptions ( new ConfigurationBuilder ( ) . Build ( ) ) ;
@@ -31,9 +31,9 @@ public void ConfigureCertificateOptions_NoPath_NoCertificate(string certificateN
3131 options . Certificate . Should ( ) . BeNull ( ) ;
3232 }
3333
34+ [ Theory ]
3435 [ InlineData ( "" ) ]
3536 [ InlineData ( CertificateName ) ]
36- [ Theory ]
3737 public void ConfigureCertificateOptions_BadPath_NoCertificate ( string certificateName )
3838 {
3939 IConfigurationRoot configurationRoot = new ConfigurationBuilder ( ) . AddInMemoryCollection ( new Dictionary < string , string ? >
@@ -50,9 +50,9 @@ public void ConfigureCertificateOptions_BadPath_NoCertificate(string certificate
5050 options . Certificate . Should ( ) . BeNull ( ) ;
5151 }
5252
53+ [ Theory ]
5354 [ InlineData ( "" ) ]
5455 [ InlineData ( CertificateName ) ]
55- [ Theory ]
5656 public void ConfigureCertificateOptions_EmptyFile_Crashes ( string certificateName )
5757 {
5858 IConfigurationRoot configurationRoot = new ConfigurationBuilder ( ) . AddInMemoryCollection ( new Dictionary < string , string ? >
@@ -69,9 +69,9 @@ public void ConfigureCertificateOptions_EmptyFile_Crashes(string certificateName
6969 options . Certificate . Should ( ) . BeNull ( ) ;
7070 }
7171
72+ [ Theory ]
7273 [ InlineData ( "" ) ]
7374 [ InlineData ( CertificateName ) ]
74- [ Theory ]
7575 public void ConfigureCertificateOptions_ThrowsOnInvalidKey ( string certificateName )
7676 {
7777 IConfigurationRoot configurationRoot = new ConfigurationBuilder ( ) . AddInMemoryCollection ( new Dictionary < string , string ? >
@@ -88,9 +88,9 @@ public void ConfigureCertificateOptions_ThrowsOnInvalidKey(string certificateNam
8888 options . Certificate . Should ( ) . BeNull ( ) ;
8989 }
9090
91+ [ Theory ]
9192 [ InlineData ( "" ) ]
9293 [ InlineData ( CertificateName ) ]
93- [ Theory ]
9494 public void ConfigureCertificateOptions_ReadsP12File_CreatesCertificate ( string certificateName )
9595 {
9696 IConfigurationRoot configurationRoot = new ConfigurationBuilder ( ) . AddCertificate ( certificateName , "instance.p12" ) . Build ( ) ;
@@ -104,9 +104,9 @@ public void ConfigureCertificateOptions_ReadsP12File_CreatesCertificate(string c
104104 options . Certificate . HasPrivateKey . Should ( ) . BeTrue ( ) ;
105105 }
106106
107+ [ Theory ]
107108 [ InlineData ( "" ) ]
108109 [ InlineData ( CertificateName ) ]
109- [ Theory ]
110110 public void ConfigureCertificateOptions_ReadsPemFiles_CreatesCertificate ( string certificateName )
111111 {
112112 IConfigurationRoot configurationRoot = new ConfigurationBuilder ( ) . AddCertificate ( certificateName , "instance.crt" , "instance.key" ) . Build ( ) ;
@@ -119,9 +119,9 @@ public void ConfigureCertificateOptions_ReadsPemFiles_CreatesCertificate(string
119119 options . Certificate . HasPrivateKey . Should ( ) . BeTrue ( ) ;
120120 }
121121
122+ [ Theory ]
122123 [ InlineData ( "" ) ]
123124 [ InlineData ( CertificateName ) ]
124- [ Theory ]
125125 public async Task CertificateOptionsUpdateOnFileContentChange ( string certificateName )
126126 {
127127 using var sandbox = new Sandbox ( ) ;
@@ -131,8 +131,8 @@ public async Task CertificateOptionsUpdateOnFileContentChange(string certificate
131131 string secondCertificateContent = await File . ReadAllTextAsync ( "instance2.crt" , TestContext . Current . CancellationToken ) ;
132132 string secondPrivateKeyContent = await File . ReadAllTextAsync ( "instance2.key" , TestContext . Current . CancellationToken ) ;
133133 var secondX509 = X509Certificate2 . CreateFromPemFile ( "instance2.crt" , "instance2.key" ) ;
134- string certificateFilePath = sandbox . CreateFile ( "cert ", firstCertificateContent ) ;
135- string privateKeyFilePath = sandbox . CreateFile ( " key", firstPrivateKeyContent ) ;
134+ string certificateFilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ".crt ", firstCertificateContent ) ;
135+ string privateKeyFilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ". key", firstPrivateKeyContent ) ;
136136
137137 if ( TestContext . Current . IsRunningOnBuildServer ( ) )
138138 {
@@ -157,14 +157,24 @@ public async Task CertificateOptionsUpdateOnFileContentChange(string certificate
157157 await File . WriteAllTextAsync ( certificateFilePath , secondCertificateContent , TestContext . Current . CancellationToken ) ;
158158 await File . WriteAllTextAsync ( privateKeyFilePath , secondPrivateKeyContent , TestContext . Current . CancellationToken ) ;
159159
160- SpinWait . SpinUntil ( ( ) => optionsMonitor . Get ( certificateName ) . Certificate ! . Equals ( secondX509 ) , 4 . Seconds ( ) ) ;
160+ SpinWait . SpinUntil ( ( ) =>
161+ {
162+ try
163+ {
164+ return optionsMonitor . Get ( certificateName ) . Certificate ! . Equals ( secondX509 ) ;
165+ }
166+ catch
167+ {
168+ return false ; // File(s) may not be readable yet. Swallow exceptions and keep spinning
169+ }
170+ } , 4 . Seconds ( ) ) ;
161171
162172 optionsMonitor . Get ( certificateName ) . Certificate . Should ( ) . Be ( secondX509 ) ;
163173 }
164174
175+ [ Theory ]
165176 [ InlineData ( "" ) ]
166177 [ InlineData ( CertificateName ) ]
167- [ Theory ]
168178 public async Task CertificateOptionsUpdateOnFileLocationChange ( string certificateName )
169179 {
170180 using var sandbox = new Sandbox ( ) ;
@@ -174,10 +184,10 @@ public async Task CertificateOptionsUpdateOnFileLocationChange(string certificat
174184 string instance2Certificate = await File . ReadAllTextAsync ( "instance2.crt" , TestContext . Current . CancellationToken ) ;
175185 string instance2PrivateKey = await File . ReadAllTextAsync ( "instance2.key" , TestContext . Current . CancellationToken ) ;
176186 var secondX509 = X509Certificate2 . CreateFromPemFile ( "instance2.crt" , "instance2.key" ) ;
177- string certificate1FilePath = sandbox . CreateFile ( "cert ", instance1Certificate ) ;
178- string privateKey1FilePath = sandbox . CreateFile ( " key", instance1PrivateKey ) ;
179- string certificate2FilePath = sandbox . CreateFile ( "cert2 ", instance2Certificate ) ;
180- string privateKey2FilePath = sandbox . CreateFile ( "key2 ", instance2PrivateKey ) ;
187+ string certificate1FilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ".crt ", instance1Certificate ) ;
188+ string privateKey1FilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ". key", instance1PrivateKey ) ;
189+ string certificate2FilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ".crt ", instance2Certificate ) ;
190+ string privateKey2FilePath = sandbox . CreateFile ( Guid . NewGuid ( ) + ".key ", instance2PrivateKey ) ;
181191
182192 if ( TestContext . Current . IsRunningOnBuildServer ( ) )
183193 {
@@ -223,7 +233,19 @@ public async Task CertificateOptionsUpdateOnFileLocationChange(string certificat
223233 changeCalled . Should ( ) . BeFalse ( "nothing has changed yet" ) ;
224234 await File . WriteAllTextAsync ( certificate2FilePath , instance1Certificate , TestContext . Current . CancellationToken ) ;
225235 await File . WriteAllTextAsync ( privateKey2FilePath , instance1PrivateKey , TestContext . Current . CancellationToken ) ;
226- SpinWait . SpinUntil ( ( ) => optionsMonitor . Get ( certificateName ) . Certificate ! . Equals ( firstX509 ) , 4 . Seconds ( ) ) ;
236+
237+ SpinWait . SpinUntil ( ( ) =>
238+ {
239+ try
240+ {
241+ return optionsMonitor . Get ( certificateName ) . Certificate ! . Equals ( firstX509 ) ;
242+ }
243+ catch
244+ {
245+ return false ; // File(s) may not be readable yet. Swallow exceptions and keep spinning
246+ }
247+ } , 4 . Seconds ( ) ) ;
248+
227249 changeCalled . Should ( ) . BeTrue ( "file contents changed" ) ;
228250 optionsMonitor . Get ( certificateName ) . Certificate . Should ( ) . Be ( firstX509 ) ;
229251 }
0 commit comments