SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
This commit is contained in:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,99 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const { fileWrite } = vi.hoisted(() => ({ fileWrite: vi.fn() }));
|
||||
|
||||
vi.mock('../src/log-file-transport', () => ({
|
||||
getFileTransport: () => ({ write: fileWrite, close: async () => {} }),
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
vi.resetModules();
|
||||
fileWrite.mockClear();
|
||||
});
|
||||
|
||||
async function setup() {
|
||||
vi.stubEnv('SNOWLUMA_LOG_LEVEL', 'trace');
|
||||
vi.stubEnv('SNOWLUMA_LOG_FILE_LEVEL', 'error');
|
||||
vi.stubEnv('SNOWLUMA_TRACE_BUFFER', '100');
|
||||
vi.spyOn(process.stdout, 'write').mockReturnValue(true);
|
||||
vi.spyOn(process.stderr, 'write').mockReturnValue(true);
|
||||
const logger = await import('../src/logger');
|
||||
return { ...logger, log: logger.createLogger('Snapshot') };
|
||||
}
|
||||
|
||||
describe('retained log snapshots', () => {
|
||||
it('returns empty snapshots before any record has been emitted', async () => {
|
||||
const logger = await setup();
|
||||
expect(logger.getRecentLogs()).toEqual([]);
|
||||
expect(logger.getLogSnapshot()).toEqual([]);
|
||||
});
|
||||
|
||||
it('merges wrapped rings in emission order and returns only the requested tail', async () => {
|
||||
const logger = await setup();
|
||||
const emitted: import('../src/logger').LogEntry[] = [];
|
||||
const unsubscribe = logger.subscribeLogs((entry) => emitted.push(entry));
|
||||
|
||||
for (let i = 0; i < 1100; i += 1) {
|
||||
logger.log.info('normal %d', i);
|
||||
logger.log.trace('trace %d', i);
|
||||
}
|
||||
|
||||
unsubscribe();
|
||||
const normal = emitted.filter((entry) => entry.level !== 'trace').slice(-1000);
|
||||
const trace = emitted.filter((entry) => entry.level === 'trace').slice(-100);
|
||||
const expected = [...normal, ...trace].sort((a, b) => a.id - b.id);
|
||||
expect(logger.getLogSnapshot()).toEqual(expected);
|
||||
|
||||
for (const limit of [1, 2, 30, 300, 1000, 1100, 2000, 0, -1, 2.9, NaN, Infinity]) {
|
||||
expect(logger.getRecentLogs(limit)).toEqual(
|
||||
expected.slice(-Math.max(1, Math.trunc(limit))),
|
||||
);
|
||||
}
|
||||
|
||||
expect(logger.getRecentLogs()).toEqual(expected.slice(-300));
|
||||
const snapshot = logger.getRecentLogs(5);
|
||||
snapshot.pop();
|
||||
expect(logger.getRecentLogs(5)).toEqual(expected.slice(-5));
|
||||
});
|
||||
|
||||
it.each(['info', 'trace'] as const)(
|
||||
'reads a tail when only the %s ring has records',
|
||||
async (level) => {
|
||||
const logger = await setup();
|
||||
logger.log[level]('first');
|
||||
logger.log[level]('second');
|
||||
expect(logger.getRecentLogs(1).map((entry) => entry.message)).toEqual(['second']);
|
||||
expect(logger.getLogSnapshot().map((entry) => entry.message)).toEqual([
|
||||
'first',
|
||||
'second',
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it('preserves ID gaps and file routing without publishing file-only entries', async () => {
|
||||
const logger = await setup();
|
||||
vi.stubEnv('SNOWLUMA_LOG_FILE_LEVEL', 'debug');
|
||||
vi.resetModules();
|
||||
const fresh = await import('../src/logger');
|
||||
fresh.setLogLevel('info');
|
||||
const entries: import('../src/logger').LogEntry[] = [];
|
||||
const unsubscribe = fresh.subscribeLogs((entry) => entries.push(entry));
|
||||
const log = fresh.createLogger('FileOnly').child({ uin: 10001 });
|
||||
log.info('before');
|
||||
fresh.runWithRequestId(42, () => log.debug('password=secret file-only\x07'));
|
||||
log.info('after');
|
||||
unsubscribe();
|
||||
|
||||
expect(entries.map((entry) => entry.message)).toEqual(['before', 'after']);
|
||||
expect(entries[1]!.id).toBe(entries[0]!.id + 2);
|
||||
expect(fresh.getLogSnapshot()).toEqual(entries);
|
||||
expect(fileWrite).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/\[req#42\] password=\*\*\* file-only/),
|
||||
10001,
|
||||
);
|
||||
expect(process.stdout.write).toHaveBeenCalledTimes(2);
|
||||
expect(logger.getLogSnapshot()).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user