The shell should attach the logical session used to initiate cursors (via find or aggregate) and use it for successive getMores.
413 lines
14 KiB
JavaScript
413 lines
14 KiB
JavaScript
// Tests query/command option $maxTimeMS.
|
|
|
|
var t = db.max_time_ms;
|
|
var exceededTimeLimit = 50; // ErrorCodes::ExceededTimeLimit
|
|
var cursor;
|
|
var res;
|
|
|
|
//
|
|
// Simple positive test for query: a ~300ms query with a 100ms time limit should be aborted.
|
|
//
|
|
|
|
t.drop();
|
|
t.insert([{}, {}, {}]);
|
|
cursor = t.find({
|
|
$where: function() {
|
|
sleep(100);
|
|
return true;
|
|
}
|
|
});
|
|
cursor.maxTimeMS(100);
|
|
assert.throws(function() {
|
|
cursor.itcount();
|
|
}, [], "expected query to abort due to time limit");
|
|
|
|
//
|
|
// Simple negative test for query: a ~300ms query with a 10s time limit should not hit the time
|
|
// limit.
|
|
//
|
|
|
|
t.drop();
|
|
t.insert([{}, {}, {}]);
|
|
cursor = t.find({
|
|
$where: function() {
|
|
sleep(100);
|
|
return true;
|
|
}
|
|
});
|
|
cursor.maxTimeMS(10 * 1000);
|
|
assert.doesNotThrow(function() {
|
|
cursor.itcount();
|
|
}, [], "expected query to not hit the time limit");
|
|
|
|
//
|
|
// Simple positive test for getmore:
|
|
// - Issue a find() that returns 2 batches: a fast batch, then a slow batch.
|
|
// - The find() has a 4-second time limit; the first batch should run "instantly", but the second
|
|
// batch takes ~15 seconds, so the getmore should be aborted.
|
|
//
|
|
|
|
t.drop();
|
|
t.insert([{_id: 0}, {_id: 1}, {_id: 2}]); // fast batch
|
|
t.insert([{_id: 3, slow: true}, {_id: 4, slow: true}, {_id: 5, slow: true}]); // slow batch
|
|
cursor = t.find({
|
|
$where: function() {
|
|
if (this.slow) {
|
|
sleep(5 * 1000);
|
|
}
|
|
return true;
|
|
}
|
|
}).sort({_id: 1});
|
|
cursor.batchSize(3);
|
|
cursor.maxTimeMS(4 * 1000);
|
|
assert.doesNotThrow(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 1 (query) to not hit the time limit");
|
|
assert.throws(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 2 (getmore) to abort due to time limit");
|
|
|
|
//
|
|
// Simple negative test for getmore:
|
|
// - Issue a find() that returns 2 batches: a fast batch, then a slow batch.
|
|
// - The find() has a 10-second time limit; the first batch should run "instantly", and the second
|
|
// batch takes only ~2 seconds, so both the query and getmore should not hit the time limit.
|
|
//
|
|
|
|
t.drop();
|
|
t.insert([{_id: 0}, {_id: 1}, {_id: 2}]); // fast batch
|
|
t.insert([{_id: 3}, {_id: 4}, {_id: 5, slow: true}]); // slow batch
|
|
cursor = t.find({
|
|
$where: function() {
|
|
if (this.slow) {
|
|
sleep(2 * 1000);
|
|
}
|
|
return true;
|
|
}
|
|
}).sort({_id: 1});
|
|
cursor.batchSize(3);
|
|
cursor.maxTimeMS(10 * 1000);
|
|
assert.doesNotThrow(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 1 (query) to not hit the time limit");
|
|
assert.doesNotThrow(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 2 (getmore) to not hit the time limit");
|
|
|
|
//
|
|
// Many-batch positive test for getmore:
|
|
// - Issue a many-batch find() with a 6-second time limit where the results take 10 seconds to
|
|
// generate; one of the later getmore ops should be aborted.
|
|
//
|
|
|
|
t.drop();
|
|
for (var i = 0; i < 5; i++) {
|
|
t.insert([{_id: 3 * i}, {_id: (3 * i) + 1}, {_id: (3 * i) + 2, slow: true}]);
|
|
}
|
|
cursor = t.find({
|
|
$where: function() {
|
|
if (this.slow) {
|
|
sleep(2 * 1000);
|
|
}
|
|
return true;
|
|
}
|
|
}).sort({_id: 1});
|
|
cursor.batchSize(3);
|
|
cursor.maxTimeMS(6 * 1000);
|
|
assert.throws(function() {
|
|
cursor.itcount();
|
|
}, [], "expected find() to abort due to time limit");
|
|
|
|
//
|
|
// Many-batch negative test for getmore:
|
|
// - Issue a many-batch find() with a 20-second time limit where the results take 10 seconds to
|
|
// generate; the find() should not hit the time limit.
|
|
//
|
|
|
|
t.drop();
|
|
for (var i = 0; i < 5; i++) {
|
|
t.insert([{_id: 3 * i}, {_id: (3 * i) + 1}, {_id: (3 * i) + 2, slow: true}]);
|
|
}
|
|
cursor = t.find({
|
|
$where: function() {
|
|
if (this.slow) {
|
|
sleep(2 * 1000);
|
|
}
|
|
return true;
|
|
}
|
|
}).sort({_id: 1});
|
|
cursor.batchSize(3);
|
|
cursor.maxTimeMS(20 * 1000);
|
|
assert.doesNotThrow(function() {
|
|
cursor.itcount();
|
|
}, [], "expected find() to not hit the time limit");
|
|
|
|
//
|
|
// Simple positive test for commands: a ~300ms command with a 100ms time limit should be aborted.
|
|
//
|
|
|
|
t.drop();
|
|
res = t.getDB().adminCommand({sleep: 1, millis: 300, maxTimeMS: 100});
|
|
assert(res.ok == 0 && res.code == exceededTimeLimit,
|
|
"expected sleep command to abort due to time limit, ok=" + res.ok + ", code=" + res.code);
|
|
|
|
//
|
|
// Simple negative test for commands: a ~300ms command with a 10s time limit should not hit the
|
|
// time limit.
|
|
//
|
|
|
|
t.drop();
|
|
res = t.getDB().adminCommand({sleep: 1, millis: 300, maxTimeMS: 10 * 1000});
|
|
assert(res.ok == 1,
|
|
"expected sleep command to not hit the time limit, ok=" + res.ok + ", code=" + res.code);
|
|
|
|
//
|
|
// Tests for input validation.
|
|
//
|
|
|
|
t.drop();
|
|
t.insert({});
|
|
|
|
// Verify lower boundary for acceptable input (0 is acceptable, 1 isn't).
|
|
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(0).itcount();
|
|
});
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(NumberInt(0)).itcount();
|
|
});
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(NumberLong(0)).itcount();
|
|
});
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: 0}).ok);
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: NumberInt(0)}).ok);
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: NumberLong(0)}).ok);
|
|
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(-1).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(NumberInt(-1)).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(NumberLong(-1)).itcount();
|
|
});
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: -1}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: NumberInt(-1)}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: NumberLong(-1)}).ok);
|
|
|
|
// Verify upper boundary for acceptable input (2^31-1 is acceptable, 2^31 isn't).
|
|
|
|
var maxValue = Math.pow(2, 31) - 1;
|
|
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(maxValue).itcount();
|
|
});
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(NumberInt(maxValue)).itcount();
|
|
});
|
|
assert.doesNotThrow.automsg(function() {
|
|
t.find().maxTimeMS(NumberLong(maxValue)).itcount();
|
|
});
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: maxValue}).ok);
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: NumberInt(maxValue)}).ok);
|
|
assert.eq(1, t.getDB().runCommand({ping: 1, maxTimeMS: NumberLong(maxValue)}).ok);
|
|
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(maxValue + 1).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(NumberInt(maxValue + 1)).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(NumberLong(maxValue + 1)).itcount();
|
|
});
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: maxValue + 1}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: NumberInt(maxValue + 1)}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: NumberLong(maxValue + 1)}).ok);
|
|
|
|
// Verify invalid values are rejected.
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(0.1).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(-0.1).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS().itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS("").itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS(true).itcount();
|
|
});
|
|
assert.throws.automsg(function() {
|
|
t.find().maxTimeMS({}).itcount();
|
|
});
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: 0.1}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: -0.1}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: undefined}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: ""}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: true}).ok);
|
|
assert.eq(0, t.getDB().runCommand({ping: 1, maxTimeMS: {}}).ok);
|
|
|
|
// Verify that the maxTimeMS command argument can be sent with $query-wrapped commands.
|
|
cursor = t.getDB().$cmd.find({ping: 1, maxTimeMS: 0}).limit(-1);
|
|
cursor._ensureSpecial();
|
|
assert.eq(1, cursor.next().ok);
|
|
|
|
// Verify that the server rejects invalid command argument $maxTimeMS.
|
|
cursor = t.getDB().$cmd.find({ping: 1, $maxTimeMS: 0}).limit(-1);
|
|
cursor._ensureSpecial();
|
|
assert.eq(0, cursor.next().ok);
|
|
|
|
// Verify that the $maxTimeMS query option can't be sent with $query-wrapped commands.
|
|
cursor = t.getDB().$cmd.find({ping: 1}).limit(-1).maxTimeMS(0);
|
|
cursor._ensureSpecial();
|
|
assert.commandFailed(cursor.next());
|
|
|
|
//
|
|
// Tests for fail points maxTimeAlwaysTimeOut and maxTimeNeverTimeOut.
|
|
//
|
|
|
|
// maxTimeAlwaysTimeOut positive test for command.
|
|
t.drop();
|
|
assert.eq(
|
|
1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "alwaysOn"}).ok);
|
|
res = t.getDB().runCommand({ping: 1, maxTimeMS: 10 * 1000});
|
|
assert(res.ok == 0 && res.code == exceededTimeLimit,
|
|
"expected command to trigger maxTimeAlwaysTimeOut fail point, ok=" + res.ok + ", code=" +
|
|
res.code);
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "off"}).ok);
|
|
|
|
// maxTimeNeverTimeOut positive test for command.
|
|
t.drop();
|
|
assert.eq(1,
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "alwaysOn"}).ok);
|
|
res = t.getDB().adminCommand({sleep: 1, millis: 300, maxTimeMS: 100});
|
|
assert(res.ok == 1,
|
|
"expected command to trigger maxTimeNeverTimeOut fail point, ok=" + res.ok + ", code=" +
|
|
res.code);
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "off"}).ok);
|
|
|
|
// maxTimeAlwaysTimeOut positive test for query.
|
|
t.drop();
|
|
assert.eq(
|
|
1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "alwaysOn"}).ok);
|
|
assert.throws(function() {
|
|
t.find().maxTimeMS(10 * 1000).itcount();
|
|
}, [], "expected query to trigger maxTimeAlwaysTimeOut fail point");
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "off"}).ok);
|
|
|
|
// maxTimeNeverTimeOut positive test for query.
|
|
assert.eq(1,
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "alwaysOn"}).ok);
|
|
t.drop();
|
|
t.insert([{}, {}, {}]);
|
|
cursor = t.find({
|
|
$where: function() {
|
|
sleep(100);
|
|
return true;
|
|
}
|
|
});
|
|
cursor.maxTimeMS(100);
|
|
assert.doesNotThrow(function() {
|
|
cursor.itcount();
|
|
}, [], "expected query to trigger maxTimeNeverTimeOut fail point");
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "off"}).ok);
|
|
|
|
// maxTimeAlwaysTimeOut positive test for getmore.
|
|
t.drop();
|
|
t.insert([{}, {}, {}]);
|
|
cursor = t.find().maxTimeMS(10 * 1000).batchSize(2);
|
|
assert.doesNotThrow.automsg(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
});
|
|
assert.eq(
|
|
1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "alwaysOn"}).ok);
|
|
assert.throws(function() {
|
|
cursor.next();
|
|
}, [], "expected getmore to trigger maxTimeAlwaysTimeOut fail point");
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "off"}).ok);
|
|
|
|
// maxTimeNeverTimeOut positive test for getmore.
|
|
t.drop();
|
|
t.insert([{_id: 0}, {_id: 1}, {_id: 2}]); // fast batch
|
|
t.insert([{_id: 3, slow: true}, {_id: 4, slow: true}, {_id: 5, slow: true}]); // slow batch
|
|
cursor = t.find({
|
|
$where: function() {
|
|
if (this.slow) {
|
|
sleep(2 * 1000);
|
|
}
|
|
return true;
|
|
}
|
|
}).sort({_id: 1});
|
|
cursor.batchSize(3);
|
|
cursor.maxTimeMS(2 * 1000);
|
|
assert.doesNotThrow(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 1 (query) to not hit the time limit");
|
|
assert.eq(1,
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "alwaysOn"}).ok);
|
|
assert.doesNotThrow(function() {
|
|
cursor.next();
|
|
cursor.next();
|
|
cursor.next();
|
|
}, [], "expected batch 2 (getmore) to trigger maxTimeNeverTimeOut fail point");
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "off"}).ok);
|
|
|
|
//
|
|
// Test that maxTimeMS is accepted by commands that have an option whitelist.
|
|
//
|
|
|
|
// "aggregate" command.
|
|
res = t.runCommand("aggregate", {pipeline: [], cursor: {}, maxTimeMS: 60 * 1000});
|
|
assert(res.ok == 1,
|
|
"expected aggregate with maxtime to succeed, ok=" + res.ok + ", code=" + res.code);
|
|
|
|
// "collMod" command.
|
|
res = t.runCommand("collMod", {usePowerOf2Sizes: true, maxTimeMS: 60 * 1000});
|
|
assert(res.ok == 1,
|
|
"expected collmod with maxtime to succeed, ok=" + res.ok + ", code=" + res.code);
|
|
|
|
// "createIndexes" command.
|
|
assert.commandWorked(
|
|
t.runCommand("createIndexes", {indexes: [{key: {x: 1}, name: "x_1"}], maxTimeMS: 60 * 1000}));
|
|
|
|
//
|
|
// Test maxTimeMS for parallelCollectionScan
|
|
//
|
|
res = t.runCommand({parallelCollectionScan: t.getName(), numCursors: 1, maxTimeMS: 60 * 1000});
|
|
assert.commandWorked(res);
|
|
var cursor = new DBCommandCursor(t.getDB(), res.cursors[0], 5);
|
|
assert.commandWorked(
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "alwaysOn"}));
|
|
assert.throws(function() {
|
|
cursor.itcount();
|
|
}, [], "expected query to abort due to time limit");
|
|
assert.commandWorked(
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeAlwaysTimeOut", mode: "off"}));
|
|
|
|
//
|
|
// test count shell helper SERVER-13334
|
|
//
|
|
t.drop();
|
|
assert.eq(1,
|
|
t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "alwaysOn"}).ok);
|
|
assert.doesNotThrow(function() {
|
|
t.find({}).maxTimeMS(1).count();
|
|
});
|
|
assert.eq(1, t.getDB().adminCommand({configureFailPoint: "maxTimeNeverTimeOut", mode: "off"}).ok);
|