mirror of https://github.com/mongodb/mongo
SERVER-101755 Add string substitution to assertion messages (#34437)
GitOrigin-RevId: 344c864a3ad16675ce9190e47ebfba143c741660
This commit is contained in:
parent
e3315cf7d7
commit
a918fa85ba
|
|
@ -576,7 +576,7 @@ class TestExceptionExtraction(unittest.TestCase):
|
|||
]
|
||||
output = execute_resmoke(resmoke_args).stdout
|
||||
|
||||
expected = "The following tests failed (with exit code):\n buildscripts/tests/resmoke_end2end/failtestfiles/js_failure.js (253 Failure executing JS file)\n uncaught exception: Error: [true] != [false] are not equal"
|
||||
expected = "The following tests failed (with exit code):\n buildscripts/tests/resmoke_end2end/failtestfiles/js_failure.js (253 Failure executing JS file)\n uncaught exception: Error: [true] and [false] are not equal"
|
||||
assert expected in output
|
||||
|
||||
def test_resmoke_fixture_error(self):
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export default [
|
|||
assert: true,
|
||||
doassert: true,
|
||||
sortDoc: true,
|
||||
formatErrorMsg: true,
|
||||
|
||||
// src/mongo/shell/bridge.d.ts
|
||||
MongoBridge: true,
|
||||
|
|
@ -189,7 +190,6 @@ export default [
|
|||
isString: true,
|
||||
printjson: true,
|
||||
printjsononeline: true,
|
||||
stringifyErrorMessageAndAttributes: true,
|
||||
toJsonForLog: true,
|
||||
tojson: true,
|
||||
tojsonObject: true,
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ export const $config = (function() {
|
|||
// become refined. Retrying swapping the zone range will allow us to target the
|
||||
// shard key in its refined state.
|
||||
const newShardKeyField = this.newShardKeyFields[1];
|
||||
const errorMsg = stringifyErrorMessageAndAttributes(e);
|
||||
const errorMsg = formatErrorMsg(e.message, e.extraAttr);
|
||||
if ((errorMsg.includes(newShardKeyField) && errorMsg.includes('are not equal')) ||
|
||||
(errorMsg.includes(newShardKeyField) &&
|
||||
errorMsg.includes('assert.eq() failed'))) {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export const $config = extendWorkload($baseConfig, function($config, $super) {
|
|||
// migrated back in. The particular error code is replaced with a more generic one, so this is
|
||||
// identified by the failed migration's error message.
|
||||
$config.data.isMoveChunkErrorAcceptable = (err) => {
|
||||
const errorMsg = stringifyErrorMessageAndAttributes(err);
|
||||
const errorMsg = formatErrorMsg(err.message, err.extraAttr);
|
||||
return (errorMsg.includes("CommandFailed") ||
|
||||
errorMsg.includes("Documents in target range may still be in use") ||
|
||||
// This error can occur when the test updates the shard key value of a document
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ const expectedGlobalVars = [
|
|||
"escape",
|
||||
"eval",
|
||||
"eventResumeTokenType",
|
||||
"formatErrorMsg",
|
||||
"gc",
|
||||
"getJSHeapLimitMB",
|
||||
"globalThis",
|
||||
|
|
@ -110,7 +111,6 @@ const expectedGlobalVars = [
|
|||
"isNumber",
|
||||
"isObject",
|
||||
"isString",
|
||||
"stringifyErrorMessageAndAttributes",
|
||||
"parseFloat",
|
||||
"parseInt",
|
||||
"print",
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ ShardingTest.prototype.checkUUIDsConsistentAcrossCluster = function() {
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (stringifyErrorMessageAndAttributes(e).indexOf("Unauthorized") < 0) {
|
||||
if (formatErrorMsg(e.message, e.extraAttr).indexOf("Unauthorized") < 0) {
|
||||
throw e;
|
||||
}
|
||||
jsTest.log.info("ignoring exception while checking UUID consistency across cluster",
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ for (let config of invalidMixedVersionsToCheck) {
|
|||
() => new ShardingTest({shouldFailInit: true, shards: config.shards, other: config.other}));
|
||||
assert.eq(
|
||||
true,
|
||||
err.message.includes(
|
||||
"Can only specify one of 'last-lts' and 'last-continuous' in binVersion, not both."),
|
||||
formatErrorMsg(err.message, err.extraAttr)
|
||||
.includes(
|
||||
"Can only specify one of 'last-lts' and 'last-continuous' in binVersion, not both."),
|
||||
"Unexpected Error");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -793,17 +793,18 @@ tests.push(function assertJsonFormat() {
|
|||
tests.push(function assertEqJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.eq(5, 2 + 2, "lorem ipsum");
|
||||
}, {msg: "assert.eq() failed : lorem ipsum", attr: {a: 5, b: 4}});
|
||||
}, {msg: "[{a}] and [{b}] are not equal : lorem ipsum", attr: {a: 5, b: 4}});
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.eq(5, 2 + 2, "lorem ipsum", kAttr);
|
||||
}, {msg: "assert.eq() failed : lorem ipsum", attr: {a: 5, b: 4, ...kAttr}});
|
||||
}, {msg: "[{a}] and [{b}] are not equal : lorem ipsum", attr: {a: 5, b: 4, ...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertDocEqJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.docEq({msg: "hello"}, {msg: "goodbye"}, "lorem ipsum", kAttr);
|
||||
}, {
|
||||
msg: "assert.docEq() failed : lorem ipsum",
|
||||
msg:
|
||||
"expected document {expectedDoc} and actual document {actualDoc} are not equal : lorem ipsum",
|
||||
attr: {expectedDoc: {msg: "hello"}, actualDoc: {msg: "goodbye"}, ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -812,7 +813,7 @@ tests.push(function assertSetEqJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
assert.setEq(new Set([1, 2, 3]), new Set([4, 5]), "lorem ipsum", kAttr);
|
||||
}, {
|
||||
msg: "assert.setEq() failed : lorem ipsum",
|
||||
msg: "expected set {expectedSet} and actual set {actualSet} are not equal : lorem ipsum",
|
||||
attr: {expectedSet: [1, 2, 3], actualSet: [4, 5], ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -821,7 +822,7 @@ tests.push(function assertSameMembersJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
assert.sameMembers([1, 2], [1], "Oops!", assert._isDocEq, kAttr);
|
||||
}, {
|
||||
msg: "assert.sameMembers() failed : Oops!",
|
||||
msg: "{aArr} != {bArr} : Oops!",
|
||||
attr: {aArr: [1, 2], bArr: [1], compareFn: "_isDocEq", ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -830,7 +831,7 @@ tests.push(function assertFuzzySameMembersJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
assert.fuzzySameMembers([{soccer: 42}], [{score: 42000}], ["score"], "Oops!", 4, kAttr);
|
||||
}, {
|
||||
msg: "assert.sameMembers() failed : Oops!",
|
||||
msg: "{aArr} != {bArr} : Oops!",
|
||||
attr: {aArr: [{soccer: 42}], bArr: [{score: 42000}], compareFn: "fuzzyCompare", ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -838,14 +839,14 @@ tests.push(function assertFuzzySameMembersJsonFormat() {
|
|||
tests.push(function assertNeqJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.neq(42, 42, "Oops!", kAttr);
|
||||
}, {msg: "assert.neq() failed : Oops!", attr: {a: 42, b: 42, ...kAttr}});
|
||||
}, {msg: "[{a}] and [{b}] are equal : Oops!", attr: {a: 42, b: 42, ...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertHasFieldsJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.hasFields({hello: "world"}, ["goodbye"], "Oops!", kAttr);
|
||||
}, {
|
||||
msg: "assert.hasFields() failed : Oops!",
|
||||
msg: "Not all of the values from {arr} were in {result} : Oops!",
|
||||
attr: {result: {hello: "world"}, arr: ["goodbye"], ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -853,20 +854,23 @@ tests.push(function assertHasFieldsJsonFormat() {
|
|||
tests.push(function assertContainsJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.contains(3, [14, 15, 926], "Oops!", kAttr);
|
||||
}, {msg: "assert.contains() failed : Oops!", attr: {element: 3, arr: [14, 15, 926], ...kAttr}});
|
||||
}, {
|
||||
msg: "{element} was not in {arr} : Oops!",
|
||||
attr: {element: 3, arr: [14, 15, 926], ...kAttr}
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function assertDoesNotContainJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.doesNotContain(3, [3, 23], "Oops!", kAttr);
|
||||
}, {msg: "assert.doesNotContain() failed : Oops!", attr: {element: 3, arr: [3, 23], ...kAttr}});
|
||||
}, {msg: "{element} is in {arr} : Oops!", attr: {element: 3, arr: [3, 23], ...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertContainsPrefixJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.containsPrefix("hello", ["hell", "help"], "Oops!", kAttr);
|
||||
}, {
|
||||
msg: "assert.containsPrefix() failed : Oops!",
|
||||
msg: "{prefix} was not a prefix in {arr} : Oops!",
|
||||
attr: {prefix: "hello", arr: ["hell", "help"], ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -888,7 +892,7 @@ tests.push(function assertSoonNoExceptJsonFormat() {
|
|||
tests.push(function assertRetryJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.retry(() => false, "Oops!", 2, 10, {runHangAnalyzer: false}, kAttr);
|
||||
}, {msg: "assert.retry() failed : Oops!", attr: {...kAttr}});
|
||||
}, {msg: "Oops!", attr: {...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertRetryNoExceptJsonFormat() {
|
||||
|
|
@ -896,7 +900,7 @@ tests.push(function assertRetryNoExceptJsonFormat() {
|
|||
assert.retryNoExcept(() => {
|
||||
throw Error("disaster");
|
||||
}, "Oops!", 2, 10, {runHangAnalyzer: false}, kAttr);
|
||||
}, {msg: "assert.retry() failed : Oops!", attr: {...kAttr}});
|
||||
}, {msg: "Oops!", attr: {...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertTimeJsonFormat() {
|
||||
|
|
@ -908,11 +912,16 @@ tests.push(function assertTimeJsonFormat() {
|
|||
try {
|
||||
assert.time(f, "Oops!", timeoutMS, {runHangAnalyzer: false}, kAttr);
|
||||
} catch (e) {
|
||||
// Override the 'timeMS' to make the test deterministic.
|
||||
// Override 'timeMS' to make the test deterministic.
|
||||
e.extraAttr.timeMS = sleepTimeMS;
|
||||
// Override 'diff' to make the test deterministic.
|
||||
e.extraAttr.diff = sleepTimeMS;
|
||||
throw e;
|
||||
}
|
||||
}, {msg: "assert.time() failed : Oops!", attr: {timeMS: sleepTimeMS, timeoutMS, ...kAttr}});
|
||||
}, {
|
||||
msg: "assert.time failed : Oops!",
|
||||
attr: {timeMS: sleepTimeMS, timeoutMS, function: f, diff: sleepTimeMS, ...kAttr}
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function assertThrowsJsonFormat() {
|
||||
|
|
@ -929,7 +938,7 @@ tests.push(function assertThrowsWithCodeJsonFormat() {
|
|||
throw err;
|
||||
}, 42, [], "Oops!", kAttr);
|
||||
}, {
|
||||
msg: "assert.throwsWithCode() failed : Oops!",
|
||||
msg: "[{code}] and [{expectedCode}] are not equal : Oops!",
|
||||
attr: {code: 24, expectedCode: [42], ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -941,7 +950,7 @@ tests.push(function assertDoesNotThrowJsonFormat() {
|
|||
throw err;
|
||||
}, [], "Oops!", kAttr);
|
||||
}, {
|
||||
msg: "assert.doesNotThrow() failed : Oops!",
|
||||
msg: "threw unexpected exception: {error} : Oops!",
|
||||
attr: {error: {message: "disaster"}, ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -950,8 +959,8 @@ tests.push(function assertCommandWorkedWrongArgumentTypeJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
assert.commandWorked("cmd", "Oops!");
|
||||
}, {
|
||||
msg: "expected result type 'object'" +
|
||||
" : unexpected result type given to assert.commandWorked()",
|
||||
msg:
|
||||
"expected result type 'object', got '{resultType}', res='{result}' : unexpected result type given to assert.commandWorked()",
|
||||
attr: {result: "cmd", resultType: "string"}
|
||||
});
|
||||
});
|
||||
|
|
@ -968,7 +977,8 @@ tests.push(function assertCommandWorkedJsonFormat() {
|
|||
};
|
||||
assert.commandWorked(res, "Oops!");
|
||||
}, {
|
||||
msg: "command failed: unexpected error : Oops!",
|
||||
msg:
|
||||
"command failed: {res} with original command request: {originalCommand} with errmsg: unexpected error : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: 0,
|
||||
|
|
@ -989,7 +999,7 @@ tests.push(function assertCommandFailedJsonFormat() {
|
|||
const res = {ok: 1, _mongo: "connection to localhost:20000", _commandObj: {hello: 1}};
|
||||
assert.commandFailed(res, "Oops!");
|
||||
}, {
|
||||
msg: "command worked when it should have failed : Oops!",
|
||||
msg: "command worked when it should have failed: {res} : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: 1,
|
||||
|
|
@ -1007,7 +1017,7 @@ tests.push(function assertCommandFailedWithCodeJsonFormat() {
|
|||
const res = {ok: 1, _mongo: "connection to localhost:20000", _commandObj: {hello: 1}};
|
||||
assert.commandFailedWithCode(res, ErrorCodes.BadValue, "Oops!");
|
||||
}, {
|
||||
msg: "command worked when it should have failed : Oops!",
|
||||
msg: "command worked when it should have failed: {res} : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: 1,
|
||||
|
|
@ -1032,7 +1042,8 @@ tests.push(function assertCommandFailedWithWrongCodeJsonFormat() {
|
|||
};
|
||||
assert.commandFailedWithCode(res, ErrorCodes.NetworkTimeout, "Oops!");
|
||||
}, {
|
||||
msg: "command did not fail with any of the following codes [ 89 ] unexpected error : Oops!",
|
||||
msg:
|
||||
"command did not fail with any of the following codes {expectedCode} {res}. errmsg: unexpected error : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: 0,
|
||||
|
|
@ -1053,7 +1064,7 @@ tests.push(function assertWriteOKJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
const res = {ok: 0};
|
||||
assert.writeOK(res, "Oops!");
|
||||
}, {msg: "unknown type of write result, cannot check ok : Oops!", attr: {res: {ok: 0}}});
|
||||
}, {msg: "unknown type of write result, cannot check ok: {res} : Oops!", attr: {res: {ok: 0}}});
|
||||
});
|
||||
|
||||
tests.push(function assertWriteErrorJsonFormat() {
|
||||
|
|
@ -1062,7 +1073,7 @@ tests.push(function assertWriteErrorJsonFormat() {
|
|||
new WriteResult({nRemoved: 0, writeErrors: [], upserted: []}, 3, {w: "majority"});
|
||||
assert.writeError(res, "Oops!");
|
||||
}, {
|
||||
msg: "no write error : Oops!",
|
||||
msg: "no write error: {res} : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: {"$undefined": true},
|
||||
|
|
@ -1083,7 +1094,8 @@ tests.push(function assertWriteErrorWithCodeJsonFormat() {
|
|||
{nRemoved: 0, writeErrors: [writeError], upserted: []}, 3, {w: "majority"});
|
||||
assert.writeErrorWithCode(res, ErrorCodes.BadValue, "Oops!");
|
||||
}, {
|
||||
msg: "found code(s) does not match any of the expected codes : Oops!",
|
||||
msg:
|
||||
"found code(s) {writeErrorCodes} does not match any of the expected codes {expectedCode}. Original command response: {res} : Oops!",
|
||||
attr: {
|
||||
res: {
|
||||
ok: {"$undefined": true},
|
||||
|
|
@ -1102,20 +1114,20 @@ tests.push(function assertWriteErrorWithCodeJsonFormat() {
|
|||
tests.push(function assertIsNullJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.isnull({ok: 1}, "Oops!", kAttr);
|
||||
}, {msg: "assert.isnull() failed : Oops!", attr: {value: {ok: 1}, ...kAttr}});
|
||||
}, {msg: "supposed to be null, was: {value} : Oops!", attr: {value: {ok: 1}, ...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertLTJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.lt(41, 18, "Oops!", kAttr);
|
||||
}, {msg: "assert less than failed : Oops!", attr: {a: 41, b: 18, ...kAttr}});
|
||||
}, {msg: "{a} is not less than {b} : Oops!", attr: {a: 41, b: 18, ...kAttr}});
|
||||
});
|
||||
|
||||
tests.push(function assertBetweenJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.between(1, 15, 10, "Oops!", true, kAttr);
|
||||
}, {
|
||||
msg: "assert.between() failed : Oops!",
|
||||
msg: "{b} is not between {a} and {c} : Oops!",
|
||||
attr: {a: 1, b: 15, c: 10, inclusive: true, ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -1123,18 +1135,20 @@ tests.push(function assertBetweenJsonFormat() {
|
|||
tests.push(function assertCloseJsonFormat() {
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.close(123.4567, 123.4678, "Oops!");
|
||||
}, {msg: "assert.close() failed : Oops!", attr: {a: 123.4567, b: 123.4678, places: 4}});
|
||||
}, {
|
||||
msg:
|
||||
"123.4567 is not equal to 123.4678 within 4 places, absolute error: 0.011099999999999, relative error: 0.00008990198254118888 : Oops!"
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function assertCloseWithinMSJsonFormat() {
|
||||
const dateForLog = (arg) => JSON.parse(JSON.stringify(arg));
|
||||
const date1 = new Date();
|
||||
sleep(10);
|
||||
const date2 = new Date();
|
||||
const date1 = Date.UTC(1970, 0, 1, 23, 59, 59, 999);
|
||||
const date2 = date1 + 10;
|
||||
assertThrowsErrorWithJson(() => {
|
||||
assert.closeWithinMS(date1, date2, "Oops!", 1, kAttr);
|
||||
}, {
|
||||
msg: "assert.closeWithinMS() failed : Oops!",
|
||||
msg: "86399999 is not equal to 86400009 within 1 millis, actual delta: 10 millis : Oops!",
|
||||
attr: {a: dateForLog(date1), b: dateForLog(date2), deltaMS: 1, ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
@ -1143,7 +1157,7 @@ tests.push(function assertIncludesJsonFormat() {
|
|||
assertThrowsErrorWithJson(() => {
|
||||
assert.includes("farmacy", "ace", "Oops!", kAttr);
|
||||
}, {
|
||||
msg: "assert.includes() failed : Oops!",
|
||||
msg: "string [{haystack}] does not include [{needle}] : Oops!",
|
||||
attr: {haystack: "farmacy", needle: "ace", ...kAttr}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ tests.push(function invalidResponsesAttemptToProvideInformationToCommandWorks()
|
|||
const error = assert.throws(() => {
|
||||
assert.commandWorked(invalidRes);
|
||||
});
|
||||
const errorMsg = stringifyErrorMessageAndAttributes(error);
|
||||
const errorMsg = formatErrorMsg(error.message, error.extraAttr);
|
||||
assert.gte(errorMsg.indexOf(invalidRes), 0);
|
||||
assert.gte(errorMsg.indexOf(typeof invalidRes), 0);
|
||||
});
|
||||
|
|
@ -310,7 +310,7 @@ tests.push(function invalidResponsesAttemptToProvideInformationCommandFailed() {
|
|||
const error = assert.throws(() => {
|
||||
assert.commandFailed(invalidRes);
|
||||
});
|
||||
const errorMsg = stringifyErrorMessageAndAttributes(error);
|
||||
const errorMsg = formatErrorMsg(error.message, error.extraAttr);
|
||||
assert.gte(errorMsg.indexOf(invalidRes), 0);
|
||||
assert.gte(errorMsg.indexOf(typeof invalidRes), 0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,5 +45,5 @@ const err = assert.throws(() => {
|
|||
});
|
||||
});
|
||||
|
||||
assert(/ResumableRangeDeleterDisabled/.test(stringifyErrorMessageAndAttributes(err)), err);
|
||||
assert(/ResumableRangeDeleterDisabled/.test(formatErrorMsg(err.message, err.extraAttr)), err);
|
||||
reshardingTest.teardown();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function runStandaloneTest(stageRegex, pipeline, expectedCommand) {
|
|||
|
||||
const result = assert.throws(() => coll.aggregate(pipeline, {cursor: {batchSize: 2}}));
|
||||
assert(isNetworkError(result));
|
||||
assert(stageRegex.test(stringifyErrorMessageAndAttributes(result)),
|
||||
assert(stageRegex.test(formatErrorMsg(result.message, result.extraAttr)),
|
||||
`Error wasn't due to stage failing: ${result}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,17 @@ declare function assert(value: boolean | any, msg?: string | function | object,
|
|||
*/
|
||||
declare function sortDoc(doc: object): any
|
||||
|
||||
/**
|
||||
* Format error message by replacing occurrences of '{key}'s in 'msg' with 'value' in [key, value] pairs from 'attr'.
|
||||
*
|
||||
* @param msg Failure message.
|
||||
* @param attr Additional attributes to be included in failure messages.
|
||||
* @param serializeFn Additional function to serialize 'value' in [key, value] pairs from 'attr'.
|
||||
*
|
||||
* @returns Failure message.
|
||||
*/
|
||||
declare function formatErrorMsg(msg: string, attr?: object, serializeFn?: function): string
|
||||
|
||||
declare module assert {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -90,6 +90,13 @@ function _convertExceptionToReturnStatus(func, excMsg) {
|
|||
return safeFunc;
|
||||
}
|
||||
|
||||
function formatErrorMsg(msg, attr = {}, serializeFn = tojson) {
|
||||
for (const [key, value] of Object.entries(attr)) {
|
||||
msg = msg.replaceAll(`{${key}}`, serializeFn(value));
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
assert = (function() {
|
||||
// Wrapping the helper function in an IIFE to avoid polluting the global namespace.
|
||||
|
||||
|
|
@ -104,7 +111,7 @@ assert = (function() {
|
|||
return msg;
|
||||
}
|
||||
|
||||
function _doassert(msg, prefix, attr, prefixOverride) {
|
||||
function _doassert(msg, prefix, attr) {
|
||||
if (TestData?.logFormat === "json") {
|
||||
if (attr?.res) {
|
||||
// Special handling for command reply a.k.a. 'res' parameters, as it might contain
|
||||
|
|
@ -115,9 +122,9 @@ assert = (function() {
|
|||
...(attr.res._mongo && {connection: attr.res._mongo})
|
||||
};
|
||||
}
|
||||
doassert(_buildAssertionMessage(msg, prefixOverride ?? prefix), attr);
|
||||
doassert(_buildAssertionMessage(msg, prefix), attr);
|
||||
}
|
||||
doassert(_buildAssertionMessage(msg, prefix), attr?.res);
|
||||
doassert(_buildAssertionMessage(msg, formatErrorMsg(prefix, attr, tojson)), attr?.res);
|
||||
}
|
||||
|
||||
function _validateAssertionMessage(msg, attr) {
|
||||
|
|
@ -189,10 +196,7 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
`[${tojson(a)}] != [${tojson(b)}] are not equal`,
|
||||
{a, b, ...attr},
|
||||
"assert.eq() failed");
|
||||
_doassert(msg, `[{a}] and [{b}] are not equal`, {a, b, ...attr});
|
||||
};
|
||||
|
||||
function _isDocEq(a, b) {
|
||||
|
|
@ -212,10 +216,8 @@ assert = (function() {
|
|||
}
|
||||
|
||||
_doassert(msg,
|
||||
"expected document " + tojson(expectedDoc) + " and actual document " +
|
||||
tojson(actualDoc) + " are not equal",
|
||||
{expectedDoc, actualDoc, ...attr},
|
||||
"assert.docEq() failed");
|
||||
"expected document {expectedDoc} and actual document {actualDoc} are not equal",
|
||||
{expectedDoc, actualDoc, ...attr});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -228,10 +230,8 @@ assert = (function() {
|
|||
const failAssertion = function() {
|
||||
_doassert(
|
||||
msg,
|
||||
"expected set " + tojson(expectedSet) + " and actual set " + tojson(actualSet) +
|
||||
" are not equal",
|
||||
{expectedSet: Array.from(expectedSet), actualSet: Array.from(actualSet), ...attr},
|
||||
"assert.setEq() failed");
|
||||
"expected set {expectedSet} and actual set {actualSet} are not equal",
|
||||
{expectedSet: Array.from(expectedSet), actualSet: Array.from(actualSet), ...attr});
|
||||
};
|
||||
if (expectedSet.size !== actualSet.size) {
|
||||
failAssertion();
|
||||
|
|
@ -253,10 +253,7 @@ assert = (function() {
|
|||
_validateAssertionMessage(msg, attr);
|
||||
|
||||
const failAssertion = function() {
|
||||
_doassert(msg,
|
||||
tojson(aArr) + " != " + tojson(bArr),
|
||||
{aArr, bArr, compareFn: compareFn.name, ...attr},
|
||||
"assert.sameMembers() failed");
|
||||
_doassert(msg, "{aArr} != {bArr}", {aArr, bArr, compareFn: compareFn.name, ...attr});
|
||||
};
|
||||
|
||||
if (aArr.length !== bArr.length) {
|
||||
|
|
@ -299,10 +296,7 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
`[${tojson(a)}] == [${tojson(b)}] are equal`,
|
||||
{a, b, ...attr},
|
||||
"assert.neq() failed");
|
||||
_doassert(msg, "[{a}] and [{b}] are equal", {a, b, ...attr});
|
||||
};
|
||||
|
||||
assert.hasFields = function(result, arr, msg, attr) {
|
||||
|
|
@ -318,10 +312,8 @@ assert = (function() {
|
|||
}
|
||||
|
||||
if (count != arr.length) {
|
||||
_doassert(msg,
|
||||
"Not all of the values from " + tojson(arr) + " were in " + tojson(result),
|
||||
{result, arr, ...attr},
|
||||
"assert.hasFields() failed");
|
||||
_doassert(
|
||||
msg, "Not all of the values from {arr} were in {result}", {result, arr, ...attr});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -339,10 +331,7 @@ assert = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
tojson(element) + " was not in " + tojson(arr),
|
||||
{element, arr, ...attr},
|
||||
"assert.contains() failed");
|
||||
_doassert(msg, "{element} was not in {arr}", {element, arr, ...attr});
|
||||
};
|
||||
|
||||
assert.doesNotContain = function(element, arr, msg, attr) {
|
||||
|
|
@ -355,10 +344,7 @@ assert = (function() {
|
|||
const match = comp == element ||
|
||||
((comp != null && element != null) && friendlyEqual(comp, element));
|
||||
if (match) {
|
||||
_doassert(msg,
|
||||
tojson(element) + " is in " + tojson(arr),
|
||||
{element, arr, ...attr},
|
||||
"assert.doesNotContain() failed");
|
||||
_doassert(msg, "{element} is in {arr}", {element, arr, ...attr});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -382,10 +368,7 @@ assert = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
tojson(prefix) + " was not a prefix in " + tojson(arr),
|
||||
{prefix, arr, ...attr},
|
||||
"assert.containsPrefix() failed");
|
||||
_doassert(msg, "{prefix} was not a prefix in {arr}", {prefix, arr, ...attr});
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -500,7 +483,7 @@ assert = (function() {
|
|||
print(msg + " Running hang analyzer from assert.retry.");
|
||||
MongoRunner.runHangAnalyzer();
|
||||
}
|
||||
_doassert(msg, null, attr, "assert.retry() failed");
|
||||
_doassert(msg, null, attr);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -556,8 +539,7 @@ assert = (function() {
|
|||
return res;
|
||||
}
|
||||
|
||||
const msgPrefix =
|
||||
"assert.time failed timeout " + timeout + "ms took " + diff + "ms : " + f + ", msg";
|
||||
const msgPrefix = "assert.time failed";
|
||||
msg = _buildAssertionMessage(msg);
|
||||
if (runHangAnalyzer) {
|
||||
msg = msg + " The hang analyzer is automatically called in assert.time functions. " +
|
||||
|
|
@ -567,8 +549,7 @@ assert = (function() {
|
|||
print(msg + " Running hang analyzer from assert.time.");
|
||||
MongoRunner.runHangAnalyzer();
|
||||
}
|
||||
_doassert(
|
||||
msg, msgPrefix, {timeMS: diff, timeoutMS: timeout, ...attr}, "assert.time() failed");
|
||||
_doassert(msg, msgPrefix, {timeMS: diff, timeoutMS: timeout, function: f, diff, ...attr});
|
||||
};
|
||||
|
||||
function assertThrowsHelper(func, params) {
|
||||
|
|
@ -649,9 +630,8 @@ assert = (function() {
|
|||
}
|
||||
if (!expectedCode.some((ec) => error.code == ec)) {
|
||||
_doassert(msg,
|
||||
`[${tojson(error.code)}] != [${tojson(expectedCode)}] are not equal`,
|
||||
{code: error.code, expectedCode, ...attr},
|
||||
"assert.throwsWithCode() failed");
|
||||
`[{code}] and [{expectedCode}] are not equal`,
|
||||
{code: error.code, expectedCode, ...attr});
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
|
@ -666,9 +646,8 @@ assert = (function() {
|
|||
if (error) {
|
||||
const {code, message} = error;
|
||||
_doassert(msg,
|
||||
"threw unexpected exception: " + error,
|
||||
{error: {...(code && {code}), ...(message && {message})}, ...attr},
|
||||
"assert.doesNotThrow() failed");
|
||||
"threw unexpected exception: {error}",
|
||||
{error: {...(code && {code}), ...(message && {message})}, ...attr});
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
@ -722,9 +701,8 @@ assert = (function() {
|
|||
function _validateCommandResponse(res, assertionName) {
|
||||
if (typeof res !== "object") {
|
||||
_doassert(`unexpected result type given to assert.${assertionName}()`,
|
||||
`expected result type 'object', got '${typeof res}', res='${res}'`,
|
||||
{result: res, resultType: typeof res},
|
||||
"expected result type 'object'");
|
||||
`expected result type 'object', got '{resultType}', res='{result}'`,
|
||||
{result: res, resultType: typeof res});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -776,21 +754,18 @@ assert = (function() {
|
|||
|
||||
// Keep this as a function so we don't call tojson if not necessary.
|
||||
const makeFailPrefix = (res) => {
|
||||
let prefix = "command failed: " + tojson(res);
|
||||
let prefix = "command failed: {res}";
|
||||
if (typeof res._commandObj === "object" && res._commandObj !== null) {
|
||||
prefix += " with original command request: " + tojson(res._commandObj);
|
||||
prefix += " with original command request: {originalCommand}";
|
||||
}
|
||||
if (typeof res._mongo === "object" && res._mongo !== null) {
|
||||
prefix += " on connection: " + res._mongo;
|
||||
prefix += " on connection: {connection}";
|
||||
}
|
||||
if (res.hasOwnProperty("errmsg")) {
|
||||
prefix += ` with errmsg: ${res.errmsg}`;
|
||||
}
|
||||
return prefix;
|
||||
};
|
||||
const makeFailPrefixOverride = (res) => {
|
||||
if (res.hasOwnProperty("errmsg")) {
|
||||
return `command failed: ${res.errmsg}`;
|
||||
}
|
||||
return "command failed";
|
||||
};
|
||||
|
||||
if (_isWriteResultType(res)) {
|
||||
// These can only contain write errors, not command errors.
|
||||
|
|
@ -801,7 +776,9 @@ assert = (function() {
|
|||
// A WriteCommandError implies ok:0.
|
||||
// Error objects may have a `code` property added (e.g.
|
||||
// DBCollection.prototype.mapReduce) without a `ok` property.
|
||||
_doassert(msg, makeFailPrefix(res), {res}, makeFailPrefixOverride(res));
|
||||
_doassert(msg,
|
||||
makeFailPrefix(res),
|
||||
{res, originalCommand: res._commandObj, connection: res._mongo});
|
||||
} else if (res.hasOwnProperty("ok")) {
|
||||
// Handle raw command responses or cases like MapReduceResult which extend command
|
||||
// response.
|
||||
|
|
@ -810,16 +787,15 @@ assert = (function() {
|
|||
ignoreWriteConcernErrors: ignoreWriteConcernErrors
|
||||
})) {
|
||||
_runHangAnalyzerForSpecificFailureTypes(res);
|
||||
_doassert(msg, makeFailPrefix(res), {res}, makeFailPrefixOverride(res));
|
||||
_doassert(msg,
|
||||
makeFailPrefix(res),
|
||||
{res, originalCommand: res._commandObj, connection: res._mongo});
|
||||
}
|
||||
} else if (res.hasOwnProperty("acknowledged")) {
|
||||
// CRUD api functions return plain js objects with an acknowledged property.
|
||||
// no-op.
|
||||
} else {
|
||||
_doassert(msg,
|
||||
"unknown type of result, cannot check ok: " + tojson(res),
|
||||
{res},
|
||||
"unknown type of result");
|
||||
_doassert(msg, "unknown type of result, cannot check ok: {res}", {res});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -836,30 +812,21 @@ assert = (function() {
|
|||
|
||||
// Keep this as a function so we don't call tojson if not necessary.
|
||||
const makeFailPrefix = (res) => {
|
||||
return "command worked when it should have failed: " + tojson(res);
|
||||
};
|
||||
const makeFailPrefixOverride = (res) => {
|
||||
if (res.hasOwnProperty("errmsg")) {
|
||||
return `command worked when it should have failed: ${res.errmsg}`;
|
||||
return `command worked when it should have failed: {res}. errmsg: ${res.errMsg}`;
|
||||
}
|
||||
return "command worked when it should have failed";
|
||||
return "command worked when it should have failed: {res}";
|
||||
};
|
||||
|
||||
const makeFailCodePrefix = (res, expectedCode) => {
|
||||
return (expectedCode !== assert._kAnyErrorCode)
|
||||
? "command did not fail with any of the following codes " + tojson(expectedCode) +
|
||||
" " + tojson(res)
|
||||
: null;
|
||||
};
|
||||
const makeFailCodePrefixOverride = (res, expectedCode) => {
|
||||
if (res.hasOwnProperty("errmsg")) {
|
||||
return (expectedCode !== assert._kAnyErrorCode)
|
||||
? "command did not fail with any of the following codes " +
|
||||
tojson(expectedCode) + " " + res.errmsg
|
||||
? `command did not fail with any of the following codes {expectedCode} {res}. errmsg: ${
|
||||
res.errmsg}`
|
||||
: null;
|
||||
}
|
||||
return (expectedCode !== assert._kAnyErrorCode)
|
||||
? "command did not fail with any of the following codes " + tojson(expectedCode)
|
||||
? "command did not fail with any of the following codes {expectedCode} {res}"
|
||||
: null;
|
||||
};
|
||||
|
||||
|
|
@ -872,20 +839,14 @@ assert = (function() {
|
|||
// DBCollection.prototype.mapReduce) without a `ok` property.
|
||||
if (expectedCode !== assert._kAnyErrorCode) {
|
||||
if (!res.hasOwnProperty("code") || !expectedCode.includes(res.code)) {
|
||||
_doassert(msg,
|
||||
makeFailCodePrefix(res, expectedCode),
|
||||
{res, expectedCode},
|
||||
makeFailCodePrefixOverride(res, expectedCode));
|
||||
_doassert(msg, makeFailCodePrefix(res, expectedCode), {res, expectedCode});
|
||||
}
|
||||
}
|
||||
} else if (res.hasOwnProperty("ok")) {
|
||||
// Handle raw command responses or cases like MapReduceResult which extend command
|
||||
// response.
|
||||
if (_rawReplyOkAndNoWriteErrors(res)) {
|
||||
_doassert(msg,
|
||||
makeFailPrefix(res, expectedCode),
|
||||
{res},
|
||||
makeFailPrefixOverride(res, expectedCode));
|
||||
_doassert(msg, makeFailPrefix(res), {res});
|
||||
}
|
||||
|
||||
if (expectedCode !== assert._kAnyErrorCode) {
|
||||
|
|
@ -900,23 +861,14 @@ assert = (function() {
|
|||
|
||||
if (!foundCode) {
|
||||
_runHangAnalyzerForSpecificFailureTypes(res);
|
||||
_doassert(msg,
|
||||
makeFailCodePrefix(res, expectedCode),
|
||||
{res, expectedCode},
|
||||
makeFailCodePrefixOverride(res, expectedCode));
|
||||
_doassert(msg, makeFailCodePrefix(res, expectedCode), {res, expectedCode});
|
||||
}
|
||||
}
|
||||
} else if (res.hasOwnProperty("acknowledged")) {
|
||||
// CRUD api functions return plain js objects with an acknowledged property.
|
||||
_doassert(msg,
|
||||
makeFailPrefix(res, expectedCode),
|
||||
{res},
|
||||
makeFailPrefixOverride(res, expectedCode));
|
||||
_doassert(msg, makeFailPrefix(res), {res});
|
||||
} else {
|
||||
_doassert(msg,
|
||||
"unknown type of result, cannot check error: " + tojson(res),
|
||||
{res},
|
||||
"unknown type of result");
|
||||
_doassert(msg, "unknown type of result, cannot check error: {res}", {res});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -996,7 +948,7 @@ assert = (function() {
|
|||
|
||||
if (errMsg) {
|
||||
_runHangAnalyzerForSpecificFailureTypes(res);
|
||||
_doassert(msg, errMsg + ": " + tojson(res), {res}, errMsg);
|
||||
_doassert(msg, errMsg + ": {res}", {res}, errMsg);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
@ -1047,7 +999,7 @@ assert = (function() {
|
|||
|
||||
if (errMsg) {
|
||||
_runHangAnalyzerForSpecificFailureTypes(res);
|
||||
_doassert(msg, errMsg + ": " + tojson(res), {res}, errMsg);
|
||||
_doassert(msg, errMsg + ": {res}", {res});
|
||||
}
|
||||
|
||||
if (expectedCode !== assert._kAnyErrorCode) {
|
||||
|
|
@ -1056,14 +1008,11 @@ assert = (function() {
|
|||
}
|
||||
const found = expectedCode.some((ec) => writeErrorCodes.has(ec));
|
||||
if (!found) {
|
||||
errMsg = "found code(s) " + tojson(Array.from(writeErrorCodes)) +
|
||||
" does not match any of the expected codes " + tojson(expectedCode) +
|
||||
". Original command response: " + tojson(res);
|
||||
errMsg =
|
||||
"found code(s) {writeErrorCodes} does not match any of the expected codes {expectedCode}. Original command response: {res}";
|
||||
_runHangAnalyzerForSpecificFailureTypes(res);
|
||||
_doassert(msg,
|
||||
errMsg,
|
||||
{res, expectedCode, writeErrorCodes: Array.from(writeErrorCodes)},
|
||||
"found code(s) does not match any of the expected codes");
|
||||
_doassert(
|
||||
msg, errMsg, {res, expectedCode, writeErrorCodes: Array.from(writeErrorCodes)});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1077,10 +1026,7 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
"supposed to be null, was: " + tojson(value),
|
||||
{value, ...attr},
|
||||
"assert.isnull() failed");
|
||||
_doassert(msg, "supposed to be null, was: {value}", {value, ...attr});
|
||||
};
|
||||
|
||||
function _shouldUseBsonWoCompare(a, b) {
|
||||
|
|
@ -1117,10 +1063,7 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
a + " is not " + description + " " + b,
|
||||
{a, b, ...attr},
|
||||
`assert ${description} failed`);
|
||||
_doassert(msg, "{a} is not " + description + " {b}", {a, b, ...attr});
|
||||
}
|
||||
|
||||
assert.lt = function(a, b, msg, attr) {
|
||||
|
|
@ -1158,10 +1101,7 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_doassert(msg,
|
||||
b + " is not between " + a + " and " + c,
|
||||
{a, b, c, inclusive, ...attr},
|
||||
"assert.between() failed");
|
||||
_doassert(msg, "{b} is not between {a} and {c}", {a, b, c, inclusive, ...attr});
|
||||
};
|
||||
|
||||
assert.betweenIn = function(a, b, c, msg, attr) {
|
||||
|
|
@ -1193,7 +1133,7 @@ assert = (function() {
|
|||
assert.close = function(a, b, msg, places = 4) {
|
||||
const [isClose, errMsg] = _isClose(a, b, places);
|
||||
if (!isClose) {
|
||||
_doassert(msg, errMsg, {a, b, places}, "assert.close() failed");
|
||||
_doassert(msg, errMsg);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1240,10 +1180,7 @@ assert = (function() {
|
|||
"actual delta: " + actualDelta + " millis";
|
||||
|
||||
const forLog = (arg) => arg instanceof Date ? JSON.parse(JSON.stringify(arg)) : arg;
|
||||
_doassert(msg,
|
||||
msgPrefix,
|
||||
{a: forLog(a), b: forLog(b), deltaMS, ...attr},
|
||||
"assert.closeWithinMS() failed");
|
||||
_doassert(msg, msgPrefix, {a: forLog(a), b: forLog(b), deltaMS, ...attr});
|
||||
};
|
||||
|
||||
assert.includes = function(haystack, needle, msg, attr) {
|
||||
|
|
@ -1251,8 +1188,8 @@ assert = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
const prefix = `string [${haystack}] does not include [${needle}]`;
|
||||
_doassert(msg, prefix, {haystack, needle, ...attr}, "assert.includes() failed");
|
||||
const prefix = "string [{haystack}] does not include [{needle}]";
|
||||
_doassert(msg, prefix, {haystack, needle, ...attr});
|
||||
};
|
||||
|
||||
assert.noAPIParams = function(cmdOptions) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ declare function isObject()
|
|||
declare function isString()
|
||||
declare function printjson()
|
||||
declare function printjsononeline()
|
||||
declare function stringifyErrorMessageAndAttributes()
|
||||
declare function toJsonForLog()
|
||||
declare function tojson()
|
||||
declare function tojsonObject()
|
||||
|
|
|
|||
|
|
@ -925,11 +925,3 @@ isNumber = function(x) {
|
|||
isObject = function(x) {
|
||||
return typeof (x) == "object";
|
||||
};
|
||||
|
||||
stringifyErrorMessageAndAttributes = function(e) {
|
||||
const escapedMsg = JSON.stringify(e.message);
|
||||
if (!e.extraAttr) {
|
||||
return escapedMsg;
|
||||
}
|
||||
return `${escapedMsg}: ${tojson(e.extraAttr)}`;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue