2828using System . Threading . Tasks ;
2929using Amazon . Runtime ;
3030using FluentAssertions ;
31+ using FluentAssertions . Execution ;
3132using MongoDB . Bson ;
3233using MongoDB . Bson . IO ;
3334using MongoDB . Bson . TestHelpers . JsonDrivenTests ;
@@ -99,17 +100,15 @@ public void AutomaticDataEncryptionKeysTest(
99100 using ( var client = ConfigureClient ( ) )
100101 using ( var clientEncryption = ConfigureClientEncryption ( client , kmsProviderFilter : kmsProvider ) )
101102 {
102- var encryptedFields = BsonDocument . Parse ( $ @ "
103- {{
103+ var encryptedFields = BsonDocument . Parse ( @"
104+ {
104105 fields:
105- [
106- {{
107- path: ""ssn"",
108- bsonType: ""string"",
106+ [{
107+ path: 'ssn',
108+ bsonType: 'string',
109109 keyId: null
110- }}
111- ]
112- }}" ) ;
110+ }]
111+ }" ) ;
113112
114113 DropCollection ( __collCollectionNamespace , encryptedFields ) ;
115114
@@ -1503,7 +1502,10 @@ void AssertException(Exception exception)
15031502 AssertTlsWithoutClientCertOnLinux ( exception ) ;
15041503 break ;
15051504 case OperatingSystemPlatform . MacOS :
1506- AssertInnerEncryptionException ( exception , Type . GetType ( "Interop+ AppleCrypto+ SslException , System . Net . Security ", throwOnError: true) , "Authentication failed , see inner exception. ", "handshake failure") ;
1505+ AssertInnerEncryptionException (
1506+ exception ,
1507+ Type . GetType ( "Interop+ AppleCrypto+ SslException , System . Net . Security ", throwOnError : true) ,
1508+ ex => ex . Message . Should ( ) . Contain ( "handshake failure" ) ) ;
15071509 break ;
15081510 default : throw new Exception( $ "Unsupported OS { currentOperatingSystem } .") ;
15091511 }
@@ -1543,7 +1545,10 @@ void AssertException(Exception exception)
15431545 AssertTlsWithoutClientCertOnLinux ( exception ) ;
15441546 break ;
15451547 case OperatingSystemPlatform . MacOS :
1546- AssertInnerEncryptionException( exception, Type. GetType( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true) , "Authentication failed, see inner exception." , "handshake failure" ) ;
1548+ AssertInnerEncryptionException (
1549+ exception ,
1550+ Type . GetType ( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true ) ,
1551+ ex => ex . Message . Should ( ) . Contain ( "handshake failure" ) ) ;
15471552 break ;
15481553 default : throw new Exception ( $ "Unsupported OS { currentOperatingSystem } .") ;
15491554 }
@@ -1581,7 +1586,10 @@ void AssertException(Exception exception)
15811586 AssertTlsWithoutClientCertOnLinux ( exception ) ;
15821587 break ;
15831588 case OperatingSystemPlatform . MacOS :
1584- AssertInnerEncryptionException ( exception , Type . GetType ( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true ) , "Authentication failed, see inner exception." , "handshake failure" ) ;
1589+ AssertInnerEncryptionException (
1590+ exception ,
1591+ Type . GetType ( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true ) ,
1592+ ex => ex . Message . Should ( ) . Contain ( "handshake failure" ) ) ;
15851593 break ;
15861594 default : throw new Exception ( $ "Unsupported OS { currentOperatingSystem } .") ;
15871595 }
@@ -1619,7 +1627,10 @@ void AssertException(Exception exception)
16191627 AssertTlsWithoutClientCertOnLinux ( exception ) ;
16201628 break ;
16211629 case OperatingSystemPlatform . MacOS :
1622- AssertInnerEncryptionException ( exception , Type . GetType ( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true ) , "Authentication failed, see inner exception." , "handshake failure" ) ;
1630+ AssertInnerEncryptionException (
1631+ exception ,
1632+ Type . GetType ( "Interop+AppleCrypto+SslException, System.Net.Security" , throwOnError : true ) ,
1633+ ex => ex . Message . Should ( ) . Contain ( "handshake failure" ) ) ;
16231634 break ;
16241635 default : throw new Exception ( $ "Unsupported OS { currentOperatingSystem } .") ;
16251636 }
@@ -1657,50 +1668,29 @@ void AssertTlsWithoutClientCertOnLinux(Exception exception)
16571668 {
16581669 AssertInnerEncryptionException (
16591670 exception ,
1660- Type . GetType ( "Interop+Crypto+OpenSslCryptographicException, System.Net.Security" , throwOnError : true ) ,
1661- "Authentication failed, see inner exception." ,
1662- "SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL." ) ;
1671+ Type . GetType ( "Interop+OpenSsl+SslException, System.Net.Security" , throwOnError : true ) ,
1672+ ex => ex . Message . Should ( ) . BeOneOf ( "SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL." , "Decrypt failed with OpenSSL error - SSL_ERROR_SSL." ) ) ;
16631673 }
16641674 catch ( XunitException )
16651675 {
1666-
1667- #if NET6_0_OR_GREATER
1668- var innerException = "Unable to write data to the transport connection: Connection reset by peer." ;
1669- #else
1670- var innerException = async
1671- ? "Unable to read data from the transport connection: Connection reset by peer."
1672- : "Unable to write data to the transport connection: Connection reset by peer." ;
1673- #endif
1674-
16751676 // With Tls1.3, there is no report of a failed handshake if the client certificate verification fails
16761677 // since the client receives a 'Finished' message from the server before sending its certificate, it assumes
16771678 // authentication and we will not know if there was an error until we next read/write from the server.
1678- AssertInnerEncryptionException < SocketException > ( exception , innerException ) ;
1679+ AssertInnerEncryptionException < SocketException > ( exception , "Connection reset by peer" ) ;
16791680 }
16801681 }
16811682
16821683 void AssertTlsWithoutClientCertOnWindows ( Exception exception )
16831684 {
16841685 try
16851686 {
1686- string [ ] innerExceptions =
1687- #if NET6_0_OR_GREATER
1688- [ "Authentication failed because the remote party sent a TLS alert" ] ;
1689- #elif NET472
1690- [ "A call to SSPI failed, see inner exception." , "The message received was unexpected or badly formatted" ] ;
1691- #else
1692- [ "Authentication failed, see inner exception." , "The message received was unexpected or badly formatted" ] ;
1693- #endif
1694- AssertInnerEncryptionException< System . ComponentModel . Win32Exception > ( exception , innerExceptions ) ;
1687+ AssertInnerEncryptionException < System . ComponentModel . Win32Exception > ( exception , "The message received was unexpected or badly formatted" ) ;
16951688 }
16961689 catch ( XunitException ) // assertation failed
16971690 {
16981691 // Sometimes the mock server triggers SocketError.ConnectionReset (10054) on windows instead the expected exception.
16991692 // It looks like a test env issue, a similar behavior presents in other drivers, so we rely on the same check on different OSs
1700- AssertInnerEncryptionException < SocketException > (
1701- exception ,
1702- "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host." ,
1703- "An existing connection was forcibly closed by the remote host" ) ;
1693+ AssertInnerEncryptionException < SocketException > ( exception , "An existing connection was forcibly closed by the remote host" ) ;
17041694 }
17051695 }
17061696
@@ -1832,7 +1822,7 @@ void AssertException(Exception ex)
18321822 // In rare cases, the thrown error is "CryptException exception: AccessDeniedException". That means you don't have authorization to perform the requested action.
18331823 // It more or less corresponds to the expected behavior here, but it's unclear why the same scenario triggers different exceptions.
18341824 // However, it looks harmless to slightly update the test assertion to avoid assertion failures on EG.
1835- AssertInnerEncryptionException < CryptException > ( ex , "Error in KMS response." , "HTTP status=400." , " \" __type\" :\" AccessDeniedException\" ") ;
1825+ AssertInnerEncryptionException < CryptException > ( ex , "\" __type\" :\" AccessDeniedException\" " ) ;
18361826 }
18371827 }
18381828 break ;
@@ -1843,18 +1833,18 @@ void AssertException(Exception ex)
18431833 case OperatingSystemPlatform . Windows :
18441834 case OperatingSystemPlatform . Linux :
18451835 {
1846- AssertInnerEncryptionException < HttpRequestException > ( ex , "Failed to acquire IMDS access token." ) ;
1836+ AssertInnerEncryptionException < MongoClientException > ( ex , "Failed to acquire IMDS access token." ) ;
18471837 }
18481838 break ;
18491839 case OperatingSystemPlatform . MacOS :
18501840 {
18511841 try
18521842 {
1853- AssertInnerEncryptionException < TaskCanceledException > ( ex , "Failed to acquire IMDS access token." ) ;
1843+ AssertInnerEncryptionException < TaskCanceledException > ( ex ) ;
18541844 }
18551845 catch ( XunitException )
18561846 {
1857- AssertInnerEncryptionException < HttpRequestException > ( ex , "Failed to acquire IMDS access token." ) ;
1847+ AssertInnerEncryptionException < MongoClientException > ( ex , "Failed to acquire IMDS access token." ) ;
18581848 }
18591849 }
18601850 break ;
@@ -1864,7 +1854,7 @@ void AssertException(Exception ex)
18641854 break ;
18651855 case "gcp" :
18661856 {
1867- AssertInnerEncryptionException < HttpRequestException > ( ex , "Failed to acquire gce metadata credentials." ) ;
1857+ AssertInnerEncryptionException < MongoClientException > ( ex , "Failed to acquire gce metadata credentials." ) ;
18681858 }
18691859 break ;
18701860 default : throw new Exception ( $ "Unexpected kms provider: { kmsProvider } .") ;
@@ -2442,12 +2432,14 @@ void RunTestCase(ClientEncryption clientEncryption, Guid existingKey, int testCa
24422432 var newLocalDataKey = CreateDataKey ( clientEncryption , "local" , new DataKeyOptions ( alternateKeyNames : new [ ] { "abc" } ) , async) ;
24432433
24442434 var exception = Record . Exception ( ( ) => CreateDataKey ( clientEncryption , "local" , new DataKeyOptions ( alternateKeyNames : new [ ] { "abc" } ) , async) ) ;
2445- var e = AssertInnerEncryptionException < MongoWriteException > ( exception ) ;
2446- e . WriteError . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ;
2435+ AssertInnerEncryptionException < MongoWriteException > (
2436+ exception ,
2437+ ex => ex . WriteError . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ) ;
24472438
24482439 exception = Record . Exception ( ( ) => CreateDataKey ( clientEncryption , "local" , new DataKeyOptions ( alternateKeyNames : new [ ] { "def" } ) , async) ) ;
2449- e = AssertInnerEncryptionException < MongoWriteException > ( exception ) ;
2450- e . WriteError . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ;
2440+ AssertInnerEncryptionException < MongoWriteException > (
2441+ exception ,
2442+ ex => ex . WriteError . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ) ;
24512443 }
24522444 break ;
24532445 case 2 :
@@ -2461,8 +2453,9 @@ void RunTestCase(ClientEncryption clientEncryption, Guid existingKey, int testCa
24612453 result [ "keyAltNames" ] . AsBsonArray . Contains ( "abc" ) ;
24622454 // 4 Add a keyAltName "def" to the key created in Step 1 and assert the operation fails due to a duplicate key
24632455 var exception = Record . Exception ( ( ) => AddAlternateKeyName ( clientEncryption , newLocalDataKey , alternateKeyName : "def" , async) ) ;
2464- var e = AssertInnerEncryptionException < MongoCommandException > ( exception ) ;
2465- e . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ;
2456+ AssertInnerEncryptionException < MongoCommandException > (
2457+ exception ,
2458+ ex => ex . Code . Should ( ) . Be ( ( int ) ServerErrorCode . DuplicateKey ) ) ;
24662459 // 5 add a keyAltName "def" to the existing key, assert the operation does not fail, and assert the returned key document contains the keyAltName "def"
24672460 result = AddAlternateKeyName ( clientEncryption , existingKey , "def" , async) ;
24682461 result [ "keyAltNames" ] . AsBsonArray . Contains ( "def" ) ;
@@ -2524,35 +2517,29 @@ private void AddOrReplace<TValue>(IDictionary<string, TValue> dict, string key,
25242517 }
25252518 }
25262519
2527- private Exception AssertInnerEncryptionException( Exception ex , Type exType , params string [ ] innerExceptionErrorMessage )
2520+ private void AssertInnerEncryptionException ( Exception ex , Type innerExceptionType , string exceptionMessageContains )
2521+ => AssertInnerEncryptionException ( ex , innerExceptionType , e => e . Message . Should ( ) . Contain( exceptionMessageContains) ) ;
2522+
2523+ private void AssertInnerEncryptionException ( Exception ex , Type innerExceptionType , Action < Exception > assert = null )
25282524 {
2529- Exception e = ex. Should( ) . BeOfType< MongoEncryptionException> ( ) . Subject. InnerException;
2530- foreach ( var innerMessage in innerExceptionErrorMessage)
2525+ ex . Should ( ) . BeOfType < MongoEncryptionException > ( ) ;
2526+ Exception e = ex ;
2527+ while ( e != null && ! innerExceptionType . IsAssignableFrom ( e . GetType ( ) ) )
25312528 {
2532- e. Message. Should( ) . Contain( innerMessage) ;
2533- if ( e. InnerException != null )
2534- {
2535- e = e. InnerException;
2536- }
2529+ e = e . InnerException ;
25372530 }
25382531
2539- if ( typeof ( OperationCanceledException) . IsAssignableFrom( exType) )
2540- {
2541- // handles OperationCanceledException and TaskCanceledException.
2542- // At least in macOS these exceptions can be triggered from the same code path in some cases
2543- e. Should( ) . BeAssignableTo< OperationCanceledException> ( ) ;
2544- }
2545- else
2546- {
2547- e. Should( ) . BeOfType( exType) ;
2548- }
2549- return e;
2532+ e . Should ( ) . NotBeNull ( $ "Cannot find inner exception of expected type: { innerExceptionType } .") ;
2533+ assert ? . Invoke ( e ) ;
25502534 }
25512535
2552- private TMostInnerException AssertInnerEncryptionException < TMostInnerException > ( Exception ex , params string [ ] innerExceptionErrorMessage ) where TMostInnerException : Exception
2553- {
2554- return ( TMostInnerException ) AssertInnerEncryptionException ( ex , typeof ( TMostInnerException ) , innerExceptionErrorMessage ) ;
2555- }
2536+ private void AssertInnerEncryptionException < TInnerException > ( Exception ex , Action < TInnerException > assert = null )
2537+ where TInnerException : Exception
2538+ => AssertInnerEncryptionException ( ex , typeof ( TInnerException ) , ex => assert ? . Invoke ( ( TInnerException ) ex ) ) ;
2539+
2540+ private void AssertInnerEncryptionException < TInnerException > ( Exception ex , string exceptionMessageContains )
2541+ where TInnerException : Exception
2542+ => AssertInnerEncryptionException < TInnerException > ( ex , e => e . Message . Should ( ) . Contain ( exceptionMessageContains ) ) ;
25562543
25572544 private IMongoClient ConfigureClient (
25582545 bool clearCollections = true ,
0 commit comments