Spaces:
Sleeping
Sleeping
File size: 4,804 Bytes
05c5ed5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
import { MemoryCache } from "./memory-cache";
describe("MemoryCache", () => {
let cache: MemoryCache;
beforeEach(() => {
cache = new MemoryCache();
});
afterEach(() => {
cache.clear();
});
test("should store and retrieve values", async () => {
await cache.set("key1", "value1");
const value = await cache.get("key1");
expect(value).toBe("value1");
});
test("should return undefined for non-existent keys", async () => {
const value = await cache.get("non-existent");
expect(value).toBeUndefined();
});
test("should respect TTL and expire items", async () => {
vi.useFakeTimers();
try {
await cache.set("expiring", "value", 100); // 100ms TTL
expect(await cache.get("expiring")).toBe("value");
// Advance time past TTL
vi.advanceTimersByTime(101);
expect(await cache.get("expiring")).toBeUndefined();
} finally {
vi.useRealTimers();
}
});
test("should use default TTL when not specified", async () => {
const cache = new MemoryCache();
vi.useFakeTimers();
try {
await cache.set("key", "value"); // Uses default TTL (Infinity)
expect(await cache.get("key")).toBe("value");
// Advance time significantly - should still be there since TTL is Infinity
vi.advanceTimersByTime(100000);
expect(await cache.get("key")).toBe("value");
} finally {
vi.useRealTimers();
}
});
test("should check if a key exists", async () => {
await cache.set("exists", "value");
expect(await cache.has("exists")).toBe(true);
expect(await cache.has("does-not-exist")).toBe(false);
});
test("should delete keys", async () => {
await cache.set("toDelete", "value");
expect(await cache.get("toDelete")).toBe("value");
await cache.delete("toDelete");
expect(await cache.get("toDelete")).toBeUndefined();
});
test("should clear all keys", async () => {
await cache.set("key1", "value1");
await cache.set("key2", "value2");
await cache.clear();
expect(await cache.get("key1")).toBeUndefined();
expect(await cache.get("key2")).toBeUndefined();
});
test("should handle complex values", async () => {
const complexValue = {
nested: {
array: [1, 2, 3],
boolean: true,
},
date: new Date().toISOString(),
};
await cache.set("complex", complexValue);
expect(await cache.get("complex")).toEqual(complexValue);
});
test("should get all valid entries", async () => {
await cache.set("key1", "value1");
await cache.set("key2", "value2");
await cache.set("key3", { nested: "value" });
const allEntries = await cache.getAll();
expect(allEntries.size).toBe(3);
expect(allEntries.get("key1")).toBe("value1");
expect(allEntries.get("key2")).toBe("value2");
expect(allEntries.get("key3")).toEqual({ nested: "value" });
});
test("should return empty map when cache is empty", async () => {
const allEntries = await cache.getAll();
expect(allEntries.size).toBe(0);
});
test("should exclude expired entries from getAll", async () => {
vi.useFakeTimers();
try {
await cache.set("valid", "value1");
await cache.set("expiring", "value2", 100); // 100ms TTL
// Before expiration
let allEntries = await cache.getAll();
expect(allEntries.size).toBe(2);
expect(allEntries.get("valid")).toBe("value1");
expect(allEntries.get("expiring")).toBe("value2");
// After expiration
vi.advanceTimersByTime(101);
allEntries = await cache.getAll();
expect(allEntries.size).toBe(1);
expect(allEntries.get("valid")).toBe("value1");
expect(allEntries.has("expiring")).toBe(false);
} finally {
vi.useRealTimers();
}
});
test("cleanup interval should remove expired items", async () => {
vi.useFakeTimers();
try {
// Create cache with cleanup interval
const cleanupCache = new MemoryCache({
cleanupIntervalMs: 200,
});
// Set item with short TTL
await cleanupCache.set("expire-me", "value", 100);
// Advance time past TTL but before cleanup
vi.advanceTimersByTime(101);
// Item should still be in store but get() will return undefined
expect(await cleanupCache.get("expire-me")).toBeUndefined();
// Advance time to trigger cleanup
vi.advanceTimersByTime(100);
// The sweep should have removed the item from the store
// We'll verify this is working by checking internal implementation
const hasKey = (cleanupCache as any).store.has("expire-me");
expect(hasKey).toBe(false);
} finally {
vi.useRealTimers();
}
});
});
|