mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-12 15:26:16 -08:00
test(ambilight): [PKG-AMBILIGHT-05] checkpoint installed canvas combinations
This commit is contained in:
1 parent
e7f31b6fc8
commit
765ddb816f
19 files changed
+1032
-85
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { hash } from '../refactor/scripts/releases.mjs'
|
||||
|
||||
const read = file => JSON.parse(fs.readFileSync(file, 'utf8'))
|
||||
const walk = directory => fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => entry.isDirectory() ? walk(path.join(directory, entry.name)) : [path.join(directory, entry.name)])
|
||||
function digest(file) {
|
||||
const bytes = fs.readFileSync(file)
|
||||
return hash(/\.(?:[cm]?[jt]s|json|css|less|html|svg|txt)$/.test(file) ? bytes.toString('utf8').replaceAll('\r\n', '\n') : bytes)
|
||||
}
|
||||
|
||||
export function verifyInstalledArtifacts(root, mapFile, names = ['artplayer', 'artplayer-plugin-chapter']) {
|
||||
assert(mapFile, 'Run yarn test:package and set ARTPLAYER_BROWSER_ARTIFACTS to its browser-artifacts.json')
|
||||
const directory = path.dirname(path.resolve(mapFile))
|
||||
const artifacts = read(mapFile)
|
||||
const report = read(path.join(directory, 'report.json'))
|
||||
assert.equal(report.task, 'ENG-07', 'Browser checks require isolated installation evidence')
|
||||
assert.equal(report.knownTypeBlockers, 0)
|
||||
assert.equal(report.node, process.versions.node, 'Build and browser-check Node versions differ')
|
||||
const toolchain = {}
|
||||
const currentManifest = read(path.join(root, 'package.json'))
|
||||
const buildManifest = read(path.join(directory, 'build/package.json'))
|
||||
for (const key of ['packageManager', 'devDependencies', 'resolutions'])
|
||||
assert.deepEqual(buildManifest[key], currentManifest[key], `Build toolchain changed: ${key}`)
|
||||
for (const file of ['yarn.lock', 'scripts/build.js', 'scripts/utils.js', 'scripts/projects.js']) {
|
||||
toolchain[file] = digest(path.join(root, file))
|
||||
assert.equal(digest(path.join(directory, 'build', file)), toolchain[file], `Stale build input: ${file}`)
|
||||
}
|
||||
const libraryInputs = location => Object.fromEntries(walk(path.join(location, 'scripts/library')).filter(file => /\.(?:[cm]?[jt]s|json)$/.test(file)).sort().map(file => [path.relative(location, file).replaceAll('\\', '/'), digest(file)]))
|
||||
const currentLibrary = libraryInputs(root)
|
||||
assert.deepEqual(libraryInputs(path.join(directory, 'build')), currentLibrary, 'Stale library build inputs; rerun yarn test:package')
|
||||
Object.assign(toolchain, currentLibrary)
|
||||
const inputs = []
|
||||
for (const name of names) {
|
||||
const pkg = report.packages.find(pkg => pkg.name === name)
|
||||
assert(pkg && artifacts[name], `Missing installed package: ${name}`)
|
||||
const file = path.resolve(directory, artifacts[name])
|
||||
const member = `package/dist/${path.basename(file)}`
|
||||
assert.equal(hash(fs.readFileSync(file)), pkg.files[member], `Installed browser artifact changed: ${name}`)
|
||||
const sourceHashes = {}
|
||||
for (const folder of ['src', 'public']) {
|
||||
const current = path.join(root, 'packages', name, folder)
|
||||
const snapshot = path.join(directory, 'build/packages', name, folder)
|
||||
if (!fs.existsSync(current)) {
|
||||
assert(!fs.existsSync(snapshot), `Source directory was removed: ${name}/${folder}`)
|
||||
continue
|
||||
}
|
||||
const inventory = location => Object.fromEntries(walk(location).map(file => [path.relative(location, file).replaceAll('\\', '/'), digest(file)]))
|
||||
const expected = inventory(current)
|
||||
assert.deepEqual(inventory(snapshot), expected, `Stale package source: ${name}/${folder}; rerun yarn test:package`)
|
||||
Object.assign(sourceHashes, Object.fromEntries(Object.entries(expected).map(([file, digest]) => [`${folder}/${file}`, digest])))
|
||||
}
|
||||
for (const file of ['package.json', 'THIRD_PARTY_NOTICES', 'tsconfig.json']) {
|
||||
const current = path.join(root, 'packages', name, file)
|
||||
const snapshot = path.join(directory, 'build/packages', name, file)
|
||||
assert.equal(fs.existsSync(current), fs.existsSync(snapshot), `Package input removed or added: ${name}/${file}`)
|
||||
if (fs.existsSync(current)) {
|
||||
sourceHashes[file] = digest(current)
|
||||
assert.equal(digest(snapshot), sourceHashes[file], `Stale package input: ${name}/${file}`)
|
||||
}
|
||||
}
|
||||
inputs.push({ name, file, member, sha256: pkg.files[member], archiveSha256: pkg.sha256, sourceHashes })
|
||||
}
|
||||
return { directory, inputs, toolchain, packages: report.packages.filter(pkg => names.includes(pkg.name)) }
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { ensureArchive, hash, readMember } from '../refactor/scripts/releases.mjs'
|
||||
import { consumerDirectory, names, readJson, removeConsumer, run, runtimeConsumer, typeConsumers, workspace, writeJson } from './package-consumer.mjs'
|
||||
import { consumerDirectory, names as defaultNames, readJson, removeConsumer, run, runtimeConsumer, typeConsumers, workspace, writeJson } from './package-consumer.mjs'
|
||||
|
||||
export function checkFiles(manifest, files, historical = []) {
|
||||
for (const field of ['main', 'module', 'types', 'legacy']) {
|
||||
@@ -67,10 +67,23 @@ export async function publishedConsumer() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkPackages({ release = false } = {}) {
|
||||
export async function checkPackages({ release = false, include = [] } = {}) {
|
||||
assert(!release || include.length === 0, 'Additional package browser preparation is not full release acceptance')
|
||||
assert.equal(process.env.npm_config_user_agent?.split(' ')[0], 'yarn/1.22.22', 'Run yarn test:package with the pinned Yarn')
|
||||
const yarn = process.env.npm_execpath
|
||||
assert(yarn && fs.existsSync(yarn), 'Missing Yarn executable')
|
||||
const supported = {
|
||||
'artplayer-plugin-ambilight': async () => (await import('../refactor/scripts/ambilight-contract.mjs')).verifyAmbilightContract(),
|
||||
'artplayer-proxy-canvas': async () => (await import('../refactor/scripts/canvas-contract.mjs')).verifyCanvasContract(),
|
||||
}
|
||||
assert(new Set(include).size === include.length, 'Duplicate additional package')
|
||||
const historicalFiles = new Map()
|
||||
for (const name of include) {
|
||||
assert(Object.hasOwn(supported, name), `Additional package needs a reviewed contract: ${name}`)
|
||||
const contract = await supported[name]()
|
||||
historicalFiles.set(name, Object.keys(contract.baseline.release.files))
|
||||
}
|
||||
const names = [...defaultNames, ...include]
|
||||
const parent = path.join(workspace, 'refactor/.cache/packages')
|
||||
fs.mkdirSync(parent, { recursive: true })
|
||||
const output = fs.mkdtempSync(path.join(parent, 'run-'))
|
||||
@@ -98,7 +111,7 @@ export async function checkPackages({ release = false } = {}) {
|
||||
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
|
||||
assert.equal(manifest.name, name)
|
||||
assert(!['preinstall', 'install', 'postinstall'].some(hook => manifest.scripts?.[hook]), 'Add lifecycle fixtures before accepting install hooks')
|
||||
checkFiles(manifest, files, Object.keys(baseline.releases.find(r => r.name === name).files))
|
||||
checkFiles(manifest, files, historicalFiles.get(name) || Object.keys(baseline.releases.find(r => r.name === name).files))
|
||||
packages.push({ name, version: manifest.version, archive: path.basename(archive), sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(file => [file, hash(readMember(archive, file))])) })
|
||||
}
|
||||
writeJson(path.join(installed, 'package.json'), { private: true, name: 'artplayer-isolated-consumer', dependencies: Object.fromEntries(packages.map(pkg => [pkg.name, `file:${path.join(output, pkg.archive).replaceAll('\\', '/')}`])) })
|
||||
@@ -123,11 +136,13 @@ export async function checkPackages({ release = false } = {}) {
|
||||
const preciseTypes = typeConsumers(installed, { precise: true })
|
||||
const source = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: workspace, encoding: 'utf8' }).trim()
|
||||
const publishedPackages = baseline.releases.map(({ name, version, files }) => ({ name, version, files }))
|
||||
const report = { task: 'ENG-07', capturedAt: new Date().toISOString(), source, toolchain: { yarn: '1.22.22', yarnPath: yarn }, node: process.versions.node, packages, runtime, publishedPackages, publishedRuntime: oldRuntime, types, preciseTypes, knownRuntimeBlockers: runtime.observations.defaultsWithoutNavigator.resolved ? 0 : 1, knownTypeBlockers: [...types, ...preciseTypes].reduce((sum, result) => sum + result.diagnostics.length, 0) }
|
||||
const report = { task: 'ENG-07', capturedAt: new Date().toISOString(), source, toolchain: { yarn: '1.22.22', yarnPath: yarn }, node: process.versions.node, packages, runtimeScope: defaultNames, typeScope: defaultNames, additionalBrowserPackages: include, runtime, publishedPackages, publishedRuntime: oldRuntime, types, preciseTypes, knownRuntimeBlockers: runtime.observations.defaultsWithoutNavigator.resolved ? 0 : 1, knownTypeBlockers: [...types, ...preciseTypes].reduce((sum, result) => sum + result.diagnostics.length, 0) }
|
||||
writeJson(path.join(output, 'report.json'), report)
|
||||
writeJson(path.join(output, 'browser-artifacts.json'), artifacts)
|
||||
writeJson(path.join(parent, 'latest.json'), { output: path.relative(workspace, output).replaceAll('\\', '/') })
|
||||
console.log(`Installed tarball contracts passed: ${runtime.checks.length} runtime checks; ${types.filter(t => !t.diagnostics.length).length}/${types.length} legacy type modes; ${preciseTypes.filter(t => !t.diagnostics.length).length}/${preciseTypes.length} precise type modes. Report: ${output}`)
|
||||
if (include.length)
|
||||
console.log(`Runtime/type fixture scope: ${defaultNames.join(', ')}. Additional packages require their own consumer and browser acceptance: ${include.join(', ')}.`)
|
||||
if (release) {
|
||||
assert.equal(report.knownTypeBlockers, 0, 'Known type blockers remain; this candidate is not release-ready')
|
||||
assert.equal(report.knownRuntimeBlockers, 0, 'Known runtime blockers remain; this candidate is not release-ready')
|
||||
@@ -141,7 +156,8 @@ export async function checkPackages({ release = false } = {}) {
|
||||
}
|
||||
|
||||
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
checkPackages({ release: process.argv.includes('--release') }).catch((error) => {
|
||||
const include = process.argv.find(arg => arg.startsWith('--include='))?.slice('--include='.length).split(',') || []
|
||||
checkPackages({ release: process.argv.includes('--release'), include }).catch((error) => {
|
||||
console.error(error)
|
||||
process.exitCode = 1
|
||||
})
|
||||
|
||||
@@ -1,71 +1,11 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { ensureArchive, hash, readMember } from '../refactor/scripts/releases.mjs'
|
||||
import { ensureArchive, readMember } from '../refactor/scripts/releases.mjs'
|
||||
import { measureBytes } from '../refactor/scripts/sizes.mjs'
|
||||
|
||||
export { verifyInstalledArtifacts as verifyPerformanceArtifacts } from './installed-artifacts.mjs'
|
||||
const read = file => JSON.parse(fs.readFileSync(file, 'utf8'))
|
||||
const walk = directory => fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => entry.isDirectory() ? walk(path.join(directory, entry.name)) : [path.join(directory, entry.name)])
|
||||
function digest(file) {
|
||||
const bytes = fs.readFileSync(file)
|
||||
return hash(/\.(?:[cm]?[jt]s|json|css|less|html|svg|txt)$/.test(file) ? bytes.toString('utf8').replaceAll('\r\n', '\n') : bytes)
|
||||
}
|
||||
|
||||
export function verifyPerformanceArtifacts(root, mapFile) {
|
||||
assert(mapFile, 'Run yarn test:package and set ARTPLAYER_BROWSER_ARTIFACTS to its browser-artifacts.json')
|
||||
const directory = path.dirname(path.resolve(mapFile))
|
||||
const artifacts = read(mapFile)
|
||||
const report = read(path.join(directory, 'report.json'))
|
||||
assert.equal(report.task, 'ENG-07', 'Performance requires isolated installation evidence')
|
||||
assert.equal(report.knownTypeBlockers, 0)
|
||||
assert.equal(report.node, process.versions.node, 'Build and benchmark Node versions differ')
|
||||
const toolchain = {}
|
||||
const currentManifest = read(path.join(root, 'package.json'))
|
||||
const buildManifest = read(path.join(directory, 'build/package.json'))
|
||||
for (const key of ['packageManager', 'devDependencies', 'resolutions'])
|
||||
assert.deepEqual(buildManifest[key], currentManifest[key], `Build toolchain changed: ${key}`)
|
||||
for (const file of ['yarn.lock', 'scripts/build.js', 'scripts/utils.js', 'scripts/projects.js']) {
|
||||
toolchain[file] = digest(path.join(root, file))
|
||||
assert.equal(digest(path.join(directory, 'build', file)), toolchain[file], `Stale build input: ${file}`)
|
||||
}
|
||||
const libraryInputs = location => Object.fromEntries(walk(path.join(location, 'scripts/library')).filter(file => /\.(?:[cm]?[jt]s|json)$/.test(file)).sort().map(file => [path.relative(location, file).replaceAll('\\', '/'), digest(file)]))
|
||||
const currentLibrary = libraryInputs(root)
|
||||
assert.deepEqual(libraryInputs(path.join(directory, 'build')), currentLibrary, 'Stale library build inputs; rerun yarn test:package')
|
||||
Object.assign(toolchain, currentLibrary)
|
||||
const inputs = []
|
||||
for (const name of ['artplayer', 'artplayer-plugin-chapter']) {
|
||||
const pkg = report.packages.find(pkg => pkg.name === name)
|
||||
assert(pkg && artifacts[name], `Missing installed package: ${name}`)
|
||||
const file = path.resolve(directory, artifacts[name])
|
||||
const member = `package/dist/${path.basename(file)}`
|
||||
assert.equal(hash(fs.readFileSync(file)), pkg.files[member], `Installed performance artifact changed: ${name}`)
|
||||
const sourceHashes = {}
|
||||
for (const folder of ['src', 'public']) {
|
||||
const current = path.join(root, 'packages', name, folder)
|
||||
const snapshot = path.join(directory, 'build/packages', name, folder)
|
||||
if (!fs.existsSync(current)) {
|
||||
assert(!fs.existsSync(snapshot), `Source directory was removed: ${name}/${folder}`)
|
||||
continue
|
||||
}
|
||||
const inventory = location => Object.fromEntries(walk(location).map(file => [path.relative(location, file).replaceAll('\\', '/'), digest(file)]))
|
||||
const expected = inventory(current)
|
||||
assert.deepEqual(inventory(snapshot), expected, `Stale package source: ${name}/${folder}; rerun yarn test:package`)
|
||||
Object.assign(sourceHashes, Object.fromEntries(Object.entries(expected).map(([file, digest]) => [`${folder}/${file}`, digest])))
|
||||
}
|
||||
for (const file of ['package.json', 'THIRD_PARTY_NOTICES', 'tsconfig.json']) {
|
||||
const current = path.join(root, 'packages', name, file)
|
||||
const snapshot = path.join(directory, 'build/packages', name, file)
|
||||
assert.equal(fs.existsSync(current), fs.existsSync(snapshot), `Package input removed or added: ${name}/${file}`)
|
||||
if (fs.existsSync(current)) {
|
||||
sourceHashes[file] = digest(current)
|
||||
assert.equal(digest(snapshot), sourceHashes[file], `Stale package input: ${name}/${file}`)
|
||||
}
|
||||
}
|
||||
inputs.push({ name, file, member, sha256: pkg.files[member], archiveSha256: pkg.sha256, sourceHashes })
|
||||
}
|
||||
return { directory, inputs, toolchain, packages: report.packages }
|
||||
}
|
||||
|
||||
export async function compareArtifactSizes(root, artifacts) {
|
||||
const releases = read(path.join(root, 'refactor/baselines/releases.json')).releases
|
||||
|
||||
Reference in new issue
Block a user