Files
usenet-indexer/tests/functional/releases_api.spec.ts
T
Daan MeijerandClaude Opus 5.5 fde1e6cc90 Rebuild: NZBs from the chunk store, and a catalog search
lib/nzb (buildNzb, parseNzb) from the current app; NzbService builds a
release's NZB from its chunks; GET /api/v1/releases?q= (every word of the
name) and GET /api/v1/releases/:id/nzb behind the api guard. A test stores
a batch, finds the release and reads its NZB back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 02:33:27 +02:00

49 lines
2.8 KiB
TypeScript

import { test } from '@japa/runner'
import db from '@adonisjs/lucid/services/db'
import testUtils from '@adonisjs/core/services/test_utils'
import User from '#models/user'
import BatchStore from '#services/batch_store'
import { RangeIndexer } from '#lib/edge/index'
import { parseNzb } from '#lib/nzb/index'
import { DEFAULT_RULES } from '#lib/rules/index'
import type { Overview } from '#lib/nntp/index'
const GROUP = 'alt.binaries.test'
function file(name: string, counter: string, parts: number, at: number): Overview[] {
return Array.from({ length: parts }, (_, i) => [at + i, {
'subject': `${counter} - "${name}" yEnc (${i + 1}/${parts})`, 'from': 'p <p@x>', 'date': 'Mon, 05 Oct 2026 10:00:00 +0000',
'message-id': `<${name}-${i + 1}@test>`, ':bytes': String(700000 + i), 'xref': `news.example ${GROUP}:${at + i}`,
}] as Overview)
}
test.group('Releases API', (group) => {
group.each.setup(() => testUtils.db().withGlobalTransaction())
test('finds a release by the words of its name and builds its NZB from the chunk store', async ({ client, assert }) => {
const [g] = await db.table('groups').insert({ name: GROUP, priority: 1 }).returning('id')
const [n] = await db.table('nodes').insert({ name: 'api-node' }).returning('id')
const [r] = await db.table('ranges').insert({ group_id: g.id, start_id: 1, end_id: 1000, next_id: 1, status: 'leased', node_id: n.id }).returning('id')
const indexer = new RangeIndexer({ group: GROUP, start: 1, end: 1000, rules: { ...DEFAULT_RULES, samplePercent: 0, droppedSignatures: [], priorities: { [GROUP]: 1 } } })
indexer.add([...file('Some.Show.S01E01.1080p.WEB.part1.rar', 'Some.Show.S01E01 [1/2]', 3, 100), ...file('Some.Show.S01E01.1080p.WEB.par2', 'Some.Show.S01E01 [2/2]', 1, 200)], 1001)
indexer.finish()
await BatchStore.store(Number(r.id), Number(n.id), indexer.take())
const user = await User.create({ email: 'u@example.invalid', password: 'secret-password' })
const token = (await User.accessTokens.create(user)).value!.release()
;(await client.get('/api/v1/releases?q=show s01e01')).assertStatus(401)
const found = await client.get('/api/v1/releases?q=show s01e01').bearerToken(token)
found.assertStatus(200)
const releases = (found.body() as { releases: { id: number; name: string }[] }).releases
assert.lengthOf(releases, 1)
const nzb = await client.get(`/api/v1/releases/${releases[0].id}/nzb`).bearerToken(token)
nzb.assertStatus(200)
assert.include(nzb.header('content-type'), 'application/x-nzb')
const parsed = parseNzb(nzb.text())!
assert.equal(parsed.meta.name, releases[0].name)
assert.deepEqual(parsed.files.map((f) => f.segments.length), [1, 3])
assert.equal(parsed.files[1].segments[2].id, 'Some.Show.S01E01.1080p.WEB.part1.rar-3@test')
})
})