diff --git a/jstests/libs/query/change_stream_util.js b/jstests/libs/query/change_stream_util.js index 86f58619077..b09775d1fe5 100644 --- a/jstests/libs/query/change_stream_util.js +++ b/jstests/libs/query/change_stream_util.js @@ -592,14 +592,24 @@ export function ChangeStreamTest(_db, options) { let changes = self.getNextChanges(cursor, expectedNumChanges, skipFirstBatch); if (ignoreOrder) { - const errMsgFunc = () => `${tojsonMaybeTruncate(changes)} != ${tojsonMaybeTruncate(expectedChanges)}`; - assert.eq(changes.length, expectedNumChanges, errMsgFunc); + const lengthMismatchErrMsg = () => + "Change stream event count mismatch (order ignored). " + + `Expected ${expectedNumChanges} event(s), observed ${changes.length}. ` + + `Expected events: ${tojsonMaybeTruncate(expectedChanges)}. ` + + `Observed events: ${tojsonMaybeTruncate(changes)}.`; + assert.eq(changes.length, expectedNumChanges, lengthMismatchErrMsg); for (let i = 0; i < changes.length; i++) { + const itemMismatchErrMsg = () => + "Change stream event mismatch (order ignored). " + + `No expected event matched observed event at index ${i}. ` + + `Observed event: ${tojsonMaybeTruncate(changes[i])}. ` + + `Expected events: ${tojsonMaybeTruncate(expectedChanges)}. ` + + `Observed events: ${tojsonMaybeTruncate(changes)}.`; assert( expectedChanges.some((expectedChange) => { return isChangeStreamEventEq(changes[i], expectedChange, eventModifier); }), - errMsgFunc, + itemMismatchErrMsg, ); } } else { diff --git a/jstests/sharding/query/change_streams/change_streams_with_config_transitions.js b/jstests/sharding/query/change_streams/change_streams_with_config_transitions.js index 311c31ba363..f38aa592b9d 100644 --- a/jstests/sharding/query/change_streams/change_streams_with_config_transitions.js +++ b/jstests/sharding/query/change_streams/change_streams_with_config_transitions.js @@ -116,6 +116,7 @@ function runTransitionTestCases(transitionType, watchMode, collSetupType) { // the transition (we use the first event by the previous test case as resume point). csCursor = null; const resumePoint = observedEvents[0]._id; + const resumeId = observedEvents[0].fullDocument._id; try { csCursor = cst.getChangeStream({watchMode: watchMode, coll: coll, resumeAfter: resumePoint}); @@ -133,7 +134,13 @@ function runTransitionTestCases(transitionType, watchMode, collSetupType) { // On the other hand, a change stream resumed before a "transition from dedicated config server" // is expected to retrieve all the subsequent events. - cst.assertNextChangesEqualUnordered({cursor: csCursor, expectedChanges: expectedEvents.slice(1)}); + // + // We exclude the event we resumed from (observedEvents[0]) rather than always slicing + // expectedEvents at index 0. In a sharded cluster the change stream delivers events in + // cluster-time order, which can differ from insertion order, so the first observed event + // may not be expectedEvents[0]. + const resumedExpected = expectedEvents.filter((e) => e.fullDocument._id !== resumeId); + cst.assertNextChangesEqualUnordered({cursor: csCursor, expectedChanges: resumedExpected}); cst.cleanUp(); }