1
0

feat: release payload disk cache, batched rip status for list, artwork 404, stricter input handling

This commit is contained in:
2026-08-29 18:44:08 +02:00
parent 39c956e67d
commit 56ffda9e88
10 changed files with 116 additions and 11 deletions

View File

@@ -35,7 +35,6 @@ describe('DiscogsClient', () => {
expect(seen[0]).toContain('/database/search')
expect(seen[0]).toContain('barcode=5021592210629')
expect(seen[0]).toContain('type=release')
expect(seen[0]).toContain('token=testtoken')
expect(seenAuth[0]).toBe('Discogs token=testtoken')
expect(results).toHaveLength(2)
expect(results[0]).toEqual({

View File

@@ -9,8 +9,10 @@ import type { FastifyInstance } from 'fastify'
export function testConfig(): Config {
// artworkDir must be a real writable directory (cached images land there)
const artworkDir = mkdtempSync(path.join(tmpdir(), 'rs-art-'))
// dataDir must be a real writable directory (release-cache payloads land there)
const dataDir = mkdtempSync(path.join(tmpdir(), 'rs-data-'))
return {
dataDir: ':memory:',
dataDir,
artworkDir,
dbPath: ':memory:',
port: 0,

View File

@@ -126,6 +126,34 @@ describe('GET /api/lookup/release/:id', () => {
await app.close()
})
it('caches release payloads on disk (second lookup costs no discogs call)', async () => {
let releaseCalls = 0
const { app, cookie } = await appWithToken(
stubFetch((url) => {
if (url.includes('/releases/1001')) {
releaseCalls++
return new Response(JSON.stringify(discogsReleaseFixture), {
status: 200,
headers: { 'content-type': 'application/json' },
})
}
return new Response('nope', { status: 404 })
})
)
await app.inject({ method: 'GET', url: '/api/lookup/release/1001', ...auth(cookie) })
await app.inject({ method: 'GET', url: '/api/lookup/release/1001', ...auth(cookie) })
expect(releaseCalls).toBe(1)
await app.close()
})
it('rejects non-integer release ids with 400', async () => {
const { app, cookie } = await appWithToken(discogsStub())
const res = await app.inject({ method: 'GET', url: '/api/lookup/release/abc', ...auth(cookie) })
expect(res.statusCode).toBe(400)
expect(res.json()).toEqual({ error: 'invalid_input' })
await app.close()
})
it('reports duplicate when release already in collection', async () => {
const { app, cookie } = await appWithToken(discogsStub())
await app.inject({ method: 'POST', url: '/api/collection', ...auth(cookie), payload: { releaseId: 1001 } })

View File

@@ -50,6 +50,14 @@ describe('static serving', () => {
await app.close()
})
it('unknown artwork paths return json 404, not the SPA', async () => {
const app = await build()
const res = await app.inject({ method: 'GET', url: '/artwork/missing.jpg' })
expect(res.statusCode).toBe(404)
expect(res.json()).toEqual({ error: 'not_found' })
await app.close()
})
it('unknown api routes return json 404, not the SPA', async () => {
const app = await build()
const res = await app.inject({ method: 'GET', url: '/api/nope' })