SERVER-101755 Add string substitution to assertion messages (#34437)

GitOrigin-RevId: 344c864a3ad16675ce9190e47ebfba143c741660
This commit is contained in:
Daniel Tabacaru 2025-04-04 15:51:03 +02:00 committed by MongoDB Bot
parent e3315cf7d7
commit a918fa85ba
15 changed files with 140 additions and 186 deletions

View File

@ -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):

View File

@ -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,

View File

@ -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'))) {

View File

@ -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

View File

@ -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",

View File

@ -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",

View File

@ -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");
}

View File

@ -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}
});
});

View File

@ -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);
});

View File

@ -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();

View File

@ -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}`);
}
}

View File

@ -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 {
/**

View File

@ -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) {

View File

@ -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()

View File

@ -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)}`;
};