repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
scripts/codegen/pi-ext-debug.test.ts
Rawimport {
chmodSync,
existsSync,
lstatSync,
mkdirSync,
mkdtempSync,
readdirSync,
readFileSync,
rmSync,
symlinkSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { sandboxEnv, withProcessEnv } from "../../test/harness";
// The template's own slug placeholder is the extension name under test.
const slug = "{{extension-slug}}";
const enable = `PI_${slug.toUpperCase().replaceAll("-", "_")}_DEBUG`;
const posix = process.platform !== "win32";
let root: string | undefined;
afterEach(() => {
if (root) rmSync(root, { recursive: true, force: true });
root = undefined;
vi.resetModules();
});
function sandbox() {
root = mkdtempSync(join(tmpdir(), "pi-ext-debug-"));
const env = sandboxEnv(root, { env: { [enable]: "1" } });
const directory = join(root, ".test-state", "pi-ext", "debug", slug);
return { env, state: join(root, ".test-state"), directory };
}
/** Load a fresh template copy, log one event and one span, then close. */
function logOnce(env: NodeJS.ProcessEnv) {
return withProcessEnv(env, async () => {
vi.resetModules();
const { defineDebug } = await import("./templates/pi-ext-debug.ts");
const { dbg, span, closeDebug } = defineDebug({
events: ["session.start"],
spans: ["request"],
fields: { count: "number" },
} as const);
expect(() => {
dbg?.("session.start", { count: 1 });
span?.("request")("finish", { count: 2 });
}).not.toThrow();
closeDebug();
});
}
const records = (directory: string) =>
readdirSync(directory).flatMap((file) =>
readFileSync(join(directory, file), "utf8")
.trim()
.split("\n")
.map((line) => JSON.parse(line)),
);
describe("pi-ext-debug template directories", () => {
it("creates missing private directories and a private file", async () => {
const { env, directory } = sandbox();
await logOnce(env);
expect(records(directory).map((record) => record.event)).toEqual([
"session.start",
"request.start",
"request.finish",
]);
if (posix) {
for (const part of [
join(directory, "..", ".."),
join(directory, ".."),
directory,
])
expect(lstatSync(part).mode & 0o777).toBe(0o700);
const [file] = readdirSync(directory);
expect(lstatSync(join(directory, file)).mode & 0o777).toBe(0o600);
}
});
it("reuses existing private directories for a new file", async () => {
const { env, directory } = sandbox();
await logOnce(env);
await logOnce(env);
expect(readdirSync(directory)).toHaveLength(2);
expect(records(directory)).toHaveLength(6);
});
it.runIf(posix)("refuses a directory readable by others", async () => {
const { env, state, directory } = sandbox();
mkdirSync(join(state, "pi-ext"), { recursive: true, mode: 0o700 });
chmodSync(join(state, "pi-ext"), 0o755);
await logOnce(env);
expect(existsSync(directory)).toBe(false);
});
it.runIf(posix)("refuses a symlinked extension directory", async () => {
const { env, state, directory } = sandbox();
const target = join(state, "elsewhere");
mkdirSync(target, { recursive: true, mode: 0o700 });
mkdirSync(join(directory, ".."), { recursive: true, mode: 0o700 });
chmodSync(join(state, "pi-ext"), 0o700);
symlinkSync(target, directory);
await logOnce(env);
expect(readdirSync(target)).toEqual([]);
});
});