refactor(test): 三份 helper 迁移共享
Task 6 审查遗留①(schema 再演进防漂移):makeWork / seedPublishedSite / cleanupSiteRows 三件套自 build-snapshot / build-pipeline / build-gates / preview-server 四文件(Task 6 审查时三份,Task 7 又落一份)迁 tests/integration/helpers.ts 共享——清场清单(21 语句 FK 反序 + 不可变 触发器开关)此后只改一处。 - makeWork 保持签名;媒体种子载荷改由 prefix 派生(bytes 仍随机唯一, 魔数校验只看 PNG 签名——行为等价);shared Work 统一携带 pngA/pngB - seedPublishedSite 增 keyPrefix 参数(各文件沿用原站点 key 派生前缀 sfbuild/sfpipe/sfgate/sfpreview);succeeded_with_issues 与 publishedCount=3 断言随迁(gallery 203/204 悬空语义文件无关) - import 域短清单清场与 publish 域各自形状不同,不共用——保留原处 零行为变更由 408 测试守护(全绿:根 382 + 主题 26);lint/typecheck 五段过。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,6 @@ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { RouteManifest } from '@sf/contracts'
|
||||
import { createBuildJob, BuildError } from '../../apps/api/src/modules/build/build.service.js'
|
||||
@@ -31,13 +30,7 @@ import {
|
||||
GATE_RULE_VERSION,
|
||||
type GateIssue,
|
||||
} from '../../apps/api/src/modules/build/gates.js'
|
||||
import { createImportJob } from '../../apps/api/src/modules/import/import.service.js'
|
||||
import { publishSiteContent } from '../../apps/api/src/modules/publish/publish.service.js'
|
||||
import { registerSource } from '../../apps/api/src/modules/source/register.service.js'
|
||||
import { rand, withImmutableCleanup, withTestDb, type Db } from './helpers.js'
|
||||
|
||||
const FIXTURES_ROOT = fileURLToPath(new URL('../fixtures', import.meta.url))
|
||||
const WXR_FIXTURE = join(FIXTURES_ROOT, 'wxr', 'mini.xml')
|
||||
import { cleanupSiteRows, makeWork, rand, seedPublishedSite, withTestDb } from './helpers.js'
|
||||
|
||||
const PNG_SIG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
|
||||
const ORIGIN = 'https://gate-fixture.example'
|
||||
@@ -349,73 +342,14 @@ describe('最小门禁(纯产物夹具直调)', () => {
|
||||
})
|
||||
|
||||
// ---- mini 全链(DB + 真实 astro 构建——P0 阻断/全过语义) ----
|
||||
|
||||
interface Work {
|
||||
work: string
|
||||
storageRoot: string
|
||||
allowedRoots: string[]
|
||||
}
|
||||
|
||||
async function makeWork(prefix: string): Promise<Work> {
|
||||
const work = await mkdtemp(join(tmpdir(), `${prefix}-`))
|
||||
const mediaDir = join(work, 'media')
|
||||
await mkdir(join(mediaDir, '2026', '10'), { recursive: true })
|
||||
await writeFile(join(mediaDir, '2026', '10', 'fixture-a.png'), Buffer.concat([PNG_SIG, Buffer.from(`gate-a-${rand()}`)]))
|
||||
await writeFile(join(mediaDir, '2026', '10', 'fixture-b.png'), Buffer.concat([PNG_SIG, Buffer.from(`gate-b-${rand()}`)]))
|
||||
return { work, storageRoot: join(work, 'storage'), allowedRoots: [FIXTURES_ROOT, work] }
|
||||
}
|
||||
|
||||
async function seedPublishedSite(db: Db, w: Work): Promise<{ key: string; siteId: string }> {
|
||||
const key = `sfgate-${rand()}`
|
||||
const reg = await registerSource(db, {
|
||||
siteKey: key,
|
||||
wxrPath: WXR_FIXTURE,
|
||||
mediaDir: join(w.work, 'media'),
|
||||
allowedRoots: w.allowedRoots,
|
||||
storageRoot: w.storageRoot,
|
||||
reportRoot: join(w.work, 'artifacts', 'register'),
|
||||
})
|
||||
const result = await createImportJob(db, { siteKey: key, reportRoot: join(w.work, 'artifacts', 'import') })
|
||||
expect(result.status).toBe('succeeded_with_issues')
|
||||
const dry = await publishSiteContent(db, { siteKey: key, dryRun: true })
|
||||
const run = await publishSiteContent(db, { siteKey: key, confirmToken: dry.confirmToken! })
|
||||
expect(run.publishedCount).toBe(3)
|
||||
return { key, siteId: reg.siteId }
|
||||
}
|
||||
|
||||
/** 本文件写入的行清场:validation 域先行(FK 链 validation_issues→validation_runs→build_jobs)+ 全链反序 */
|
||||
async function cleanupSiteRows(db: Db, siteId: string): Promise<void> {
|
||||
await db.execute(`delete from validation_issues where validation_run_id in
|
||||
(select id from validation_runs where site_id = '${siteId}')`)
|
||||
await db.execute(`delete from validation_runs where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from build_artifacts where build_job_id in
|
||||
(select id from build_jobs where site_id = '${siteId}')`)
|
||||
await withImmutableCleanup(db, 'build_input_snapshots', 'build_input_snapshots_immutable', `site_id = '${siteId}'`)
|
||||
await db.execute(`delete from build_jobs where site_id = '${siteId}'`)
|
||||
await withImmutableCleanup(db, 'audit_logs', 'audit_logs_immutable', `site_id = '${siteId}'`)
|
||||
await db.execute(`delete from site_config_revisions where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from route_registry where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from media_usages where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from media_assets where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from content_terms where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from terms where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from taxonomies where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from source_records where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from entry_locales where site_id = '${siteId}'`)
|
||||
await withImmutableCleanup(db, 'content_revisions', 'content_revisions_immutable', `site_id = '${siteId}'`)
|
||||
await db.execute(`delete from content_entries where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from import_jobs where site_id = '${siteId}'`)
|
||||
await withImmutableCleanup(db, 'source_snapshots', 'source_snapshots_immutable', `site_id = '${siteId}'`)
|
||||
await db.execute(`delete from source_connections where site_id = '${siteId}'`)
|
||||
await db.execute(`delete from sites where id = '${siteId}'`)
|
||||
}
|
||||
// 三件套(makeWork/seedPublishedSite/cleanupSiteRows)迁 tests/integration/helpers.ts 共享(Task 9 收敛)
|
||||
|
||||
describe('P0 阻断语义(mini 全链:门禁接入 build 状态机)', () => {
|
||||
it('任一 P0 → validation_runs FAIL + validation_issues 落库(severity/rule/url/evidence)+ job failed + dist 清场', { timeout: 300_000 }, async () => {
|
||||
await withTestDb(async (db) => {
|
||||
const w = await makeWork('sf-gate-block')
|
||||
try {
|
||||
const { key, siteId } = await seedPublishedSite(db, w)
|
||||
const { key, siteId } = await seedPublishedSite(db, w, 'sfgate')
|
||||
try {
|
||||
const artifactsRoot = join(w.work, 'artifacts')
|
||||
let blockedJobId = ''
|
||||
@@ -493,7 +427,7 @@ describe('P0 阻断语义(mini 全链:门禁接入 build 状态机)', () =
|
||||
await withTestDb(async (db) => {
|
||||
const w = await makeWork('sf-gate-batch')
|
||||
try {
|
||||
const { key, siteId } = await seedPublishedSite(db, w)
|
||||
const { key, siteId } = await seedPublishedSite(db, w, 'sfgate')
|
||||
try {
|
||||
const artifactsRoot = join(w.work, 'artifacts')
|
||||
let batchJobId = ''
|
||||
@@ -536,7 +470,7 @@ describe('P0 阻断语义(mini 全链:门禁接入 build 状态机)', () =
|
||||
await withTestDb(async (db) => {
|
||||
const w = await makeWork('sf-gate-pass')
|
||||
try {
|
||||
const { key, siteId } = await seedPublishedSite(db, w)
|
||||
const { key, siteId } = await seedPublishedSite(db, w, 'sfgate')
|
||||
try {
|
||||
const statuses: string[] = []
|
||||
const result = await createBuildJob(db, {
|
||||
|
||||
Reference in New Issue
Block a user