109 lines
3.1 KiB
TypeScript
109 lines
3.1 KiB
TypeScript
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { setVerbose } from "./globals.js";
|
|
import { logDebug, logError, logInfo, logSuccess, logWarn } from "./logger.js";
|
|
import { DEFAULT_LOG_DIR, resetLogger, setLoggerOverride } from "./logging.js";
|
|
import type { RuntimeEnv } from "./runtime.js";
|
|
|
|
describe("logger helpers", () => {
|
|
afterEach(() => {
|
|
resetLogger();
|
|
setLoggerOverride(null);
|
|
setVerbose(false);
|
|
});
|
|
|
|
it("formats messages through runtime log/error", () => {
|
|
const log = vi.fn();
|
|
const error = vi.fn();
|
|
const runtime: RuntimeEnv = { log, error, exit: vi.fn() };
|
|
|
|
logInfo("info", runtime);
|
|
logWarn("warn", runtime);
|
|
logSuccess("ok", runtime);
|
|
logError("bad", runtime);
|
|
|
|
expect(log).toHaveBeenCalledTimes(3);
|
|
expect(error).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("only logs debug when verbose is enabled", () => {
|
|
const logVerbose = vi.spyOn(console, "log");
|
|
setVerbose(false);
|
|
logDebug("quiet");
|
|
expect(logVerbose).not.toHaveBeenCalled();
|
|
|
|
setVerbose(true);
|
|
logVerbose.mockClear();
|
|
logDebug("loud");
|
|
expect(logVerbose).toHaveBeenCalled();
|
|
logVerbose.mockRestore();
|
|
});
|
|
|
|
it("writes to configured log file at configured level", () => {
|
|
const logPath = pathForTest();
|
|
cleanup(logPath);
|
|
setLoggerOverride({ level: "info", file: logPath });
|
|
fs.writeFileSync(logPath, "");
|
|
logInfo("hello");
|
|
logDebug("debug-only"); // may be filtered depending on level mapping
|
|
const content = fs.readFileSync(logPath, "utf-8");
|
|
expect(content.length).toBeGreaterThan(0);
|
|
cleanup(logPath);
|
|
});
|
|
|
|
it("filters messages below configured level", () => {
|
|
const logPath = pathForTest();
|
|
cleanup(logPath);
|
|
setLoggerOverride({ level: "warn", file: logPath });
|
|
logInfo("info-only");
|
|
logWarn("warn-only");
|
|
const content = fs.readFileSync(logPath, "utf-8");
|
|
expect(content).toContain("warn-only");
|
|
cleanup(logPath);
|
|
});
|
|
|
|
it("uses daily rolling default log file and prunes old ones", () => {
|
|
resetLogger();
|
|
setLoggerOverride({}); // force defaults regardless of user config
|
|
const today = new Date().toISOString().slice(0, 10);
|
|
const todayPath = path.join(DEFAULT_LOG_DIR, `clawdbot-${today}.log`);
|
|
|
|
// create an old file to be pruned
|
|
const oldPath = path.join(DEFAULT_LOG_DIR, "clawdbot-2000-01-01.log");
|
|
fs.mkdirSync(DEFAULT_LOG_DIR, { recursive: true });
|
|
fs.writeFileSync(oldPath, "old");
|
|
fs.utimesSync(oldPath, new Date(0), new Date(0));
|
|
cleanup(todayPath);
|
|
|
|
logInfo("roll-me");
|
|
|
|
expect(fs.existsSync(todayPath)).toBe(true);
|
|
expect(fs.readFileSync(todayPath, "utf-8")).toContain("roll-me");
|
|
expect(fs.existsSync(oldPath)).toBe(false);
|
|
|
|
cleanup(todayPath);
|
|
});
|
|
});
|
|
|
|
function pathForTest() {
|
|
const file = path.join(
|
|
os.tmpdir(),
|
|
`clawdbot-log-${crypto.randomUUID()}.log`,
|
|
);
|
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
return file;
|
|
}
|
|
|
|
function cleanup(file: string) {
|
|
try {
|
|
fs.rmSync(file, { force: true });
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|