diff options
author | Haley Connelly <haley.connelly@mongodb.com> | 2021-10-27 21:09:21 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-10-27 21:49:01 +0000 |
commit | 14c24398c1ed8e2c680ed133c48c976d205868f9 (patch) | |
tree | f2dec6a98c948e1b41803f6b08520dd6a6e754d9 /jstests | |
parent | dea0353a2927370505ae22307d5d72362af9017b (diff) | |
download | mongo-14c24398c1ed8e2c680ed133c48c976d205868f9.tar.gz |
SERVER-61019 Move clustered_indexes_utils.js content under ClusteredCollectionUtil class
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/core/clustered_collection_basic.js (renamed from jstests/core/clustered_indexes.js) | 6 | ||||
-rw-r--r-- | jstests/core/clustered_collection_creation.js | 74 | ||||
-rw-r--r-- | jstests/core/clustered_collection_nonreplicated_basic.js (renamed from jstests/core/clustered_indexes_nonreplicated.js) | 6 | ||||
-rw-r--r-- | jstests/libs/clustered_collection_util.js | 173 | ||||
-rw-r--r-- | jstests/libs/clustered_indexes_utils.js | 129 | ||||
-rw-r--r-- | jstests/noPassthrough/clustered_collection_ttl.js | 4 |
6 files changed, 201 insertions, 191 deletions
diff --git a/jstests/core/clustered_indexes.js b/jstests/core/clustered_collection_basic.js index 5fa3672fd52..2f56ce4d211 100644 --- a/jstests/core/clustered_indexes.js +++ b/jstests/core/clustered_collection_basic.js @@ -15,9 +15,9 @@ (function() { "use strict"; -load("jstests/libs/clustered_indexes_utils.js"); +load("jstests/libs/clustered_collection_util.js"); -if (areClusteredIndexesEnabled(db.getMongo()) == false) { +if (ClusteredCollectionUtil.areClusteredIndexesEnabled(db.getMongo()) == false) { jsTestLog('Skipping test because the clustered indexes feature flag is disabled'); return; } @@ -28,5 +28,5 @@ const replicatedColl = replicatedDB[collName]; replicatedColl.drop(); -validateClusteredCollection(replicatedDB, collName, '_id'); +ClusteredCollectionUtil.testBasicClusteredCollection(replicatedDB, collName, '_id'); })(); diff --git a/jstests/core/clustered_collection_creation.js b/jstests/core/clustered_collection_creation.js index ac442edc418..e8483ebe700 100644 --- a/jstests/core/clustered_collection_creation.js +++ b/jstests/core/clustered_collection_creation.js @@ -1,7 +1,7 @@ /** * Tests the options used to create a clustered collection. Validates the created collection's * listIndexes and listCollections outputs and ensures the clusteredIndex cannot be dropped - * regardless of the creation options used. + * regardless of the create options used. * Covers clustering on {_id: 1} for replicated collections, and clustering on non-_id fields for * non-replicated collections. * @@ -15,36 +15,16 @@ (function() { "use strict"; -const clusteredIndexesEnabled = assert - .commandWorked(db.getMongo().adminCommand( - {getParameter: 1, featureFlagClusteredIndexes: 1})) - .featureFlagClusteredIndexes.value; +load("jstests/libs/clustered_collection_util.js"); -if (!clusteredIndexesEnabled) { +if (!ClusteredCollectionUtil.areClusteredIndexesEnabled(db.getMongo())) { jsTestLog('Skipping test because the clustered indexes feature flag is disabled'); return; } -// listCollections should include the clusteredIndex. -const validateListCollections = function(db, collName, fullCreationOptions) { - const listColls = - assert.commandWorked(db.runCommand({listCollections: 1, filter: {name: collName}})); - const listCollsOptions = listColls.cursor.firstBatch[0].options; - assert(listCollsOptions.clusteredIndex); - assert.docEq(listCollsOptions.clusteredIndex, fullCreationOptions.clusteredIndex); -}; - -// The clusteredIndex should appear in listIndexes with additional "clustered" field. -const validateListIndexes = function(db, collName, fullCreationOptions) { - const listIndexes = assert.commandWorked(db[collName].runCommand("listIndexes")); - const expectedListIndexesOutput = - Object.extend({clustered: true}, fullCreationOptions.clusteredIndex); - assert.docEq(listIndexes.cursor.firstBatch[0], expectedListIndexesOutput); -}; - // Cannot create an index with the same key as the cluster key -const validateClusteredIndexAlreadyExists = function(db, collName, fullCreationOptions) { - const clusterKey = fullCreationOptions.clusteredIndex.key; +const validateClusteredIndexAlreadyExists = function(db, collName, fullCreateOptions) { + const clusterKey = fullCreateOptions.clusteredIndex.key; const res = db[collName].createIndex(clusterKey); assert.commandFailedWithCode(res, ErrorCodes.CannotCreateIndex); const clusterKeyField = Object.keys(clusterKey)[0]; @@ -57,9 +37,9 @@ const validateClusteredIndexAlreadyExists = function(db, collName, fullCreationO // It is illegal to drop the clusteredIndex. Verify that the various ways of dropping the // clusteredIndex fail accordingly. -const validateClusteredIndexUndroppable = function(db, collName, fullCreationOptions) { - const expectedIndexName = fullCreationOptions.clusteredIndex.name; - const expectedIndexKey = fullCreationOptions.clusteredIndex.key; +const validateClusteredIndexUndroppable = function(db, collName, fullCreateOptions) { + const expectedIndexName = fullCreateOptions.clusteredIndex.name; + const expectedIndexKey = fullCreateOptions.clusteredIndex.key; assert.commandFailedWithCode(db[collName].dropIndex(expectedIndexKey), 5979800); @@ -69,39 +49,25 @@ const validateClusteredIndexUndroppable = function(db, collName, fullCreationOpt 5979800); }; -const validateCreatedCollection = function(db, collName, creationOptions) { - // Upon creating a collection, fields absent in the user provided creation options are filled in - // with default values. The fullCreationOptions should contain default values for the fields not +const validateCreatedCollection = function(db, collName, createOptions) { + // Upon creating a collection, fields absent in the user provided create options are filled in + // with default values. The fullCreateOptions should contain default values for the fields not // specified by the user. - let fullCreationOptions = creationOptions; + const fullCreateOptions = ClusteredCollectionUtil.constructFullCreateOptions(createOptions); - // If the creationOptions don't specify the name, expect the default. - if (!creationOptions.clusteredIndex.name) { - const clusterKey = Object.keys(creationOptions.clusteredIndex.key)[0]; - if (clusterKey == "_id") { - fullCreationOptions.clusteredIndex.name = "_id_"; - } else { - fullCreationOptions.clusteredIndex.name = clusterKey + "_1"; - } - } - - // If the creationOptions don't specify 'v', expect the default. - if (!creationOptions.clusteredIndex.v) { - fullCreationOptions.clusteredIndex.v = 2; - } + ClusteredCollectionUtil.validateListCollections(db, collName, fullCreateOptions); + ClusteredCollectionUtil.validateListIndexes(db, collName, fullCreateOptions); - validateListCollections(db, collName, fullCreationOptions); - validateListIndexes(db, collName, fullCreationOptions); - validateClusteredIndexAlreadyExists(db, collName, fullCreationOptions); - validateClusteredIndexUndroppable(db, collName, fullCreationOptions); + validateClusteredIndexAlreadyExists(db, collName, fullCreateOptions); + validateClusteredIndexUndroppable(db, collName, fullCreateOptions); }; /** - * Creates, validates, and drops a clustered collection with the provided creationOptions. + * Creates, validates, and drops a clustered collection with the provided createOptions. */ -const runSuccessfulCreate = function(db, coll, creationOptions) { - assert.commandWorked(db.createCollection(coll.getName(), creationOptions)); - validateCreatedCollection(db, coll.getName(), creationOptions); +const runSuccessfulCreate = function(db, coll, createOptions) { + assert.commandWorked(db.createCollection(coll.getName(), createOptions)); + validateCreatedCollection(db, coll.getName(), createOptions); coll.drop(); }; diff --git a/jstests/core/clustered_indexes_nonreplicated.js b/jstests/core/clustered_collection_nonreplicated_basic.js index f9117814650..47e14c04a89 100644 --- a/jstests/core/clustered_indexes_nonreplicated.js +++ b/jstests/core/clustered_collection_nonreplicated_basic.js @@ -21,9 +21,9 @@ (function() { "use strict"; -load("jstests/libs/clustered_indexes_utils.js"); +load("jstests/libs/clustered_collection_util.js"); -if (areClusteredIndexesEnabled(db.getMongo()) == false) { +if (ClusteredCollectionUtil.areClusteredIndexesEnabled(db.getMongo()) == false) { jsTestLog('Skipping test because the clustered indexes feature flag is disabled'); return; } @@ -34,5 +34,5 @@ const nonReplicatedColl = nonReplicatedDB[collName]; nonReplicatedColl.drop(); -validateClusteredCollection(nonReplicatedDB, collName, 'ts'); +ClusteredCollectionUtil.testBasicClusteredCollection(nonReplicatedDB, collName, 'ts'); })(); diff --git a/jstests/libs/clustered_collection_util.js b/jstests/libs/clustered_collection_util.js new file mode 100644 index 00000000000..1e6d9f18bcd --- /dev/null +++ b/jstests/libs/clustered_collection_util.js @@ -0,0 +1,173 @@ +/** + * Utilities for testing clustered collections. + */ +var ClusteredCollectionUtil = class { + static areClusteredIndexesEnabled(conn) { + const clusteredIndexesEnabled = + assert + .commandWorked(conn.adminCommand({getParameter: 1, featureFlagClusteredIndexes: 1})) + .featureFlagClusteredIndexes.value; + + if (!clusteredIndexesEnabled) { + return false; + } + return true; + } + + // Returns a copy of the 'createOptions' used to create the clustered collection with default + // values for fields absent in the user provided 'createOptions'. + static constructFullCreateOptions(createOptions) { + const fullCreateOptions = createOptions; + + // If the createOptions don't specify the name, expect the default. + if (!createOptions.clusteredIndex.name) { + const clusterKey = Object.keys(createOptions.clusteredIndex.key)[0]; + if (clusterKey == "_id") { + fullCreateOptions.clusteredIndex.name = "_id_"; + } else { + fullCreateOptions.clusteredIndex.name = clusterKey + "_1"; + } + } + + // If the createOptions don't specify 'v', expect the default. + if (!createOptions.clusteredIndex.v) { + fullCreateOptions.clusteredIndex.v = 2; + } + + return fullCreateOptions; + } + + // Provided the createOptions used to create the collection, validates the output from + // listCollections contains the correct information about the clusteredIndex. + static validateListCollections(db, collName, createOptions) { + const fullCreateOptions = ClusteredCollectionUtil.constructFullCreateOptions(createOptions); + const listColls = + assert.commandWorked(db.runCommand({listCollections: 1, filter: {name: collName}})); + const listCollsOptions = listColls.cursor.firstBatch[0].options; + assert(listCollsOptions.clusteredIndex); + assert.docEq(listCollsOptions.clusteredIndex, fullCreateOptions.clusteredIndex); + } + + // The clusteredIndex should appear in listIndexes with additional "clustered" field. + static validateListIndexes(db, collName, fullCreationOptions) { + const listIndexes = assert.commandWorked(db[collName].runCommand("listIndexes")); + const expectedListIndexesOutput = + Object.extend({clustered: true}, fullCreationOptions.clusteredIndex); + assert.docEq(listIndexes.cursor.firstBatch[0], expectedListIndexesOutput); + } + + static testBasicClusteredCollection(db, collName, clusterKey) { + const lengths = [100, 1024, 1024 * 1024, 3 * 1024 * 1024]; + const coll = db[collName]; + const clusterKeyString = new String(clusterKey); + + assert.commandWorked(db.createCollection( + collName, {clusteredIndex: {key: {[clusterKey]: 1}, unique: true}})); + + // Expect that duplicates are rejected. + for (let len of lengths) { + let id = 'x'.repeat(len); + assert.commandWorked(coll.insert({[clusterKey]: id})); + assert.commandFailedWithCode(coll.insert({[clusterKey]: id}), ErrorCodes.DuplicateKey); + assert.eq(1, coll.find({[clusterKey]: id}).itcount()); + } + + // Updates should work. + for (let len of lengths) { + let id = 'x'.repeat(len); + + // Validate the below for _id-clustered collection only until the following tickets are + // addressed: + // * TODO SERVER-60734 replacement updates should preserve the cluster key + // * TODO SERVER-60702 enable bounded collscans for arbitary cluster keys + if (clusterKey == "_id") { + assert.commandWorked(coll.update({[clusterKey]: id}, {a: len})); + + assert.eq(1, coll.find({[clusterKey]: id}).itcount()); + assert.eq(len, coll.findOne({[clusterKey]: id})['a']); + } + } + + // This section is based on jstests/core/timeseries/clustered_index_crud.js with + // specific additions for general-purpose (non-timeseries) clustered collections + assert.commandWorked(coll.insert({[clusterKey]: 0, a: 1})); + assert.commandWorked(coll.insert({[clusterKey]: 1, a: 1})); + assert.eq(1, coll.find({[clusterKey]: 0}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: "", a: 2})); + assert.eq(1, coll.find({[clusterKey]: ""}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: NumberLong("9223372036854775807"), a: 3})); + assert.eq(1, coll.find({[clusterKey]: NumberLong("9223372036854775807")}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: {a: 1, b: 1}, a: 4})); + assert.eq(1, coll.find({[clusterKey]: {a: 1, b: 1}}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: {a: {b: 1}, c: 1}, a: 5})); + assert.commandWorked(coll.insert({[clusterKey]: -1, a: 6})); + assert.eq(1, coll.find({[clusterKey]: -1}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: "123456789012", a: 7})); + assert.eq(1, coll.find({[clusterKey]: "123456789012"}).itcount()); + if (clusterKey == "_id") { + assert.commandWorked(coll.insert({a: 8})); + } else { + // Missing required cluster key field. + assert.commandFailedWithCode(coll.insert({a: 8}), 2); + assert.commandWorked(coll.insert({[clusterKey]: "withFieldA", a: 8})); + } + assert.eq(1, coll.find({a: 8}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: null, a: 9})); + assert.eq(1, coll.find({[clusterKey]: null}).itcount()); + assert.commandWorked(coll.insert({[clusterKey]: 'x'.repeat(99), a: 10})); + + if (clusterKey == "_id") { + assert.commandWorked(coll.insert({})); + } else { + // Missing required ts field. + assert.commandFailedWithCode(coll.insert({}), 2); + assert.commandWorked(coll.insert({[clusterKey]: 'missingFieldA'})); + } + // Can build a secondary index with a 3MB RecordId doc. + assert.commandWorked(coll.createIndex({a: 1})); + // Can drop the secondary index + assert.commandWorked(coll.dropIndex({a: 1})); + + // This key is too large. + assert.commandFailedWithCode( + coll.insert({[clusterKey]: 'x'.repeat(8 * 1024 * 1024), a: 11}), 5894900); + + // Look up using the secondary index on {a: 1} + assert.commandWorked(coll.createIndex({a: 1})); + + // TODO remove the branch once SERVER-60734 "replacement updates should preserve the cluster + // key" is resolved. + if (clusterKey == "_id") { + assert.eq(1, coll.find({a: null}).itcount()); + } else { + assert.eq(5, coll.find({a: null}).itcount()); + } + assert.eq(0, coll.find({a: 0}).itcount()); + assert.eq(2, coll.find({a: 1}).itcount()); + assert.eq(1, coll.find({a: 2}).itcount()); + assert.eq(1, coll.find({a: 8}).itcount()); + assert.eq(1, coll.find({a: 9}).itcount()); + assert.eq(null, coll.findOne({a: 9})[clusterKeyString]); + assert.eq(1, coll.find({a: 10}).itcount()); + assert.eq(99, coll.findOne({a: 10})[clusterKeyString].length); + + // TODO make it unconditional once SERVER-60734 "replacement updates should preserve the + // cluster key" is resolved. + if (clusterKey == "_id") { + for (let len of lengths) { + // Secondary index lookups for documents with large RecordId's. + assert.eq(1, coll.find({a: len}).itcount()); + assert.eq(len, coll.findOne({a: len})[clusterKeyString].length); + } + } + + // No support for numeric type differentiation. + assert.commandWorked(coll.insert({[clusterKey]: 42.0})); + assert.commandFailedWithCode(coll.insert({[clusterKey]: 42}), ErrorCodes.DuplicateKey); + assert.commandFailedWithCode(coll.insert({[clusterKey]: NumberLong("42")}), + ErrorCodes.DuplicateKey); + assert.eq(1, coll.find({[clusterKey]: 42.0}).itcount()); + assert.eq(1, coll.find({[clusterKey]: 42}).itcount()); + assert.eq(1, coll.find({[clusterKey]: NumberLong("42")}).itcount()); + } +}; diff --git a/jstests/libs/clustered_indexes_utils.js b/jstests/libs/clustered_indexes_utils.js deleted file mode 100644 index d394dcbd488..00000000000 --- a/jstests/libs/clustered_indexes_utils.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Utilies for clustered collections. - */ - -function areClusteredIndexesEnabled(conn) { - const clusteredIndexesEnabled = - assert.commandWorked(conn.adminCommand({getParameter: 1, featureFlagClusteredIndexes: 1})) - .featureFlagClusteredIndexes.value; - - if (!clusteredIndexesEnabled) { - return false; - } - return true; -} - -function validateClusteredCollection(db, collName, clusterKey) { - const lengths = [100, 1024, 1024 * 1024, 3 * 1024 * 1024]; - const coll = db[collName]; - const clusterKeyString = new String(clusterKey); - - assert.commandWorked( - db.createCollection(collName, {clusteredIndex: {key: {[clusterKey]: 1}, unique: true}})); - - // Expect that duplicates are rejected. - for (let len of lengths) { - let id = 'x'.repeat(len); - assert.commandWorked(coll.insert({[clusterKey]: id})); - assert.commandFailedWithCode(coll.insert({[clusterKey]: id}), ErrorCodes.DuplicateKey); - assert.eq(1, coll.find({[clusterKey]: id}).itcount()); - } - - // Updates should work. - for (let len of lengths) { - let id = 'x'.repeat(len); - - // Validate the below for _id-clustered collection only until the following tickets are - // addressed: - // * TODO SERVER-60734 replacement updates should preserve the cluster key - // * TODO SERVER-60702 enable bounded collscans for arbitary cluster keys - if (clusterKey == "_id") { - assert.commandWorked(coll.update({[clusterKey]: id}, {a: len})); - - assert.eq(1, coll.find({[clusterKey]: id}).itcount()); - assert.eq(len, coll.findOne({[clusterKey]: id})['a']); - } - } - - // This section is based on jstests/core/timeseries/clustered_index_crud.js with - // specific additions for general-purpose (non-timeseries) clustered collections - assert.commandWorked(coll.insert({[clusterKey]: 0, a: 1})); - assert.commandWorked(coll.insert({[clusterKey]: 1, a: 1})); - assert.eq(1, coll.find({[clusterKey]: 0}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: "", a: 2})); - assert.eq(1, coll.find({[clusterKey]: ""}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: NumberLong("9223372036854775807"), a: 3})); - assert.eq(1, coll.find({[clusterKey]: NumberLong("9223372036854775807")}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: {a: 1, b: 1}, a: 4})); - assert.eq(1, coll.find({[clusterKey]: {a: 1, b: 1}}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: {a: {b: 1}, c: 1}, a: 5})); - assert.commandWorked(coll.insert({[clusterKey]: -1, a: 6})); - assert.eq(1, coll.find({[clusterKey]: -1}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: "123456789012", a: 7})); - assert.eq(1, coll.find({[clusterKey]: "123456789012"}).itcount()); - if (clusterKey == "_id") { - assert.commandWorked(coll.insert({a: 8})); - } else { - // Missing required cluster key field. - assert.commandFailedWithCode(coll.insert({a: 8}), 2); - assert.commandWorked(coll.insert({[clusterKey]: "withFieldA", a: 8})); - } - assert.eq(1, coll.find({a: 8}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: null, a: 9})); - assert.eq(1, coll.find({[clusterKey]: null}).itcount()); - assert.commandWorked(coll.insert({[clusterKey]: 'x'.repeat(99), a: 10})); - - if (clusterKey == "_id") { - assert.commandWorked(coll.insert({})); - } else { - // Missing required ts field. - assert.commandFailedWithCode(coll.insert({}), 2); - assert.commandWorked(coll.insert({[clusterKey]: 'missingFieldA'})); - } - // Can build a secondary index with a 3MB RecordId doc. - assert.commandWorked(coll.createIndex({a: 1})); - // Can drop the secondary index - assert.commandWorked(coll.dropIndex({a: 1})); - - // This key is too large. - assert.commandFailedWithCode(coll.insert({[clusterKey]: 'x'.repeat(8 * 1024 * 1024), a: 11}), - 5894900); - - // Look up using the secondary index on {a: 1} - assert.commandWorked(coll.createIndex({a: 1})); - - // TODO remove the branch once SERVER-60734 "replacement updates should preserve the cluster - // key" is resolved. - if (clusterKey == "_id") { - assert.eq(1, coll.find({a: null}).itcount()); - } else { - assert.eq(5, coll.find({a: null}).itcount()); - } - assert.eq(0, coll.find({a: 0}).itcount()); - assert.eq(2, coll.find({a: 1}).itcount()); - assert.eq(1, coll.find({a: 2}).itcount()); - assert.eq(1, coll.find({a: 8}).itcount()); - assert.eq(1, coll.find({a: 9}).itcount()); - assert.eq(null, coll.findOne({a: 9})[clusterKeyString]); - assert.eq(1, coll.find({a: 10}).itcount()); - assert.eq(99, coll.findOne({a: 10})[clusterKeyString].length); - - // TODO make it unconditional once SERVER-60734 "replacement updates should preserve the cluster - // key" is resolved. - if (clusterKey == "_id") { - for (let len of lengths) { - // Secondary index lookups for documents with large RecordId's. - assert.eq(1, coll.find({a: len}).itcount()); - assert.eq(len, coll.findOne({a: len})[clusterKeyString].length); - } - } - - // No support for numeric type differentiation. - assert.commandWorked(coll.insert({[clusterKey]: 42.0})); - assert.commandFailedWithCode(coll.insert({[clusterKey]: 42}), ErrorCodes.DuplicateKey); - assert.commandFailedWithCode(coll.insert({[clusterKey]: NumberLong("42")}), - ErrorCodes.DuplicateKey); - assert.eq(1, coll.find({[clusterKey]: 42.0}).itcount()); - assert.eq(1, coll.find({[clusterKey]: 42}).itcount()); - assert.eq(1, coll.find({[clusterKey]: NumberLong("42")}).itcount()); -}
\ No newline at end of file diff --git a/jstests/noPassthrough/clustered_collection_ttl.js b/jstests/noPassthrough/clustered_collection_ttl.js index 64707d948da..377fb7fbe4c 100644 --- a/jstests/noPassthrough/clustered_collection_ttl.js +++ b/jstests/noPassthrough/clustered_collection_ttl.js @@ -8,13 +8,13 @@ */ (function() { "use strict"; -load("jstests/libs/clustered_indexes_utils.js"); +load("jstests/libs/clustered_collection_util.js"); load('jstests/libs/dateutil.js'); // Run TTL monitor constantly to speed up this test. const conn = MongoRunner.runMongod({setParameter: 'ttlMonitorSleepSecs=1'}); -if (areClusteredIndexesEnabled(conn) == false) { +if (ClusteredCollectionUtil.areClusteredIndexesEnabled(conn) == false) { jsTestLog('Skipping test because the clustered indexes feature flag is disabled'); MongoRunner.stopMongod(conn); return; |