

























@@ -25,6 +25,40 @@ function getSentNoticeBodies(sendMessage: ReturnType<typeof vi.fn>): string[] {
2525return (sendMessage.mock.calls as unknown[][]).map(getSentNoticeBodyFromCall);
2626}
272728+function expectBodiesContain(bodies: string[], text: string) {
29+expect(bodies.some((body) => body.includes(text))).toBe(true);
30+}
31+32+function expectBodiesExclude(bodies: string[], text: string) {
33+expect(bodies.some((body) => body.includes(text))).toBe(false);
34+}
35+36+function requireRecord(value: unknown, label: string): Record<string, unknown> {
37+expect(typeof value).toBe("object");
38+expect(value).not.toBeNull();
39+if (typeof value !== "object" || value === null) {
40+throw new Error(`${label} was not an object`);
41+}
42+return value as Record<string, unknown>;
43+}
44+45+function expectRecordFields(record: Record<string, unknown>, fields: Record<string, unknown>) {
46+for (const [key, value] of Object.entries(fields)) {
47+expect(record[key]).toEqual(value);
48+}
49+}
50+51+function expectWarnContextFields(
52+logger: { warn: ReturnType<typeof vi.fn> },
53+callIndex: number,
54+message: string,
55+fields: Record<string, unknown>,
56+) {
57+const call = logger.warn.mock.calls[callIndex - 1] as unknown[];
58+expect(call?.[0]).toBe(message);
59+expectRecordFields(requireRecord(call?.[1], "logger warning context"), fields);
60+}
61+2862function createHarness(params?: {
2963cfg?: CoreConfig;
3064accountId?: string;
@@ -275,10 +309,12 @@ describe("registerMatrixMonitorEvents verification routing", () => {
275309});
276310277311await flushTasks();
278-expect(onRoomMessage).toHaveBeenCalledWith(
279-"!room:example.org",
280-expect.objectContaining({ event_id: "$reaction1", type: EventType.Reaction }),
281-);
312+const roomMessageCalls = onRoomMessage.mock.calls as unknown[][];
313+expect(roomMessageCalls[0]?.[0]).toBe("!room:example.org");
314+expectRecordFields(requireRecord(roomMessageCalls[0]?.[1], "reaction event"), {
315+event_id: "$reaction1",
316+type: EventType.Reaction,
317+});
282318expect(sendMessage).not.toHaveBeenCalled();
283319});
284320@@ -593,10 +629,8 @@ describe("registerMatrixMonitorEvents verification routing", () => {
593629594630await flushTasks();
595631const bodies = getSentNoticeBodies(sendMessage);
596-expect(bodies).toEqual(expect.arrayContaining([expect.stringContaining("SAS emoji:")]));
597-expect(bodies).toEqual(
598-expect.arrayContaining([expect.stringContaining("SAS decimal: 6158 1986 3513")]),
599-);
632+expectBodiesContain(bodies, "SAS emoji:");
633+expectBodiesContain(bodies, "SAS decimal: 6158 1986 3513");
600634});
601635602636it("rehydrates an in-progress DM verification before resolving SAS notices", async () => {
@@ -963,7 +997,7 @@ describe("registerMatrixMonitorEvents verification routing", () => {
963997964998await vi.waitFor(() => {
965999const bodies = getSentNoticeBodies(sendMessage);
966-expect(bodies).toEqual(expect.arrayContaining([expect.stringContaining("SAS emoji:")]));
1000+expectBodiesContain(bodies, "SAS emoji:");
9671001});
9681002} finally {
9691003vi.useRealTimers();
@@ -1217,13 +1251,9 @@ describe("registerMatrixMonitorEvents verification routing", () => {
12171251});
1218125212191253await flushTasks();
1220-expect(getSentNoticeBodies(sendMessage)).toEqual(
1221-expect.arrayContaining([expect.stringContaining("SAS decimal: 6158 1986 3513")]),
1222-);
12231254const bodies = getSentNoticeBodies(sendMessage);
1224-expect(bodies).not.toEqual(
1225-expect.arrayContaining([expect.stringContaining("SAS decimal: 1111 2222 3333")]),
1226-);
1255+expectBodiesContain(bodies, "SAS decimal: 6158 1986 3513");
1256+expectBodiesExclude(bodies, "SAS decimal: 1111 2222 3333");
12271257});
1228125812291259it("preserves strict-room SAS fallback when active DM inspection cannot resolve a room", async () => {
@@ -1325,13 +1355,9 @@ describe("registerMatrixMonitorEvents verification routing", () => {
13251355});
1326135613271357await flushTasks();
1328-expect(getSentNoticeBodies(sendMessage)).toEqual(
1329-expect.arrayContaining([expect.stringContaining("SAS decimal: 6158 1986 3513")]),
1330-);
13311358const bodies = getSentNoticeBodies(sendMessage);
1332-expect(bodies).not.toEqual(
1333-expect.arrayContaining([expect.stringContaining("SAS decimal: 1111 2222 3333")]),
1334-);
1359+expectBodiesContain(bodies, "SAS decimal: 6158 1986 3513");
1360+expectBodiesExclude(bodies, "SAS decimal: 1111 2222 3333");
13351361});
1336136213371363it("does not emit SAS notices for cancelled verification events", async () => {
@@ -1485,16 +1511,12 @@ describe("registerMatrixMonitorEvents verification routing", () => {
14851511new Error("The sender's device has not sent us the keys for this message."),
14861512);
148715131488-expect(logger.warn).toHaveBeenNthCalledWith(
1489-1,
1490-"Failed to decrypt message",
1491-expect.objectContaining({
1492-roomId: "!room:example.org",
1493-eventId: "$enc-self",
1494-sender: "@gumadeiras:matrix.example.org",
1495-senderMatchesOwnUser: true,
1496-}),
1497-);
1514+expectWarnContextFields(logger, 1, "Failed to decrypt message", {
1515+roomId: "!room:example.org",
1516+eventId: "$enc-self",
1517+sender: "@gumadeiras:matrix.example.org",
1518+senderMatchesOwnUser: true,
1519+});
14981520expect(logger.warn).toHaveBeenNthCalledWith(
149915212,
15001522"matrix: failed to decrypt a message from this same Matrix user. This usually means another Matrix device did not share the room key, or another OpenClaw runtime is using the same account. Check 'openclaw matrix verify status --verbose --account ops' and 'openclaw matrix devices list --account ops'.",
@@ -1528,15 +1550,12 @@ describe("registerMatrixMonitorEvents verification routing", () => {
15281550);
1529155115301552expect(logger.warn).toHaveBeenCalledTimes(1);
1531-expect(logger.warn).toHaveBeenCalledWith(
1532-"Failed to decrypt message",
1533-expect.objectContaining({
1534-roomId: "!room:example.org",
1535-eventId: "$enc-other",
1536-sender: "@alice:matrix.example.org",
1537-senderMatchesOwnUser: false,
1538-}),
1539-);
1553+expectWarnContextFields(logger, 1, "Failed to decrypt message", {
1554+roomId: "!room:example.org",
1555+eventId: "$enc-other",
1556+sender: "@alice:matrix.example.org",
1557+senderMatchesOwnUser: false,
1558+});
15401559});
1541156015421561it("classifies repeated fresh post-healthy-sync decrypt failures separately", async () => {
@@ -1570,43 +1589,32 @@ describe("registerMatrixMonitorEvents verification routing", () => {
15701589);
15711590}
157215911573-expect(logger.warn).toHaveBeenNthCalledWith(
1574-1,
1575-"Failed to decrypt fresh post-healthy-sync message",
1576-expect.objectContaining({
1577-eventId: "$enc-fresh-1",
1578-freshAfterHealthySync: true,
1579-postHealthySyncFailureCount: 1,
1580-}),
1581-);
1582-expect(logger.warn).toHaveBeenNthCalledWith(
1583-2,
1584-"Failed to decrypt fresh post-healthy-sync message",
1585-expect.objectContaining({
1586-eventId: "$enc-fresh-2",
1587-freshAfterHealthySync: true,
1588-postHealthySyncFailureCount: 2,
1589-}),
1590-);
1591-expect(logger.warn).toHaveBeenNthCalledWith(
1592-3,
1593-"Failed to decrypt fresh post-healthy-sync message",
1594-expect.objectContaining({
1595-eventId: "$enc-fresh-3",
1596-freshAfterHealthySync: true,
1597-postHealthySyncFailureCount: 3,
1598-}),
1599-);
1600-expect(logger.warn).toHaveBeenNthCalledWith(
1592+expectWarnContextFields(logger, 1, "Failed to decrypt fresh post-healthy-sync message", {
1593+eventId: "$enc-fresh-1",
1594+freshAfterHealthySync: true,
1595+postHealthySyncFailureCount: 1,
1596+});
1597+expectWarnContextFields(logger, 2, "Failed to decrypt fresh post-healthy-sync message", {
1598+eventId: "$enc-fresh-2",
1599+freshAfterHealthySync: true,
1600+postHealthySyncFailureCount: 2,
1601+});
1602+expectWarnContextFields(logger, 3, "Failed to decrypt fresh post-healthy-sync message", {
1603+eventId: "$enc-fresh-3",
1604+freshAfterHealthySync: true,
1605+postHealthySyncFailureCount: 3,
1606+});
1607+expectWarnContextFields(
1608+logger,
160116094,
16021610"matrix: repeated fresh encrypted messages are still failing to decrypt after Matrix resumed healthy sync. This device may still be missing new room keys. Check 'openclaw matrix verify status --verbose --account ops' and 'openclaw matrix devices list --account ops'.",
1603-expect.objectContaining({
1611+{
16041612failureCount: 3,
16051613roomCount: 3,
16061614senderCount: 3,
16071615rooms: ["!room-a:example.org", "!room-b:example.org", "!room-c:example.org"],
16081616sampleEventIds: ["$enc-fresh-1", "$enc-fresh-2", "$enc-fresh-3"],
1609-}),
1617+},
16101618);
16111619} finally {
16121620vi.useRealTimers();
@@ -1639,13 +1647,10 @@ describe("registerMatrixMonitorEvents verification routing", () => {
16391647);
1640164816411649expect(logger.warn).toHaveBeenCalledTimes(1);
1642-expect(logger.warn).toHaveBeenCalledWith(
1643-"Failed to decrypt message",
1644-expect.objectContaining({
1645-eventId: "$enc-old",
1646-freshAfterHealthySync: false,
1647-}),
1648-);
1650+expectWarnContextFields(logger, 1, "Failed to decrypt message", {
1651+eventId: "$enc-old",
1652+freshAfterHealthySync: false,
1653+});
1649165416501655healthySyncSinceMs = Date.now();
16511656@@ -1661,15 +1666,11 @@ describe("registerMatrixMonitorEvents verification routing", () => {
16611666new Error("The sender's device has not sent us the keys for this message."),
16621667);
166316681664-expect(logger.warn).toHaveBeenNthCalledWith(
1665-2,
1666-"Failed to decrypt fresh post-healthy-sync message",
1667-expect.objectContaining({
1668-eventId: "$enc-fresh-after-ready",
1669-freshAfterHealthySync: true,
1670-postHealthySyncFailureCount: 1,
1671-}),
1672-);
1669+expectWarnContextFields(logger, 2, "Failed to decrypt fresh post-healthy-sync message", {
1670+eventId: "$enc-fresh-after-ready",
1671+freshAfterHealthySync: true,
1672+postHealthySyncFailureCount: 1,
1673+});
16731674} finally {
16741675vi.useRealTimers();
16751676}
@@ -1708,19 +1709,21 @@ describe("registerMatrixMonitorEvents verification routing", () => {
17081709}
17091710}
171017111711-expect(logger.warn).toHaveBeenNthCalledWith(
1712+expectWarnContextFields(
1713+logger,
171217144,
17131715"matrix: repeated fresh encrypted messages are still failing to decrypt after Matrix resumed healthy sync. This device may still be missing new room keys. Check 'openclaw matrix verify status --verbose --account ops' and 'openclaw matrix devices list --account ops'.",
1714-expect.objectContaining({
1716+{
17151717sampleEventIds: ["$enc-wave-1-1", "$enc-wave-1-2", "$enc-wave-1-3"],
1716-}),
1718+},
17171719);
1718-expect(logger.warn).toHaveBeenNthCalledWith(
1720+expectWarnContextFields(
1721+logger,
171917228,
17201723"matrix: repeated fresh encrypted messages are still failing to decrypt after Matrix resumed healthy sync. This device may still be missing new room keys. Check 'openclaw matrix verify status --verbose --account ops' and 'openclaw matrix devices list --account ops'.",
1721-expect.objectContaining({
1724+{
17221725sampleEventIds: ["$enc-wave-2-1", "$enc-wave-2-2", "$enc-wave-2-3"],
1723-}),
1726+},
17241727);
17251728} finally {
17261729vi.useRealTimers();
@@ -1770,39 +1773,28 @@ describe("registerMatrixMonitorEvents verification routing", () => {
17701773);
17711774}
177217751773-expect(logger.warn).toHaveBeenNthCalledWith(
1774-5,
1775-"Failed to decrypt fresh post-healthy-sync message",
1776-expect.objectContaining({
1777-eventId: "$enc-second-1",
1778-freshAfterHealthySync: true,
1779-postHealthySyncFailureCount: 1,
1780-}),
1781-);
1782-expect(logger.warn).toHaveBeenNthCalledWith(
1783-6,
1784-"Failed to decrypt fresh post-healthy-sync message",
1785-expect.objectContaining({
1786-eventId: "$enc-second-2",
1787-freshAfterHealthySync: true,
1788-postHealthySyncFailureCount: 2,
1789-}),
1790-);
1791-expect(logger.warn).toHaveBeenNthCalledWith(
1792-7,
1793-"Failed to decrypt fresh post-healthy-sync message",
1794-expect.objectContaining({
1795-eventId: "$enc-second-3",
1796-freshAfterHealthySync: true,
1797-postHealthySyncFailureCount: 3,
1798-}),
1799-);
1800-expect(logger.warn).toHaveBeenNthCalledWith(
1776+expectWarnContextFields(logger, 5, "Failed to decrypt fresh post-healthy-sync message", {
1777+eventId: "$enc-second-1",
1778+freshAfterHealthySync: true,
1779+postHealthySyncFailureCount: 1,
1780+});
1781+expectWarnContextFields(logger, 6, "Failed to decrypt fresh post-healthy-sync message", {
1782+eventId: "$enc-second-2",
1783+freshAfterHealthySync: true,
1784+postHealthySyncFailureCount: 2,
1785+});
1786+expectWarnContextFields(logger, 7, "Failed to decrypt fresh post-healthy-sync message", {
1787+eventId: "$enc-second-3",
1788+freshAfterHealthySync: true,
1789+postHealthySyncFailureCount: 3,
1790+});
1791+expectWarnContextFields(
1792+logger,
180117938,
18021794"matrix: repeated fresh encrypted messages are still failing to decrypt after Matrix resumed healthy sync. This device may still be missing new room keys. Check 'openclaw matrix verify status --verbose --account ops' and 'openclaw matrix devices list --account ops'.",
1803-expect.objectContaining({
1795+{
18041796sampleEventIds: ["$enc-second-1", "$enc-second-2", "$enc-second-3"],
1805-}),
1797+},
18061798);
18071799} finally {
18081800vi.useRealTimers();
@@ -1833,14 +1825,11 @@ describe("registerMatrixMonitorEvents verification routing", () => {
18331825).resolves.toBeUndefined();
1834182618351827expect(logger.warn).toHaveBeenCalledTimes(1);
1836-expect(logger.warn).toHaveBeenCalledWith(
1837-"Failed to decrypt message",
1838-expect.objectContaining({
1839-roomId: "!room:example.org",
1840-eventId: "$enc-lookup-fail",
1841-senderMatchesOwnUser: false,
1842-}),
1843-);
1828+expectWarnContextFields(logger, 1, "Failed to decrypt message", {
1829+roomId: "!room:example.org",
1830+eventId: "$enc-lookup-fail",
1831+senderMatchesOwnUser: false,
1832+});
18441833expect(logVerboseMessage).toHaveBeenCalledWith(
18451834"matrix: failed resolving self user id for decrypt warning: Error: lookup failed",
18461835);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。