Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GODRIVER-3140 Update client-side-encryption spec tests. #1651

Draft
wants to merge 11 commits into
base: v1
Choose a base branch
from
19 changes: 18 additions & 1 deletion mongo/integration/cmd_monitoring_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,24 @@ func compareValues(mt *mtest.T, key string, expected, actual bson.RawValue) erro
if typeVal, err := e.LookupErr("$$type"); err == nil {
// $$type represents a type assertion
// for example {field: {$$type: "binData"}} should assert that "field" is an element with a binary value
return checkValueType(mt, key, actual.Type, typeVal.StringValue())
switch t := typeVal.Type; t {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional. Use a different name for this variable, such as typ.

case bson.TypeString:
return checkValueType(mt, key, actual.Type, typeVal.StringValue())
case bson.TypeArray:
array := typeVal.Array()
elems, err := array.Values()
if err != nil {
return err
}
for _, elem := range elems {
if checkValueType(mt, key, actual.Type, elem.StringValue()) == nil {
return nil
}
}
return fmt.Errorf("BSON type mismatch for key %s; expected %s, got %s", key, array.String(), actual)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("BSON type mismatch for key %s; expected %s, got %s", key, array.String(), actual)
return fmt.Errorf("BSON type mismatch for key %q; expected %s, got %q", key, array, actual.Type)

%s will use the bson.RawValue.String() method for array. Additionally, suggest using the actual type rather than the value of actual in the error message.

default:
return fmt.Errorf("unsupported $$type: %s", t.String())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf("unsupported $$type: %s", t.String())
return fmt.Errorf("unsupported $$type: %q", t)

q will use the bsontype String() method.

}
}

