runtime-plan-live-202607141.../planning-contract/contract-validator.test.ts

312 lines
8.8 KiB
TypeScript

/**
* 계획 계약 검증기 테스트
*/
import {
validateGoalClarity,
validateStepCompleteness,
validateExecutability,
validateRiskAssessment,
validateVerifiability,
validateTemporalConstraints,
validateRollbackCapability,
validateContract,
createEpitaph
} from './contract-validator';
import { Plan } from './types';
describe('계획 계약 검증기', () => {
describe('조항 1: 목표 명확성', () => {
it('명확한 목표는 통과해야 함', () => {
const plan: Plan = {
id: 'test-1',
goal: {
description: '테스트 파일 10개 생성',
criteria: ['파일 10개 생성됨', '각 파일 크기 > 0'],
produces: ['test-files']
},
steps: []
};
const result = validateGoalClarity(plan);
expect(result.passed).toBe(true);
expect(result.issues).toHaveLength(0);
});
it('모호한 표현이 있으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-2',
goal: {
description: '테스트 파일을 잘 생성',
criteria: []
},
steps: []
};
const result = validateGoalClarity(plan);
expect(result.passed).toBe(false);
expect(result.issues.length).toBeGreaterThan(0);
});
it('판단 기준이 없으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-3',
goal: {
description: '파일 생성',
criteria: []
},
steps: []
};
const result = validateGoalClarity(plan);
expect(result.passed).toBe(false);
expect(result.issues).toContain('목표 달성 판단 기준이 없음');
});
});
describe('조항 2: 단계 완전성', () => {
it('올바른 의존성 순서는 통과해야 함', () => {
const plan: Plan = {
id: 'test-4',
goal: {
description: '빌드 완료',
criteria: ['빌드 성공'],
produces: ['build-output']
},
steps: [
{ id: 'step1', description: '의존성 설치', produces: ['deps'] },
{ id: 'step2', description: '컴파일', dependencies: ['step1'], produces: ['build-output'] }
]
};
const result = validateStepCompleteness(plan);
expect(result.passed).toBe(true);
});
it('순서 위반이 있으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-5',
goal: {
description: '빌드 완료',
criteria: ['빌드 성공']
},
steps: [
{ id: 'step1', description: '컴파일', dependencies: ['step2'] },
{ id: 'step2', description: '의존성 설치' }
]
};
const result = validateStepCompleteness(plan);
expect(result.passed).toBe(false);
});
});
describe('조항 3: 실행 가능성', () => {
it('사용 가능한 명령어는 통과해야 함', () => {
const plan: Plan = {
id: 'test-6',
goal: { description: '테스트', criteria: ['완료'] },
steps: [
{ id: 'step1', command: 'npm', timeout: 30000 }
]
};
const result = validateExecutability(plan, ['npm', 'node']);
expect(result.passed).toBe(true);
});
it('타임아웃 없으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-7',
goal: { description: '테스트', criteria: ['완료'] },
steps: [
{ id: 'step1', command: 'npm' }
]
};
const result = validateExecutability(plan, ['npm']);
expect(result.passed).toBe(false);
expect(result.issues).toContain('단계 step1: 타임아웃 미설정');
});
});
describe('조항 4: 리스크 평가', () => {
it('리스크와 완화 전략이 있으면 통과해야 함', () => {
const plan: Plan = {
id: 'test-8',
goal: { description: '배포', criteria: ['성공'] },
steps: [],
risks: [
{
id: 'risk1',
description: '네트워크 오류',
severity: 'medium',
mitigation: '재시도 로직 구현'
}
]
};
const result = validateRiskAssessment(plan);
expect(result.passed).toBe(true);
});
it('고위험 리스크에 대안 경로 없으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-9',
goal: { description: '배포', criteria: ['성공'] },
steps: [],
risks: [
{
id: 'risk1',
description: '데이터 손상',
severity: 'critical'
}
]
};
const result = validateRiskAssessment(plan);
expect(result.passed).toBe(false);
});
});
describe('조항 5: 검증 가능성', () => {
it('예상 결과와 어설션이 있으면 통과해야 함', () => {
const plan: Plan = {
id: 'test-10',
goal: { description: '파일 생성', criteria: ['완료'] },
steps: [
{
id: 'step1',
description: '파일 생성',
expectedOutcome: '파일이 생성됨',
assertions: ['file.exists()']
}
]
};
const result = validateVerifiability(plan);
expect(result.passed).toBe(true);
});
it('어설션 없으면 실패해야 함', () => {
const plan: Plan = {
id: 'test-11',
goal: { description: '파일 생성', criteria: ['완료'] },
steps: [
{
id: 'step1',
description: '파일 생성',
expectedOutcome: '파일이 생성됨'
}
]
};
const result = validateVerifiability(plan);
expect(result.passed).toBe(false);
});
});
describe('조항 6: 시간적 제약', () => {
it('시간 제약이 설정되면 통과해야 함', () => {
const plan: Plan = {
id: 'test-12',
goal: { description: '빌드', criteria: ['완료'] },
steps: [
{ id: 'step1', timeout: 60000 }
],
estimatedDuration: 120000,
timeoutStrategy: '실패 후 롤백'
};
const result = validateTemporalConstraints(plan);
expect(result.passed).toBe(true);
});
});
describe('조항 7: 롤백 가능성', () => {
it('올바른 롤백 시퀀스가 있으면 통과해야 함', () => {
const plan: Plan = {
id: 'test-13',
goal: { description: '배포', criteria: ['완료'] },
steps: [],
rollbackCommands: [
{ id: 'rb1', command: 'rollback-step2', order: 2, verification: 'check-state' },
{ id: 'rb2', command: 'rollback-step1', order: 1, verification: 'check-state' }
]
};
const result = validateRollbackCapability(plan);
expect(result.passed).toBe(true);
});
});
describe('전체 계약 검증', () => {
it('모든 조항 충족 시 A 등급 부여', () => {
const plan: Plan = {
id: 'test-full',
goal: {
description: '완전한 테스트 계획',
criteria: ['모든 단계 성공'],
produces: ['result']
},
steps: [
{
id: 'step1',
description: '준비',
command: 'prepare',
timeout: 10000,
expectedOutcome: '준비 완료',
assertions: ['ready'],
produces: ['prepared']
},
{
id: 'step2',
description: '실행',
command: 'execute',
dependencies: ['step1'],
timeout: 30000,
expectedOutcome: '실행 완료',
assertions: ['completed'],
produces: ['result']
}
],
risks: [
{
id: 'risk1',
description: '실패 가능성',
severity: 'low',
mitigation: '재시도'
}
],
estimatedDuration: 60000,
timeoutStrategy: '중단',
rollbackCommands: [
{ id: 'rb1', command: 'cleanup', order: 1, verification: 'check-clean' }
]
};
const result = validateContract(plan, ['prepare', 'execute']);
expect(result.grade).toBe('A');
});
});
describe('에피타이드 생성', () => {
it('올바른 에피타이드를 생성해야 함', () => {
const plan: Plan = {
id: 'test-epitaph',
goal: { description: '테스트', criteria: ['완료'] },
steps: []
};
const validation = validateContract(plan);
const epitaph = createEpitaph(plan, validation, {
status: 'success',
duration: 5000
});
expect(epitaph.planId).toBe('test-epitaph');
expect(epitaph.timestamp).toBeDefined();
expect(epitaph.executionResult.status).toBe('success');
});
});
});