summaryrefslogtreecommitdiffstats
path: root/tests/cache-lock.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cache-lock.test.ts')
-rw-r--r--tests/cache-lock.test.ts141
1 files changed, 141 insertions, 0 deletions
diff --git a/tests/cache-lock.test.ts b/tests/cache-lock.test.ts
new file mode 100644
index 0000000..c67ba01
--- /dev/null
+++ b/tests/cache-lock.test.ts
@@ -0,0 +1,141 @@
+import { test, expect } from 'bun:test';
+import { generateInstanceId } from '../scripts/cache/lock';
+import type { CacheLock } from '../scripts/cache/utils';
+
+test('generateInstanceId returns non-empty string', () => {
+ const id = generateInstanceId();
+ expect(typeof id).toBe('string');
+ expect(id.length).toBeGreaterThan(0);
+});
+
+test('generateInstanceId includes timestamp', () => {
+ const before = Date.now();
+ const id = generateInstanceId();
+ const after = Date.now();
+
+ const timestampPart = id.split('-')[0];
+ const timestamp = parseInt(timestampPart, 10);
+
+ expect(timestamp).toBeGreaterThanOrEqual(before);
+ expect(timestamp).toBeLessThanOrEqual(after);
+});
+
+test('generateInstanceId includes random component', () => {
+ const id1 = generateInstanceId();
+ const id2 = generateInstanceId();
+
+ expect(id1).not.toBe(id2);
+});
+
+test('generateInstanceId format is timestamp-randomstring', () => {
+ const id = generateInstanceId();
+ const parts = id.split('-');
+ expect(parts.length).toBe(2);
+
+ const [timestamp, random] = parts;
+ expect(timestamp).toMatch(/^\d+$/);
+ expect(random).toMatch(/^[a-z0-9]+$/);
+ expect(random.length).toBeGreaterThan(0);
+ expect(random.length).toBeLessThan(10);
+});
+
+// Helper function to test isLockStale logic (since it's private)
+function isLockStale(lock: CacheLock, currentHostname: string): boolean {
+ const lockAge = Date.now() - lock.timestamp;
+ const timeSinceRenewal = lock.renewedAt ? Date.now() - lock.renewedAt : lockAge;
+
+ // Check 1: Timestamp-based staleness (30 minutes)
+ if (timeSinceRenewal > 30 * 60 * 1000) {
+ return true;
+ }
+
+ // Check 2: Process-based staleness (only on same machine)
+ if (lock.hostname === currentHostname) {
+ // For testing, assume process doesn't exist if pid is -1
+ if (lock.pid === -1) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+test('isLockStale returns true for old lock (over 30 minutes)', () => {
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: Date.now() - 31 * 60 * 1000, // 31 minutes ago
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ pid: 12345,
+ hostname: 'test-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(true);
+});
+
+test('isLockStale returns false for recent lock (under 30 minutes)', () => {
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: Date.now() - 29 * 60 * 1000, // 29 minutes ago
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ pid: 12345,
+ hostname: 'test-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(false);
+});
+
+test('isLockStale respects renewedAt timestamp', () => {
+ const now = Date.now();
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: now - 40 * 60 * 1000, // 40 minutes ago
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ renewedAt: now - 10 * 60 * 1000, // Renewed 10 minutes ago
+ pid: 12345,
+ hostname: 'test-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(false);
+});
+
+test('isLockStale returns true when lock on same host but process dead', () => {
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: Date.now() - 10 * 60 * 1000, // 10 minutes ago
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ pid: -1, // Simulate dead process
+ hostname: 'test-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(true);
+});
+
+test('isLockStale returns false when lock on different host (even if old process)', () => {
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: Date.now() - 10 * 60 * 1000,
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ pid: -1,
+ hostname: 'different-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(false);
+});
+
+test('isLockStale handles missing renewedAt', () => {
+ const lock: CacheLock = {
+ locked: true,
+ timestamp: Date.now() - 35 * 60 * 1000, // 35 minutes ago
+ instance: 'test-instance',
+ ttl: 30 * 60 * 1000,
+ pid: 12345,
+ hostname: 'test-host'
+ };
+
+ expect(isLockStale(lock, 'test-host')).toBe(true);
+});