Files
vue-seo-layer/tests/lru.test.ts
Jakub Zych e3baa7028c feat: redirect and 410 enforcement, X-Robots-Tag and the resolve cache
- the Nitro middleware answers redirect (301/302, Location from the answer
  only, same-site targets as paths as in v0.1.1) and gone (410) before the
  render and the route cache, sets X-Robots-Tag, and answers 404 for a
  pagination.invalid answer; other not_found answers stay with Nuxt
- resolve answers cached in an LRU (seo.resolveCacheTtl, default 60 s,
  1000 entries) with in-flight de-duplication; a clear detaches loads in
  flight so no answer fetched before a purge is stored after it
- the playground route-caches /blog/** (swr 300)
2026-11-04 09:20:20 +01:00

106 lines
3.8 KiB
TypeScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { createLru } from '../server/lib/lru.ts'
function clock(start = 1000) {
let t = start
return { now: () => t, advance: (ms: number) => (t += ms) }
}
test('lru: get answers a value within its TTL and nothing after it', () => {
const c = clock()
const lru = createLru<string>({ max: 10, ttlMs: 60_000, now: c.now })
lru.set('/a', 'A')
assert.equal(lru.get('/a'), 'A')
c.advance(59_999)
assert.equal(lru.get('/a'), 'A')
c.advance(1)
assert.equal(lru.get('/a'), undefined)
assert.equal(lru.size, 0)
})
test('lru: the least recently used entry goes first when full', () => {
const lru = createLru<number>({ max: 2, ttlMs: 60_000 })
lru.set('a', 1)
lru.set('b', 2)
assert.equal(lru.get('a'), 1) // a is now the most recent
lru.set('c', 3)
assert.equal(lru.get('b'), undefined)
assert.equal(lru.get('a'), 1)
assert.equal(lru.get('c'), 3)
assert.equal(lru.size, 2)
})
test('lru: load calls the loader once for concurrent requests of one key', async () => {
const lru = createLru<string>({ max: 10, ttlMs: 60_000 })
let calls = 0
let release: (v: string) => void = () => {}
const loader = () => {
calls++
return new Promise<string>((r) => (release = r))
}
const one = lru.load('/x', loader)
const two = lru.load('/x', loader)
release('X')
assert.deepEqual(await Promise.all([one, two]), ['X', 'X'])
assert.equal(calls, 1)
assert.equal(await lru.load('/x', loader), 'X')
assert.equal(calls, 1, 'a cached value needs no call')
})
test('lru: a value the cacheable test refuses is not stored, and a failed load is not cached', async () => {
const lru = createLru<string | null>({ max: 10, ttlMs: 60_000 })
let calls = 0
await lru.load('/n', async () => (calls++, null), (v) => v !== null)
await lru.load('/n', async () => (calls++, null), (v) => v !== null)
assert.equal(calls, 2)
await assert.rejects(lru.load('/e', async () => Promise.reject(new Error('down'))))
assert.equal(await lru.load('/e', async () => 'ok'), 'ok')
})
test('lru: clear empties the cache and an answer started before it is never stored', async () => {
const lru = createLru<string>({ max: 10, ttlMs: 60_000 })
let release: (v: string) => void = () => {}
const stale = lru.load('/p', () => new Promise<string>((r) => (release = r)))
lru.clear()
release('stale')
assert.equal(await stale, 'stale', 'the request in flight still gets its answer')
assert.equal(lru.get('/p'), undefined, 'but it is not cached after the purge')
let calls = 0
assert.equal(await lru.load('/p', async () => (calls++, 'fresh')), 'fresh')
assert.equal(calls, 1)
})
test('lru: a load after clear does not join a load started before it', async () => {
const lru = createLru<string>({ max: 10, ttlMs: 60_000 })
let releaseOld: (v: string) => void = () => {}
const old = lru.load('/q', () => new Promise<string>((r) => (releaseOld = r)))
lru.clear()
const fresh = lru.load('/q', async () => 'new')
releaseOld('old')
assert.equal(await old, 'old')
assert.equal(await fresh, 'new')
assert.equal(lru.get('/q'), 'new')
})
test('lru: ttl 0 caches nothing but still shares a load in flight', async () => {
const lru = createLru<string>({ max: 10, ttlMs: 0 })
let calls = 0
const loader = async () => (calls++, 'v')
await Promise.all([lru.load('/z', loader), lru.load('/z', loader)])
assert.equal(calls, 1)
await lru.load('/z', loader)
assert.equal(calls, 2)
lru.set('/z', 'w')
assert.equal(lru.get('/z'), undefined)
})
test('lru: a loader that throws at once rejects and leaves nothing in flight', async () => {
const lru = createLru<string>({ max: 10, ttlMs: 60_000 })
const boom = (() => {
throw new Error('sync')
}) as unknown as () => Promise<string>
await assert.rejects(lru.load('/s', boom), /sync/)
assert.equal(await lru.load('/s', async () => 'after'), 'after')
})