From 5df9fc5cbea71244831be57874be64339bc7cfb5 Mon Sep 17 00:00:00 2001 From: axisrow Date: Mon, 28 Sep 2026 01:09:50 +0800 Subject: [PATCH] test(usage): mock the keychain cache write path in buffer tests Follow-up to the #22 review (PRRT_kwDOUqBlWc6mTGSl): only the read side (statSync) was mocked, so a future full-miss test would write a real marker into the developer's ~/.cache. Mock writeFileSync and mkdirSync like usage-token.test.ts does, and add the miss-branch test: a dump-keychain scan finding nothing must record the keychain-fallback-empty marker and still yield no token. Co-Authored-By: Claude Code --- .../__tests__/usage-token-buffer.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/utils/__tests__/usage-token-buffer.test.ts b/src/utils/__tests__/usage-token-buffer.test.ts index db3970a1f..408aecf13 100644 --- a/src/utils/__tests__/usage-token-buffer.test.ts +++ b/src/utils/__tests__/usage-token-buffer.test.ts @@ -36,6 +36,11 @@ describe('getUsageToken dump-keychain behavior', () => { mockedExecFileSync.mockImplementation(realExecFileSync); vi.spyOn(process, 'platform', 'get').mockReturnValue('darwin'); vi.spyOn(fs, 'statSync').mockImplementation(() => { throw new Error('cache missing'); }); + // The write side of the keychain cache (usage-fetch.ts + // keychain-fallback-empty marker, usage.json cache, lock file) must + // never touch the real ~/.cache during tests. + vi.spyOn(fs, 'mkdirSync').mockReturnValue(undefined); + vi.spyOn(fs, 'writeFileSync').mockReturnValue(undefined); }); afterEach(() => { @@ -90,4 +95,21 @@ describe('getUsageToken dump-keychain behavior', () => { expect(getUsageToken()).toBe('hashed-token'); expect(dumpMaxBuffer).toBe(8 * 1024 * 1024); }); + + it('writes the keychain miss marker when the dump finds no credentials', () => { + const readSpy = vi.spyOn(fs, 'readFileSync').mockImplementation(() => { throw new Error('no files'); }); + const writeSpy = vi.spyOn(fs, 'writeFileSync'); + + mockedExecFileSync.mockImplementation((command: string) => { + if (command === 'security') { + throw new Error('security: item not found'); + } + throw new Error(`Unexpected command: ${command}`); + }); + + expect(getUsageToken()).toBeNull(); + expect(writeSpy).toHaveBeenCalledWith(expect.stringContaining('keychain-fallback-empty'), ''); + expect(writeSpy).not.toHaveBeenCalledWith(expect.stringContaining('usage.lock'), expect.anything()); + readSpy.mockRestore(); + }); });