Skip to content

Commit 476af2b

Browse files
authored
CSHARP-5439: Fix flaky CSFLE tests (#1577)
1 parent b51b370 commit 476af2b

File tree

2 files changed

+62
-75
lines changed

2 files changed

+62
-75
lines changed

evergreen/evergreen.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,7 +2684,7 @@ buildvariants:
26842684
- name: test-csfle-with-mongocryptd-net60
26852685

26862686
- matrix_name: "csfle-with-azure-kms-tests-linux"
2687-
matrix_spec: { ssl: "nossl", os: "ubuntu-1804" }
2687+
matrix_spec: { ssl: "nossl", os: "ubuntu-2004" }
26882688
display_name: "CSFLE with AZURE KMS ${os}"
26892689
batchtime: 20160 # 14 days
26902690
tasks:
@@ -2693,7 +2693,7 @@ buildvariants:
26932693
- name: test-csfle-with-mongocryptd-net60
26942694

26952695
- matrix_name: "csfle-with-gcp-kms-tests-linux"
2696-
matrix_spec: { ssl: "nossl", os: "ubuntu-1804" }
2696+
matrix_spec: { ssl: "nossl", os: "ubuntu-2004" }
26972697
display_name: "CSFLE with GCP KMS ${os}"
26982698
batchtime: 20160 # 14 days
26992699
tasks:

tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs

Lines changed: 60 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using System.Threading.Tasks;
2929
using Amazon.Runtime;
3030
using FluentAssertions;
31+
using FluentAssertions.Execution;
3132
using MongoDB.Bson;
3233
using MongoDB.Bson.IO;
3334
using 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

Comments
 (0)