summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2019-04-19 13:52:12 -0400
committerA. Jesse Jiryu Davis <jesse@mongodb.com>2019-04-24 10:47:53 -0400
commitf202c4c1ba24b9f561e8b11dac5b04fa0eeb4919 (patch)
treeceedc4c78d52590629e81e3aa77bec774dab27a1 /jstests
parent66fcbb20e58550e652dd95449c696f17ad2f9ce2 (diff)
downloadmongo-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.js51
-rw-r--r--jstests/core/txns/listcollections_autocomplete.js59
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);
+})();