From e09478549ae88ba5119b0de22ec5b3b4ed2c32cf Mon Sep 17 00:00:00 2001 From: Kathleen Tuite Date: Wed, 18 Sep 2024 12:39:09 -0700 Subject: [PATCH] test of migration --- ...240914-02-remove-orphaned-client-audits.js | 2 + test/integration/other/migrations.js | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js index 6be9365cf..9dd633a71 100644 --- a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js +++ b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js @@ -16,6 +16,8 @@ const up = (db) => db.raw(` DELETE FROM client_audits WHERE "blobId" NOT IN ( SELECT "blobId" FROM submission_attachments + WHERE "blobId" IS NOT NULL + AND "isClientAudit" IS true ); `); diff --git a/test/integration/other/migrations.js b/test/integration/other/migrations.js index 4ed27339a..8b6354a4e 100644 --- a/test/integration/other/migrations.js +++ b/test/integration/other/migrations.js @@ -4,8 +4,11 @@ const uuid = require('uuid').v4; const config = require('config'); const { testContainerFullTrx, testServiceFullTrx } = require('../setup'); const { sql } = require('slonik'); +const { createReadStream } = require('fs'); const { Actor, Config } = require(appRoot + '/lib/model/frames'); const { withDatabase } = require(appRoot + '/lib/model/migrate'); +const { exhaust } = require(appRoot + '/lib/worker/worker'); + const testData = require('../../data/xml'); const populateUsers = require('../fixtures/01-users'); const populateForms = require('../fixtures/02-forms'); @@ -988,3 +991,75 @@ testMigration('20240215-02-dedupe-verbs.js', () => { for (const { verbs } of roles) verbs.should.eql([...new Set(verbs)]); })); }); + +testMigration('20240914-02-remove-orphaned-client-audits.js', () => { + it('should remove orphaned client audits', testServiceFullTrx(async (service, container) => { + await populateUsers(container); + await populateForms(container); + + const asAlice = await service.login('alice'); + + await asAlice.post('/v1/projects/1/forms?publish=true') + .send(testData.forms.clientAudits) + .expect(200); + + // Send the submission with the client audit attachment + await asAlice.post('/v1/projects/1/submission') + .set('X-OpenRosa-Version', '1.0') + .attach('audit.csv', createReadStream(appRoot + '/test/data/audit.csv'), { filename: 'audit.csv' }) + .attach('xml_submission_file', Buffer.from(testData.instances.clientAudits.one), { filename: 'data.xml' }) + .expect(201); + + await asAlice.post('/v1/projects/1/submission') + .set('X-OpenRosa-Version', '1.0') + .attach('log.csv', createReadStream(appRoot + '/test/data/audit2.csv'), { filename: 'log.csv' }) + .attach('xml_submission_file', Buffer.from(testData.instances.clientAudits.two), { filename: 'data.xml' }) + .expect(201); + + await exhaust(container); + + // there should be 8 total rows (5 + 3) + let numClientAudits = await container.oneFirst(sql`select count(*) from client_audits`); + numClientAudits.should.equal(8); + + // there should be 2 blobs + let blobCount = await container.oneFirst(sql`select count(*) from blobs`); + blobCount.should.equal(2); + + // delete one of the submissions + await asAlice.delete('/v1/projects/1/forms/audits/submissions/one') + .expect(200); + + // simulate purge without client audit purge + await container.run(sql`delete from submissions + where submissions."deletedAt" is not null`); + + // purge unattached blobs (will not purge any because one is still referenced) + await container.Blobs.purgeUnattached(true); + + // blobs count should still be 2 + blobCount = await container.oneFirst(sql`select count(*) from blobs`); + blobCount.should.equal(2); + + // client audits still equals 8 after purge (3 orphaned) + numClientAudits = await container.oneFirst(sql`select count(*) from client_audits`); + numClientAudits.should.equal(8); + + // clean up orphaned client audits + await up(); + + numClientAudits = await container.oneFirst(sql`select count(*) from client_audits`); + numClientAudits.should.equal(3); + + // blob count will still be two + blobCount = await container.oneFirst(sql`select count(*) from blobs`); + blobCount.should.equal(2); + + // but next run of purging unattached blobs will purge one + await container.Blobs.purgeUnattached(true); + + // blobs count should finally be 1 + blobCount = await container.oneFirst(sql`select count(*) from blobs`); + blobCount.should.equal(1); + })); +});