@@ -2,9 +2,11 @@ const { readFileSync } = require('fs');
22const appRoot = require ( 'app-root-path' ) ;
33const uuid = require ( 'uuid/v4' ) ;
44const config = require ( 'config' ) ;
5- const { testServiceFullTrx } = require ( '../setup' ) ;
5+ const { testContainerFullTrx , testServiceFullTrx } = require ( '../setup' ) ;
66const { sql } = require ( 'slonik' ) ;
77// eslint-disable-next-line import/no-dynamic-require
8+ const { Actor, Config } = require ( appRoot + '/lib/model/frames' ) ;
9+ // eslint-disable-next-line import/no-dynamic-require
810const { withDatabase } = require ( appRoot + '/lib/model/migrate' ) ;
911const testData = require ( '../../data/xml' ) ;
1012const populateUsers = require ( '../fixtures/01-users' ) ;
@@ -14,23 +16,19 @@ const { getFormFields } = require('../../../lib/data/schema');
1416
1517const withTestDatabase = withDatabase ( config . get ( 'test.database' ) ) ;
1618const migrationsDir = appRoot + '/lib/model/migrations' ;
17- const upToMigration = ( toName ) => withTestDatabase ( async ( migrator ) => {
19+ const upToMigration = ( toName , inclusive = true ) => withTestDatabase ( async ( migrator ) => {
1820 await migrator . raw ( 'drop owned by current_user' ) ;
19- // eslint-disable-next-line no-constant-condition
20- while ( true ) {
21+ const migrations = await migrator . migrate . list ( { directory : migrationsDir } ) ;
22+ const pending = migrations [ 1 ] . map ( ( { file } ) => file ) ;
23+ const index = pending . indexOf ( toName ) ;
24+ if ( index === - 1 ) throw new Error ( `Could not find migration ${ toName } ` ) ;
25+ const end = inclusive ? index + 1 : index ;
26+ for ( let i = 0 ; i < end ; i += 1 )
2127 // eslint-disable-next-line no-await-in-loop
2228 await migrator . migrate . up ( { directory : migrationsDir } ) ;
23- // eslint-disable-next-line no-await-in-loop
24- const migrations = await migrator . migrate . list ( { directory : migrationsDir } ) ;
25- const applied = migrations [ 0 ] ;
26- const remaining = migrations [ 1 ] ;
27- if ( toName === applied [ applied . length - 1 ] ) break ;
28- if ( remaining . length === 0 ) {
29- // eslint-disable-next-line no-console
30- console . log ( 'Could not find migration' , toName ) ;
31- break ;
32- }
33- }
29+ // Confirm that the migrations completed as expected.
30+ const [ completed ] = await migrator . migrate . list ( { directory : migrationsDir } ) ;
31+ completed . should . eql ( pending . slice ( 0 , end ) ) ;
3432} ) ;
3533const up = ( ) => withTestDatabase ( ( migrator ) =>
3634 migrator . migrate . up ( { directory : migrationsDir } ) ) ;
@@ -367,3 +365,98 @@ describe('datbase migrations: intermediate form schema', function() {
367365 res . count . should . equal ( 2 ) ; // only 2 schema IDs represented here
368366 } ) ) ;
369367} ) ;
368+
369+ // eslint-disable-next-line func-names, space-before-function-paren
370+ describe ( 'database migrations: 20230123-01-remove-google-backups' , function ( ) {
371+ this . timeout ( 10000 ) ;
372+
373+ beforeEach ( ( ) => upToMigration ( '20230123-01-remove-google-backups.js' , false ) ) ;
374+
375+ it ( 'deletes backups configs' , testContainerFullTrx ( async ( { Configs } ) => {
376+ await Configs . set ( 'backups.main' , { a : 'b' } ) ;
377+ await Configs . set ( 'backups.google' , { c : 'd' } ) ;
378+ await Configs . set ( 'analytics' , { enabled : false } ) ;
379+ await up ( ) ;
380+ ( await Configs . get ( 'backups.main' ) ) . isEmpty ( ) . should . be . true ( ) ;
381+ ( await Configs . get ( 'backups.google' ) ) . isEmpty ( ) . should . be . true ( ) ;
382+ ( await Configs . get ( 'analytics' ) ) . isDefined ( ) . should . be . true ( ) ;
383+ } ) ) ;
384+
385+ describe ( 'backup creation token' , ( ) => {
386+ // Much of this was copied from the old endpoint
387+ // /v1/config/backups/initiate.
388+ const createToken = async ( { Actors, Assignments, Sessions } ) => {
389+ const expiresAt = new Date ( ) ;
390+ expiresAt . setHours ( expiresAt . getHours ( ) + 1 ) ;
391+ const actor = await Actors . create ( new Actor ( {
392+ type : 'singleUse' ,
393+ displayName : 'Backup creation token' ,
394+ expiresAt,
395+ meta : {
396+ keys : { some : 'data' }
397+ }
398+ } ) ) ;
399+ await Assignments . grantSystem ( actor , 'initbkup' , Config . species ) ;
400+ await Sessions . create ( actor ) ;
401+ return actor . id ;
402+ } ;
403+
404+ it ( 'consumes a token' , testContainerFullTrx ( async ( container ) => {
405+ const actorId = await createToken ( container ) ;
406+ const { one } = container ;
407+ const count = ( ) => one ( sql `SELECT
408+ (SELECT count(*) FROM actors WHERE id = ${ actorId } AND "deletedAt" IS NOT NULL) AS "deletedActors",
409+ (SELECT count(*) FROM assignments WHERE "actorId" = ${ actorId } ) AS assignments,
410+ (SELECT count(*) FROM sessions WHERE "actorId" = ${ actorId } ) AS sessions` ) ;
411+ ( await count ( ) ) . should . eql ( {
412+ deletedActors : 0 ,
413+ assignments : 1 ,
414+ sessions : 1
415+ } ) ;
416+ await up ( ) ;
417+ ( await count ( ) ) . should . eql ( {
418+ deletedActors : 1 ,
419+ assignments : 0 ,
420+ sessions : 0
421+ } ) ;
422+ } ) ) ;
423+
424+ it ( 'does not modify other actor data' , testServiceFullTrx ( async ( service , container ) => {
425+ await populateUsers ( container ) ;
426+ await service . login ( 'alice' ) ;
427+ await createToken ( container ) ;
428+ const { one } = container ;
429+ const count = ( ) => one ( sql `SELECT
430+ (SELECT count(*) FROM actors where "deletedAt" is not null) AS "deletedActors",
431+ (SELECT count(*) FROM assignments) AS assignments,
432+ (SELECT count(*) FROM sessions) AS sessions` ) ;
433+ ( await count ( ) ) . should . eql ( {
434+ deletedActors : 0 ,
435+ assignments : 3 ,
436+ sessions : 2
437+ } ) ;
438+ await up ( ) ;
439+ // The counts decrease in the way that we would expect from the previous
440+ // test.
441+ ( await count ( ) ) . should . eql ( {
442+ deletedActors : 1 ,
443+ assignments : 2 ,
444+ sessions : 1
445+ } ) ;
446+ } ) ) ;
447+ } ) ;
448+
449+ it ( 'deletes the role that grants backup.verify' , testContainerFullTrx ( async ( { Roles } ) => {
450+ const rolesBefore = await Roles . getAll ( ) ;
451+ const canVerify = rolesBefore . filter ( ( { verbs } ) =>
452+ verbs . includes ( 'backup.verify' ) ) ;
453+ canVerify . length . should . equal ( 1 ) ;
454+ canVerify [ 0 ] . system . should . equal ( 'initbkup' ) ;
455+ await up ( ) ;
456+ const rolesAfter = await Roles . getAll ( ) ;
457+ const deleted = rolesBefore . filter ( roleBefore =>
458+ ! rolesAfter . some ( roleAfter => roleAfter . id === roleBefore . id ) ) ;
459+ deleted . length . should . equal ( 1 ) ;
460+ deleted [ 0 ] . system . should . equal ( 'initbkup' ) ;
461+ } ) ) ;
462+ } ) ;
0 commit comments