diff --git a/common/testutil/testutil.go b/common/testutil/testutil.go index 8e2bffc1b..186db2574 100644 --- a/common/testutil/testutil.go +++ b/common/testutil/testutil.go @@ -18,6 +18,7 @@ import ( "github.com/mongodb/mongo-tools/common/db" "github.com/mongodb/mongo-tools/common/options" + "github.com/pkg/errors" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -91,20 +92,53 @@ func GetBareArgs() []string { return args } -// GetFCV returns the featureCompatibilityVersion string for an mgo Session +// GetFCVErr returns the featureCompatibilityVersion string for an mgo Session // or the empty string if it can't be found. -func GetFCV(s *mongo.Client) string { +// +// See SkipUnlessFCVAtLeast() to simplify FCV checks. +func GetFCVErr(s *mongo.Client) (string, error) { coll := s.Database("admin").Collection("system.version") var result struct { Version string } res := coll.FindOne(context.TODO(), bson.M{"_id": "featureCompatibilityVersion"}) - //nolint:errcheck - res.Decode(&result) - return result.Version + + err := res.Decode(&result) + if err != nil { + return "", errors.Wrap(err, "failed to get FCV") + } + + return result.Version, nil +} + +// GetFCV is like GetFCVErr but panicks instead of returning an error. +// Avoid this function in new code. +func GetFCV(s *mongo.Client) string { + version, err := GetFCVErr(s) + if err != nil { + panic(err) + } + + return version +} + +// SkipUnlessFCVAtLeast skips the present test unless the server’s FCV +// is at least minFCV. +func SkipUnlessFCVAtLeast(t *testing.T, s *mongo.Client, minFCV string) { + fcv, err := GetFCVErr(s) + require.NoError(t, err, "should get FCV") + + cmp, err := CompareFCV(fcv, minFCV) + require.NoError(t, err, "should compare FCVs (got %#q; want %#q)", fcv, minFCV) + + if cmp < 0 { + t.Skipf("This test requires a server with FCV %#q or later", minFCV) + } } // CompareFCV compares two strings as dot-delimited tuples of integers. +// +// See SkipUnlessFCVAtLeast() to simplify FCV checks. func CompareFCV(x, y string) (int, error) { left, err := dottedStringToSlice(x) if err != nil { diff --git a/mongorestore/mongorestore_test.go b/mongorestore/mongorestore_test.go index d7e81b831..0818f136c 100644 --- a/mongorestore/mongorestore_test.go +++ b/mongorestore/mongorestore_test.go @@ -2188,6 +2188,67 @@ func setupTimeseriesWithMixedSchema(dbName string, collName string) error { return nil } +func TestRestoreTimeseriesCollectionsWithTTL(t *testing.T) { + testtype.SkipUnlessTestType(t, testtype.IntegrationTestType) + ctx := context.Background() + + sessionProvider, _, err := testutil.GetBareSessionProvider() + require.NoError(t, err, "should find cluster") + + defer sessionProvider.Close() + + session, err := sessionProvider.GetSession() + require.NoError(t, err, "should find session") + + testutil.SkipUnlessFCVAtLeast(t, session, "7.0") + + dbName := t.Name() + + db := session.Database(dbName) + require.NoError(t, db.Drop(ctx), "should drop db") + + err = db.CreateCollection( + ctx, + "coll", + mopt.CreateCollection(). + SetTimeSeriesOptions( + mopt.TimeSeries(). + SetTimeField("time"). + SetMetaField("meta"), + ), + ) + require.NoError(t, err, "should create collection") + + _, err = db.Collection("coll").Indexes().CreateOne( + ctx, + mongo.IndexModel{ + Keys: bson.D{{"time", 1}}, + Options: mopt.Index(). + SetPartialFilterExpression( + bson.D{{"meta", 123123}}, + ).SetExpireAfterSeconds( + 123123, + ), + }, + ) + require.NoError(t, err, "should create index") + + withArchiveMongodump(t, func(file string) { + args := []string{ + DropOption, + ArchiveOption + "=" + file, + } + + restore, err := getRestoreWithArgs(args...) + require.NoError(t, err, "restore should run") + defer restore.Close() + + result := restore.Restore() + require.NoError(t, result.Err, "can run mongorestore (result: %+v)", result) + require.EqualValues(t, 0, result.Failures, "mongorestore reports 0 failures") + }) +} + func TestRestoreTimeseriesCollections(t *testing.T) { testtype.SkipUnlessTestType(t, testtype.IntegrationTestType) ctx := context.Background()