


























@@ -0,0 +1,130 @@
1+import fs from "node:fs/promises";
2+import os from "node:os";
3+import path from "node:path";
4+import { afterEach, describe, expect, it, vi } from "vitest";
5+import {
6+deleteCachedTelegramBotInfo,
7+readCachedTelegramBotInfo,
8+resolveTelegramBotInfoCachePath,
9+TELEGRAM_BOT_INFO_CACHE_MAX_AGE_MS,
10+writeCachedTelegramBotInfo,
11+} from "./bot-info-cache.js";
12+import type { TelegramBotInfo } from "./bot-info.js";
13+14+const tempRoots: string[] = [];
15+16+const botInfo: TelegramBotInfo = {
17+id: 123456,
18+is_bot: true,
19+first_name: "OpenClaw",
20+username: "openclaw_bot",
21+can_join_groups: true,
22+can_read_all_group_messages: false,
23+can_manage_bots: false,
24+supports_inline_queries: false,
25+can_connect_to_business: false,
26+has_main_web_app: false,
27+has_topics_enabled: false,
28+allows_users_to_create_topics: false,
29+};
30+31+async function useTempStateDir(): Promise<NodeJS.ProcessEnv> {
32+const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-tg-bot-info-"));
33+tempRoots.push(stateDir);
34+return { ...process.env, OPENCLAW_STATE_DIR: stateDir };
35+}
36+37+afterEach(async () => {
38+vi.unstubAllEnvs();
39+await Promise.all(
40+tempRoots.splice(0).map((root) => fs.rm(root, { recursive: true, force: true })),
41+);
42+});
43+44+describe("Telegram bot info cache", () => {
45+it("reads botInfo for the same account and bot token", async () => {
46+const env = await useTempStateDir();
47+48+await writeCachedTelegramBotInfo({
49+accountId: "ops",
50+botToken: "123456:secret",
51+ botInfo,
52+ env,
53+});
54+55+await expect(
56+readCachedTelegramBotInfo({ accountId: "ops", botToken: "123456:secret", env }),
57+).resolves.toMatchObject({ botInfo });
58+});
59+60+it("ignores botInfo written for a different token fingerprint", async () => {
61+const env = await useTempStateDir();
62+63+await writeCachedTelegramBotInfo({
64+accountId: "ops",
65+botToken: "123456:old-secret",
66+ botInfo,
67+ env,
68+});
69+70+await expect(
71+readCachedTelegramBotInfo({ accountId: "ops", botToken: "123456:new-secret", env }),
72+).resolves.toBeNull();
73+});
74+75+it("treats stale botInfo as a cache miss", async () => {
76+const env = await useTempStateDir();
77+78+await writeCachedTelegramBotInfo({
79+accountId: "ops",
80+botToken: "123456:secret",
81+ botInfo,
82+ env,
83+});
84+85+await expect(
86+readCachedTelegramBotInfo({
87+accountId: "ops",
88+botToken: "123456:secret",
89+ env,
90+now: new Date(Date.now() + TELEGRAM_BOT_INFO_CACHE_MAX_AGE_MS + 1),
91+}),
92+).resolves.toBeNull();
93+});
94+95+it("deletes cached botInfo for an account", async () => {
96+const env = await useTempStateDir();
97+98+await writeCachedTelegramBotInfo({
99+accountId: "ops",
100+botToken: "123456:secret",
101+ botInfo,
102+ env,
103+});
104+await deleteCachedTelegramBotInfo({ accountId: "ops", env });
105+106+await expect(
107+readCachedTelegramBotInfo({ accountId: "ops", botToken: "123456:secret", env }),
108+).resolves.toBeNull();
109+});
110+111+it("treats malformed persisted botInfo as a cache miss", async () => {
112+const env = await useTempStateDir();
113+const filePath = resolveTelegramBotInfoCachePath("ops", env);
114+await fs.mkdir(path.dirname(filePath), { recursive: true });
115+await fs.writeFile(
116+filePath,
117+JSON.stringify({
118+version: 1,
119+tokenFingerprint: "not-the-token",
120+fetchedAt: new Date().toISOString(),
121+botInfo: { id: 123456, is_bot: true },
122+}),
123+"utf8",
124+);
125+126+await expect(
127+readCachedTelegramBotInfo({ accountId: "ops", botToken: "123456:secret", env }),
128+).resolves.toBeNull();
129+});
130+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。