feat:Strengthen the testing framework

This commit is contained in:
saturn
2026-03-15 18:15:25 +08:00
parent eec27fbabf
commit ecbd183a77
31 changed files with 2326 additions and 85 deletions

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env node
import { execSync } from 'node:child_process'
import { pathToFileURL } from 'node:url'
const RULES = [
{
name: 'api',
source: /^src\/app\/api\//,
tests: [/^tests\/integration\/api\/contract\//, /^tests\/system\//, /^tests\/regression\//],
message: 'changing src/app/api/** requires a matching contract, system, or regression test change',
},
{
name: 'worker',
source: /^src\/lib\/workers\//,
tests: [/^tests\/unit\/worker\//, /^tests\/system\//, /^tests\/regression\//],
message: 'changing src/lib/workers/** requires a matching worker, system, or regression test change',
},
{
name: 'task',
source: /^src\/lib\/task\//,
tests: [/^tests\/unit\/task\//, /^tests\/system\//, /^tests\/regression\//],
message: 'changing src/lib/task/** requires a matching task, system, or regression test change',
},
{
name: 'media',
source: /^src\/lib\/media\//,
tests: [/^tests\/unit\//, /^tests\/system\//, /^tests\/regression\//],
message: 'changing src/lib/media/** requires a matching unit, system, or regression test change',
},
{
name: 'provider',
source: /^src\/lib\/(generator-api|generators|model-gateway|lipsync|providers)\//,
tests: [/^tests\/unit\/(providers|model-gateway|llm)\//, /^tests\/integration\/provider\//, /^tests\/system\//, /^tests\/regression\//],
message: 'changing provider/gateway code requires provider contract, system, or regression test change',
},
]
function normalizeChangedFiles(rawFiles) {
return rawFiles
.flatMap((item) => item.split(/[\n,]/))
.map((item) => item.trim())
.filter(Boolean)
}
function readGitChangedFiles() {
try {
const output = execSync('git diff --name-only --cached', {
cwd: process.cwd(),
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
})
return normalizeChangedFiles([output])
} catch {
return []
}
}
export function inspectChangedFiles(changedFiles) {
const changed = normalizeChangedFiles(changedFiles)
const changedTests = changed.filter((file) => file.startsWith('tests/'))
const violations = []
for (const rule of RULES) {
const impactedSources = changed.filter((file) => rule.source.test(file))
if (impactedSources.length === 0) continue
const hasMatchingTestChange = changedTests.some((file) => rule.tests.some((pattern) => pattern.test(file)))
if (!hasMatchingTestChange) {
violations.push(`${rule.name}: ${rule.message}; sources=${impactedSources.join(',')}`)
}
}
return violations
}
function fail(violations) {
console.error('\n[changed-file-test-impact-guard] Missing matching test changes')
for (const violation of violations) {
console.error(` - ${violation}`)
}
process.exit(1)
}
function runCli() {
const inputFiles = process.argv.slice(2)
const changedFiles = inputFiles.length > 0
? normalizeChangedFiles(inputFiles)
: normalizeChangedFiles([process.env.TEST_IMPACT_CHANGED_FILES || '', ...readGitChangedFiles()])
if (changedFiles.length === 0) {
console.log('[changed-file-test-impact-guard] SKIP no changed files detected')
process.exit(0)
}
const violations = inspectChangedFiles(changedFiles)
if (violations.length > 0) {
fail(violations)
}
console.log(`[changed-file-test-impact-guard] OK files=${changedFiles.length}`)
}
const entryHref = process.argv[1] ? pathToFileURL(process.argv[1]).href : null
if (entryHref && import.meta.url === entryHref) {
runCli()
}

View File

@@ -6,7 +6,10 @@ import path from 'path'
const root = process.cwd()
const targetDirs = [
path.join(root, 'tests', 'integration', 'api', 'contract'),
path.join(root, 'tests', 'integration', 'provider'),
path.join(root, 'tests', 'integration', 'chain'),
path.join(root, 'tests', 'system'),
path.join(root, 'tests', 'regression'),
]
function fail(title, details = []) {