diff --git a/mongoimport/csv_test.go b/mongoimport/csv_test.go index b68faca8f..26d7b8d31 100644 --- a/mongoimport/csv_test.go +++ b/mongoimport/csv_test.go @@ -195,7 +195,7 @@ func TestCSVStreamDocument(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var r *CSVInputReader if tc.file != "" { - fileHandle := openTestCSVFile(t, tc.file) + fileHandle := openTestFixture(t, tc.file) r = NewCSVInputReader(tc.colSpecs, fileHandle, os.Stdout, 1, false, false) } else { r = NewCSVInputReader( @@ -486,7 +486,7 @@ func TestCSVReadAndValidateHeader(t *testing.T) { {"b", 5.4}, {"c", "string"}, } - fileHandle := openTestCSVFile(t, "testdata/test.csv") + fileHandle := openTestFixture(t, "testdata/test.csv") r := NewCSVInputReader(colSpecs, fileHandle, os.Stdout, 1, false, false) // buffered generously: test.csv holds more lines than this test // checks, and StreamDocument must not block trying to send them @@ -502,17 +502,6 @@ func TestCSVReadAndValidateHeader(t *testing.T) { ) } -// registers its own teardown so each table case gets a fresh handle. -func openTestCSVFile(t *testing.T, path string) *os.File { - t.Helper() - - fileHandle, err := os.Open(path) - require.NoError(t, err, "should open the test fixture") - t.Cleanup(func() { fileHandle.Close() }) - - return fileHandle -} - func TestCSVConvert(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.UnitTestType) diff --git a/mongoimport/helpers_test.go b/mongoimport/helpers_test.go new file mode 100644 index 000000000..98bae0568 --- /dev/null +++ b/mongoimport/helpers_test.go @@ -0,0 +1,26 @@ +// Copyright (C) MongoDB, Inc. 2014-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 mongoimport + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +// openTestFixture is shared by csv_test.go, json_test.go, and tsv_test.go. +// It registers its own teardown so each caller gets a fresh handle. +func openTestFixture(t *testing.T, path string) *os.File { + t.Helper() + + fileHandle, err := os.Open(path) + require.NoError(t, err, "should open the test fixture") + t.Cleanup(func() { fileHandle.Close() }) + + return fileHandle +} diff --git a/mongoimport/json_test.go b/mongoimport/json_test.go index ef472b382..17682dd51 100644 --- a/mongoimport/json_test.go +++ b/mongoimport/json_test.go @@ -9,7 +9,6 @@ package mongoimport import ( "bytes" "io" - "os" "testing" "github.com/mongodb/mongo-tools/common/testtype" @@ -54,7 +53,7 @@ func TestJSONArrayStreamDocument(t *testing.T) { } t.Run("an error should be thrown if a plain JSON file is supplied", func(t *testing.T) { - fileHandle := openTestJSONFile(t, "testdata/test_plain.json") + fileHandle := openTestFixture(t, "testdata/test_plain.json") r := NewJSONInputReader(true, true, fileHandle, 1) require.Error( t, @@ -77,7 +76,7 @@ func TestJSONArrayStreamDocument(t *testing.T) { {"b", "string"}, {"c", 52.9}, } - fileHandle := openTestJSONFile(t, "testdata/test_array.json") + fileHandle := openTestFixture(t, "testdata/test_array.json") r := NewJSONInputReader(true, true, fileHandle, 1) streamOutChan := make(chan bson.D, 50) require.NoError( @@ -187,7 +186,7 @@ func TestJSONPlainStreamDocument(t *testing.T) { for _, tc := range fileCases { t.Run(tc.name, func(t *testing.T) { - fileHandle := openTestJSONFile(t, tc.file) + fileHandle := openTestFixture(t, tc.file) r := NewJSONInputReader(false, true, fileHandle, 1) streamOutChan := make(chan bson.D, len(tc.expectedReads)) require.NoError( @@ -218,17 +217,6 @@ func TestJSONPlainStreamDocument(t *testing.T) { } } -// registers its own teardown so each subtest gets a fresh handle. -func openTestJSONFile(t *testing.T, path string) *os.File { - t.Helper() - - fileHandle, err := os.Open(path) - require.NoError(t, err, "should open the test fixture") - t.Cleanup(func() { fileHandle.Close() }) - - return fileHandle -} - func TestReadJSONArraySeparator(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.UnitTestType) diff --git a/mongoimport/mongoimport_test.go b/mongoimport/mongoimport_test.go index a4ff18191..6a2359e6f 100644 --- a/mongoimport/mongoimport_test.go +++ b/mongoimport/mongoimport_test.go @@ -27,7 +27,6 @@ import ( "github.com/mongodb/mongo-tools/common/testtype" "github.com/mongodb/mongo-tools/common/testutil" "github.com/mongodb/mongo-tools/common/wcwrapper" - . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/v2/bson" @@ -1531,20 +1530,23 @@ func runNestedFieldsTestCase( // Regression test for TOOLS-1694 to prevent issue from TOOLS-1115. func TestHiddenOptionsDefaults(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.UnitTestType) - Convey("With a new mongoimport with empty options", t, func() { - imp := NewMockMongoImport() - imp.ToolOptions = options.New("", "", "", "", true, options.EnabledOptions{}) - Convey("Then parsing should fill args with expected defaults", func() { - _, err := imp.ToolOptions.ParseArgs([]string{}) - So(err, ShouldBeNil) - - // collection cannot be empty in validate - imp.ToolOptions.Collection = "col" - So(imp.validateSettings(), ShouldBeNil) - So(imp.IngestOptions.NumDecodingWorkers, ShouldEqual, runtime.NumCPU()) - So(imp.IngestOptions.BulkBufferSize, ShouldEqual, 1000) - }) - }) + + imp := NewMockMongoImport() + imp.ToolOptions = options.New("", "", "", "", true, options.EnabledOptions{}) + + _, err := imp.ToolOptions.ParseArgs([]string{}) + require.NoError(t, err, "should parse an empty argument list") + + // collection cannot be empty in validate + imp.ToolOptions.Collection = "col" + require.NoError(t, imp.validateSettings(), "should validate the filled-in settings") + assert.Equal( + t, + runtime.NumCPU(), + imp.IngestOptions.NumDecodingWorkers, + "should default the decoding worker count to the CPU count", + ) + assert.Equal(t, 1000, imp.IngestOptions.BulkBufferSize, "should default the bulk buffer size") } // generateTestData creates the files used in TestImportMIOSOE. @@ -1591,76 +1593,101 @@ func generateTestData() error { func TestImportMIOSOE(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.IntegrationTestType) - if err := generateTestData(); err != nil { - t.Fatalf("Could not generate test data: %v", err) - } + require.NoError(t, generateTestData(), "should generate the test data file") client, err := testutil.GetBareSession() - if err != nil { - t.Fatalf("No server available?? (%v)", err) - } + require.NoError(t, err, "must connect to the server") database := client.Database("miodb") coll := database.Collection("mio") - Convey("default restore ignores dup key errors", t, func() { + t.Run("default restore ignores dup key errors", func(t *testing.T) { imp, err := getImportWithArgs(mioSoeFile, "--collection", coll.Name(), "--db", database.Name(), "--drop") - So(err, ShouldBeNil) - So(imp.IngestOptions.MaintainInsertionOrder, ShouldBeFalse) + require.NoError(t, err, "should build the import with the given args") + require.False( + t, + imp.IngestOptions.MaintainInsertionOrder, + "should default to unordered insertion", + ) nSuccess, nFailure, err := imp.ImportDocuments() - So(err, ShouldBeNil) + require.NoError(t, err, "should tolerate the duplicate key without failing the import") - So(nSuccess, ShouldEqual, 20000) - So(nFailure, ShouldEqual, 1) + assert.EqualValues(t, 20000, nSuccess, "should import every non-duplicate document") + assert.EqualValues(t, 1, nFailure, "should count the single duplicate key as a failure") count, err := coll.CountDocuments(t.Context(), bson.M{}) - So(err, ShouldBeNil) - So(count, ShouldEqual, 20000) + require.NoError(t, err, "should count the imported documents") + assert.EqualValues(t, 20000, count, "should have inserted every non-duplicate document") }) - Convey("--maintainInsertionOrder stops exactly on dup key errors", t, func() { + t.Run("--maintainInsertionOrder stops exactly on dup key errors", func(t *testing.T) { imp, err := getImportWithArgs(mioSoeFile, "--collection", coll.Name(), "--db", database.Name(), "--drop", "--maintainInsertionOrder") - So(err, ShouldBeNil) - So(imp.IngestOptions.MaintainInsertionOrder, ShouldBeTrue) - So(imp.IngestOptions.NumInsertionWorkers, ShouldEqual, 1) + require.NoError(t, err, "should build the import with the given args") + require.True( + t, + imp.IngestOptions.MaintainInsertionOrder, + "should honor --maintainInsertionOrder", + ) + require.Equal( + t, + 1, + imp.IngestOptions.NumInsertionWorkers, + "should force a single insertion worker", + ) nSuccess, nFailure, err := imp.ImportDocuments() - So(err, ShouldNotBeNil) + require.Error(t, err, "should stop the import at the duplicate key") - So(nSuccess, ShouldEqual, 10000) - So(nFailure, ShouldEqual, 1) - So(err, ShouldNotBeNil) + assert.EqualValues(t, 10000, nSuccess, "should stop right before the duplicate key") + assert.EqualValues(t, 1, nFailure, "should count the duplicate key as a failure") count, err := coll.CountDocuments(t.Context(), bson.M{}) - So(err, ShouldBeNil) - So(count, ShouldEqual, 10000) + require.NoError(t, err, "should count the imported documents") + assert.EqualValues( + t, + 10000, + count, + "should have inserted only the documents before the duplicate", + ) }) - Convey("--stopOnError stops on dup key errors", t, func() { + t.Run("--stopOnError stops on dup key errors", func(t *testing.T) { imp, err := getImportWithArgs(mioSoeFile, "--collection", coll.Name(), "--db", database.Name(), "--drop", "--stopOnError") - So(err, ShouldBeNil) - So(imp.IngestOptions.StopOnError, ShouldBeTrue) + require.NoError(t, err, "should build the import with the given args") + require.True(t, imp.IngestOptions.StopOnError, "should honor --stopOnError") nSuccess, nFailure, err := imp.ImportDocuments() - So(err, ShouldNotBeNil) + require.Error(t, err, "should stop the import at the duplicate key") - So(nSuccess, ShouldAlmostEqual, 10000, imp.IngestOptions.BulkBufferSize) - So(nFailure, ShouldEqual, 1) + assert.InDelta( + t, + 10000, + nSuccess, + float64(imp.IngestOptions.BulkBufferSize), + "should stop near the duplicate key, within one buffer's worth of documents", + ) + assert.EqualValues(t, 1, nFailure, "should count the duplicate key as a failure") count, err := coll.CountDocuments(t.Context(), bson.M{}) - So(err, ShouldBeNil) - So(count, ShouldAlmostEqual, 10000, imp.IngestOptions.BulkBufferSize) + require.NoError(t, err, "should count the imported documents") + assert.InDelta( + t, + 10000, + count, + float64(imp.IngestOptions.BulkBufferSize), + "should have inserted near the duplicate key, within one buffer's worth of documents", + ) }) _ = database.Drop(t.Context()) diff --git a/mongoimport/tsv_test.go b/mongoimport/tsv_test.go index 8b47f35d7..b0bae82b6 100644 --- a/mongoimport/tsv_test.go +++ b/mongoimport/tsv_test.go @@ -179,7 +179,7 @@ func TestTSVStreamDocument(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var r *TSVInputReader if tc.file != "" { - fileHandle := openTestTSVFile(t, tc.file) + fileHandle := openTestFixture(t, tc.file) r = NewTSVInputReader(tc.colSpecs, fileHandle, os.Stdout, 1, false, false) } else { r = NewTSVInputReader( @@ -206,17 +206,6 @@ func TestTSVStreamDocument(t *testing.T) { } } -// registers its own teardown so each table case gets a fresh handle. -func openTestTSVFile(t *testing.T, path string) *os.File { - t.Helper() - - fileHandle, err := os.Open(path) - require.NoError(t, err, "should open the test fixture") - t.Cleanup(func() { fileHandle.Close() }) - - return fileHandle -} - func TestTSVReadAndValidateHeader(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.UnitTestType)