diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-06-11 15:28:37 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-06-11 15:28:37 -0400 |
commit | 951f7a2c184af7c5d46945b56dcfbc13fd3c5197 (patch) | |
tree | 484783677e35a44eae5ed6903880f40c7b0fc336 /jstests | |
parent | 01a945fc58986f25ebf51d2436f75e140ca16aa1 (diff) | |
download | mongo-951f7a2c184af7c5d46945b56dcfbc13fd3c5197.tar.gz |
Revert "SERVER-41065 Make evaluate() thread safe by passing 'Variables' as a parameter"
This reverts commit 17cdb38b6db716dc47485a60ddff3c543e713e3d.
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/aggregation/bugs/server9840.js | 99 | ||||
-rw-r--r-- | jstests/aggregation/expressions/let.js | 132 | ||||
-rw-r--r-- | jstests/aggregation/sources/graphLookup/variables.js | 41 | ||||
-rw-r--r-- | jstests/aggregation/sources/lookup/lookup_subpipeline.js | 17 | ||||
-rw-r--r-- | jstests/concurrency/fsm_workloads/schema_validator_with_expr_variables.js | 80 |
5 files changed, 99 insertions, 270 deletions
diff --git a/jstests/aggregation/bugs/server9840.js b/jstests/aggregation/bugs/server9840.js new file mode 100644 index 00000000000..4316730370a --- /dev/null +++ b/jstests/aggregation/bugs/server9840.js @@ -0,0 +1,99 @@ +// SERVER-9840 variables in expressions and $let + +load('jstests/aggregation/extras/utils.js'); +var t = db.server9840; +t.drop(); + +function test(expression, expected) { + t.drop(); + t.insert({zero: 0, one: 1, two: 2, three: 3, nested: {four: 4}}); + + // Test in projection: + var result = t.aggregate({$project: {_id: 0, res: expression}}).toArray(); + assert.eq(result, [{res: expected}]); + + // Test in group: + var result = t.aggregate({$group: {_id: 0, res: {$sum: expression}}}).toArray(); + assert.eq(result, [{_id: 0, res: expected}]); +} + +// basics +test('$two', 2); +test('$$CURRENT.two', 2); +test('$$ROOT.two', 2); + +// using sub expressions +test({$add: ['$two', '$$CURRENT.three']}, 5); +test({$add: ['$$CURRENT.two', '$$ROOT.nested.four']}, 6); + +// $let simple +test({$let: {vars: {a: 10}, in : '$$a'}}, 10); +test({$let: {vars: {a: '$zero'}, in : '$$a'}}, 0); +test({$let: {vars: {a: {$add: ['$one', '$two']}, b: 10}, in : {$multiply: ['$$a', '$$b']}}}, 30); + +// $let changing CURRENT +test({$let: {vars: {CURRENT: '$$ROOT.nested'}, in : {$multiply: ['$four', '$$ROOT.two']}}}, 8); +test({ + $let: { + vars: {CURRENT: '$$CURRENT.nested'}, // using original value of CURRENT + in : {$multiply: ['$four', '$$ROOT.two']} + } +}, + 8); +test({ + $let: { + vars: {CURRENT: '$nested'}, // same as last + in : {$multiply: ['$four', '$$ROOT.two']} + } +}, + 8); +test({ + $let: { + vars: {CURRENT: {$const: {ten: 10}}}, // "artificial" object + in : {$multiply: ['$ten', '$$ROOT.two']} + } +}, + 20); +test({ + $let: { + vars: {CURRENT: '$three'}, // sets current to the number 3 (not an object) + in : {$multiply: ['$$CURRENT', '$$ROOT.two']} + } +}, + 6); + +// swapping with $let (ensures there is no ordering dependency in vars) +test({ + $let: { + vars: {x: 6, y: 10}, + in : { + $let: { + vars: {x: '$$y', y: '$$x'}, // now {x:10, y:6} + in : {$subtract: ['$$x', '$$y']} + } + } + } +}, // not commutative! + 4); // 10-6 not 6-10 or 6-6 + +// unicode is allowed +test({$let: {vars: {'日本語': 10}, in : '$$日本語'}}, 10); // Japanese for "Japanese language" + +// Can use ROOT and CURRENT directly with no subfield (SERVER-5916) +t.drop(); +t.insert({_id: 'obj'}); +assert.eq(t.aggregate({$project: {_id: 0, obj: '$$ROOT'}}).toArray(), [{obj: {_id: 'obj'}}]); +assert.eq(t.aggregate({$project: {_id: 0, obj: '$$CURRENT'}}).toArray(), [{obj: {_id: 'obj'}}]); +assert.eq(t.aggregate({$group: {_id: 0, objs: {$push: '$$ROOT'}}}).toArray(), + [{_id: 0, objs: [{_id: 'obj'}]}]); +assert.eq(t.aggregate({$group: {_id: 0, objs: {$push: '$$CURRENT'}}}).toArray(), + [{_id: 0, objs: [{_id: 'obj'}]}]); + +// check name validity checks +assertErrorCode(t, {$project: {a: {$let: {vars: {ROOT: 1}, in : '$$ROOT'}}}}, 16867); +assertErrorCode(t, {$project: {a: {$let: {vars: {FOO: 1}, in : '$$FOO'}}}}, 16867); +assertErrorCode(t, {$project: {a: {$let: {vars: {_underbar: 1}, in : '$$FOO'}}}}, 16867); +assertErrorCode(t, {$project: {a: {$let: {vars: {'a.b': 1}, in : '$$FOO'}}}}, 16868); +assertErrorCode(t, {$project: {a: {$let: {vars: {'a b': 1}, in : '$$FOO'}}}}, 16868); +assertErrorCode(t, {$project: {a: '$$_underbar'}}, 16870); +assertErrorCode(t, {$project: {a: '$$with spaces'}}, 16871); diff --git a/jstests/aggregation/expressions/let.js b/jstests/aggregation/expressions/let.js deleted file mode 100644 index 5de6db8eebf..00000000000 --- a/jstests/aggregation/expressions/let.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Basic integration tests for the $let expression. - */ -(function() { - "use strict"; - - load("jstests/aggregation/extras/utils.js"); // For assertErrorCode. - - let coll = db.agg_expr_let; - coll.drop(); - assert.commandWorked(coll.insert({zero: 0, one: 1, two: 2, three: 3, nested: {four: 4}})); - - function testExpr(expression, output) { - const res = coll.aggregate([{$project: {output: expression}}]).toArray(); - assert.eq(res.length, 1, tojson(res)); - assert.eq(res[0].output, output, tojson(res)); - - // Test in group: - const result = coll.aggregate({$group: {_id: 0, res: {$sum: expression}}}).toArray(); - assert.eq(result, [{_id: 0, res: output}]); - } - - // Basic tests. - testExpr('$two', 2); - testExpr('$$CURRENT.two', 2); - testExpr('$$ROOT.two', 2); - - // Using sub expressions. - testExpr({$add: ['$two', '$$CURRENT.three']}, 5); - testExpr({$add: ['$$CURRENT.two', '$$ROOT.nested.four']}, 6); - - // Verify that the variables defined in $let work. - testExpr({$let: {vars: {a: 10}, in : '$$a'}}, 10); - testExpr({$let: {vars: {a: '$zero'}, in : '$$a'}}, 0); - testExpr({$let: {vars: {a: {$add: ['$one', '$two']}, b: 10}, in : {$multiply: ['$$a', '$$b']}}}, - 30); - - // Verify that the outer level variable works in inner level $let. - testExpr({ - $let: { - vars: {var1: 1}, - in : {$let: {vars: {var2: "$$var1"}, in : {$sum: ["$$var1", "$$var2"]}}} - } - }, - 2); - - // Verify that the outer level variables get overwritten by inner level variables. - testExpr({ - $let: { - vars: {var1: "$one"}, - in : {$let: {vars: {var2: "$$var1", var1: 3}, in : {$sum: ["$$var2", "$$var1"]}}} - } - }, - 4); - - // $let changing CURRENT - testExpr({$let: {vars: {CURRENT: '$$ROOT.nested'}, in : {$multiply: ['$four', '$$ROOT.two']}}}, - 8); - testExpr({ - $let: { - vars: {CURRENT: '$$CURRENT.nested'}, // using original value of CURRENT - in : {$multiply: ['$four', '$$ROOT.two']} - } - }, - 8); - testExpr({ - $let: { - vars: {CURRENT: '$nested'}, // same as last - in : {$multiply: ['$four', '$$ROOT.two']} - } - }, - 8); - testExpr({ - $let: { - vars: {CURRENT: {$const: {ten: 10}}}, // "artificial" object - in : {$multiply: ['$ten', '$$ROOT.two']} - } - }, - 20); - testExpr({ - $let: { - vars: {CURRENT: '$three'}, // sets current to the number 3 (not an object) - in : {$multiply: ['$$CURRENT', '$$ROOT.two']} - } - }, - 6); - - // Swapping with $let (ensures there is no ordering dependency in vars). - testExpr({ - $let: { - vars: {x: 6, y: 10}, - in : { - $let: { - vars: {x: '$$y', y: '$$x'}, // now {x:10, y:6} - in : {$subtract: ['$$x', '$$y']} - } - } - } - }, // Not commutative! - 4); // 10-6 not 6-10 or 6-6 - - // Unicode is allowed. - testExpr({$let: {vars: {'日本語': 10}, in : '$$日本語'}}, - 10); // Japanese for "Japanese language". - - // Can use ROOT and CURRENT directly with no subfield (SERVER-5916). - coll.drop(); - coll.insert({_id: 'obj'}); - assert.eq(coll.aggregate({$project: {_id: 0, obj: '$$ROOT'}}).toArray(), [{obj: {_id: 'obj'}}]); - assert.eq(coll.aggregate({$project: {_id: 0, obj: '$$CURRENT'}}).toArray(), - [{obj: {_id: 'obj'}}]); - assert.eq(coll.aggregate({$group: {_id: 0, objs: {$push: '$$ROOT'}}}).toArray(), - [{_id: 0, objs: [{_id: 'obj'}]}]); - assert.eq(coll.aggregate({$group: {_id: 0, objs: {$push: '$$CURRENT'}}}).toArray(), - [{_id: 0, objs: [{_id: 'obj'}]}]); - - // Check name validity checks. - assertErrorCode(coll, {$project: {a: {$let: {vars: {ROOT: 1}, in : '$$ROOT'}}}}, 16867); - assertErrorCode(coll, {$project: {a: {$let: {vars: {FOO: 1}, in : '$$FOO'}}}}, 16867); - assertErrorCode(coll, {$project: {a: {$let: {vars: {_underbar: 1}, in : '$$FOO'}}}}, 16867); - assertErrorCode(coll, {$project: {a: {$let: {vars: {'a.b': 1}, in : '$$FOO'}}}}, 16868); - assertErrorCode(coll, {$project: {a: {$let: {vars: {'a b': 1}, in : '$$FOO'}}}}, 16868); - assertErrorCode(coll, {$project: {a: '$$_underbar'}}, 16870); - assertErrorCode(coll, {$project: {a: '$$with spaces'}}, 16871); - - // Verify that variables defined in '$let' cannot be used to initialize other variables. - assertErrorCode( - coll, - [{$project: {output: {$let: {vars: {var1: "$one", var2: "$$var1"}, in : "$$var1"}}}}], - 17276); - -}()); diff --git a/jstests/aggregation/sources/graphLookup/variables.js b/jstests/aggregation/sources/graphLookup/variables.js deleted file mode 100644 index 87e2c8b3975..00000000000 --- a/jstests/aggregation/sources/graphLookup/variables.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Tests to verify that $graphLookup can use the variables defined in an outer scope. - */ -(function() { - "use strict"; - - let local = db.graph_lookup_var_local; - let foreign = db.graph_lookup_var_foreign; - local.drop(); - foreign.drop(); - - foreign.insert({from: "b", to: "a", _id: 0}); - local.insert({}); - - const basicGraphLookup = { - $graphLookup: { - from: "graph_lookup_var_foreign", - startWith: "$$var1", - connectFromField: "from", - connectToField: "to", - as: "resultsFromGraphLookup" - } - }; - - const lookup = { - $lookup: { - from: "graph_lookup_var_local", - let : {var1: "a"}, - pipeline: [basicGraphLookup], - as: "resultsFromLookup" - } - }; - - // Verify that $graphLookup can use the variable 'var1' which is defined in parent $lookup. - let res = local.aggregate([lookup]).toArray(); - assert.eq(res.length, 1); - assert.eq(res[0].resultsFromLookup.length, 1); - assert.eq(res[0].resultsFromLookup[0].resultsFromGraphLookup.length, 1); - assert.eq(res[0].resultsFromLookup[0].resultsFromGraphLookup[0], {_id: 0, from: "b", to: "a"}); - -})(); diff --git a/jstests/aggregation/sources/lookup/lookup_subpipeline.js b/jstests/aggregation/sources/lookup/lookup_subpipeline.js index 39d2ff0d850..bb7bddc3eca 100644 --- a/jstests/aggregation/sources/lookup/lookup_subpipeline.js +++ b/jstests/aggregation/sources/lookup/lookup_subpipeline.js @@ -376,23 +376,6 @@ } }], 17276); - assertErrorCode( - coll, - [{$lookup: {let : {var1: 1, var2: "$$var1"}, pipeline: [], from: "from", as: "as"}}], - 17276); - assertErrorCode(coll, - [{ - $lookup: { - let : { - var1: {$let: {vars: {var1: 2}, in : "$$var1"}}, - var2: {$let: {vars: {var1: 4}, in : "$$var2"}}, - }, - pipeline: [], - from: "from", - as: "as" - } - }], - 17276); // The dotted path offset of a non-object variable is equivalent referencing an undefined // field. diff --git a/jstests/concurrency/fsm_workloads/schema_validator_with_expr_variables.js b/jstests/concurrency/fsm_workloads/schema_validator_with_expr_variables.js deleted file mode 100644 index ea847215a29..00000000000 --- a/jstests/concurrency/fsm_workloads/schema_validator_with_expr_variables.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Test to verify that the schema validator works correctly in a multi-threaded environment, when - * $expr uses expressions which mutate variable values while executing ($let, $map etc). - * @tags: [requires_non_retryable_writes] - */ - -"use strict"; - -var $config = (function() { - function setup(db, collName) { - for (let i = 0; i < 200; ++i) { - assertAlways.commandWorked( - db[collName].insert({_id: i, a: i, one: 1, counter: 0, array: [0, i]})); - } - - // Add a validator which checks that field 'a' has value 5 and sum of the elements in field - // 'array' is 5. The expression is purposefully complex so that it can create a stress on - // expressions with variables. - assertAlways.commandWorked(db.runCommand({ - collMod: collName, - validator: { - $expr: { - $and: [ - { - $eq: [ - 5, - { - $let: { - vars: {item: {$multiply: ["$a", "$one"]}}, - in : {$multiply: ["$$item", "$one"]} - } - } - ] - }, - { - $eq: [ - 5, - { - $sum: { - $map: - {"input": "$array", "as": "item", "in": "$$item"} - } - } - ] - } - ] - } - } - })); - } - - const states = { - applyValidator: function(db, collName) { - assertAlways.commandWorked(db[collName].update({_id: 5}, {$inc: {counter: 1}})); - assertAlways.commandFailedWithCode( - db[collName].update({_id: 4}, {$set: {a: 4}, $inc: {counter: 1}}), - ErrorCodes.DocumentValidationFailure); - - // Update all the documents in the collection. - assertAlways.commandWorked(db[collName].update( - {}, {$set: {a: 5, array: [2, 3]}, $inc: {counter: 1}}, {multi: true})); - - // Validation fails when elements of 'array' doesn't add up to 5. - assertAlways.commandFailedWithCode( - db[collName].update({_id: 4}, {$set: {a: 5, array: [2, 2]}}), - ErrorCodes.DocumentValidationFailure); - } - }; - - let transitions = {applyValidator: {applyValidator: 1}}; - - return { - threadCount: 50, - iterations: 100, - states: states, - startState: "applyValidator", - transitions: transitions, - setup: setup - }; -})(); |