mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
193 lines
6.9 KiB
JavaScript
193 lines
6.9 KiB
JavaScript
import { beforeAll, describe, expect, it } from 'vitest'
|
|
import { classifyNodeServerChanges, collectNodeServerInputs } from './node-server-change-scope.mjs'
|
|
import { NODE_SERVER_RUNNERS, nodeServerQualification } from './node-server-qualification.mjs'
|
|
import { discoverUnitFiles } from './ci-unit-files.mjs'
|
|
import { planUnitSelection } from './ci-unit-selection.mjs'
|
|
import { classifyPrJobs } from './pr-code-change-scope.mjs'
|
|
|
|
const policyTests = [
|
|
'config/scripts/node-server-change-scope.test.mjs',
|
|
'config/scripts/node-server-qualification.test.mjs'
|
|
]
|
|
|
|
const unavailableGraph = async () => {
|
|
throw new Error('graph unavailable')
|
|
}
|
|
|
|
describe('modified Node-server policy self-tests', () => {
|
|
let inputs
|
|
let unitFiles
|
|
beforeAll(async () => {
|
|
inputs = await collectNodeServerInputs()
|
|
unitFiles = discoverUnitFiles()
|
|
}, 60_000)
|
|
|
|
it.each(policyTests)(
|
|
'keeps %s in required root units without native qualification',
|
|
async (file) => {
|
|
expect(classifyPrJobs([file], { allowMobileCiTools: true })).toMatchObject({
|
|
test: true,
|
|
static_analysis: true,
|
|
typecheck: true,
|
|
mobile_ci_tools: false
|
|
})
|
|
expect(inputs.has(file)).toBe(false)
|
|
const scope = await classifyNodeServerChanges([file], async () => inputs, {
|
|
modifiedFiles: [file]
|
|
})
|
|
expect(scope).toMatchObject({ shouldRun: false, graphResolved: true, matchedFiles: [] })
|
|
const plan = planUnitSelection({
|
|
files: unitFiles,
|
|
changed: [file],
|
|
graph: () => {
|
|
throw new Error('config edits must select the full unit inventory')
|
|
},
|
|
timings: {},
|
|
event: { pull_request: { draft: true } },
|
|
mode: 'selected'
|
|
})
|
|
expect(plan.mode).toBe('shadow')
|
|
expect(plan.executionFiles).toEqual(unitFiles)
|
|
expect(plan.executionFiles).toContain(file)
|
|
}
|
|
)
|
|
|
|
it('keeps both modified policy self-tests in root units', async () => {
|
|
const scope = await classifyNodeServerChanges(policyTests, async () => inputs, {
|
|
modifiedFiles: policyTests
|
|
})
|
|
expect(scope.shouldRun).toBe(false)
|
|
expect(unitFiles).toEqual(expect.arrayContaining(policyTests))
|
|
})
|
|
|
|
it.each(policyTests)('requests the real graph before excluding %s', async (file) => {
|
|
const scope = await classifyNodeServerChanges([file], unavailableGraph, {
|
|
deferGraph: true,
|
|
modifiedFiles: [file]
|
|
})
|
|
expect(scope.graphRequired).toBe(true)
|
|
expect(scope.shouldRun).toBeUndefined()
|
|
})
|
|
|
|
it.each([
|
|
{ evidence: 'incomplete modified paths', changed: policyTests, modified: [policyTests[0]] },
|
|
{ evidence: 'missing modified paths', changed: policyTests },
|
|
{
|
|
evidence: 'duplicate modified paths',
|
|
changed: policyTests,
|
|
modified: [policyTests[0], policyTests[0]]
|
|
},
|
|
{
|
|
evidence: 'foreign modified path',
|
|
changed: policyTests,
|
|
modified: [policyTests[0], 'config/scripts/foreign.test.mjs']
|
|
},
|
|
{
|
|
evidence: 'unproven rename side',
|
|
changed: [...policyTests, 'config/scripts/node-server-renamed.test.mjs'],
|
|
modified: policyTests
|
|
},
|
|
{
|
|
evidence: 'duplicate changed paths',
|
|
changed: [policyTests[0], policyTests[0]],
|
|
modified: policyTests
|
|
}
|
|
])('retains full qualification with $evidence', async ({ changed, modified }) => {
|
|
const scope = await classifyNodeServerChanges(changed, unavailableGraph, {
|
|
modifiedFiles: modified
|
|
})
|
|
expect(scope.shouldRun).toBe(true)
|
|
expect(scope.graphUnavailable).toBeUndefined()
|
|
expect(nodeServerQualification(changed, scope)).toEqual({
|
|
qualification: true,
|
|
runners: NODE_SERVER_RUNNERS
|
|
})
|
|
})
|
|
|
|
it.each([
|
|
'config/scripts/node-server-change-scope.mjs',
|
|
'config/scripts/node-server-qualification.mjs',
|
|
'config/scripts/workspace-source-exports.test.mjs',
|
|
'.github/workflows/node-server-tests.yml',
|
|
'.github/actions/prepare-native-runtime/action.yml',
|
|
'pnpm-lock.yaml'
|
|
])('keeps full qualification for mixed edits including %s', async (file) => {
|
|
const changed = [...policyTests, file]
|
|
const scope = await classifyNodeServerChanges(changed, unavailableGraph, {
|
|
modifiedFiles: changed
|
|
})
|
|
expect(scope.shouldRun).toBe(true)
|
|
expect(scope.graphUnavailable).toBeUndefined()
|
|
expect(nodeServerQualification(changed, scope)).toEqual({
|
|
qualification: true,
|
|
runners: NODE_SERVER_RUNNERS
|
|
})
|
|
})
|
|
|
|
it.each([
|
|
'config/scripts/node-server-concurrency.test.mjs',
|
|
'config/scripts/node-server-packaged-chat-selection.test.mjs'
|
|
])(
|
|
'preserves unrelated %s routing with complete, absent, or non-modification evidence',
|
|
async (file) => {
|
|
expect(inputs.has(file)).toBe(false)
|
|
for (const modifiedFiles of [[file], undefined, []]) {
|
|
const scope = await classifyNodeServerChanges([file], async () => inputs, { modifiedFiles })
|
|
expect(scope.shouldRun).toBe(false)
|
|
expect(scope.graphUnavailable).toBeUndefined()
|
|
}
|
|
}
|
|
)
|
|
|
|
it.each([
|
|
'config/scripts/node-server-concurrency.test.mjs',
|
|
'config/scripts/node-server-packaged-chat-selection.test.mjs'
|
|
])('preserves both unmodified rename sides for unrelated %s', async (file) => {
|
|
const changed = [file, file.replace('.test.mjs', '-renamed.test.mjs')]
|
|
const scope = await classifyNodeServerChanges(changed, async () => inputs, {
|
|
modifiedFiles: []
|
|
})
|
|
expect(scope.shouldRun).toBe(false)
|
|
expect(scope.graphUnavailable).toBeUndefined()
|
|
})
|
|
|
|
it('preserves unrelated tests when only part of their changed vector is modified', async () => {
|
|
const changed = [
|
|
'config/scripts/node-server-concurrency.test.mjs',
|
|
'config/scripts/node-server-packaged-chat-selection.test.mjs'
|
|
]
|
|
const scope = await classifyNodeServerChanges(changed, async () => inputs, {
|
|
modifiedFiles: [changed[0]]
|
|
})
|
|
expect(scope.shouldRun).toBe(false)
|
|
expect(scope.graphUnavailable).toBeUndefined()
|
|
})
|
|
|
|
it.each(policyTests)(
|
|
'retains native qualification when %s becomes a real graph input',
|
|
async (file) => {
|
|
const reachable = await collectNodeServerInputs({ entryPoints: [file] })
|
|
expect(reachable.has(file)).toBe(true)
|
|
const scope = await classifyNodeServerChanges([file], async () => reachable, {
|
|
modifiedFiles: [file]
|
|
})
|
|
expect(scope).toMatchObject({ shouldRun: true, graphResolved: true, matchedFiles: [file] })
|
|
expect(nodeServerQualification([file], scope)).toEqual({
|
|
qualification: true,
|
|
runners: NODE_SERVER_RUNNERS
|
|
})
|
|
}
|
|
)
|
|
|
|
it('retains full qualification when graph collection fails', async () => {
|
|
const scope = await classifyNodeServerChanges(policyTests, unavailableGraph, {
|
|
modifiedFiles: policyTests
|
|
})
|
|
expect(scope).toMatchObject({ shouldRun: true, graphUnavailable: true })
|
|
expect(nodeServerQualification(policyTests, scope)).toEqual({
|
|
qualification: true,
|
|
runners: NODE_SERVER_RUNNERS
|
|
})
|
|
})
|
|
})
|