a := actual.Document()
Expand Down
14 changes: 12 additions & 2 deletions mongo/integration/json_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ func createClientOptions(t testing.TB, opts bson.Raw) *options.ClientOptions {
case "socketTimeoutMS":
st := convertValueToMilliseconds(t, opt)
clientOpts.SetSocketTimeout(st)
case "timeoutMS":
clientOpts.SetTimeout(time.Duration(opt.Int32()) * time.Millisecond)
case "minPoolSize":
clientOpts.SetMinPoolSize(uint64(opt.AsInt64()))
case "maxPoolSize":
Expand Down Expand Up @@ -470,8 +472,9 @@ func errorFromResult(t testing.TB, result interface{}) *operationError {
if err != nil {
return nil
}
if expected.ErrorCodeName == nil && expected.ErrorContains == nil && len(expected.ErrorLabelsOmit) == 0 &&
len(expected.ErrorLabelsContain) == 0 {
if expected.ErrorCodeName == nil && expected.ErrorContains == nil &&
len(expected.ErrorLabelsOmit) == 0 && len(expected.ErrorLabelsContain) == 0 &&
expected.IsTimeoutError == nil {
return nil
}

Expand Down Expand Up @@ -563,6 +566,13 @@ func verifyError(expected *operationError, actual error) error {
return fmt.Errorf("expected error %w to not contain label %q", actual, label)
}
}
if expected.IsTimeoutError != nil {
isTimeoutError := mongo.IsTimeout(actual)
if *expected.IsTimeoutError != isTimeoutError {
return fmt.Errorf("expected error %w to be a timeout error: %v, is timeout error: %v",
actual, *expected.IsTimeoutError, isTimeoutError)
}
}
return nil
}

Expand Down
5 changes: 5 additions & 0 deletions mongo/integration/mtest/mongotest.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,11 @@ func (t *T) TrackFailPoint(fpName string) {

// ClearFailPoints disables all previously set failpoints for this test.
func (t *T) ClearFailPoints() {
if t.clientOpts != nil && t.clientOpts.AutoEncryptionOptions != nil && len(t.failPointNames) > 0 {
t.Logf("configureFailPoint is not supported for auto encryption, skipping ClearFailPoints()")
t.failPointNames = t.failPointNames[:0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added spec tests include both AutoEncryptionOptions and "configureFailPoint", which seems to suggest that "configureFailPoint" is being run successfully during the test (to enable the failpoint). Does disabling failpoints behave differently than enabling failpoints when AutoEncryptionOptions are set?

Copy link
Collaborator Author

@qingyang-hu qingyang-hu Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, clearing fail point fails for "mongocrypt error 1: command not supported for auto encryption: configureFailPoint".
^ The issue was caused because of GODRIVER-2123.

return
}
db := t.Client.Database("admin")
for _, fp := range t.failPointNames {
cmd := bson.D{
Expand Down
1 change: 1 addition & 0 deletions mongo/integration/unified_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ type operationError struct {
ErrorCodeName *string `bson:"errorCodeName"`
ErrorLabelsContain []string `bson:"errorLabelsContain"`
ErrorLabelsOmit []string `bson:"errorLabelsOmit"`
IsTimeoutError *bool `bson:"isTimeoutError"`
}

const dataPath string = "../../testdata/"
Expand Down
200 changes: 200 additions & 0 deletions testdata/client-side-encryption/legacy/timeoutMS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
{
"runOn": [
{
"minServerVersion": "4.4"
}
],
"database_name": "cse-timeouts-db",
"collection_name": "cse-timeouts-coll",
"data": [],
"json_schema": {
"properties": {
"encrypted_w_altname": {
"encrypt": {
"keyId": "/altname",
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
},
"random": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string_equivalent": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType": "object"
},
"key_vault_data": [
{
"status": 1,
"_id": {
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "aws",
"key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
"region": "us-east-1"
},
"updateDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyMaterial": {
"$binary": {
"base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyAltNames": [
"altname",
"another_altname"
]
}
],
"tests": [
{
"description": "timeoutMS applied to listCollections to get collection schema",
"failPoint": {
"configureFailPoint": "failCommand",
"mode": {
"times": 1
},
"data": {
"failCommands": [
"listCollections"
],
"blockConnection": true,
"blockTimeMS": 60
}
},
"clientOptions": {
"autoEncryptOpts": {
"kmsProviders": {
"aws": {}
}
},
"timeoutMS": 50
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0",
"random": "abc"
}
},
"result": {
"isTimeoutError": true
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "cse-timeouts-coll"
},
"maxTimeMS": {
"$$type": [
"int",
"long"
]
}
},
"command_name": "listCollections"
}
}
]
},
{
"description": "remaining timeoutMS applied to find to get keyvault data",
"failPoint": {
"configureFailPoint": "failCommand",
"mode": {
"times": 2
},
"data": {
"failCommands": [
"listCollections",
"find"
],
"blockConnection": true,
"blockTimeMS": 30
}
},
"clientOptions": {
"autoEncryptOpts": {
"kmsProviders": {
"aws": {}
}
},
"timeoutMS": 50
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0",
"random": "abc"
}
},
"result": {
"isTimeoutError": true
}
}
]
}
]
}
67 changes: 67 additions & 0 deletions testdata/client-side-encryption/legacy/timeoutMS.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
runOn:
- minServerVersion: "4.4"
database_name: &database_name "cse-timeouts-db"
collection_name: &collection_name "cse-timeouts-coll"

data: []
json_schema: {'properties': {'encrypted_w_altname': {'encrypt': {'keyId': '/altname', 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'random': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'}}, 'encrypted_string_equivalent': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'}
key_vault_data: [{'status': 1, '_id': {'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'masterKey': {'provider': 'aws', 'key': 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', 'region': 'us-east-1'}, 'updateDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyMaterial': {'$binary': {'base64': 'AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1552949630483'}}, 'keyAltNames': ['altname', 'another_altname']}]

tests:
- description: "timeoutMS applied to listCollections to get collection schema"
failPoint:
configureFailPoint: failCommand
mode: { times: 1 }
data:
failCommands: ["listCollections"]
blockConnection: true
blockTimeMS: 60
clientOptions:
autoEncryptOpts:
kmsProviders:
aws: {} # Credentials filled in from environment.
timeoutMS: 50
operations:
- name: insertOne
arguments:
document: &doc0 { _id: 1, encrypted_string: "string0", random: "abc" }
result:
isTimeoutError: true
expectations:
# Auto encryption will request the collection info.
- command_started_event:
command:
listCollections: 1
filter:
name: *collection_name
maxTimeMS: { $$type: ["int", "long"] }
command_name: listCollections

# Test that timeoutMS applies to the sum of all operations done for client-side encryption. This is done by blocking
# listCollections and find for 30ms each and running an insertOne with timeoutMS=50. There should be one
# listCollections command and one "find" command, so the sum should take more than timeoutMS. A second listCollections
# event doesn't occur due to the internal MongoClient lacking configured auto encryption, plus libmongocrypt holds the
# collection schema in cache for a minute.
#
# This test does not include command monitoring expectations because the exact command sequence is dependent on the
# amount of time taken by mongocryptd communication. In slow runs, mongocryptd communication can breach the timeout
# and result in the final "find" not being sent.
- description: "remaining timeoutMS applied to find to get keyvault data"
failPoint:
configureFailPoint: failCommand
mode: { times: 2 }
data:
failCommands: ["listCollections", "find"]
blockConnection: true
blockTimeMS: 30
clientOptions:
autoEncryptOpts:
kmsProviders:
aws: {} # Credentials filled in from environment.
timeoutMS: 50
operations:
- name: insertOne
arguments:
document: *doc0
result:
isTimeoutError: true
Loading