-
-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Description
Both storage implementations (inMemoryStore
and fileStore
) lack unit tests. These are critical components that handle OAuth token persistence and need comprehensive test coverage.
What needs to be done
Create unit tests for both storage implementations covering:
For inMemoryStore
:
- All CRUD operations (get, set, delete, clear)
- Verify isolation between different keys
- Test null/undefined handling
- Verify memory is actually cleared
For fileStore
:
- All CRUD operations with file system
- Missing file scenarios (first run)
- Invalid JSON in existing file
- File permission errors
- Concurrent access scenarios
- Directory creation
- File path edge cases
Why this matters
Token storage is security-critical:
- Lost tokens force users to re-authenticate
- Corrupted storage could expose partial tokens
- Race conditions could mix tokens between users
- Storage bugs could leak tokens in logs or temp files
Implementation considerations
-
Test isolation: How do we ensure tests don't interfere with each other's file system state? Should we use temp directories?
-
Mock vs Integration: Should we mock the file system or test against real files? Both approaches have merits.
-
Alternative approach: Consider property-based testing (e.g., fast-check) to find edge cases automatically
-
Performance testing: Should we test performance characteristics? (e.g., how many tokens can be stored before slowdown)
-
Security testing: Should we verify tokens are not logged or exposed in error messages?
Test structure suggestion
// src/storage/memory.test.ts
import { expect, test, describe, beforeEach } from "bun:test";
import { inMemoryStore } from "./memory";
describe("inMemoryStore", () => {
let store: TokenStore;
beforeEach(() => {
store = inMemoryStore();
});
test("should return null for non-existent keys", async () => {
const result = await store.get("non-existent");
expect(result).toBeNull();
});
test("should store and retrieve tokens", async () => {
const tokens = {
access_token: "access123",
refresh_token: "refresh456",
expires_at: new Date(Date.now() + 3600000).toISOString()
};
await store.set("test-key", tokens);
const retrieved = await store.get("test-key");
expect(retrieved).toEqual(tokens);
});
test("should handle concurrent operations", async () => {
// Test race conditions...
});
});
// src/storage/file.test.ts
import { expect, test, describe, beforeEach, afterEach } from "bun:test";
import { fileStore } from "./file";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
describe("fileStore", () => {
let tempDir: string;
let store: TokenStore;
beforeEach(async () => {
tempDir = await mkdtemp(join(tmpdir(), "oauth-test-"));
store = fileStore(join(tempDir, "tokens.json"));
});
afterEach(async () => {
await rm(tempDir, { recursive: true, force: true });
});
// ... tests
});
Edge cases to test
- Unicode characters in keys/values
- Very large tokens
- Deeply nested token objects
- Circular references (should these be handled?)
- Storage quota exceeded
- File system full
- Read-only file system
- Symbolic links
- Network file systems
Skills required
- TypeScript
- Testing with Bun
- File system operations
- Async/await patterns
- Test isolation techniques
Difficulty
Easy - Good for learning the codebase and testing practices