diff --git a/integration/indexes_compat_test.go b/integration/indexes_compat_test.go index d45b07c95a92..c3ad7e96c8fe 100644 --- a/integration/indexes_compat_test.go +++ b/integration/indexes_compat_test.go @@ -27,7 +27,7 @@ import ( "github.com/FerretDB/FerretDB/integration/shareddata" ) -func TestIndexesCompatList(t *testing.T) { +func TestListIndexesCompat(t *testing.T) { t.Parallel() s := setup.SetupCompatWithOpts(t, &setup.SetupCompatOpts{ @@ -67,7 +67,7 @@ func TestIndexesCompatList(t *testing.T) { } } -func TestIndexesCompatCreate(t *testing.T) { +func TestCreateIndexesCompat(t *testing.T) { setup.SkipForTigrisWithReason(t, "Indexes creation is not supported for Tigris") t.Parallel() @@ -304,55 +304,62 @@ func TestCreateIndexesCommandCompat(t *testing.T) { resultType compatTestCaseResultType // defaults to nonEmptyResult skip string // optional, skip test with a specified reason }{ - "invalid-collection-name": { + "InvalidCollectionName": { collectionName: 42, key: bson.D{{"v", -1}}, indexName: "custom-name", resultType: emptyResult, }, - "nil-collection-name": { + "NilCollectionName": { collectionName: nil, key: bson.D{{"v", -1}}, indexName: "custom-name", resultType: emptyResult, }, - "index-name-not-set": { + "EmptyCollectionName": { + collectionName: "", + key: bson.D{{"v", -1}}, + indexName: "custom-name", + resultType: emptyResult, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + "IndexNameNotSet": { collectionName: "test", key: bson.D{{"v", -1}}, indexName: nil, resultType: emptyResult, skip: "https://github.com/FerretDB/FerretDB/issues/2311", }, - "empty-index-name": { + "EmptyIndexName": { collectionName: "test", key: bson.D{{"v", -1}}, indexName: "", resultType: emptyResult, skip: "https://github.com/FerretDB/FerretDB/issues/2311", }, - "non-string-index-name": { + "NonStringIndexName": { collectionName: "test", key: bson.D{{"v", -1}}, indexName: 42, resultType: emptyResult, }, - "existing-name-different-key-length": { + "ExistingNameDifferentKeyLength": { collectionName: "test", key: bson.D{{"_id", 1}, {"v", 1}}, indexName: "_id_", // the same name as the default index skip: "https://github.com/FerretDB/FerretDB/issues/2311", }, - "invalid-key": { + "InvalidKey": { collectionName: "test", key: 42, resultType: emptyResult, }, - "empty-key": { + "EmptyKey": { collectionName: "test", key: bson.D{}, resultType: emptyResult, }, - "key-not-set": { + "KeyNotSet": { collectionName: "test", resultType: emptyResult, skip: "https://github.com/FerretDB/FerretDB/issues/2311", @@ -436,7 +443,7 @@ func TestCreateIndexesCommandCompat(t *testing.T) { } } -func TestIndexesCompatDrop(t *testing.T) { +func TestDropIndexesCompat(t *testing.T) { setup.SkipForTigrisWithReason(t, "Indexes are not supported for Tigris") t.Parallel() @@ -483,6 +490,10 @@ func TestIndexesCompatDrop(t *testing.T) { dropIndexName: "nonexistent_1", resultType: emptyResult, }, + "Empty": { + dropIndexName: "", + resultType: emptyResult, + }, } { name, tc := name, tc t.Run(name, func(t *testing.T) { @@ -579,6 +590,22 @@ func TestDropIndexesCommandCompat(t *testing.T) { }, toDrop: bson.A{"v_-1", "v_1_foo_1"}, }, + "MultipleIndexesByKey": { + toCreate: []mongo.IndexModel{ + {Keys: bson.D{{"v", -1}}}, + {Keys: bson.D{{"v.foo", -1}}}, + }, + toDrop: bson.A{bson.D{{"v", -1}}, bson.D{{"v.foo", -1}}}, + resultType: emptyResult, + }, + "NonExistentMultipleIndexes": { + toDrop: bson.A{"non-existent", "invalid"}, + resultType: emptyResult, + }, + "InvalidMultipleIndexType": { + toDrop: bson.A{1}, + resultType: emptyResult, + }, "DocumentIndex": { toCreate: []mongo.IndexModel{ {Keys: bson.D{{"v", -1}}}, @@ -593,6 +620,19 @@ func TestDropIndexesCommandCompat(t *testing.T) { }, toDrop: "*", }, + "WrongExpression": { + toCreate: []mongo.IndexModel{ + {Keys: bson.D{{"v", -1}}}, + {Keys: bson.D{{"foo.bar", 1}}}, + {Keys: bson.D{{"foo", 1}, {"bar", 1}}}, + }, + toDrop: "***", + resultType: emptyResult, + }, + "NonExistentDescendingID": { + toDrop: bson.D{{"_id", -1}}, + resultType: emptyResult, + }, "MultipleKeyIndex": { toCreate: []mongo.IndexModel{ {Keys: bson.D{{"_id", -1}, {"v", 1}}}, diff --git a/integration/indexes_test.go b/integration/indexes_test.go index d7016bea4ee3..00cad97cabe8 100644 --- a/integration/indexes_test.go +++ b/integration/indexes_test.go @@ -172,3 +172,143 @@ func TestIndexesDropCommandErrors(t *testing.T) { }) } } + +func TestCreateIndexesInvalidSpec(t *testing.T) { + setup.SkipForTigrisWithReason(t, "Indexes are not supported for Tigris") + + t.Parallel() + + for name, tc := range map[string]struct { + indexes any + err *mongo.CommandError + altMessage string + skip string + }{ + "EmptyIndexes": { + indexes: bson.A{}, + err: &mongo.CommandError{ + Code: 2, + Name: "BadValue", + Message: "Must specify at least one index to create", + }, + }, + "NilIndexes": { + indexes: nil, + err: &mongo.CommandError{ + Code: 10065, + Name: "Location10065", + Message: "invalid parameter: expected an object (indexes)", + }, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + "InvalidType": { + indexes: 42, + err: &mongo.CommandError{ + Code: 14, + Name: "TypeMismatch", + Message: "BSON field 'createIndexes.indexes' is the wrong type 'int', expected type 'array'", + }, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + } { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + if tc.skip != "" { + t.Skip(tc.skip) + } + + t.Parallel() + + provider := shareddata.ArrayDocuments // one provider is enough to check for errors + ctx, collection := setup.Setup(t, provider) + + command := bson.D{ + {"createIndexes", collection.Name()}, + {"indexes", tc.indexes}, + } + + var res bson.D + err := collection.Database().RunCommand(ctx, command).Decode(&res) + + require.Nil(t, res) + AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err) + }) + } +} + +func TestDropIndexesInvalidCollection(t *testing.T) { + setup.SkipForTigrisWithReason(t, "Indexes are not supported for Tigris") + + t.Parallel() + + for name, tc := range map[string]struct { + collectionName any + indexName any + err *mongo.CommandError + altMessage string + skip string + }{ + "NonExistentCollection": { + collectionName: "non-existent", + indexName: "index", + err: &mongo.CommandError{ + Code: 26, + Name: "NamespaceNotFound", + Message: "ns not found TestDropIndexesInvalidCollection-NonExistentCollection.non-existent", + }, + }, + "InvalidTypeCollection": { + collectionName: 42, + indexName: "index", + err: &mongo.CommandError{ + Code: 2, + Name: "BadValue", + Message: "collection name has invalid type int", + }, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + "NilCollection": { + collectionName: nil, + indexName: "index", + err: &mongo.CommandError{ + Code: 2, + Name: "BadValue", + Message: "collection name has invalid type null", + }, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + "EmptyCollection": { + collectionName: "", + indexName: "index", + err: &mongo.CommandError{ + Code: 73, + Name: "InvalidNamespace", + Message: "Invalid namespace specified 'TestIndexesDropInvalidCollection-EmptyCollection.'", + }, + skip: "https://github.com/FerretDB/FerretDB/issues/2311", + }, + } { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + if tc.skip != "" { + t.Skip(tc.skip) + } + + t.Parallel() + + provider := shareddata.ArrayDocuments // one provider is enough to check for errors + ctx, collection := setup.Setup(t, provider) + + command := bson.D{ + {"dropIndexes", tc.collectionName}, + {"index", tc.indexName}, + } + + var res bson.D + err := collection.Database().RunCommand(ctx, command).Decode(&res) + + require.Nil(t, res) + AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err) + }) + } +} diff --git a/internal/handlers/pg/msg_createindexes.go b/internal/handlers/pg/msg_createindexes.go index f4194af59298..2fd7c9941c17 100644 --- a/internal/handlers/pg/msg_createindexes.go +++ b/internal/handlers/pg/msg_createindexes.go @@ -273,7 +273,6 @@ func processIndexKey(keyDoc *types.Document) (pgdb.IndexKey, error) { var orderParam int64 if orderParam, err = commonparams.GetWholeNumberParam(order); err != nil { - // TODO Add better validation and return proper error: https://github.com/FerretDB/FerretDB/issues/2311 return nil, commonerrors.NewCommandErrorMsgWithArgument( commonerrors.ErrNotImplemented, fmt.Sprintf("Index key value %q is not implemented yet", order), @@ -289,7 +288,6 @@ func processIndexKey(keyDoc *types.Document) (pgdb.IndexKey, error) { case -1: indexOrder = types.Descending default: - // TODO Add better validation: https://github.com/FerretDB/FerretDB/issues/2311 return nil, commonerrors.NewCommandErrorMsgWithArgument( commonerrors.ErrNotImplemented, fmt.Sprintf("Index key value %q is not implemented yet", orderParam),