// Two generations from the same form used to collide: the image key was the // request-body hash plus the figure's *position*, and the unique constraint on // (owner, workflow, key) then handed back the first generation's job. The second // deck showed the first deck's picture — and since the decks are not the same // length, on a slide about something else. const test = require('node:test'); const assert = require('node:assert/strict'); const deckBuild = require('../src/utils/deckBuild'); const resourceImages = require('../src/utils/resourceImages'); const deckSchema = require('../src/utils/deckSchema'); // opts.images is the job queue, not the generatedImages module. function recorder() { const keys = []; return { keys, images: { enqueue: async (owner, workflow, input, key) => { keys.push(key); return { jobId: 'job-' + keys.length, status: 'pending' }; } } }; } function deckOf(prompts) { return deckSchema.normalise({ slides: prompts.map((p, i) => ({ type: 'figure', heading: 'Slide ' + i, bullets: ['a'], image_prompt: p })) }); } test('the same form twice, with different figures, makes different jobs', async () => { const a = recorder(); await deckBuild.drawFigures(deckOf(['a neuron diagram', 'a rash photograph']), { owner: 1, body: { topic: 'x' }, subject: 'x', imageModel: 'm', images: a.images }); const b = recorder(); await deckBuild.drawFigures(deckOf(['a completely different airway diagram', 'a bilirubin chart']), { owner: 1, body: { topic: 'x' }, subject: 'x', imageModel: 'm', images: b.images }); assert.equal(a.keys.length, 2); assert.equal(b.keys.length, 2); for (const key of b.keys) { assert.ok(!a.keys.includes(key), 'a second generation must not reuse the first generation\'s key: ' + key); } }); test('the identical figure requested again does dedupe, so a resubmit is not billed twice', async () => { const a = recorder(); const opts = { owner: 1, body: { topic: 'x' }, subject: 'x', imageModel: 'm', images: a.images }; await deckBuild.drawFigures(deckOf(['a neuron diagram']), opts); const b = recorder(); await deckBuild.drawFigures(deckOf(['a neuron diagram']), { ...opts, images: b.images }); assert.deepEqual(a.keys, b.keys, 'same request, same drawing, same key'); }); test('two figures in one deck are still two jobs', async () => { const a = recorder(); await deckBuild.drawFigures(deckOf(['diagram one', 'diagram two']), { owner: 1, body: { topic: 'x' }, subject: 'x', imageModel: 'm', images: a.images }); assert.equal(a.keys.length, 2); assert.notEqual(a.keys[0], a.keys[1]); }); test('the key no longer contains the slide index, which is what collided', async () => { const src = require('fs').readFileSync(require('path').join(__dirname, '..', 'src/utils/deckBuild.js'), 'utf8'); assert.doesNotMatch(src, /requestKey\(opts\.body\) \+ ':' \+ request\.index/); assert.match(src, /Keyed on what is being drawn, not on where it sits/); });