|
|
@@ -23,11 +23,14 @@ test('checks Maildir access with Dovecot mail worker uid instead of container ro
|
|
|
assert.doesNotMatch(scriptSource, /trap .*rm -f -- \"\$probe\"/);
|
|
|
});
|
|
|
|
|
|
-test('runs the Maildir migration without consuming the SSH heredoc stdin', () => {
|
|
|
+test('keeps the Maildir migration as an explicit deployment option', () => {
|
|
|
+ assert.match(scriptSource, /run_maildir_migration="\$\{MAILHUB_DEPLOY_RUN_MAILDIR_MIGRATION:-0\}"/);
|
|
|
+ assert.match(scriptSource, /if \[\[ "\$\{run_maildir_migration\}" == "1" \]\]; then/);
|
|
|
assert.match(
|
|
|
scriptSource,
|
|
|
/docker compose run --rm --no-deps -T app <\/dev\/null node scripts\/migrate-sqlite-maildir\.js/
|
|
|
);
|
|
|
+ assert.match(scriptSource, /Skipping Maildir migration check; set MAILHUB_DEPLOY_RUN_MAILDIR_MIGRATION=1 to run it\./);
|
|
|
});
|
|
|
|
|
|
test('isolates runtime probes and setup scripts from the SSH heredoc stdin', () => {
|
|
|
@@ -76,24 +79,41 @@ test('continues after remote tools actively consume their stdin', { skip: !canRu
|
|
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
|
const events = readEvents(fixture.logFile);
|
|
|
- assert.ok(events.includes('migrate'), events.join('\n'));
|
|
|
+ assert.equal(events.includes('migrate'), false, events.join('\n'));
|
|
|
assert.ok(events.includes('sync:1'), events.join('\n'));
|
|
|
assert.equal(events.at(-1), 'final:ps', events.join('\n'));
|
|
|
});
|
|
|
|
|
|
-test('prepares the certificate and Dovecot image before entering the maintenance window', { skip: !canRun }, (t) => {
|
|
|
+test('skips the Maildir migration maintenance window by default', { skip: !canRun }, (t) => {
|
|
|
const fixture = createFixture(t);
|
|
|
const result = runDeploy(fixture);
|
|
|
|
|
|
+ assert.equal(result.status, 0, result.stderr);
|
|
|
+ const events = readEvents(fixture.logFile);
|
|
|
+ const offlineSync = events.indexOf('sync:0');
|
|
|
+ const pull = events.indexOf('pull:dovecot');
|
|
|
+ const up = events.indexOf('up');
|
|
|
+ assert.equal(events.includes('stop:app,dovecot'), false, events.join('\n'));
|
|
|
+ assert.equal(events.includes('migrate'), false, events.join('\n'));
|
|
|
+ assert.ok(offlineSync >= 0 && offlineSync < up, events.join('\n'));
|
|
|
+ assert.ok(pull >= 0 && pull < up, events.join('\n'));
|
|
|
+});
|
|
|
+
|
|
|
+test('runs the opt-in Maildir migration without consuming the SSH heredoc stdin', { skip: !canRun }, (t) => {
|
|
|
+ const fixture = createFixture(t);
|
|
|
+ const result = runDeploy(fixture, { runMaildirMigration: '1' });
|
|
|
+
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
|
const events = readEvents(fixture.logFile);
|
|
|
const offlineSync = events.indexOf('sync:0');
|
|
|
const pull = events.indexOf('pull:dovecot');
|
|
|
const stop = events.indexOf('stop:app,dovecot');
|
|
|
+ const migrate = events.indexOf('migrate');
|
|
|
const up = events.indexOf('up');
|
|
|
assert.ok(offlineSync >= 0 && offlineSync < stop, events.join('\n'));
|
|
|
assert.ok(pull >= 0 && pull < stop, events.join('\n'));
|
|
|
- assert.ok(stop < up, events.join('\n'));
|
|
|
+ assert.ok(stop >= 0 && stop < migrate, events.join('\n'));
|
|
|
+ assert.ok(migrate >= 0 && migrate < up, events.join('\n'));
|
|
|
});
|
|
|
|
|
|
test('reports the previous revision when deployment fails', { skip: !canRun }, (t) => {
|
|
|
@@ -116,7 +136,7 @@ test('reports the previous revision when deployment fails', { skip: !canRun }, (
|
|
|
|
|
|
test('stops the app for migration and restarts the previous container if migration fails', { skip: !canRun }, (t) => {
|
|
|
const fixture = createFixture(t);
|
|
|
- const result = runDeploy(fixture, { migrationStatus: '23' });
|
|
|
+ const result = runDeploy(fixture, { migrationStatus: '23', runMaildirMigration: '1' });
|
|
|
|
|
|
assert.equal(result.status, 23);
|
|
|
assert.match(result.stderr, /Restarting the pre-migration MailHub mail services\./);
|
|
|
@@ -133,7 +153,7 @@ test('stops the app for migration and restarts the previous container if migrati
|
|
|
|
|
|
test('keeps the maintenance window explicit after cutover health checks fail', { skip: !canRun }, (t) => {
|
|
|
const fixture = createFixture(t);
|
|
|
- const result = runDeploy(fixture, { runtimeStatus: '29' });
|
|
|
+ const result = runDeploy(fixture, { runtimeStatus: '29', runMaildirMigration: '1' });
|
|
|
|
|
|
assert.notEqual(result.status, 0);
|
|
|
assert.match(result.stderr, /Maildir cutover is already committed; legacy mail services will not be restarted/);
|
|
|
@@ -253,7 +273,10 @@ exit 0
|
|
|
return { root, fakeBin, remoteDir, logFile };
|
|
|
}
|
|
|
|
|
|
-function runDeploy(fixture, { syncStatus = '0', migrationStatus = '0', runtimeStatus = '0' } = {}) {
|
|
|
+function runDeploy(
|
|
|
+ fixture,
|
|
|
+ { syncStatus = '0', migrationStatus = '0', runtimeStatus = '0', runMaildirMigration = '0' } = {}
|
|
|
+) {
|
|
|
return spawnSync('bash', [scriptPath], {
|
|
|
cwd: fixture.root,
|
|
|
encoding: 'utf8',
|
|
|
@@ -268,7 +291,8 @@ function runDeploy(fixture, { syncStatus = '0', migrationStatus = '0', runtimeSt
|
|
|
MAILHUB_DEPLOY_TEST_REMOTE_DIR: fixture.remoteDir,
|
|
|
MAILHUB_DEPLOY_TEST_SYNC_STATUS: syncStatus,
|
|
|
MAILHUB_DEPLOY_TEST_MIGRATION_STATUS: migrationStatus,
|
|
|
- MAILHUB_DEPLOY_TEST_RUNTIME_STATUS: runtimeStatus
|
|
|
+ MAILHUB_DEPLOY_TEST_RUNTIME_STATUS: runtimeStatus,
|
|
|
+ MAILHUB_DEPLOY_RUN_MAILDIR_MIGRATION: runMaildirMigration
|
|
|
}
|
|
|
});
|
|
|
}
|