summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorKaitlin Mahar <kaitlin.mahar@mongodb.com>2023-02-16 15:50:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-02-16 17:57:16 +0000
commitddf2bfb6a3e3b1a17723e77166690eb6f00ad36d (patch)
tree3b8b561bed2a153be92e59efd226f96fe358e7e3 /jstests
parentf74fb285c7eeeb24d2284b980a6b5df977803b3b (diff)
downloadmongo-ddf2bfb6a3e3b1a17723e77166690eb6f00ad36d.tar.gz
SERVER-60064 Make create command idempotent on mongod
Diffstat (limited to 'jstests')
-rw-r--r--jstests/core/ddl/create_collection.js104
-rw-r--r--jstests/core/views/invalid_view_prevents_creating_new_view.js49
-rw-r--r--jstests/core/views/views_creation.js78
-rw-r--r--jstests/replsets/noop_writes_wait_for_write_concern.js9
4 files changed, 185 insertions, 55 deletions
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);
})();
diff --git a/jstests/core/views/invalid_view_prevents_creating_new_view.js b/jstests/core/views/invalid_view_prevents_creating_new_view.js
new file mode 100644
index 00000000000..c9134938938
--- /dev/null
+++ b/jstests/core/views/invalid_view_prevents_creating_new_view.js
@@ -0,0 +1,49 @@
+/**
+ * Test that, when an existing view in system.views is invalid because of a $out in the
+ * pipeline, the database errors on creation of a new view.
+ *
+ * The test runs commands that are not allowed with security token: applyOps.
+ * @tags: [
+ * not_allowed_with_security_token,
+ * # applyOps is not available on mongos.
+ * assumes_against_mongod_not_mongos,
+ * assumes_superuser_permissions,
+ * # applyOps is not retryable.
+ * requires_non_retryable_commands,
+ * # Tenant migrations don't support applyOps.
+ * tenant_migration_incompatible,
+ * ]
+ */
+(function() {
+"use strict";
+
+// For arrayEq.
+load("jstests/aggregation/extras/utils.js");
+
+const viewsDBName = jsTestName();
+
+let viewsDB = db.getSiblingDB(viewsDBName);
+assert.commandWorked(viewsDB.dropDatabase());
+
+// Create an initial collection and view so the DB and system.views collection exist.
+assert.commandWorked(viewsDB.runCommand({create: "collection"}));
+assert.commandWorked(viewsDB.runCommand({create: "testView", viewOn: "collection"}));
+
+assert.commandWorked(viewsDB.adminCommand({
+ applyOps: [{
+ op: "i",
+ ns: viewsDBName + ".system.views",
+ o: {
+ _id: viewsDBName + ".invalidView",
+ viewOn: "collection",
+ pipeline: [{$project: {_id: false}}, {$out: "notExistingCollection"}],
+ }
+ }]
+}));
+assert.commandFailedWithCode(
+ viewsDB.runCommand({create: "viewWithBadViewCatalog", viewOn: "collection", pipeline: []}),
+ ErrorCodes.OptionNotSupportedOnView);
+assert.commandWorked(viewsDB.adminCommand({
+ applyOps: [{op: "d", ns: viewsDBName + ".system.views", o: {_id: viewsDBName + ".invalidView"}}]
+}));
+}());
diff --git a/jstests/core/views/views_creation.js b/jstests/core/views/views_creation.js
index e7b9baa3484..fa6c8eb7594 100644
--- a/jstests/core/views/views_creation.js
+++ b/jstests/core/views/views_creation.js
@@ -1,18 +1,10 @@
/**
* Test the creation of views with various options.
*
- * The test runs commands that are not allowed with security token: applyOps.
* @tags: [
- * not_allowed_with_security_token,
- * # Commands on views not supported in implicitly sharded suites.
- * assumes_unsharded_collection,
- * # applyOps is not available on mongos.
- * assumes_against_mongod_not_mongos,
* assumes_superuser_permissions,
- * # applyOps is not retryable.
- * requires_non_retryable_commands,
- * # Tenant migrations don't support applyOps.
- * tenant_migration_incompatible,
+ * # TODO SERVER-73967: Remove this tag.
+ * does_not_support_stepdowns,
* ]
*/
(function() {
@@ -119,23 +111,51 @@ assert.commandFailedWithCode(viewsDB.runCommand({
}),
40600);
-// These test that, when an existing view in system.views is invalid because of a $out in the
-// pipeline, the database errors on creation of a new view.
-assert.commandWorked(viewsDB.adminCommand({
- applyOps: [{
- op: "i",
- ns: viewsDBName + ".system.views",
- o: {
- _id: viewsDBName + ".invalidView",
- viewOn: "collection",
- pipeline: [{$project: {_id: false}}, {$out: "notExistingCollection"}]
- }
- }]
-}));
-assert.commandFailedWithCode(
- viewsDB.runCommand({create: "viewWithBadViewCatalog", viewOn: "collection", pipeline: []}),
- ErrorCodes.OptionNotSupportedOnView);
-assert.commandWorked(viewsDB.adminCommand({
- applyOps: [{op: "d", ns: viewsDBName + ".system.views", o: {_id: viewsDBName + ".invalidView"}}]
-}));
+// 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;
+}
+
+// Test that creating a view which already exists with identical options reports success.
+let repeatedCmd = {
+ create: "existingViewTest",
+ viewOn: "collection",
+ pipeline: [{$match: {x: 1}}],
+ collation: {locale: "uk"},
+};
+assert.commandWorked(viewsDB.runCommand(repeatedCmd));
+assert.commandWorked(viewsDB.runCommand(repeatedCmd));
+
+// Test that creating a view with the same name as an existing view but different options fails.
+
+// Different collation.
+assert.commandFailedWithCode(viewsDB.runCommand({
+ create: "existingViewTest",
+ viewOn: "collection",
+ pipeline: [{$match: {x: 1}}],
+ collation: {locale: "fr"},
+}),
+ ErrorCodes.NamespaceExists);
+
+// Different pipeline.
+assert.commandFailedWithCode(viewsDB.runCommand({
+ create: "existingViewTest",
+ viewOn: "collection",
+ pipeline: [{$match: {x: 2}}],
+ collation: {locale: "uk"},
+}),
+ ErrorCodes.NamespaceExists);
+// viewOn collection is different.
+assert.commandFailedWithCode(viewsDB.runCommand({
+ create: "existingViewTest",
+ viewOn: "collection1",
+ pipeline: [{$match: {x: 1}}],
+ collation: {locale: "uk"},
+}),
+ ErrorCodes.NamespaceExists);
+
+// Test that creating a view when there is already a collection with the same name fails.
+assert.commandFailedWithCode(viewsDB.runCommand({create: "collection", viewOn: "collection"}),
+ ErrorCodes.NamespaceExists);
}());
diff --git a/jstests/replsets/noop_writes_wait_for_write_concern.js b/jstests/replsets/noop_writes_wait_for_write_concern.js
index 1fc4bfdcb13..828ace51871 100644
--- a/jstests/replsets/noop_writes_wait_for_write_concern.js
+++ b/jstests/replsets/noop_writes_wait_for_write_concern.js
@@ -233,7 +233,14 @@ commands.push({
assert.commandWorkedIgnoringWriteConcernErrors(db.runCommand({create: collName}));
},
confirmFunc: function(res) {
- assert.commandFailedWithCode(res, ErrorCodes.NamespaceExists);
+ // Branching is needed for multiversion tests as 'create' is only idempotent as of 7.0.
+ // TODO SERVER-74062: update this to stop branching on the server version and always
+ // assert the command worked ignoring write concern errors.
+ if (db.version().split('.')[0] >= 7) {
+ assert.commandWorkedIgnoringWriteConcernErrors(res);
+ } else {
+ assert.commandFailedWithCode(res, ErrorCodes.NamespaceExists);
+ }
}
});