Files
Firelink/scripts/check-updates.node-test.js
T
NimBold bbfc6e9eb1 fix(network): harden native proxy discovery and FFmpeg provider matching
- discover active macOS dynamic store proxies via scutil before networksetup

- treat missing registry keys and unavailable probe tools as clean absence instead of hard error

- support two-part versions and tag-exact asset patterns in BtbN FFmpeg updates

- normalize BtbN n-prefixed FFmpeg versions in sidecar status checks
2026-09-05 08:41:10 +03:30

297 lines
8.6 KiB
JavaScript

import assert from 'node:assert/strict';
import { test } from 'node:test';
import {
checkRows,
diffCargoMetadata,
fetchJson,
fetchText,
latestBtbnFfmpegStableBuild,
latestMartinRiedlMacArm64Release,
npmExecutable,
providerAssetHashes,
} from './check-updates.js';
async function withMockFetch(mockFetch, callback) {
const originalFetch = globalThis.fetch;
globalThis.fetch = mockFetch;
try {
return await callback();
} finally {
globalThis.fetch = originalFetch;
}
}
test('fetchJson retries transient HTTP responses before succeeding', async () => {
let attempts = 0;
const result = await withMockFetch(async () => {
attempts += 1;
if (attempts < 3) return new Response('temporarily unavailable', { status: 503 });
return new Response(JSON.stringify({ status: 'ok' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}, () => fetchJson('https://example.test/releases'));
assert.deepEqual(result, { status: 'ok' });
assert.equal(attempts, 3);
});
test('fetchText does not retry terminal HTTP responses', async () => {
let attempts = 0;
await assert.rejects(
() =>
withMockFetch(async () => {
attempts += 1;
return new Response('not found', { status: 404 });
}, () => fetchText('https://example.test/missing')),
/404: https:\/\/example\.test\/missing/
);
assert.equal(attempts, 1);
});
test('checkRows fails closed when a latest version is unavailable', () => {
assert.throws(
() =>
checkRows(
[{ target: 'test-target', engine: 'test-engine', version: '1.0.0', url: 'https://example.test/engine' }],
{}
),
/Latest version is unavailable for test-target test-engine/
);
});
test('checkRows does not fall back to the generic release for target-specific engines', () => {
assert.throws(
() =>
checkRows(
[{ target: 'test-target', engine: 'ffmpeg', version: '8.1.2', url: 'https://example.test/engine' }],
{ ffmpeg: '9.0.1' },
{},
{},
new Set(['ffmpeg'])
),
/Latest provider version is unavailable for test-target ffmpeg/
);
});
test('checkRows detects a provider hash change when version and URL are current', () => {
const outdated = checkRows(
[{
target: 'test-target',
engine: 'test-engine',
version: '1.0.0',
url: 'https://example.test/engine',
sha256: 'a'.repeat(64),
}],
{ 'test-engine': '1.0.0' },
{},
{},
new Set(),
{},
{ 'https://example.test/engine': 'b'.repeat(64) },
);
assert.equal(outdated, 1);
});
test('checkRows compares packaged source provenance without confusing the payload digest', () => {
const outdated = checkRows(
[{
target: 'aarch64-apple-darwin',
engine: 'ffmpeg',
version: '9.0.1',
url: 'https://example.test/ffmpeg.zip',
sourceSha256: 'a'.repeat(64),
sha256: 'b'.repeat(64),
}],
{ ffmpeg: '9.0.1' },
{ 'aarch64-apple-darwin:ffmpeg': '9.0.1' },
{ 'aarch64-apple-darwin:ffmpeg': 'https://example.test/ffmpeg.zip' },
new Set(['ffmpeg']),
{ 'aarch64-apple-darwin:ffmpeg': 'a'.repeat(64) },
);
assert.equal(outdated, 0);
});
test('checkRows detects an aria2 asset digest change when the provider supplies it', () => {
const url = 'https://github.com/aria2/aria2/releases/download/release-1.37.0/aria2-1.37.0-win-64bit-build1.zip';
const digest = 'b'.repeat(64);
const hashes = providerAssetHashes({
aria2: { assets: [{ browser_download_url: url, digest: `sha256:${digest}` }] },
});
const outdated = checkRows(
[{
target: 'x86_64-pc-windows-msvc',
engine: 'aria2c',
version: '1.37.0',
url,
sha256: 'a'.repeat(64),
}],
{ aria2c: '1.37.0' },
{},
{},
new Set(),
{},
hashes,
);
assert.equal(outdated, 1);
});
test('npm executable selection uses the Windows command shim when needed', () => {
assert.equal(npmExecutable('win32'), 'npm.cmd');
assert.equal(npmExecutable('darwin'), 'npm');
assert.equal(npmExecutable('linux'), 'npm');
});
test('selects a complete BtbN build for the current stable series', async () => {
const digest = value => `sha256:${value.repeat(64)}`;
const release = {
tag_name: 'autobuild-test',
assets: [
{
name: 'ffmpeg-n9.0.1-11-ge47273f4d9-win64-gpl-9.0.zip',
browser_download_url: 'https://example.test/windows.zip',
digest: digest('a'),
},
{
name: 'ffmpeg-n9.0.1-11-ge47273f4d9-linux64-gpl-9.0.tar.xz',
browser_download_url: 'https://example.test/linux.tar.xz',
digest: digest('b'),
},
{
name: 'ffmpeg-n8.1.2-50-g1a748fe2cd-win64-gpl-8.1.zip',
browser_download_url: 'https://example.test/old.zip',
digest: digest('c'),
},
],
};
const result = await withMockFetch(
async () => new Response(JSON.stringify([release]), { status: 200 }),
() => latestBtbnFfmpegStableBuild('9.0.1'),
);
assert.equal(result.version, '9.0.1-11-ge47273f4d9');
assert.equal(result.urls.windows, 'https://example.test/windows.zip');
assert.equal(result.hashes.linux, 'b'.repeat(64));
});
test('selects a complete BtbN build for a two-part stable version and tag-exact assets', async () => {
const digest = value => `sha256:${value.repeat(64)}`;
const release = {
tag_name: 'autobuild-test',
assets: [
{
name: 'ffmpeg-n9.0-win64-gpl-9.0.zip',
browser_download_url: 'https://example.test/windows-exact.zip',
digest: digest('e'),
},
{
name: 'ffmpeg-n9.0-linux64-gpl-9.0.tar.xz',
browser_download_url: 'https://example.test/linux-exact.tar.xz',
digest: digest('f'),
},
],
};
const result = await withMockFetch(
async () => new Response(JSON.stringify([release]), { status: 200 }),
() => latestBtbnFfmpegStableBuild('9.0'),
);
assert.equal(result.version, '9.0');
assert.equal(result.urls.windows, 'https://example.test/windows-exact.zip');
assert.equal(result.hashes.linux, 'f'.repeat(64));
});
test('rejects an incomplete BtbN stable target tuple', async () => {
const release = {
tag_name: 'autobuild-test',
assets: [{
name: 'ffmpeg-n9.0.1-11-ge47273f4d9-win64-gpl-9.0.zip',
browser_download_url: 'https://example.test/windows.zip',
digest: `sha256:${'a'.repeat(64)}`,
}],
};
const result = await withMockFetch(
async () => new Response(JSON.stringify([release]), { status: 200 }),
() => latestBtbnFfmpegStableBuild('9.0.1'),
);
assert.equal(result, undefined);
});
test('requires a complete Martin Riedl stable artifact and digest', async () => {
const html = `
<h2>Download Release Build</h2>
<div><h3>macOS (Apple Silicon/arm64)</h3>
<p><b>Release: </b>9.0.1</p>
<a href="/download/macos/arm64/build/ffmpeg.zip">FFmpeg (ZIP)</a></div>`;
const result = await withMockFetch(
async url => new Response(
String(url).endsWith('.sha256') ? `${'d'.repeat(64)} ffmpeg.zip\n` : html,
{ status: 200 },
),
() => latestMartinRiedlMacArm64Release(),
);
assert.deepEqual(result, {
version: '9.0.1',
url: 'https://ffmpeg.martin-riedl.de/download/macos/arm64/build/ffmpeg.zip',
sha256: 'd'.repeat(64),
});
});
test('reports compatible Cargo resolution drift from structured metadata', () => {
const metadata = versions => ({
packages: Object.entries(versions).map(([name, version]) => ({
name,
version,
source: 'registry+https://github.com/rust-lang/crates.io-index',
})),
});
assert.deepEqual(
diffCargoMetadata(metadata({ indexmap: '2.14.1', serde: '1.0.229' }), metadata({
indexmap: '2.14.2',
serde: '1.0.229',
})),
[{
name: 'indexmap',
version: '2.14.1',
latest: '2.14.2',
source: 'registry+https://github.com/rust-lang/crates.io-index',
}],
);
});
test('reports packages added to or removed from the resolved Cargo graph', () => {
const metadata = packages => ({
packages: packages.map(([name, version]) => ({
name,
version,
source: 'registry+https://github.com/rust-lang/crates.io-index',
})),
});
assert.deepEqual(
diffCargoMetadata(
metadata([['removed-crate', '1.0.0'], ['stable-crate', '1.0.0']]),
metadata([['added-crate', '2.0.0'], ['stable-crate', '1.0.0']]),
),
[
{
name: 'added-crate',
version: null,
latest: '2.0.0',
source: 'registry+https://github.com/rust-lang/crates.io-index',
},
{
name: 'removed-crate',
version: '1.0.0',
latest: null,
source: 'registry+https://github.com/rust-lang/crates.io-index',
},
],
);
});