diff options
author | Zixuan Zhuang <zixuan.zhuang@mongodb.com> | 2023-03-21 19:40:51 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-03-21 20:24:42 +0000 |
commit | 0f6baedfbb04cd0f1434d091b5ff9e23a6da15c9 (patch) | |
tree | 20a31b9623771a3281c69674fe25277551c9e08c /jstests | |
parent | eb49b1fea5972be2345dddd9b8ab2274da701edf (diff) | |
download | mongo-0f6baedfbb04cd0f1434d091b5ff9e23a6da15c9.tar.gz |
SERVER-74264 Backport to 6.3
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/auth/sbe_plan_cache_user_roles.js | 56 | ||||
-rw-r--r-- | jstests/noPassthroughWithMongod/now_variable.js | 97 |
2 files changed, 141 insertions, 12 deletions
diff --git a/jstests/auth/sbe_plan_cache_user_roles.js b/jstests/auth/sbe_plan_cache_user_roles.js new file mode 100644 index 00000000000..a42e36bf372 --- /dev/null +++ b/jstests/auth/sbe_plan_cache_user_roles.js @@ -0,0 +1,56 @@ +/** + * Test $$USER_ROLES works correctly with the SBE plan cache. The same query should return the + * updated user role info when a different user logs in. + * @tags: [ + * featureFlagUserRoles, + * # Multiple servers can mess up the plan cache list. + * assumes_standalone_mongod, + * ] + */ +(function() { +"use strict"; +load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. + +const mongod = MongoRunner.runMongod(); +const dbName = "test"; +const db = mongod.getDB(dbName); + +// Create two users, each with different roles. +assert.commandWorked( + db.runCommand({createUser: "user1", pwd: "pwd", roles: [{role: "read", db: dbName}]})); +assert.commandWorked( + db.runCommand({createUser: "user2", pwd: "pwd", roles: [{role: "readWrite", db: dbName}]})); + +const coll = db.sbe_plan_cache_user_roles; +coll.drop(); + +const verifyPlanCache = function(role) { + if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { + const caches = coll.getPlanCache().list(); + assert.eq(1, caches.length, caches); + assert.eq(caches[0].cachedPlan.stages.includes(role), false, caches); + } +}; + +assert.commandWorked(coll.insert({_id: 1})); + +// While logged in as user1, we should see user1's roles. +db.auth("user1", "pwd"); +let results = coll.find({}, {roles: "$$USER_ROLES"}).toArray(); +assert.eq(results.length, 1); +assert.eq(results[0].roles, [{_id: "test.read", role: "read", db: "test"}]); +// It can take two executions of a query for a plan to get cached. +coll.find({}, {roles: "$$USER_ROLES"}).toArray(); +verifyPlanCache("test.read"); +db.logout(); + +// While logged in as user2, we should see user2's roles. +db.auth("user2", "pwd"); +results = coll.find({}, {roles: "$$USER_ROLES"}).toArray(); +assert.eq(results.length, 1); +assert.eq(results[0].roles, [{_id: "test.readWrite", role: "readWrite", db: "test"}]); +verifyPlanCache("test.readWrite"); +db.logout(); + +MongoRunner.stopMongod(mongod); +})();
\ No newline at end of file diff --git a/jstests/noPassthroughWithMongod/now_variable.js b/jstests/noPassthroughWithMongod/now_variable.js index 8b74602fe9d..341959956cb 100644 --- a/jstests/noPassthroughWithMongod/now_variable.js +++ b/jstests/noPassthroughWithMongod/now_variable.js @@ -4,6 +4,7 @@ (function() { "use strict"; +load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. load("jstests/libs/sbe_assert_error_override.js"); // Override error-code-checking APIs. const coll = db[jsTest.name()]; @@ -39,22 +40,37 @@ assert.commandWorked(db.createView( const viewWithClusterTime = db["viewWithClusterTime"]; function runTests(query) { - const results = query().toArray(); - assert.eq(results.length, numdocs); + const runAndCompare = function() { + const results = query().toArray(); + assert.eq(results.length, numdocs); - // Make sure the values are the same for all documents - for (let i = 0; i < numdocs; ++i) { - assert.eq(results[0].timeField, results[i].timeField); - } + // Make sure the values are the same for all documents + for (let i = 0; i < numdocs; ++i) { + assert.eq(results[0].timeField, results[i].timeField); + } + return results; + }; + + const results = runAndCompare(); // Sleep for a while and then rerun. sleep(3000); - const resultsLater = query().toArray(); - assert.eq(resultsLater.length, numdocs); + const resultsLater = runAndCompare(); // Later results should be later in time. - assert.lte(results[0].timeField, resultsLater[0].timeField); + assert.lt(results[0].timeField, resultsLater[0].timeField); + + // Sleep for a while and then run for the third time. + // + // Test when the query is cached (it can take two executions of a query for a plan to get + // cached). + sleep(3000); + + const resultsLast = runAndCompare(); + + // 'resultsLast' should be later in time than 'resultsLater'. + assert.lt(resultsLater[0].timeField, resultsLast[0].timeField); } function runTestsExpectFailure(query) { @@ -64,7 +80,7 @@ function runTestsExpectFailure(query) { } function baseCollectionNowFind() { - return otherColl.find({$expr: {$lte: ["$timeField", "$$NOW"]}}); + return otherColl.find({$expr: {$lt: ["$timeField", "$$NOW"]}}); } function baseCollectionClusterTimeFind() { @@ -98,6 +114,18 @@ function withExprNow() { return viewWithNow.find({$expr: {$eq: ["$timeField", "$$NOW"]}}); } +function projWithNow() { + return coll.find({}, {timeField: "$$NOW"}); +} + +function aggWithNow() { + return coll.aggregate([{$project: {timeField: "$$NOW"}}]); +} + +function aggWithNowNotPushedDown() { + return coll.aggregate([{$_internalInhibitOptimization: {}}, {$project: {timeField: "$$NOW"}}]); +} + function withExprClusterTime() { return db.runCommand({ find: viewWithClusterTime.getName(), @@ -106,10 +134,16 @@ function withExprClusterTime() { } // Test that $$NOW is usable in all contexts. -runTests(baseCollectionNowFind); -runTests(baseCollectionNowAgg); +// +// $$NOW used at insertion time, it is expected values are not changed. +assert.eq(baseCollectionNowFind().toArray().length, numdocs); +// $$NOW used in the query, it is expected to update its time value for different runs. runTests(fromViewWithNow); runTests(withExprNow); +runTests(baseCollectionNowAgg); +runTests(projWithNow); +runTests(aggWithNow); +runTests(aggWithNowNotPushedDown); // Test that $$NOW can be used in explain for both find and aggregate. assert.commandWorked(coll.explain().find({$expr: {$lte: ["$timeField", "$$NOW"]}}).finish()); @@ -121,4 +155,43 @@ runTestsExpectFailure(baseCollectionClusterTimeFind); runTestsExpectFailure(baseCollectionClusterTimeAgg); runTestsExpectFailure(fromViewWithClusterTime); runTestsExpectFailure(withExprClusterTime); + +if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { + function verifyPlanCacheSize(query) { + coll.getPlanCache().clear(); + + query().toArray(); + // It can take two executions of a query for a plan to get cached. + query().toArray(); + + const caches = coll.getPlanCache().list(); + assert.eq(caches.length, 1, caches); + assert.eq(caches[0].cachedPlan.stages.includes("Date"), false, caches); + } + + // Query with $$NOW will be cached. + verifyPlanCacheSize(projWithNow); + verifyPlanCacheSize(aggWithNow); + // $$NOW is not in SBE query. + verifyPlanCacheSize(fromViewWithNow); + verifyPlanCacheSize(withExprNow); + // $$NOW could not be pushed down into SBE. + verifyPlanCacheSize(baseCollectionNowAgg); + verifyPlanCacheSize(aggWithNowNotPushedDown); +} + +// Insert an doc with a future time. +const futureColl = db[coll.getName() + "_future"]; +futureColl.drop(); +const time = new Date(); +time.setSeconds(time.getSeconds() + 3); +assert.commandWorked(futureColl.insert({timeField: time})); + +// The 'timeField' value is later than '$$NOW' in '$expr'. +assert.eq(0, futureColl.find({$expr: {$lt: ["$timeField", "$$NOW"]}}).itcount()); +// The '$$NOW' in '$expr' should advance its value after sleeping for 3 second, the 'timeField' +// value should be earlier than it now. +assert.soon(() => { + return futureColl.find({$expr: {$lt: ["$timeField", "$$NOW"]}}).itcount() == 1; +}, "$$NOW should catch up after 3 seconds"); }()); |