mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-02 11:54:29 -07:00
fix(anime): restore bridge install after validation failure
- Preserve the previous install when post-swap validation fails - Cover rollback behavior with an installer regression test
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { access, mkdir, mkdtemp, readdir, rename, writeFile } from 'node:fs/promises';
|
||||
import { access, mkdir, mkdtemp, readdir, rename, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
@@ -288,3 +288,28 @@ test('stageBridgeUpdate commit restores the existing install when activation fai
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test('stageBridgeUpdate commit restores the existing install when post-swap validation fails', async () => {
|
||||
const root = await tempRoot();
|
||||
const managed = path.join(root, 'managed');
|
||||
await writeBundle(managed, 'MExtensionServer-v1.0.5.0.jar');
|
||||
await writeBundleMarker(managed, 'v1.0.5.0');
|
||||
const { options } = fakeUpstream();
|
||||
const staged = await stageBridgeUpdate({ ...options, installDir: managed, systemDirs: [] });
|
||||
const stagedJar = path.join(`${managed}.next`, `MExtensionServer-${LATEST}.jar`);
|
||||
await rm(stagedJar);
|
||||
|
||||
await assert.rejects(
|
||||
staged.commit(),
|
||||
/The updated anime bridge is missing its java runtime or jar/,
|
||||
);
|
||||
|
||||
assert.ok(await exists(path.join(managed, 'MExtensionServer-v1.0.5.0.jar')));
|
||||
assert.equal(await readBundleMarker(managed), 'v1.0.5.0');
|
||||
assert.ok(await exists(`${managed}.next`));
|
||||
assert.ok(!(await exists(stagedJar)));
|
||||
assert.deepEqual(
|
||||
(await readdir(root)).filter((entry) => entry.startsWith('managed.backup-')),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -324,8 +324,23 @@ export async function stageBridgeUpdate(options: EnsureBridgeOptions): Promise<S
|
||||
}
|
||||
|
||||
const binaries = await findBundleBinaries(options.installDir);
|
||||
if (!binaries)
|
||||
throw new Error('The updated anime bridge is missing its java runtime or jar.');
|
||||
if (!binaries) {
|
||||
const validationError = new Error(
|
||||
'The updated anime bridge is missing its java runtime or jar.',
|
||||
);
|
||||
try {
|
||||
await renameImpl(options.installDir, stagingDir);
|
||||
await renameImpl(backupDir, options.installDir);
|
||||
backupHoldsInstall = false;
|
||||
} catch (restoreError) {
|
||||
throw new AggregateError(
|
||||
[validationError, restoreError],
|
||||
`The updated anime bridge failed validation and the previous install could not be ` +
|
||||
`restored. The previous install remains at ${backupDir}.`,
|
||||
);
|
||||
}
|
||||
throw validationError;
|
||||
}
|
||||
await rm(backupRoot, { recursive: true, force: true });
|
||||
backupHoldsInstall = false;
|
||||
return describeInstall(binaries, options.installDir, 'managed');
|
||||
|
||||
Reference in New Issue
Block a user