




















@@ -1350,6 +1350,145 @@ describe("createTelegramBot", () => {
13501350}
13511351});
135213521353+it("sends a friendly retry hint when the pairing allowlist store cannot be read", async () => {
1354+loadConfig.mockReturnValue({
1355+channels: { telegram: { dmPolicy: "pairing" } },
1356+});
1357+readChannelAllowFromStore.mockRejectedValueOnce(new Error("store temporarily unavailable"));
1358+upsertChannelPairingRequest.mockClear();
1359+sendMessageSpy.mockClear();
1360+replySpy.mockClear();
1361+1362+createTelegramBot({ token: "tok" });
1363+const handler = getOnHandler("message") as (ctx: Record<string, unknown>) => Promise<void>;
1364+1365+await handler({
1366+message: {
1367+chat: { id: 1234, type: "private" },
1368+text: "hello",
1369+message_id: 9,
1370+date: 1736380800,
1371+from: { id: 123456789, username: "testuser" },
1372+},
1373+me: { username: "openclaw_bot" },
1374+getFile: async () => ({ download: async () => new Uint8Array() }),
1375+});
1376+1377+expect(upsertChannelPairingRequest).not.toHaveBeenCalled();
1378+expect(replySpy).not.toHaveBeenCalled();
1379+expect(sendMessageSpy).toHaveBeenCalledTimes(1);
1380+expect(sendMessageSpy).toHaveBeenCalledWith(
1381+1234,
1382+"⚠️ Couldn't process this message, please try again in a moment.",
1383+expect.objectContaining({
1384+reply_parameters: expect.objectContaining({ message_id: 9 }),
1385+}),
1386+);
1387+});
1388+1389+it("keeps the same private chat usable after a transient pairing store read failure", async () => {
1390+loadConfig.mockReturnValue({
1391+channels: { telegram: { dmPolicy: "pairing" } },
1392+});
1393+readChannelAllowFromStore
1394+.mockRejectedValueOnce(new Error("store temporarily unavailable"))
1395+.mockResolvedValueOnce(["123456789"]);
1396+upsertChannelPairingRequest.mockClear();
1397+sendMessageSpy.mockClear();
1398+replySpy.mockClear();
1399+1400+createTelegramBot({ token: "tok" });
1401+const handler = getOnHandler("message") as (ctx: Record<string, unknown>) => Promise<void>;
1402+1403+const firstMessage = {
1404+chat: { id: 1234, type: "private" },
1405+text: "hello",
1406+date: 1736380800,
1407+message_id: 10,
1408+from: { id: 123456789, username: "testuser" },
1409+};
1410+await handler({
1411+message: firstMessage,
1412+me: { username: "openclaw_bot" },
1413+getFile: async () => ({ download: async () => new Uint8Array() }),
1414+});
1415+await handler({
1416+message: {
1417+ ...firstMessage,
1418+text: "still there?",
1419+date: 1736380801,
1420+message_id: 11,
1421+},
1422+me: { username: "openclaw_bot" },
1423+getFile: async () => ({ download: async () => new Uint8Array() }),
1424+});
1425+1426+expect(readChannelAllowFromStore).toHaveBeenCalledTimes(2);
1427+expect(upsertChannelPairingRequest).not.toHaveBeenCalled();
1428+// First message: failure → retry hint via sendMessageSpy. Second message: success → agent reply via replySpy.
1429+expect(sendMessageSpy).toHaveBeenCalledTimes(1);
1430+expect(sendMessageSpy.mock.calls[0]?.[1]).toMatch(/please try again/i);
1431+expect(replySpy).toHaveBeenCalledTimes(1);
1432+});
1433+1434+it("allows a configured private sender when the pairing allowlist store cannot be read", async () => {
1435+loadConfig.mockReturnValue({
1436+channels: { telegram: { dmPolicy: "pairing", allowFrom: ["123456789"] } },
1437+});
1438+readChannelAllowFromStore.mockRejectedValueOnce(new Error("store temporarily unavailable"));
1439+upsertChannelPairingRequest.mockClear();
1440+sendMessageSpy.mockClear();
1441+replySpy.mockClear();
1442+1443+createTelegramBot({ token: "tok" });
1444+const handler = getOnHandler("message") as (ctx: Record<string, unknown>) => Promise<void>;
1445+1446+await handler({
1447+message: {
1448+chat: { id: 1234, type: "private" },
1449+text: "hello",
1450+date: 1736380800,
1451+from: { id: 123456789, username: "testuser" },
1452+},
1453+me: { username: "openclaw_bot" },
1454+getFile: async () => ({ download: async () => new Uint8Array() }),
1455+});
1456+1457+expect(readChannelAllowFromStore).not.toHaveBeenCalled();
1458+expect(upsertChannelPairingRequest).not.toHaveBeenCalled();
1459+expect(sendMessageSpy).not.toHaveBeenCalled();
1460+expect(replySpy).toHaveBeenCalledTimes(1);
1461+});
1462+1463+it("does not require the pairing allowlist store for open private messages", async () => {
1464+loadConfig.mockReturnValue({
1465+channels: { telegram: { dmPolicy: "open", allowFrom: ["*"] } },
1466+});
1467+readChannelAllowFromStore.mockRejectedValueOnce(new Error("store temporarily unavailable"));
1468+upsertChannelPairingRequest.mockClear();
1469+sendMessageSpy.mockClear();
1470+replySpy.mockClear();
1471+1472+createTelegramBot({ token: "tok" });
1473+const handler = getOnHandler("message") as (ctx: Record<string, unknown>) => Promise<void>;
1474+1475+await handler({
1476+message: {
1477+chat: { id: 1234, type: "private" },
1478+text: "hello",
1479+date: 1736380800,
1480+from: { id: 123456789, username: "testuser" },
1481+},
1482+me: { username: "openclaw_bot" },
1483+getFile: async () => ({ download: async () => new Uint8Array() }),
1484+});
1485+1486+expect(readChannelAllowFromStore).not.toHaveBeenCalled();
1487+expect(upsertChannelPairingRequest).not.toHaveBeenCalled();
1488+expect(sendMessageSpy).not.toHaveBeenCalled();
1489+expect(replySpy).toHaveBeenCalledTimes(1);
1490+});
1491+13531492it("ignores private self-authored message updates instead of issuing a pairing challenge", async () => {
13541493loadConfig.mockReturnValue({
13551494channels: { telegram: { dmPolicy: "pairing" } },
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。