diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 371e05e5f1..d3c12b5aa5 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -44,6 +44,10 @@ functions: # Define an alias for the task runner script. TASK_RUNNER_ALIAS: &task-runner src/go.mongodb.org/mongo-driver/.evergreen/run-task.sh args: [.evergreen/setup-system.sh] + - command: subprocess.exec + params: + binary: bash + args: [*task-runner, init-submodule] - command: expansions.update params: file: src/go.mongodb.org/mongo-driver/expansion.yml diff --git a/Taskfile.yml b/Taskfile.yml index 3fcf7a9293..bedcac92e5 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -17,6 +17,8 @@ tasks: check-license: bash etc/check_license.sh + init-submodule: git submodule update --init + build: deps: [install-libmongocrypt] cmds: @@ -149,9 +151,9 @@ tasks: evg-test-load-balancers: # Load balancer should be tested with all unified tests as well as tests in the following # components: retryable reads, retryable writes, change streams, initial DNS seedlist discovery. - - go test ${BUILD_TAGS} ./internal/integration -run TestUnifiedSpecs/retryable-reads -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - - go test ${BUILD_TAGS} ./internal/integration -run TestRetryableWritesSpec -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - - go test ${BUILD_TAGS} ./internal/integration -run TestChangeStreamSpec -v -timeout {{.TEST_TIMEOUT}}s >> test.suite + - go test ${BUILD_TAGS} ./internal/integration/unified -run TestUnifiedSpec/retryable-reads -v -timeout {{.TEST_TIMEOUT}}s >> test.suite + - go test ${BUILD_TAGS} ./internal/integration/unified -run TestUnifiedSpec/retryable-writes -v -timeout {{.TEST_TIMEOUT}}s >> test.suite + - go test ${BUILD_TAGS} ./internal/integration/unified -run TestUnifiedSpec/change-streams -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestInitialDNSSeedlistDiscoverySpec/load_balanced -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestLoadBalancerSupport -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestLoadBalancedConnectionHandshake -v -timeout {{.TEST_TIMEOUT}}s >> test.suite @@ -174,13 +176,10 @@ tasks: - go test ${BUILD_TAGS} ./internal/integration -run TestWriteConcernError -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestErrorsCodeNamePropagated -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestLoadBalancerSupport -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - - go test ${BUILD_TAGS} ./internal/integration -run TestUnifiedSpecs/retryable-reads -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestRetryableReadsProse -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestRetryableWritesSpec -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestRetryableWritesProse -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - - go test ${BUILD_TAGS} ./internal/integration -run TestUnifiedSpecs/sessions -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestSessionsProse -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - - go test ${BUILD_TAGS} ./internal/integration -run TestUnifiedSpecs/transactions/legacy -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestConvenientTransactions -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration -run TestCursor -v -timeout {{.TEST_TIMEOUT}}s >> test.suite - go test ${BUILD_TAGS} ./internal/integration/unified -run TestUnifiedSpec -v -timeout {{.TEST_TIMEOUT}}s >> test.suite diff --git a/internal/integration/retryable_writes_spec_test.go b/internal/integration/retryable_writes_spec_test.go deleted file mode 100644 index d4cc783554..0000000000 --- a/internal/integration/retryable_writes_spec_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) MongoDB, Inc. 2017-present. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -package integration - -import ( - "bytes" - "io/ioutil" - "path" - "testing" - - "go.mongodb.org/mongo-driver/v2/bson" - "go.mongodb.org/mongo-driver/v2/internal/assert" - "go.mongodb.org/mongo-driver/v2/internal/failpoint" - "go.mongodb.org/mongo-driver/v2/internal/integration/mtest" -) - -const retryableWritesTestDir = "../../testdata/retryable-writes/legacy" - -type retryableWritesTestFile struct { - RunOn []mtest.RunOnBlock `bson:"runOn"` - Data []bson.Raw `bson:"data"` - Tests []retryableWritesTest `bson:"tests"` -} - -type retryableWritesTest struct { - Description string `bson:"description"` - ClientOptions bson.Raw `bson:"clientOptions"` - UseMultipleMongoses bool `bson:"useMultipleMongoses"` - FailPoint *failpoint.FailPoint `bson:"failPoint"` - Operation crudOperation `bson:"operation"` - Outcome crudOutcome `bson:"outcome"` -} - -func TestRetryableWritesSpec(t *testing.T) { - for _, file := range jsonFilesInDir(t, retryableWritesTestDir) { - t.Run(file, func(t *testing.T) { - runRetryableWritesFile(t, path.Join(retryableWritesTestDir, file)) - }) - } -} - -func runRetryableWritesFile(t *testing.T, filePath string) { - content, err := ioutil.ReadFile(filePath) - assert.Nil(t, err, "ReadFile error for %v: %v", filePath, err) - - var testFile retryableWritesTestFile - vr, err := bson.NewExtJSONValueReader(bytes.NewReader(content), false) - assert.Nil(t, err, "NewExtJSONValueReader error: %v", err) - dec := bson.NewDecoder(vr) - dec.SetRegistry(specTestRegistry) - err = dec.Decode(&testFile) - assert.Nil(t, err, "decode error: %v", err) - - mt := mtest.New(t, mtest.NewOptions().RunOn(testFile.RunOn...).CreateClient(false)) - - for _, test := range testFile.Tests { - runRetryableWritesTest(mt, test, testFile) - } -} - -func runRetryableWritesTest(mt *mtest.T, test retryableWritesTest, testFile retryableWritesTestFile) { - // Use a low heartbeat frequency so the Client will quickly recover when using failpoints that cause SDAM state - // changes. - testClientOpts := createClientOptions(mt, test.ClientOptions) - testClientOpts.SetHeartbeatInterval(defaultHeartbeatInterval) - opts := mtest.NewOptions().ClientOptions(testClientOpts) - if mtest.ClusterTopologyKind() == mtest.Sharded && !test.UseMultipleMongoses { - // pin to a single mongos - opts = opts.ClientType(mtest.Pinned) - } - - mt.RunOpts(test.Description, opts, func(mt *mtest.T) { - // setup - insert test data and set fail point - insertDocuments(mt, mt.Coll, testFile.Data) - if test.FailPoint != nil { - mt.SetFailPoint(*test.FailPoint) - } - - // run operation and verify outcome/error - runCrudOperation(mt, test.Description, test.Operation, test.Outcome) - }) -} diff --git a/internal/integration/unified/unified_spec_runner.go b/internal/integration/unified/unified_spec_runner.go index 01b64fd35a..7d2466a3ae 100644 --- a/internal/integration/unified/unified_spec_runner.go +++ b/internal/integration/unified/unified_spec_runner.go @@ -98,6 +98,9 @@ func runTestFile(t *testing.T, filepath string, expectValidFail bool, opts ...*O mtOpts := mtest.NewOptions(). RunOn(fileReqs...). CreateClient(false) + if strings.Contains(filepath, "atlas-data-lake-testing") { + mtOpts.AtlasDataLake(true) + } mt := mtest.New(t, mtOpts) for _, testCase := range testCases { diff --git a/internal/integration/unified/unified_spec_test.go b/internal/integration/unified/unified_spec_test.go index eba98345f4..79a8590178 100644 --- a/internal/integration/unified/unified_spec_test.go +++ b/internal/integration/unified/unified_spec_test.go @@ -8,42 +8,41 @@ package unified import ( "context" - "path" "testing" + + "go.mongodb.org/mongo-driver/v2/internal/spectest" ) var ( passDirectories = []string{ - "unified-test-format/valid-pass", - "versioned-api", - "crud/unified", - "change-streams", - "transactions/unified", - "load-balancers", - "collection-management", - "command-monitoring", - "command-monitoring/logging", - "connection-monitoring-and-pooling/logging", - "sessions", - "retryable-reads/unified", - "retryable-writes/unified", - "client-side-encryption/unified", - "client-side-operations-timeout", - "gridfs", - "server-selection/logging", - "server-discovery-and-monitoring/unified", - "run-command", - "index-management", + "unified-test-format/tests/valid-pass", + "versioned-api/tests", + "crud/tests/unified", + "change-streams/tests/unified", + "transactions/tests/unified", + "load-balancers/tests", + "collection-management/tests", + "command-logging-and-monitoring/tests/monitoring", + "command-logging-and-monitoring/tests/logging", + "connection-monitoring-and-pooling/tests/logging", + "sessions/tests", + "retryable-reads/tests/unified", + "retryable-writes/tests/unified", + "client-side-encryption/tests/unified", + "client-side-operations-timeout/tests", + "gridfs/tests", + "server-selection/tests/logging", + "server-discovery-and-monitoring/tests/unified", + "run-command/tests/unified", + "index-management/tests", + "transactions-convenient-api/tests/unified", + "atlas-data-lake-testing/tests/unified", } failDirectories = []string{ - "unified-test-format/valid-fail", + "unified-test-format/tests/valid-fail", } ) -const ( - dataDirectory = "../../../testdata" -) - func TestUnifiedSpec(t *testing.T) { // Ensure the cluster is in a clean state before test execution begins. if err := terminateOpenSessions(context.Background()); err != nil { @@ -52,13 +51,13 @@ func TestUnifiedSpec(t *testing.T) { for _, testDir := range passDirectories { t.Run(testDir, func(t *testing.T) { - runTestDirectory(t, path.Join(dataDirectory, testDir), false) + runTestDirectory(t, spectest.Path(testDir), false) }) } for _, testDir := range failDirectories { t.Run(testDir, func(t *testing.T) { - runTestDirectory(t, path.Join(dataDirectory, testDir), true) + runTestDirectory(t, spectest.Path(testDir), true) }) } } diff --git a/internal/integration/unified_spec_test.go b/internal/integration/unified_spec_test.go index 9a02246862..a54523124b 100644 --- a/internal/integration/unified_spec_test.go +++ b/internal/integration/unified_spec_test.go @@ -13,7 +13,7 @@ import ( "fmt" "io/ioutil" "os" - "path" + "path/filepath" "reflect" "sync" "testing" @@ -157,14 +157,8 @@ type operationError struct { ErrorLabelsOmit []string `bson:"errorLabelsOmit"` } -const dataPath string = "../../testdata/" - var directories = []string{ - "transactions/legacy", - "convenient-transactions", - "retryable-reads/legacy", - "read-write-concern/operation", - "atlas-data-lake-testing", + "read-write-concern/tests/operation", } var checkOutcomeOpts = options.Collection().SetReadPreference(readpref.Primary()).SetReadConcern(readconcern.Local()) @@ -178,9 +172,9 @@ var specTestRegistry = func() *bson.Registry { func TestUnifiedSpecs(t *testing.T) { for _, specDir := range directories { t.Run(specDir, func(t *testing.T) { - for _, fileName := range jsonFilesInDir(t, path.Join(dataPath, specDir)) { + for _, fileName := range jsonFilesInDir(t, spectest.Path(specDir)) { t.Run(fileName, func(t *testing.T) { - runSpecTestFile(t, specDir, fileName) + runSpecTestFile(t, filepath.Join(specDir, fileName)) }) } }) @@ -189,8 +183,7 @@ func TestUnifiedSpecs(t *testing.T) { // specDir: name of directory for a spec in the data/ folder // fileName: name of test file in specDir -func runSpecTestFile(t *testing.T, specDir, fileName string) { - filePath := path.Join(dataPath, specDir, fileName) +func runSpecTestFile(t *testing.T, filePath string) { content, err := ioutil.ReadFile(filePath) assert.Nil(t, err, "unable to read spec test file %v: %v", filePath, err) @@ -206,9 +199,6 @@ func runSpecTestFile(t *testing.T, specDir, fileName string) { mtOpts := mtest.NewOptions(). RunOn(testFile.RunOn...). CreateClient(false) - if specDir == "atlas-data-lake-testing" { - mtOpts.AtlasDataLake(true) - } mt := mtest.New(t, mtOpts) for _, test := range testFile.Tests { diff --git a/internal/serverselector/server_selector_test.go b/internal/serverselector/server_selector_test.go index b00d0a0ecd..c1a8411785 100644 --- a/internal/serverselector/server_selector_test.go +++ b/internal/serverselector/server_selector_test.go @@ -157,7 +157,7 @@ func compareServers(t *testing.T, expected []*serverDesc, actual []description.S } } -var maxStalenessTestsDir = spectest.TestPath(2, "max-staleness") +var maxStalenessTestsDir = spectest.Path("max-staleness/tests") // Test case for all max staleness spec tests. func TestMaxStalenessSpec(t *testing.T) { @@ -176,7 +176,7 @@ func TestMaxStalenessSpec(t *testing.T) { } } -var selectorTestsDir = spectest.TestPath(2, "server-selection") +var selectorTestsDir = spectest.Path("server-selection/tests") func selectServers(t *testing.T, test *testCase) error { servers := make([]description.Server, 0, len(test.TopologyDescription.Servers)) diff --git a/internal/spectest/spectest.go b/internal/spectest/spectest.go index 1b57599011..33f9f1f426 100644 --- a/internal/spectest/spectest.go +++ b/internal/spectest/spectest.go @@ -10,7 +10,6 @@ import ( "os" "path" "path/filepath" - "strings" "testing" "go.mongodb.org/mongo-driver/v2/internal/require" @@ -33,19 +32,20 @@ func FindJSONFilesInDir(t *testing.T, dir string) []string { files = append(files, entry.Name()) } + if len(files) == 0 { + t.Fatalf("no JSON files found in %q", dir) + } + return files } -// TestPath will construct a path to a test file in the specifications git -// submodule. The path will be relative to the current package so a depth should -// be provided to indicate how many directories to go up. -func TestPath(depth int, testDir string, subDirs ...string) string { - const basePath = "testdata/specifications/source/" - - // Create a string of "../" repeated 'depth' times - relativePath := strings.Repeat("../", depth) - // Construct the full path - fullPath := relativePath + basePath + testDir + "/tests/" + filepath.Join(subDirs...) +// Path returns the absolute path to the given specifications repo file or +// subdirectory. +func Path(subdir string) string { + testPath, err := filepath.Abs("../../../testdata/specifications/source/") + if err != nil { + panic(err) + } - return fullPath + return filepath.Join(testPath, subdir) } diff --git a/mongo/read_write_concern_spec_test.go b/mongo/read_write_concern_spec_test.go index f7b6270264..42c6a3a4c4 100644 --- a/mongo/read_write_concern_spec_test.go +++ b/mongo/read_write_concern_spec_test.go @@ -36,7 +36,7 @@ var ( reg.RegisterTypeMapEntry(bson.TypeEmbeddedDocument, reflect.TypeOf(bson.Raw{})) return reg }() - readWriteConcernTestsDir = spectest.TestPath(1, "read-write-concern") + readWriteConcernTestsDir = spectest.Path("read-write-concern/tests") ) type connectionStringTestFile struct { diff --git a/x/mongo/driver/auth/auth_spec_test.go b/x/mongo/driver/auth/auth_spec_test.go index c5f2a9a4be..6a8666f015 100644 --- a/x/mongo/driver/auth/auth_spec_test.go +++ b/x/mongo/driver/auth/auth_spec_test.go @@ -38,7 +38,7 @@ type testContainer struct { } // Note a test supporting the deprecated gssapiServiceName property was removed from data/auth/auth_tests.json -var authTestsDir = spectest.TestPath(4, "auth", "legacy") +var authTestsDir = spectest.Path("auth/tests/legacy") func runTestsInFile(t *testing.T, dirname string, filename string) { filepath := path.Join(dirname, filename) diff --git a/x/mongo/driver/connstring/connstring_spec_test.go b/x/mongo/driver/connstring/connstring_spec_test.go index 128092e1a7..4f6e8d2101 100644 --- a/x/mongo/driver/connstring/connstring_spec_test.go +++ b/x/mongo/driver/connstring/connstring_spec_test.go @@ -47,8 +47,8 @@ type testContainer struct { Tests []testCase } -var connstringTestsDir = spectest.TestPath(4, "connection-string") -var urioptionsTestDir = spectest.TestPath(4, "uri-options") +var connstringTestsDir = spectest.Path("connection-string/tests") +var urioptionsTestDir = spectest.Path("uri-options/tests") func (h *host) toString() string { switch h.Type { diff --git a/x/mongo/driver/topology/CMAP_spec_test.go b/x/mongo/driver/topology/CMAP_spec_test.go index eabefead7d..6f23eaa36e 100644 --- a/x/mongo/driver/topology/CMAP_spec_test.go +++ b/x/mongo/driver/topology/CMAP_spec_test.go @@ -114,7 +114,7 @@ type testInfo struct { sync.Mutex } -var cmapTestDir = spectest.TestPath(4, "connection-monitoring-and-pooling", "cmap-format") +var cmapTestDir = spectest.Path("connection-monitoring-and-pooling/tests/cmap-format") func TestCMAPSpec(t *testing.T) { for _, testFileName := range spectest.FindJSONFilesInDir(t, cmapTestDir) { diff --git a/x/mongo/driver/topology/sdam_spec_test.go b/x/mongo/driver/topology/sdam_spec_test.go index 55ac65e978..f17eb4a2d8 100644 --- a/x/mongo/driver/topology/sdam_spec_test.go +++ b/x/mongo/driver/topology/sdam_spec_test.go @@ -203,7 +203,7 @@ func serverClosed(e *event.ServerClosedEvent) { lock.Unlock() } -var testsDir = spectest.TestPath(4, "server-discovery-and-monitoring") +var testsDir = spectest.Path("server-discovery-and-monitoring/tests") var publishedEvents []interface{} var lock sync.Mutex diff --git a/x/mongo/driver/topology/server_rtt_test.go b/x/mongo/driver/topology/server_rtt_test.go index 9b4ba676e6..7c842867fe 100644 --- a/x/mongo/driver/topology/server_rtt_test.go +++ b/x/mongo/driver/topology/server_rtt_test.go @@ -27,7 +27,7 @@ func TestServerSelectionRTTSpec(t *testing.T) { NewAvgRtt float64 `json:"new_avg_rtt"` } - testsDir := spectest.TestPath(4, "server-selection", "rtt") + testsDir := spectest.Path("server-selection/tests/rtt") for _, file := range spectest.FindJSONFilesInDir(t, testsDir) { func(t *testing.T, filename string) { diff --git a/x/mongo/driver/topology/topology_test.go b/x/mongo/driver/topology/topology_test.go index c3453d4026..b95c84fc54 100644 --- a/x/mongo/driver/topology/topology_test.go +++ b/x/mongo/driver/topology/topology_test.go @@ -808,7 +808,7 @@ type inWindowTestCase struct { // can't be effectively accomplished just with server descriptions like most other server selection // algorithms. func TestServerSelectionSpecInWindow(t *testing.T) { - testsDir := spectest.TestPath(4, "server-selection", "in_window") + testsDir := spectest.Path("server-selection/tests/in_window") files := spectest.FindJSONFilesInDir(t, testsDir)