Skip to content

Commit fca4f0f

Browse files
committed
fix(usage): improve storage test coverage and streamline atomic write
1 parent cb505dd commit fca4f0f

2 files changed

Lines changed: 21 additions & 18 deletions

File tree

source/usage/storage.spec.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,9 @@ test('writeUsageData handles write errors gracefully', t => {
355355
process.env.XDG_DATA_HOME || path.join(os.tmpdir(), 'test-data');
356356
const configDir = path.join(dataHome, 'nanocoder');
357357

358-
// Make directory if needed, then make it read-only
359-
fs.mkdirSync(configDir, {recursive: true});
360-
fs.chmodSync(configDir, 0o444);
358+
// Create a file where directory is expected to cause cross-platform write failure
359+
fs.rmSync(configDir, {recursive: true, force: true});
360+
fs.writeFileSync(configDir, 'not-a-directory', 'utf-8');
361361

362362
const mockData: UsageData = {
363363
sessions: [],
@@ -369,8 +369,8 @@ test('writeUsageData handles write errors gracefully', t => {
369369
// Should not throw
370370
t.notThrows(() => writeUsageData(mockData));
371371

372-
// Restore permissions for cleanup
373-
fs.chmodSync(configDir, 0o755);
372+
// Cleanup
373+
fs.rmSync(configDir, {force: true});
374374
});
375375

376376
// ============================================================================
@@ -670,6 +670,20 @@ test('clearUsageData handles non-existent file', t => {
670670
t.notThrows(() => clearUsageData());
671671
});
672672

673+
test('clearUsageData handles unlink errors gracefully', t => {
674+
const dataHome =
675+
process.env.XDG_DATA_HOME || path.join(os.tmpdir(), 'test-data');
676+
const usagePath = path.join(dataHome, 'nanocoder', 'usage.json');
677+
678+
fs.mkdirSync(usagePath, {recursive: true});
679+
680+
// Should not throw when attempting to unlink a directory
681+
t.notThrows(() => clearUsageData());
682+
683+
// Cleanup directory
684+
fs.rmSync(usagePath, {recursive: true, force: true});
685+
});
686+
673687
test('clearUsageData is idempotent', async t => {
674688
// Add and clear data
675689
await addSession(createMockSession());

source/usage/storage.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,8 @@ export function readUsageData(): UsageData {
120120
*/
121121
function atomicWriteFileSync(filePath: string, data: string): void {
122122
const tmpPath = `${filePath}.${crypto.randomUUID()}.tmp`;
123-
try {
124-
fs.writeFileSync(tmpPath, data, 'utf-8');
125-
fs.renameSync(tmpPath, filePath);
126-
} catch (error) {
127-
try {
128-
if (fs.existsSync(tmpPath)) {
129-
fs.unlinkSync(tmpPath);
130-
}
131-
} catch {
132-
// Ignore cleanup errors
133-
}
134-
throw error;
135-
}
123+
fs.writeFileSync(tmpPath, data, 'utf-8');
124+
fs.renameSync(tmpPath, filePath);
136125
}
137126

138127
/** Serializes read-modify-write of usage.json to prevent lost updates from concurrent session completion */

0 commit comments

Comments
 (0)