mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
test: add database migration tests
This commit is contained in:
parent
d0e461e206
commit
02504690cf
23
package-lock.json
generated
23
package-lock.json
generated
@ -9798,6 +9798,10 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/migrations-test": {
|
||||||
|
"resolved": "tools/migrations-test",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/mime": {
|
"node_modules/mime": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
@ -13728,7 +13732,6 @@
|
|||||||
"version": "17.7.2",
|
"version": "17.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cliui": "^8.0.1",
|
"cliui": "^8.0.1",
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
@ -14102,7 +14105,8 @@
|
|||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
"winston": "^3.9.0",
|
"winston": "^3.9.0",
|
||||||
"winston-daily-rotate-file": "^4.7.1"
|
"winston-daily-rotate-file": "^4.7.1",
|
||||||
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.5.3",
|
"@types/node": "^20.5.3",
|
||||||
@ -14399,6 +14403,21 @@
|
|||||||
"js-levenshtein": "^1.1.6",
|
"js-levenshtein": "^1.1.6",
|
||||||
"yaml": "^2.4.5"
|
"yaml": "^2.4.5"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tools/migrations-test": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^12.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tools/migrations-test/node_modules/commander": {
|
||||||
|
"version": "12.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
||||||
|
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,8 @@
|
|||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
"winston": "^3.9.0",
|
"winston": "^3.9.0",
|
||||||
"winston-daily-rotate-file": "^4.7.1"
|
"winston-daily-rotate-file": "^4.7.1",
|
||||||
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.5.3",
|
"@types/node": "^20.5.3",
|
||||||
|
@ -311,6 +311,12 @@ const install = async ({ services, app, useapi }) => {
|
|||||||
|
|
||||||
const { SUService } = require('./services/SUService');
|
const { SUService } = require('./services/SUService');
|
||||||
services.registerService('su', SUService);
|
services.registerService('su', SUService);
|
||||||
|
|
||||||
|
const { ShutdownService } = require('./services/ShutdownService');
|
||||||
|
services.registerService('shutdown', ShutdownService);
|
||||||
|
|
||||||
|
const { BootScriptService } = require('./services/BootScriptService');
|
||||||
|
services.registerService('boot-script', BootScriptService);
|
||||||
}
|
}
|
||||||
|
|
||||||
const install_legacy = async ({ services }) => {
|
const install_legacy = async ({ services }) => {
|
||||||
|
@ -20,6 +20,9 @@ const { AdvancedBase } = require("@heyputer/puter-js-common");
|
|||||||
const { Context } = require('./util/context');
|
const { Context } = require('./util/context');
|
||||||
const BaseService = require("./services/BaseService");
|
const BaseService = require("./services/BaseService");
|
||||||
const useapi = require('useapi');
|
const useapi = require('useapi');
|
||||||
|
const yargs = require('yargs/yargs')
|
||||||
|
const { hideBin } = require('yargs/helpers')
|
||||||
|
|
||||||
|
|
||||||
class Kernel extends AdvancedBase {
|
class Kernel extends AdvancedBase {
|
||||||
constructor ({ entry_path } = {}) {
|
constructor ({ entry_path } = {}) {
|
||||||
@ -67,7 +70,9 @@ class Kernel extends AdvancedBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boot () {
|
boot () {
|
||||||
this._runtime_init();
|
const args = yargs(hideBin(process.argv)).argv
|
||||||
|
|
||||||
|
this._runtime_init({ args });
|
||||||
|
|
||||||
// const express = require('express')
|
// const express = require('express')
|
||||||
// const app = express();
|
// const app = express();
|
||||||
@ -111,6 +116,7 @@ class Kernel extends AdvancedBase {
|
|||||||
services,
|
services,
|
||||||
config,
|
config,
|
||||||
logger: this.bootLogger,
|
logger: this.bootLogger,
|
||||||
|
args,
|
||||||
}, 'app');
|
}, 'app');
|
||||||
globalThis.root_context = root_context;
|
globalThis.root_context = root_context;
|
||||||
|
|
||||||
|
42
src/backend/src/services/BootScriptService.js
Normal file
42
src/backend/src/services/BootScriptService.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const { Context } = require("../util/context");
|
||||||
|
const BaseService = require("./BaseService");
|
||||||
|
|
||||||
|
class BootScriptService extends BaseService {
|
||||||
|
static MODULES = {
|
||||||
|
fs: require('fs'),
|
||||||
|
}
|
||||||
|
async ['__on_boot.ready'] () {
|
||||||
|
const args = Context.get('args');
|
||||||
|
if ( ! args['boot-script'] ) return;
|
||||||
|
const script_name = args['boot-script'];
|
||||||
|
|
||||||
|
const require = this.require;
|
||||||
|
const fs = require('fs');
|
||||||
|
const boot_json_raw = fs.readFileSync(script_name, 'utf8');
|
||||||
|
const boot_json = JSON.parse(boot_json_raw);
|
||||||
|
await this.run_script(boot_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
async run_script (boot_json) {
|
||||||
|
const scope = {
|
||||||
|
runner: 'boot-script',
|
||||||
|
['end-puter-process']: ({ args }) => {
|
||||||
|
const svc_shutdown = this.services.get('shutdown');
|
||||||
|
svc_shutdown.shutdown(args[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( let i=0 ; i < boot_json.length ; i++ ) {
|
||||||
|
const statement = boot_json[i];
|
||||||
|
const [cmd, ...args] = statement;
|
||||||
|
if ( ! scope[cmd] ) {
|
||||||
|
throw new Error(`Unknown command: ${cmd}`);
|
||||||
|
}
|
||||||
|
await scope[cmd]({ scope, args });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
BootScriptService
|
||||||
|
};
|
11
src/backend/src/services/ShutdownService.js
Normal file
11
src/backend/src/services/ShutdownService.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const BaseService = require("./BaseService");
|
||||||
|
|
||||||
|
class ShutdownService extends BaseService {
|
||||||
|
shutdown ({ reason, code } = {}) {
|
||||||
|
this.log.info(`Puter is shutting down: ${reason ?? 'no reason provided'}`);
|
||||||
|
process.stdout.write('\x1B[0m\r\n');
|
||||||
|
process.exit(code ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { ShutdownService };
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
const { es_import_promise } = require("../../fun/dev-console-ui-utils");
|
const { es_import_promise } = require("../../fun/dev-console-ui-utils");
|
||||||
const { surrounding_box } = require("../../fun/dev-console-ui-utils");
|
const { surrounding_box } = require("../../fun/dev-console-ui-utils");
|
||||||
|
const { Context } = require("../../util/context");
|
||||||
const { CompositeError } = require("../../util/errorutil");
|
const { CompositeError } = require("../../util/errorutil");
|
||||||
const structutil = require("../../util/structutil");
|
const structutil = require("../../util/structutil");
|
||||||
const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService");
|
const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService");
|
||||||
@ -44,7 +45,14 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
|||||||
this.db = new Database(this.config.path);
|
this.db = new Database(this.config.path);
|
||||||
|
|
||||||
// Database upgrade logic
|
// Database upgrade logic
|
||||||
const TARGET_VERSION = 24;
|
const HIGHEST_VERSION = 24;
|
||||||
|
const TARGET_VERSION = (() => {
|
||||||
|
const args = Context.get('args');
|
||||||
|
if ( args['database-target-version'] ) {
|
||||||
|
return parseInt(args['database-target-version']);
|
||||||
|
}
|
||||||
|
return HIGHEST_VERSION;
|
||||||
|
})();
|
||||||
|
|
||||||
const [{ user_version }] = do_setup
|
const [{ user_version }] = do_setup
|
||||||
? [{ user_version: -1 }]
|
? [{ user_version: -1 }]
|
||||||
@ -53,105 +61,93 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
|||||||
|
|
||||||
const upgrade_files = [];
|
const upgrade_files = [];
|
||||||
|
|
||||||
if ( user_version === -1 ) {
|
const available_migrations = [
|
||||||
upgrade_files.push('0001_create-tables.sql');
|
[-1, [
|
||||||
upgrade_files.push('0002_add-default-apps.sql');
|
'0001_create-tables.sql',
|
||||||
}
|
'0002_add-default-apps.sql',
|
||||||
|
]],
|
||||||
|
[0, [
|
||||||
|
'0003_user-permissions.sql',
|
||||||
|
]],
|
||||||
|
[1, [
|
||||||
|
'0004_sessions.sql',
|
||||||
|
]],
|
||||||
|
[2, [
|
||||||
|
'0005_background-apps.sql',
|
||||||
|
]],
|
||||||
|
[3, [
|
||||||
|
'0006_update-apps.sql',
|
||||||
|
]],
|
||||||
|
[4, [
|
||||||
|
'0007_sessions.sql',
|
||||||
|
]],
|
||||||
|
[5, [
|
||||||
|
'0008_otp.sql',
|
||||||
|
]],
|
||||||
|
[6, [
|
||||||
|
'0009_app-prefix-fix.sql',
|
||||||
|
]],
|
||||||
|
[7, [
|
||||||
|
'0010_add-git-app.sql',
|
||||||
|
]],
|
||||||
|
[8, [
|
||||||
|
'0011_notification.sql',
|
||||||
|
]],
|
||||||
|
[9, [
|
||||||
|
'0012_appmetadata.sql',
|
||||||
|
]],
|
||||||
|
[10, [
|
||||||
|
'0013_protected-apps.sql',
|
||||||
|
]],
|
||||||
|
[11, [
|
||||||
|
'0014_share.sql',
|
||||||
|
]],
|
||||||
|
[12, [
|
||||||
|
'0015_group.sql',
|
||||||
|
]],
|
||||||
|
[13, [
|
||||||
|
'0016_group-permissions.sql',
|
||||||
|
]],
|
||||||
|
[14, [
|
||||||
|
'0017_publicdirs.sql',
|
||||||
|
]],
|
||||||
|
[15, [
|
||||||
|
'0018_fix-0003.sql',
|
||||||
|
]],
|
||||||
|
[16, [
|
||||||
|
'0019_fix-0016.sql',
|
||||||
|
]],
|
||||||
|
[17, [
|
||||||
|
'0020_dev-center.sql',
|
||||||
|
]],
|
||||||
|
[18, [
|
||||||
|
'0021_app-owner-id.sql',
|
||||||
|
]],
|
||||||
|
[19, [
|
||||||
|
'0022_dev-center-max.sql',
|
||||||
|
]],
|
||||||
|
[20, [
|
||||||
|
'0023_fix-kv.sql',
|
||||||
|
]],
|
||||||
|
[21, [
|
||||||
|
'0024_default-groups.sql',
|
||||||
|
]],
|
||||||
|
[22, [
|
||||||
|
'0025_system-user.dbmig.js',
|
||||||
|
]],
|
||||||
|
[23, [
|
||||||
|
'0026_user-groups.dbmig.js',
|
||||||
|
]],
|
||||||
|
];
|
||||||
|
|
||||||
if ( user_version <= 0 ) {
|
for ( const [v_lt_or_eq, files] of available_migrations ) {
|
||||||
upgrade_files.push('0003_user-permissions.sql');
|
if ( v_lt_or_eq + 1 >= TARGET_VERSION && TARGET_VERSION !== HIGHEST_VERSION ) {
|
||||||
|
this.log.noticeme(`Early exit: target version set to ${TARGET_VERSION}`);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if ( user_version <= v_lt_or_eq ) {
|
||||||
if ( user_version <= 1 ) {
|
upgrade_files.push(...files);
|
||||||
upgrade_files.push('0004_sessions.sql');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( user_version <= 2 ) {
|
|
||||||
upgrade_files.push('0005_background-apps.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 3 ) {
|
|
||||||
upgrade_files.push('0006_update-apps.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 4 ) {
|
|
||||||
upgrade_files.push('0007_sessions.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 5 ) {
|
|
||||||
upgrade_files.push('0008_otp.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 6 ) {
|
|
||||||
upgrade_files.push('0009_app-prefix-fix.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 7 ) {
|
|
||||||
upgrade_files.push('0010_add-git-app.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 8 ) {
|
|
||||||
upgrade_files.push('0011_notification.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 9 ) {
|
|
||||||
upgrade_files.push('0012_appmetadata.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 10 ) {
|
|
||||||
upgrade_files.push('0013_protected-apps.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 11 ) {
|
|
||||||
upgrade_files.push('0014_share.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 12 ) {
|
|
||||||
upgrade_files.push('0015_group.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 13 ) {
|
|
||||||
upgrade_files.push('0016_group-permissions.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 14 ) {
|
|
||||||
upgrade_files.push('0017_publicdirs.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 15 ) {
|
|
||||||
upgrade_files.push('0018_fix-0003.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 16 ) {
|
|
||||||
upgrade_files.push('0019_fix-0016.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 17 ) {
|
|
||||||
upgrade_files.push('0020_dev-center.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 18 ) {
|
|
||||||
upgrade_files.push('0021_app-owner-id.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 19 ) {
|
|
||||||
upgrade_files.push('0022_dev-center-max.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 20 ) {
|
|
||||||
upgrade_files.push('0023_fix-kv.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 21 ) {
|
|
||||||
upgrade_files.push('0024_default-groups.sql');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 22 ) {
|
|
||||||
upgrade_files.push('0025_system-user.dbmig.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_version <= 23 ) {
|
|
||||||
upgrade_files.push('0026_user-groups.dbmig.js');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( upgrade_files.length > 0 ) {
|
if ( upgrade_files.length > 0 ) {
|
||||||
|
@ -28,6 +28,7 @@ const { generate_identifier } = require('../../util/identifier.js');
|
|||||||
const { stringify_log_entry } = require('./LogService.js');
|
const { stringify_log_entry } = require('./LogService.js');
|
||||||
const BaseService = require('../BaseService.js');
|
const BaseService = require('../BaseService.js');
|
||||||
const { split_lines } = require('../../util/stdioutil.js');
|
const { split_lines } = require('../../util/stdioutil.js');
|
||||||
|
const { Context } = require('../../util/context.js');
|
||||||
|
|
||||||
class AlarmService extends BaseService {
|
class AlarmService extends BaseService {
|
||||||
async _construct () {
|
async _construct () {
|
||||||
@ -251,6 +252,15 @@ class AlarmService extends BaseService {
|
|||||||
svc_devConsole.add_widget(this.alarm_widget);
|
svc_devConsole.add_widget(this.alarm_widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const args = Context.get('args');
|
||||||
|
if ( args['quit-on-alarm'] ) {
|
||||||
|
const svc_shutdown = this.services.get('shutdown');
|
||||||
|
svc_shutdown.shutdown({
|
||||||
|
reason: '--quit-on-alarm is set',
|
||||||
|
code: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ( alarm.no_alert ) return;
|
if ( alarm.no_alert ) return;
|
||||||
|
|
||||||
const severity = alarm.severity ?? 'critical';
|
const severity = alarm.severity ?? 'critical';
|
||||||
|
139
tools/migrations-test/main.js
Normal file
139
tools/migrations-test/main.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
const path_ = require('node:path');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const { spawnSync } = require('node:child_process');
|
||||||
|
const prompt = require('prompt-sync')({sigint: true});
|
||||||
|
|
||||||
|
const ind_str = () => Array(ind).fill(' --').join('');
|
||||||
|
|
||||||
|
let ind = 0;
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
// log with unicode warning symbols in yellow
|
||||||
|
warn: (msg) => {
|
||||||
|
console.log(`\x1b[33;1m[!]${ind_str()} ${msg}\x1b[0m`);
|
||||||
|
},
|
||||||
|
crit: (msg) => {
|
||||||
|
console.log(`\x1b[31;1m[!]${ind_str()} ${msg}\x1b[0m`);
|
||||||
|
},
|
||||||
|
info: (msg) => {
|
||||||
|
console.log(`\x1B[36;1m[i]\x1B[0m${ind_str()} ${msg}`);
|
||||||
|
},
|
||||||
|
named: (name, value) => {
|
||||||
|
console.log(`\x1B[36;1m[i]${ind_str()} ${name}\x1B[0m ${value}`);
|
||||||
|
},
|
||||||
|
error: e => {
|
||||||
|
if ( e instanceof UserError ) {
|
||||||
|
log.crit(e.message);
|
||||||
|
} else {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
indent () { ind++; },
|
||||||
|
dedent () { ind--; },
|
||||||
|
heading (title) {
|
||||||
|
const circle = '🔵';
|
||||||
|
console.log(`\n\x1b[36;1m${circle} ${title} ${circle}\x1b[0m`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const areyousure = (message, options = {}) => {
|
||||||
|
const { crit } = options;
|
||||||
|
const logfn = crit ? log.crit : log.warn;
|
||||||
|
|
||||||
|
logfn(message);
|
||||||
|
const answer = prompt(`\x1B[35;1m[?]\x1B[0m ${ options?.prompt ?? 'Are you sure?' } (y/n): `);
|
||||||
|
if ( answer !== 'y' ) {
|
||||||
|
|
||||||
|
if ( options.fail_hint ) {
|
||||||
|
log.info(options.fail_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\x1B[31;21;1mAborted.\x1B[0m`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! fs.existsSync('.is_puter_repository') ) {
|
||||||
|
throw new Error('This script must be run from the root of a puter repository');
|
||||||
|
}
|
||||||
|
|
||||||
|
areyousure(
|
||||||
|
'This script will delete all data in the database. Are you sure you want to proceed?',
|
||||||
|
{ crit: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
let backup_created = false;
|
||||||
|
|
||||||
|
const DBPATH = 'volatile/runtime/puter-database.sqlite';
|
||||||
|
const delete_db = () => {
|
||||||
|
if ( ! fs.existsSync(DBPATH) ) {
|
||||||
|
log.info('No database file to remove');
|
||||||
|
// no need to create a backup if the database doesn't exist
|
||||||
|
backup_created = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( ! backup_created ) {
|
||||||
|
log.info(`Creating a backup of the database...`);
|
||||||
|
const RANDOM = Math.floor(Math.random() * 1000000);
|
||||||
|
const DATE = new Date().toISOString().replace(/:/g, '-');
|
||||||
|
fs.renameSync(DBPATH, `${DBPATH}_${DATE}_${RANDOM}.bak`);
|
||||||
|
backup_created = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info('Removing database file');
|
||||||
|
fs.unlinkSync(DBPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pwd = process.cwd();
|
||||||
|
const boot_script_path = path_.join(pwd, 'tools/migrations-test/noop.puter.json');
|
||||||
|
|
||||||
|
const launch_puter = (args) => {
|
||||||
|
const ret = spawnSync(
|
||||||
|
'node',
|
||||||
|
['tools/run-selfhosted.js', ...args],
|
||||||
|
{
|
||||||
|
stdio: 'inherit',
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
NO_VAR_RUNTIME: '1',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ret.ok = ret.status === 0;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
delete_db();
|
||||||
|
log.info(`Test case: fresh install`);
|
||||||
|
if ( ! launch_puter([
|
||||||
|
'--quit-on-alarm',
|
||||||
|
`--boot-script=${boot_script_path}`,
|
||||||
|
]).ok ) {
|
||||||
|
log.crit('Migration to v21 raised alarm');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
delete_db();
|
||||||
|
log.info(`Test case: migrate to 21, then migrate to 24`);
|
||||||
|
if ( ! launch_puter([
|
||||||
|
`--database-target-version=21`,
|
||||||
|
'--quit-on-alarm',
|
||||||
|
`--boot-script=${boot_script_path}`,
|
||||||
|
]).ok ) {
|
||||||
|
log.crit('Migration to v21 raised alarm');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if ( ! launch_puter([
|
||||||
|
`--database-target-version=24`,
|
||||||
|
'--quit-on-alarm',
|
||||||
|
`--boot-script=${boot_script_path}`,
|
||||||
|
]).ok ) {
|
||||||
|
log.crit('Migration to v24 raised alarm');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('No migration scripts produced any obvious errors.');
|
||||||
|
log.warn('This is not a substitute for release candidate migration testing!');
|
3
tools/migrations-test/noop.puter.json
Normal file
3
tools/migrations-test/noop.puter.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
["end-puter-process", { "reason": "migrations test" }]
|
||||||
|
]
|
15
tools/migrations-test/package.json
Normal file
15
tools/migrations-test/package.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "migrations-test",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^12.1.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user