Each release chunk is a release inserted once: release_key the SHA-1 of the identity, the owner group and the first article (deterministic; no numbering under a group lock), identity_key the identity's SHA-1 bytes, poster_id and group_set_id through catalog_refs (cached per process), source as a code (weak-stem added), the name into release_texts. A finished release's candidates are claimable at once; a provisional tail release is finished by a later chunk of its key, a finished one sent again is left alone. Gone: joins into earlier releases and across groups, key numbering, the group lock, the fragment merger. Interim: chunks, counts and samples keyed by ranges.block_id, a range without a block gets one. Readers follow: search (posters and group_sets joined, words through release_texts, posters by id, source by code), the par2 merger, the sidecar folder, the judge's scraped rule, the spot inspector, the spotter, the NZB service, releases:regroup, edge:bench. Tests insert fixtures through tests/functional/helpers/releases.ts; the suites pass again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
44 lines
2.9 KiB
TypeScript
44 lines
2.9 KiB
TypeScript
import { test } from '@japa/runner'
|
|
import db from '@adonisjs/lucid/services/db'
|
|
import testUtils from '@adonisjs/core/services/test_utils'
|
|
import { Prober } from '#services/prober'
|
|
import { insertRelease } from '#tests/functional/helpers/releases'
|
|
|
|
test.group('Prober', (group) => {
|
|
group.each.setup(() => testUtils.db().withGlobalTransaction())
|
|
|
|
test('a claim takes each tier: the readable tiers also take unreadable candidates, a kind with only one of them too', async ({ assert }) => {
|
|
const row = { id: await insertRelease({ release_key: 'pb'.padEnd(40, '0'), identity_key: 'pb'.padEnd(40, '0'), name: 'pb', source: 'subject', groups: '[]', files: 3 }) }
|
|
const candidate = (kind: string, unreadable: boolean, ready = true) => ({
|
|
release_id: row.id, kind, message_id: `<${kind}-${unreadable}-${ready}@x>`, file: kind, ready, unreadable,
|
|
})
|
|
// One per kind, so each tier's id range is a single id (the slices' starts aren't random then).
|
|
await db.table('probe_candidates').multiInsert([candidate('lone', true), candidate('par2', true), candidate('archive', false), candidate('7z-tail', false, false)])
|
|
|
|
const prober = new Prober() as any
|
|
await prober.claimTiers()
|
|
assert.sameMembers(prober.queue.map((c: { kind: string }) => c.kind), ['lone', 'par2', 'archive'])
|
|
const status = Object.fromEntries((await db.from('probe_candidates').select('kind', 'status')).map((c) => [c.kind, c.status]))
|
|
assert.deepEqual(status, { 'lone': 'taken', 'par2': 'taken', 'archive': 'taken', '7z-tail': 'waiting' })
|
|
})
|
|
|
|
test('a flush stores a name with a NUL in it, and one article that two releases have as a candidate', async ({ assert }) => {
|
|
const release = async (key: string) =>
|
|
insertRelease({ release_key: key.padEnd(40, '0'), identity_key: key.padEnd(40, '0'), name: key, source: 'subject', groups: '[]', files: 1 })
|
|
const a = await release('fa')
|
|
const b = await release('fb')
|
|
const candidate = async (releaseId: number) =>
|
|
Number((await db.table('probe_candidates').insert({ release_id: releaseId, kind: 'archive', message_id: '<same@x>', file: 'x.rar', status: 'taken' }).returning('id'))[0].id)
|
|
const inspection = { yencName: 'x.rar', size: 1000, type: null, names: ['Movie\u0000.mkv'], entries: 1, passworded: false }
|
|
const prober = new Prober() as any
|
|
for (const releaseId of [a, b]) {
|
|
prober.outcomes.push({ candidate: { id: await candidate(releaseId), releaseId, kind: 'archive', messageId: '<same@x>' }, status: 'done', inspection })
|
|
}
|
|
await prober.flush()
|
|
assert.deepEqual((await db.from('probe_candidates').select('status')).map((c) => c.status), ['done', 'done'])
|
|
const cached = await db.from('probe_cache').where('message_id', '<same@x>').firstOrFail()
|
|
assert.deepEqual(cached.result.names, ['Movie.mkv'])
|
|
assert.equal((await db.from('release_inspections').count('* as n'))[0].n, '2')
|
|
})
|
|
})
|