diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2019-04-19 13:52:12 -0400 |
---|---|---|
committer | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2019-04-24 10:47:53 -0400 |
commit | f202c4c1ba24b9f561e8b11dac5b04fa0eeb4919 (patch) | |
tree | ceedc4c78d52590629e81e3aa77bec774dab27a1 /jstests | |
parent | 66fcbb20e58550e652dd95449c696f17ad2f9ce2 (diff) | |
download | mongo-f202c4c1ba24b9f561e8b11dac5b04fa0eeb4919.tar.gz |
SERVER-35638 Short timeout to autocomplete collection names
Also resolves SERVER-40736, test autocompletion of collection names for users
without the listCollections permission.
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/auth/autocomplete_auth.js | 51 | ||||
-rw-r--r-- | jstests/core/txns/listcollections_autocomplete.js | 59 |
2 files changed, 110 insertions, 0 deletions
diff --git a/jstests/auth/autocomplete_auth.js b/jstests/auth/autocomplete_auth.js new file mode 100644 index 00000000000..5e15cae3718 --- /dev/null +++ b/jstests/auth/autocomplete_auth.js @@ -0,0 +1,51 @@ +/** + * Tests that when a user who lacks the listCollections privilege types 'db.<tab>' in the shell, + * autocompletion shows the collections on which she has permissions. + * + * @tags: [ + * assumes_superuser_permissions, + * assumes_write_concern_unchanged, + * creates_and_authenticates_user, + * requires_auth, + * requires_non_retryable_commands, + * ] + */ + +// Get shell's global scope. +const self = this; + +(function() { + 'use strict'; + + const testName = jsTest.name(); + const conn = MongoRunner.runMongod({auth: ''}); + const admin = conn.getDB('admin'); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + + admin.getSiblingDB(testName).createRole({ + role: 'coachTicket', + privileges: [{resource: {db: testName, collection: 'coachClass'}, actions: ['find']}], + roles: [] + }); + + admin.getSiblingDB(testName).createUser( + {user: 'coachPassenger', pwd: 'password', roles: ['coachTicket']}); + + const testDB = conn.getDB(testName); + testDB.coachClass.insertOne({}); + testDB.businessClass.insertOne({}); + + // Must use 'db' to test autocompletion. + self.db = new Mongo(conn.host).getDB(testName); + assert(db.auth('coachPassenger', 'password')); + const authzErrorCode = 13; + assert.commandFailedWithCode(db.runCommand({listCollections: 1}), authzErrorCode); + assert.commandWorked(db.runCommand({find: 'coachClass'})); + assert.commandFailedWithCode(db.runCommand({find: 'businessClass'}), authzErrorCode); + shellAutocomplete('db.'); + assert(__autocomplete__.includes('db.coachClass'), + `Completions should include 'coachClass': ${__autocomplete__}`); + assert(!__autocomplete__.includes('db.businessClass'), + `Completions should NOT include 'businessClass': ${__autocomplete__}`); +})(); diff --git a/jstests/core/txns/listcollections_autocomplete.js b/jstests/core/txns/listcollections_autocomplete.js new file mode 100644 index 00000000000..cf9196a4ff1 --- /dev/null +++ b/jstests/core/txns/listcollections_autocomplete.js @@ -0,0 +1,59 @@ +/** + * Auto complete returns quickly if listCollections is blocked by the transaction lock. + * + * @tags: [uses_transactions] + */ +(function() { + 'use strict'; + + function testAutoComplete() { + // This method updates a global object with an array of strings on success. + assert.soon(() => { + shellAutocomplete("db."); + return true; + }, null, 30 * 1000); + return __autocomplete__; + } + + // Create a collection. + const collName = 'listcollections_autocomplete'; + assert.commandWorked(db[collName].insertOne({}, {writeConcern: {w: 'majority'}})); + + jsTestLog("Start transaction"); + + const session = db.getMongo().startSession(); + const sessionDb = session.getDatabase('test'); + const sessionColl = sessionDb[collName]; + session.startTransaction_forTesting(); + assert.commandWorked(sessionColl.insertOne({})); + + jsTestLog("Start dropDatabase in parallel shell"); + + // Wait for global X lock while blocked behind transaction with global IX lock. + var awaitShell = startParallelShell(function() { + db.getSiblingDB("test2").dropDatabase(); + }); + + jsTestLog("Wait for dropDatabase to appear in currentOp"); + + assert.soon(() => { + return db.currentOp({'command.dropDatabase': 1}).inprog; + }); + + jsTestLog("Test that autocompleting collection names fails quickly"); + + let db_stuff = testAutoComplete(); + assert(!db_stuff.includes(collName), + `Completions should not include "${collName}": ${db_stuff}`); + + // Verify we have some results despite the timeout. + assert.contains('db.adminCommand(', db_stuff); + + jsTestLog("Abort transaction autocomplete collection names"); + + assert.commandWorked(session.abortTransaction_forTesting()); + awaitShell(); + db_stuff = testAutoComplete(); + assert.contains('db.adminCommand(', db_stuff); + assert.contains(`db.${collName}`, db_stuff); +})(); |