Files
Genarrative/scripts/export-ci-npm-download-cache.test.mjs
T
lhk229 1e6b0e5684 优化 Gitea CI 镜像下载缓存与维护日志
使用专用 BuildKit builder 持久复用 Cargo 与 npm 下载缓存,并支持从可信镜像导入
按当前依赖物化镜像下载快照,配置独立缓存回收策略
补齐 AGC vendor 本地依赖清单并缩小构建上下文
增加缓存维护阶段、耗时和失败日志路径
补充下载缓存与构建上下文测试,同步部署说明和共享记忆
2026-09-22 11:23:46 +00:00

84 lines
3.1 KiB
JavaScript

import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { existsSync } from 'node:fs';
import fs from 'node:fs/promises';
import { createRequire } from 'node:module';
import os from 'node:os';
import path from 'node:path';
import test from 'node:test';
import { fileURLToPath } from 'node:url';
const npmRoot = [
path.resolve(path.dirname(process.execPath), 'node_modules/npm'),
path.resolve(path.dirname(process.execPath), '../lib/node_modules/npm'),
...(process.env.npm_execpath
? [path.resolve(path.dirname(process.env.npm_execpath), '..')]
: []),
].find((root) => existsSync(path.join(root, 'node_modules/cacache')));
assert.ok(npmRoot, 'tests require the cacache bundled with npm');
const cacache = createRequire(path.join(npmRoot, 'package.json'))('cacache');
const script = fileURLToPath(
new URL('./export-ci-npm-download-cache.mjs', import.meta.url),
);
async function fixture(t) {
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ci-npm-snapshot-'));
t.after(() => fs.rm(root, { recursive: true, force: true }));
const source = path.join(root, 'source');
const destination = path.join(root, 'destination');
const lock = path.join(root, 'package-lock.json');
const key =
'make-fetch-happen:request-cache:https://registry.npmjs.org/example/-/example-1.0.0.tgz';
const metadata = {
url: key.slice('make-fetch-happen:request-cache:'.length),
};
const integrity = String(
await cacache.put(source, key, 'current-package', { metadata }),
);
await cacache.put(source, 'old-package', 'unused-old-version');
await fs.writeFile(
lock,
JSON.stringify({ packages: { 'node_modules/example': { integrity } } }),
);
const run = () =>
spawnSync(process.execPath, [script, npmRoot, lock, source, destination], {
encoding: 'utf8',
});
return { source, destination, key, metadata, integrity, run };
}
test('exports only current lock content, preserving npm request metadata for offline use', async (t) => {
const f = await fixture(t);
const result = f.run();
assert.equal(result.status, 0, result.stderr);
assert.deepEqual(Object.keys(await cacache.ls(f.destination)), [f.key]);
const output = await cacache.get(f.destination, f.key);
assert.equal(output.data.toString(), 'current-package');
assert.deepEqual(output.metadata, f.metadata);
// 输出是独立快照;移走持久缓存仍可使用,不依赖挂载、链接或旧 builder。
await fs.rm(f.source, { recursive: true });
assert.equal(
(await cacache.get(f.destination, f.key)).data.toString(),
'current-package',
);
});
test('rejects a corrupted cached package instead of publishing it', async (t) => {
const f = await fixture(t);
const digest = Buffer.from(f.integrity.split('-')[1], 'base64').toString(
'hex',
);
const contentPath = path.join(
f.source,
'content-v2',
'sha512',
digest.slice(0, 2),
digest.slice(2, 4),
digest.slice(4),
);
await fs.writeFile(contentPath, 'corrupted-package');
const result = f.run();
assert.notEqual(result.status, 0);
assert.match(result.stderr, /EINTEGRITY|EBADSIZE/);
});