mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-27 03:02:51 +08:00
152 lines
8.3 KiB
JavaScript
152 lines
8.3 KiB
JavaScript
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { spawnSync } = require('node:child_process');
|
|
|
|
const root = path.resolve(__dirname, '..');
|
|
const installerPath = path.join(root, 'scripts/install.sh');
|
|
const source = fs.readFileSync(installerPath, 'utf8');
|
|
const sourceInstaller = fs.readFileSync(path.join(root, 'install.sh'), 'utf8');
|
|
const sourceDependencyFunctions = sourceInstaller.slice(
|
|
sourceInstaller.indexOf('dependency_ready()'),
|
|
sourceInstaller.indexOf('\n# 检测包管理器')
|
|
);
|
|
const functions = source.slice(source.indexOf('info()'), source.lastIndexOf('\nmain "$@"'));
|
|
const program = source.slice(0, source.lastIndexOf('\nmain "$@"'));
|
|
const currentVersion = fs.readFileSync(path.join(root, 'Makefile'), 'utf8').match(/^PKG_VERSION:=(.+)$/m)[1];
|
|
|
|
function shell(body, env = {}) {
|
|
return spawnSync('/bin/sh', ['-c', body], {
|
|
encoding: 'utf8',
|
|
env: { ...process.env, ...env }
|
|
});
|
|
}
|
|
|
|
test('online installer is valid POSIX shell and uses the fixed repository', () => {
|
|
const result = spawnSync('/bin/sh', ['-n', installerPath], { encoding: 'utf8' });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(source, /^REPOSITORY="tpxcer\/minigate"$/m);
|
|
assert.match(source, /releases\/latest\/download/);
|
|
});
|
|
|
|
test('source installer skips package installation when a working OpenSSL CLI already exists', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-source-deps-'));
|
|
const calls = path.join(tempDir, 'apk-calls');
|
|
const openssl = path.join(tempDir, 'openssl');
|
|
const apk = path.join(tempDir, 'apk');
|
|
fs.writeFileSync(openssl, '#!/bin/sh\n[ "$1" = version ]\n', { mode: 0o755 });
|
|
fs.writeFileSync(apk, `#!/bin/sh\nprintf '%s\\n' "$*" >> ${JSON.stringify(calls)}\n[ "$1" = info ] && [ "$3" != openssl-util ]\n`, { mode: 0o755 });
|
|
|
|
const result = shell(`${sourceDependencyFunctions}\ninstall_dependencies`, { PATH: tempDir });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
const log = fs.existsSync(calls) ? fs.readFileSync(calls, 'utf8') : '';
|
|
assert.doesNotMatch(log, /openssl-util/);
|
|
});
|
|
|
|
test('source installer installs openssl-util when OpenSSL CLI is unavailable', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-source-deps-'));
|
|
const calls = path.join(tempDir, 'apk-calls');
|
|
const apk = path.join(tempDir, 'apk');
|
|
fs.writeFileSync(apk, `#!/bin/sh\nprintf '%s\\n' "$*" >> ${JSON.stringify(calls)}\nif [ "$1" = info ]; then [ "$3" != openssl-util ]; else exit 0; fi\n`, { mode: 0o755 });
|
|
|
|
const result = shell(`${sourceDependencyFunctions}\ninstall_dependencies`, { PATH: tempDir });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(fs.readFileSync(calls, 'utf8'), /add openssl-util/);
|
|
});
|
|
|
|
test('release manifest selects one valid minigate source asset', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-install-test-'));
|
|
const sumsPath = path.join(tempDir, 'SHA256SUMS');
|
|
const hash = 'a'.repeat(64);
|
|
fs.writeFileSync(sumsPath, [
|
|
`${'b'.repeat(64)} minigate_2026.9.14-3_all.ipk`,
|
|
`${hash} minigate-v2026.9.14-3-src.tar.gz`,
|
|
`${hash} luci-app-minigate-v2026.9.14-3-src.tar.gz`
|
|
].join('\n'));
|
|
|
|
const result = shell(`${functions}\nread_release "$SUMS" && printf '%s|%s|%s' "$RELEASE_VERSION" "$SOURCE_NAME" "$EXPECTED_HASH"`, { SUMS: sumsPath });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.equal(result.stdout, `2026.9.14-3|minigate-v2026.9.14-3-src.tar.gz|${hash}`);
|
|
});
|
|
|
|
test('release manifest rejects duplicate or malformed source entries', () => {
|
|
for (const entries of [
|
|
[`${'a'.repeat(64)} minigate-v2026.9.14-3-src.tar.gz`, `${'b'.repeat(64)} minigate-v2026.9.14-4-src.tar.gz`],
|
|
[`${'a'.repeat(64)} minigate-v2026.9.14-0-src.tar.gz`],
|
|
[`not-a-hash minigate-v2026.9.14-3-src.tar.gz`]
|
|
]) {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-install-test-'));
|
|
const sumsPath = path.join(tempDir, 'SHA256SUMS');
|
|
fs.writeFileSync(sumsPath, entries.join('\n'));
|
|
const result = shell(`${functions}\nread_release "$SUMS"`, { SUMS: sumsPath });
|
|
assert.notEqual(result.status, 0, entries.join(','));
|
|
}
|
|
});
|
|
|
|
test('source metadata must match the selected release version', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-install-test-'));
|
|
fs.mkdirSync(path.join(tempDir, 'scripts'), { recursive: true });
|
|
fs.mkdirSync(path.join(tempDir, 'root/usr/lib/minigate'), { recursive: true });
|
|
fs.writeFileSync(path.join(tempDir, 'Makefile'), 'PKG_VERSION:=2026.9.14-3\n');
|
|
fs.writeFileSync(path.join(tempDir, 'scripts/build-ipk.sh'), 'PKG_VERSION="2026.9.14-3"\n');
|
|
fs.writeFileSync(path.join(tempDir, 'root/usr/lib/minigate/update.sh'), 'CURRENT_VERSION="2026.9.14-3"\n');
|
|
fs.writeFileSync(path.join(tempDir, 'install.sh'), '#!/bin/sh\n');
|
|
|
|
const valid = shell(`${functions}\nRELEASE_VERSION=2026.9.14-3; verify_metadata "$SOURCE_DIR"`, { SOURCE_DIR: tempDir });
|
|
assert.equal(valid.status, 0, valid.stderr);
|
|
const invalid = shell(`${functions}\nRELEASE_VERSION=2026.9.14-4; verify_metadata "$SOURCE_DIR"`, { SOURCE_DIR: tempDir });
|
|
assert.notEqual(invalid.status, 0);
|
|
});
|
|
|
|
test('online installer verifies and installs a mocked latest release end to end', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-install-test-'));
|
|
const sourceDir = path.join(tempDir, 'source');
|
|
const archivePath = path.join(tempDir, `minigate-v${currentVersion}-src.tar.gz`);
|
|
const sumsPath = path.join(tempDir, 'SHA256SUMS');
|
|
const markerPath = path.join(tempDir, 'installed');
|
|
fs.mkdirSync(path.join(sourceDir, 'scripts'), { recursive: true });
|
|
fs.mkdirSync(path.join(sourceDir, 'root/usr/lib/minigate'), { recursive: true });
|
|
fs.writeFileSync(path.join(sourceDir, 'Makefile'), `PKG_VERSION:=${currentVersion}\n`);
|
|
fs.writeFileSync(path.join(sourceDir, 'scripts/build-ipk.sh'), `PKG_VERSION="${currentVersion}"\n`);
|
|
fs.writeFileSync(path.join(sourceDir, 'root/usr/lib/minigate/update.sh'), `CURRENT_VERSION="${currentVersion}"\n`);
|
|
fs.writeFileSync(path.join(sourceDir, 'install.sh'), '#!/bin/sh\nprintf installed > "$INSTALL_MARKER"\n');
|
|
const tar = spawnSync('tar', ['-czf', archivePath, '-C', sourceDir, '.'], { encoding: 'utf8' });
|
|
assert.equal(tar.status, 0, tar.stderr);
|
|
const digest = spawnSync('shasum', ['-a', '256', archivePath], { encoding: 'utf8' }).stdout.split(/\s+/)[0];
|
|
fs.writeFileSync(sumsPath, `${digest} ${path.basename(archivePath)}\n`);
|
|
|
|
const result = shell(`${program}
|
|
check_system() { :; }
|
|
detect_downloader() { DOWNLOADER=test; }
|
|
fetch_to_file() {
|
|
case "$1" in
|
|
*/SHA256SUMS) cp "$TEST_SUMS" "$2" ;;
|
|
*/minigate-v*-src.tar.gz) cp "$TEST_ARCHIVE" "$2" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
restart_luci() { printf restarted >> "$INSTALL_MARKER"; }
|
|
main
|
|
`, { TEST_SUMS: sumsPath, TEST_ARCHIVE: archivePath, INSTALL_MARKER: markerPath });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.equal(fs.readFileSync(markerPath, 'utf8'), 'installedrestarted');
|
|
assert.match(result.stdout, new RegExp(`minigate v${currentVersion.replaceAll('.', '\\.')} 安装完成`));
|
|
});
|
|
|
|
test('online installer stops before installation when SHA-256 does not match', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-install-test-'));
|
|
const archivePath = path.join(tempDir, 'source.tar.gz');
|
|
fs.writeFileSync(archivePath, 'not an archive');
|
|
const result = shell(`${functions}\nEXPECTED_HASH=${'0'.repeat(64)}; verify_source "$ARCHIVE"`, { ARCHIVE: archivePath });
|
|
assert.notEqual(result.status, 0);
|
|
assert.match(result.stderr, /SHA-256/);
|
|
});
|
|
|
|
test('README exposes the short command and keeps a fixed-version fallback', () => {
|
|
const readme = fs.readFileSync(path.join(root, 'README.md'), 'utf8');
|
|
assert.match(readme, /curl -fsSL https:\/\/raw\.githubusercontent\.com\/tpxcer\/minigate\/main\/scripts\/install\.sh \| sh/);
|
|
assert.ok(readme.includes(`releases/download/v${currentVersion}/minigate-v${currentVersion}-src.tar.gz`));
|
|
});
|