From ddf2bfb6a3e3b1a17723e77166690eb6f00ad36d Mon Sep 17 00:00:00 2001 From: Kaitlin Mahar Date: Thu, 16 Feb 2023 15:50:47 +0000 Subject: SERVER-60064 Make create command idempotent on mongod --- jstests/core/ddl/create_collection.js | 104 ++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 25 deletions(-) (limited to 'jstests/core/ddl') diff --git a/jstests/core/ddl/create_collection.js b/jstests/core/ddl/create_collection.js index a9273f0c948..a38d9efb970 100644 --- a/jstests/core/ddl/create_collection.js +++ b/jstests/core/ddl/create_collection.js @@ -1,10 +1,8 @@ -// Cannot implicitly shard accessed collections because of collection existing when none -// expected. // FCV4.4 is required for creating a collection with a long name. // @tags: [ -// assumes_against_mongod_not_mongos, -// assumes_no_implicit_collection_creation_after_drop, // requires_capped, +// # TODO SERVER-73967: Remove this tag. +// does_not_support_stepdowns, // ] // Tests for the "create" command. @@ -12,9 +10,15 @@ "use strict"; load("jstests/libs/index_catalog_helpers.js"); +load("jstests/libs/clustered_collections/clustered_collection_util.js"); + +// TODO SERVER-73934: Change assertions on 'drop' command results throughout this file to +// always expect the command worked. Currently, they can return NamespaceNotFound on +// server versions < 7.0. // "create" command rejects invalid options. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode(db.createCollection("create_collection", {unknown: 1}), 40415); // Cannot create a collection with null characters. @@ -25,7 +29,8 @@ assert.commandFailedWithCode(db.createCollection("ab\0"), ErrorCodes.InvalidName // The collection name length limit was upped in 4.4, try creating a collection with a longer // name than previously allowed. const longCollName = 'a'.repeat(200); -db[longCollName].drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: longCollName}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection(longCollName)); // @@ -33,7 +38,8 @@ assert.commandWorked(db.createCollection(longCollName)); // // "idIndex" field not allowed with "viewOn". -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection("create_collection")); assert.commandFailedWithCode(db.runCommand({ create: "create_view", @@ -43,36 +49,42 @@ assert.commandFailedWithCode(db.runCommand({ ErrorCodes.InvalidOptions); // "idIndex" field not allowed with "autoIndexId". -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode( db.createCollection("create_collection", {autoIndexId: false, idIndex: {key: {_id: 1}, name: "_id_"}}), ErrorCodes.InvalidOptions); // "idIndex" field must be an object. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode(db.createCollection("create_collection", {idIndex: 1}), ErrorCodes.TypeMismatch); // "idIndex" field cannot be empty. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode(db.createCollection("create_collection", {idIndex: {}}), ErrorCodes.FailedToParse); // "idIndex" field must be a specification for an _id index. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode( db.createCollection("create_collection", {idIndex: {key: {a: 1}, name: "a_1"}}), ErrorCodes.BadValue); // "idIndex" field must have "key" equal to {_id: 1}. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode( db.createCollection("create_collection", {idIndex: {key: {a: 1}, name: "_id_"}}), ErrorCodes.BadValue); // The name of an _id index gets corrected to "_id_". -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "a_1"}})); var indexSpec = IndexCatalogHelpers.findByKeyPattern(db.create_collection.getIndexes(), {_id: 1}); @@ -80,14 +92,16 @@ assert.neq(indexSpec, null); assert.eq(indexSpec.name, "_id_", tojson(indexSpec)); // "idIndex" field must only contain fields that are allowed for an _id index. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "_id_", sparse: true}}), ErrorCodes.InvalidIndexSpecificationOption); // "create" creates v=2 _id index when "v" is not specified in "idIndex". -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "_id_"}})); indexSpec = IndexCatalogHelpers.findByName(db.create_collection.getIndexes(), "_id_"); @@ -95,7 +109,8 @@ assert.neq(indexSpec, null); assert.eq(indexSpec.v, 2, tojson(indexSpec)); // "create" creates v=1 _id index when "idIndex" has "v" equal to 1. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "_id_", v: 1}})); indexSpec = IndexCatalogHelpers.findByName(db.create_collection.getIndexes(), "_id_"); @@ -103,7 +118,8 @@ assert.neq(indexSpec, null); assert.eq(indexSpec.v, 1, tojson(indexSpec)); // "create" creates v=2 _id index when "idIndex" has "v" equal to 2. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "_id_", v: 2}})); indexSpec = IndexCatalogHelpers.findByName(db.create_collection.getIndexes(), "_id_"); @@ -111,27 +127,31 @@ assert.neq(indexSpec, null); assert.eq(indexSpec.v, 2, tojson(indexSpec)); // "collation" field of "idIndex" must match collection default collation. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode( db.createCollection("create_collection", {idIndex: {key: {_id: 1}, name: "_id_", collation: {locale: "en_US"}}}), ErrorCodes.BadValue); -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode(db.createCollection("create_collection", { collation: {locale: "fr_CA"}, idIndex: {key: {_id: 1}, name: "_id_", collation: {locale: "en_US"}} }), ErrorCodes.BadValue); -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandFailedWithCode(db.createCollection("create_collection", { collation: {locale: "fr_CA"}, idIndex: {key: {_id: 1}, name: "_id_", collation: {locale: "simple"}} }), ErrorCodes.BadValue); -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection("create_collection", { collation: {locale: "en_US", strength: 3}, idIndex: {key: {_id: 1}, name: "_id_", collation: {locale: "en_US"}} @@ -142,7 +162,8 @@ assert.eq(indexSpec.collation.locale, "en_US", tojson(indexSpec)); // If "collation" field is not present in "idIndex", _id index inherits collection default // collation. -db.create_collection.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection( "create_collection", {collation: {locale: "en_US"}, idIndex: {key: {_id: 1}, name: "_id_"}})); indexSpec = IndexCatalogHelpers.findByName(db.create_collection.getIndexes(), "_id_"); @@ -158,11 +179,14 @@ assert.commandFailedWithCode(db.createCollection('capped_no_size_no_max', {cappe ErrorCodes.InvalidOptions); assert.commandFailedWithCode(db.createCollection('capped_no_size', {capped: true, max: 10}), ErrorCodes.InvalidOptions); -db.no_capped.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "no_capped"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection('no_capped'), {capped: false}); -db.capped_no_max.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "capped_no_max"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked(db.createCollection('capped_no_max', {capped: true, size: 256})); -db.capped_with_max_and_size.drop(); +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "capped_with_max_and_size"}), + ErrorCodes.NamespaceNotFound); assert.commandWorked( db.createCollection('capped_with_max_and_size', {capped: true, max: 10, size: 256})); @@ -171,4 +195,34 @@ assert.commandFailedWithCode(db.createCollection('size_no_capped', {size: 256}), ErrorCodes.InvalidOptions); assert.commandFailedWithCode(db.createCollection('size_capped_false', {capped: false, size: 256}), ErrorCodes.InvalidOptions); + +// The remainder of this test file will not work if all collections are automatically clustered +// because a repeat attempt to create a collection will not have ``clusteredIndex`` set but +// the existing collection will. +if (ClusteredCollectionUtil.areAllCollectionsClustered(db.getMongo())) { + return; +} + +// The remainder of this test will not work on server versions < 7.0 as the 'create' command +// is not idempotent there. TODO SERVER-74062: remove this. +if (db.version().split('.')[0] < 7) { + return; +} + +assert.commandWorkedOrFailedWithCode(db.runCommand({drop: "create_collection"}), + ErrorCodes.NamespaceNotFound); + +// Creating a collection that already exists with no options specified reports success. +assert.commandWorked(db.createCollection("create_collection")); +assert.commandWorked(db.createCollection("create_collection")); + +assert.commandWorked(db.runCommand({drop: "create_collection"})); + +// Creating a collection that already exists with the same options reports success. +assert.commandWorked(db.createCollection("create_collection"), {collation: {locale: "fr"}}); +assert.commandWorked(db.createCollection("create_collection"), {collation: {locale: "fr"}}); + +// Creating a collection that already exists with different options reports failure. +assert.commandFailedWithCode(db.createCollection("create_collection", {collation: {locale: "uk"}}), + ErrorCodes.NamespaceExists); })(); -- cgit v1.2.1