readCacheRoutes.test.ts 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import { mkdtempSync } from 'node:fs'
  2. import { tmpdir } from 'node:os'
  3. import { join } from 'node:path'
  4. import request from 'supertest'
  5. import { afterEach, describe, expect, it } from 'vitest'
  6. import { createApplication, type ApplicationRuntime } from '../../src/server/app.js'
  7. import type { ServerConfig } from '../../src/server/config.js'
  8. const runtimes: ApplicationRuntime[] = []
  9. afterEach(() => { for (const runtime of runtimes.splice(0)) runtime.close() })
  10. describe('authenticated read cache routes', () => {
  11. it('hits cached reads, honors fresh reads and never bypasses logout authentication', async () => {
  12. const home = mkdtempSync(join(tmpdir(), 'yaoyao-read-cache-routes-'))
  13. const config: ServerConfig = { host: '127.0.0.1', port: 8800, upstream: new URL('http://127.0.0.1:19119'),
  14. allowedHosts: new Set(), home, mediaRoot: home, attachmentsRoot: home, imagesRoot: home, mediaOwner: 'test',
  15. allowInsecureLan: false, insecureLan: false, production: false }
  16. let sessionReads = 0, statusReads = 0, currentTitle = 'original'
  17. const runtime = createApplication({ config, fetchImpl: (async (input, init) => {
  18. const path = new URL(String(input)).pathname
  19. if (path === '/api/status') { statusReads++; return Response.json({ auth_required: false }) }
  20. if (path === '/api/profiles' || path === '/api/plugins/yaoyao/profiles') return Response.json({ profiles: [{ name: 'default', is_default: true }] })
  21. if (path === '/api/sessions' && (init?.method ?? 'GET') === 'GET') { sessionReads++; return Response.json({ sessions: [{ id: 'one', title: currentTitle }] }) }
  22. if (path === '/api/sessions/one' && init?.method === 'PATCH') { currentTitle = 'renamed'; return Response.json({ ok: true }) }
  23. return Response.json({ ok: true })
  24. }) as typeof fetch })
  25. runtimes.push(runtime)
  26. const agent = request.agent(runtime.app.callback()), origin = 'http://127.0.0.1:8800'
  27. const start = await agent.get('/api/app/bootstrap').set('Host', '127.0.0.1:8800').expect(200)
  28. const login = await agent.post('/api/app/login').set('Host', '127.0.0.1:8800').set('Origin', origin)
  29. .set('X-CSRF-Token', start.body.csrfToken).send({ username: 'admin', password: 'admin' }).expect(200)
  30. await agent.put('/api/app/account/credentials').set('Host', '127.0.0.1:8800').set('Origin', origin)
  31. .set('X-CSRF-Token', login.body.csrfToken).send({ currentPassword: 'admin', newPassword: 'fixture-password', username: 'owner' }).expect(200)
  32. const statusBefore = statusReads
  33. const first = await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').expect(200)
  34. const statusAfterColdRead = statusReads
  35. const second = await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').expect(200)
  36. expect(second.body).toEqual(first.body)
  37. expect(sessionReads).toBe(1)
  38. expect(statusAfterColdRead - statusBefore).toBeLessThanOrEqual(1)
  39. expect(statusReads).toBe(statusAfterColdRead)
  40. currentTitle = 'external-change'
  41. const fresh = await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').set('X-Yaoyao-Cache', 'bypass').expect(200)
  42. expect(fresh.body.sessions[0].title).toBe('external-change')
  43. const after = await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').expect(200)
  44. expect(after.body.sessions[0].title).toBe('external-change')
  45. expect(sessionReads).toBe(3)
  46. await agent.patch('/api/sessions/one').set('Host', '127.0.0.1:8800').send({ title: 'renamed' }).expect(200)
  47. const renamed = await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').expect(200)
  48. expect(renamed.body.sessions[0].title).toBe('renamed')
  49. expect(sessionReads).toBe(4)
  50. await agent.post('/auth/logout').set('Host', '127.0.0.1:8800').send({}).expect(200)
  51. await agent.get('/api/sessions').set('Host', '127.0.0.1:8800').expect(401)
  52. expect(sessionReads).toBe(4)
  53. })
  54. })