Skip to content

Commit bc14842

Browse files
test: gate symlink assertions on file symlink capability
Co-authored-by: ANIRUDDHA ADAK <[email protected]>
1 parent 5715744 commit bc14842

2 files changed

Lines changed: 35 additions & 25 deletions

File tree

extensions/qqbot/src/engine/utils/file-utils.test.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,18 @@ import * as os from "node:os";
44
import * as path from "node:path";
55
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
66

7-
async function probeFileSymlinkCapability(): Promise<boolean> {
8-
const probeDir = await fs.promises.mkdtemp(
9-
path.join(os.tmpdir(), "openclaw-qqbot-symlink-probe-"),
10-
);
11-
const targetFile = path.join(probeDir, "target.txt");
12-
const linkFile = path.join(probeDir, "link.txt");
7+
async function createSymlinkedFile(targetPath: string, linkPath: string): Promise<boolean> {
138
try {
14-
await fs.promises.writeFile(targetFile, "content");
15-
await fs.promises.symlink(targetFile, linkFile);
9+
await fs.promises.writeFile(targetPath, "image-bytes");
10+
await fs.promises.symlink(targetPath, linkPath, "file");
1611
return true;
1712
} catch {
13+
await fs.promises.rm(linkPath, { force: true });
14+
await fs.promises.rm(targetPath, { force: true });
1815
return false;
19-
} finally {
20-
await fs.promises.rm(probeDir, { recursive: true, force: true });
2116
}
2217
}
2318

24-
const canCreateFileSymlinks = await probeFileSymlinkCapability();
25-
2619
const adapterMocks = vi.hoisted(() => ({
2720
fetchMedia: vi.fn(),
2821
}));
@@ -116,11 +109,12 @@ describe("qqbot file-utils downloadFile", () => {
116109
expect(adapterMocks.fetchMedia).not.toHaveBeenCalled();
117110
});
118111

119-
it.skipIf(!canCreateFileSymlinks)("rejects symlinked local media helpers", async () => {
112+
it("rejects symlinked local media helpers", async ({ skip }) => {
120113
const targetPath = path.join(tempDir, "target.png");
121114
const linkPath = path.join(tempDir, "link.png");
122-
await fs.promises.writeFile(targetPath, "image-bytes");
123-
await fs.promises.symlink(targetPath, linkPath);
115+
if (!(await createSymlinkedFile(targetPath, linkPath))) {
116+
skip("file symlinks are unavailable on this host");
117+
}
124118

125119
expect(checkFileSize(linkPath).ok).toBe(false);
126120
await expect(readFileAsync(linkPath)).rejects.toThrow(/symbolic link|symlink|regular file/i);

extensions/zalo/src/token.test.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ import { describe, expect, it } from "vitest";
66
import { resolveZaloToken } from "./token.js";
77
import type { ZaloConfig } from "./types.js";
88

9+
function createSymlinkedFile(targetPath: string, linkPath: string): boolean {
10+
try {
11+
fs.writeFileSync(targetPath, "file-token\n", "utf8");
12+
fs.symlinkSync(targetPath, linkPath, "file");
13+
return true;
14+
} catch {
15+
fs.rmSync(linkPath, { force: true });
16+
fs.rmSync(targetPath, { force: true });
17+
return false;
18+
}
19+
}
20+
921
describe("resolveZaloToken", () => {
1022
it("falls back to top-level token for non-default accounts without overrides", () => {
1123
const cfg = {
@@ -75,17 +87,21 @@ describe("resolveZaloToken", () => {
7587
expect(res.source).toBe("config");
7688
});
7789

78-
it.runIf(process.platform !== "win32")("rejects symlinked token files", () => {
90+
it("rejects symlinked token files", ({ skip }) => {
7991
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-zalo-token-"));
80-
const tokenFile = path.join(dir, "token.txt");
81-
const tokenLink = path.join(dir, "token-link.txt");
82-
fs.writeFileSync(tokenFile, "file-token\n", "utf8");
83-
fs.symlinkSync(tokenFile, tokenLink);
92+
try {
93+
const tokenFile = path.join(dir, "token.txt");
94+
const tokenLink = path.join(dir, "token-link.txt");
95+
if (!createSymlinkedFile(tokenFile, tokenLink)) {
96+
skip("file symlinks are unavailable on this host");
97+
}
8498

85-
const cfg = {
86-
tokenFile: tokenLink,
87-
} as ZaloConfig;
88-
expect(() => resolveZaloToken(cfg)).toThrow(/Zalo token file.*must not be a symlink/);
89-
fs.rmSync(dir, { recursive: true, force: true });
99+
const cfg = {
100+
tokenFile: tokenLink,
101+
} as ZaloConfig;
102+
expect(() => resolveZaloToken(cfg)).toThrow(/Zalo token file.*must not be a symlink/);
103+
} finally {
104+
fs.rmSync(dir, { recursive: true, force: true });
105+
}
90106
});
91107
});

0 commit comments

Comments
 (0)