Skip to content

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

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

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
13 changes: 11 additions & 2 deletions internal/integration/json_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ func createClientOptions(t testing.TB, opts bson.Raw) *options.ClientOptions {
case "serverSelectionTimeoutMS":
sst := convertValueToMilliseconds(t, opt)
clientOpts.SetServerSelectionTimeout(sst)
case "timeoutMS":
clientOpts.SetTimeout(time.Duration(opt.Int32()) * time.Millisecond)
case "minPoolSize":
clientOpts.SetMinPoolSize(uint64(opt.AsInt64()))
case "maxPoolSize":
Expand Down Expand Up @@ -454,8 +456,8 @@ 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 && expected.IsTimeoutError == nil &&
len(expected.ErrorLabelsOmit) == 0 && len(expected.ErrorLabelsContain) == 0 {
return nil
}

Expand Down Expand Up @@ -547,6 +549,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
48 changes: 35 additions & 13 deletions internal/integration/mtest/mongotest.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ const (
namespaceExistsErrCode int32 = 48
)

type failPoint struct {
name string
client *mongo.Client
}

// T is a wrapper around testing.T.
type T struct {
// connsCheckedOut is the net number of connections checked out during test execution.
Expand All @@ -68,7 +73,8 @@ type T struct {
createdColls []*Collection // collections created in this test
proxyDialer *proxyDialer
dbName, collName string
failPointNames []string
hasFailPoint bool
failPoints []failPoint
minServerVersion string
maxServerVersion string
validTopologies []TopologyKind
Expand Down Expand Up @@ -166,7 +172,14 @@ func (t *T) cleanup() {

// always disconnect the client regardless of clientType because Client.Disconnect will work against
// all deployments
_ = t.Client.Disconnect(context.Background())
if !t.hasFailPoint {
_ = t.Client.Disconnect(context.Background())
}
for _, fp := range t.failPoints {
_ = fp.client.Disconnect(context.Background())
}
t.hasFailPoint = false
t.failPoints = t.failPoints[:0]
}

// Run creates a new T instance for a sub-test and runs the given callback. It also creates a new collection using the
Expand Down Expand Up @@ -220,7 +233,7 @@ func (t *T) RunOpts(name string, opts *Options, callback func(mt *T)) {
sub.ClearCollections()
}
// only disconnect client if it's not being shared
if sub.shareClient == nil || !*sub.shareClient {
if (sub.shareClient == nil || !*sub.shareClient) && !sub.hasFailPoint {
_ = sub.Client.Disconnect(context.Background())
}
assert.Equal(sub, 0, sessions, "%v sessions checked out", sessions)
Expand Down Expand Up @@ -364,7 +377,10 @@ func (t *T) ResetClient(opts *options.ClientOptions) {
t.clientOpts = opts
}

_ = t.Client.Disconnect(context.Background())
if !t.hasFailPoint {
_ = t.Client.Disconnect(context.Background())
}
t.hasFailPoint = false
t.createTestClient()
t.DB = t.Client.Database(t.dbName)
t.Coll = t.DB.Collection(t.collName, t.collOpts)
Expand Down Expand Up @@ -523,7 +539,8 @@ func (t *T) SetFailPoint(fp failpoint.FailPoint) {
if err := SetFailPoint(fp, t.Client); err != nil {
t.Fatal(err)
}
t.failPointNames = append(t.failPointNames, fp.ConfigureFailPoint)
t.hasFailPoint = true
t.failPoints = append(t.failPoints, failPoint{name: fp.ConfigureFailPoint, client: t.Client})
}

// SetFailPointFromDocument sets the fail point represented by the given document for the client associated with T. This
Expand All @@ -536,29 +553,34 @@ func (t *T) SetFailPointFromDocument(fp bson.Raw) {
}

name := fp.Index(0).Value().StringValue()
t.failPointNames = append(t.failPointNames, name)
t.hasFailPoint = true
t.failPoints = append(t.failPoints, failPoint{name: name, client: t.Client})
}

// TrackFailPoint adds the given fail point to the list of fail points to be disabled when the current test finishes.
// This function does not create a fail point on the server.
func (t *T) TrackFailPoint(fpName string) {
t.failPointNames = append(t.failPointNames, fpName)
t.hasFailPoint = true
t.failPoints = append(t.failPoints, failPoint{name: fpName, client: t.Client})
}

// ClearFailPoints disables all previously set failpoints for this test.
func (t *T) ClearFailPoints() {
db := t.Client.Database("admin")
for _, fp := range t.failPointNames {
for _, fp := range t.failPoints {
cmd := failpoint.FailPoint{
ConfigureFailPoint: fp,
ConfigureFailPoint: fp.name,
Mode: failpoint.ModeOff,
}
err := db.RunCommand(context.Background(), cmd).Err()
err := fp.client.Database("admin").RunCommand(context.Background(), cmd).Err()
if err != nil {
t.Fatalf("error clearing fail point %s: %v", fp, err)
t.Fatalf("error clearing fail point %s: %v", fp.name, err)
}
if fp.client != t.Client {
_ = fp.client.Disconnect(context.Background())
}
}
t.failPointNames = t.failPointNames[:0]
t.hasFailPoint = false
t.failPoints = t.failPoints[:0]
}

// CloneDatabase modifies the default database for this test to match the given options.
Expand Down
1 change: 1 addition & 0 deletions internal/integration/unified_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type operationError struct {
ErrorCodeName *string `bson:"errorCodeName"`
ErrorLabelsContain []string `bson:"errorLabelsContain"`
ErrorLabelsOmit []string `bson:"errorLabelsOmit"`
IsTimeoutError *bool `bson:"isTimeoutError"`
}

var directories = []string{
Expand Down
7 changes: 0 additions & 7 deletions internal/spectest/skip.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,6 @@ var skipTests = map[string][]string{
"TestBsonBinaryVectorSpec/Tests_of_Binary_subtype_9,_Vectors,_with_dtype_FLOAT32/Insufficient_vector_data_with_5_bytes_FLOAT32/Marshaling",
},

// TODO(GODRIVER-3521): Extend Legacy Unified Spec Runner to include
// client-side-encryption timeoutMS.
"Extend Legacy Unified Spec Runner for client-side-encryption timeoutMS (GODRIVER-3521)": {
"TestClientSideEncryptionSpec/timeoutMS.json/remaining_timeoutMS_applied_to_find_to_get_keyvault_data",
"TestClientSideEncryptionSpec/timeoutMS.json/timeoutMS_applied_to_listCollections_to_get_collection_schema",
},

// TODO(GODRIVER-3486): Support auto encryption in unified tests.
"Support auto encryption in unified tests (GODRIVER-3486)": {
"TestUnifiedSpec/unified-test-format/tests/valid-pass/poc-queryable-encryption.json/insert,_replace,_and_find_with_queryable_encryption",
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
}
}
]
}
]
}
Loading
Loading