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 test from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
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 { tmpdir } from 'node:os';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import {
|
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);
|
const binaries = await findBundleBinaries(options.installDir);
|
||||||
if (!binaries)
|
if (!binaries) {
|
||||||
throw new Error('The updated anime bridge is missing its java runtime or jar.');
|
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 });
|
await rm(backupRoot, { recursive: true, force: true });
|
||||||
backupHoldsInstall = false;
|
backupHoldsInstall = false;
|
||||||
return describeInstall(binaries, options.installDir, 'managed');
|
return describeInstall(binaries, options.installDir, 'managed');
|
||||||
|
|||||||
Reference in New Issue
Block a user