OpenAPI 자체 부트스트랩
Shepherd의 실행 중인 HTTP API를 Shepherd 자체 기능으로 테스트: API 정의 + 케이스 + 시나리오 오케스트레이션 + 실행.
실행
# A. 단일 체인 부트스트랩 (로그인 → 추출 → 인증된 체인 + 부정 401):
# 실제 체인 실행 메커니즘을 검증합니다.
python3 .claude/skills/openapi-bootstrap/selftest.py
# B. 전체 모듈 시나리오 커버리지: OpenAPI 태그당 하나의 CRUD/생명주기 시나리오,
# 모듈별 보고서와 함께 실행됩니다.
python3 .claude/skills/openapi-bootstrap/scenarios_all.py
# C. 테스트 계획 작업 자체 점검 (계획 CRUD, 계획 문서, 케이스 링크,
# 계획 실행, 단일 케이스 재실행, 스케줄)
python3 .claude/skills/openapi-bootstrap/plans_selftest.py
scenarios_all.py는 비즈니스 모듈당 하나의 실제 연쇄 시나리오를 구축하며(20개 모듈),
api 케이스(종류=CASE, 인증 헤더/변수 추출/어서션 포함)를 참조하고,
CRUD/생명주기 체인으로 정렬하여 환경 내에서 인프로세스로 실행합니다.
실패 전략 CONTINUE → 한 번의 실행으로 모든 모듈에 대한 단계별 통과/실패 + 이유가 산출됩니다.
현재 모두 통과: 20/20 모듈, 114/114 단계. "케이스 업데이트" 엔드포인트는 없습니다 → 각 실행은
이전 홀더 정의를 삭제하고(케이스도 함께 캐스케이드) 다시 구축합니다.
영구 리소스(프로젝트/사용자/요구사항)는 실행당 고유 접미사를 가지므로
반복 실행 시 고유 제약 조건에 걸리지 않습니다.
구축 중 확인된 실제 제약 조건(체인에 반영됨; 백엔드 열거형이 변경되면 동기화 유지):
- 리소스 풀
poolType∈ {Node,Kubernetes} (LOCAL 없음);allOrg=false인 경우,orgIds는 비어 있지 않아야 합니다. - 작업 생성
POST /decomposition/{id}/task는{"taskId": <슬러그>}를 반환합니다. (id가 아님); 포인트/상태 엔드포인트는 해당 taskId를 사용합니다. - 전달 실행기
CLAUDE_CODE/CODEX는 동기식 스텁입니다:POST /delivery는 한 단계로 완료되며, 직접DELIVERED로 생성됩니다. (실행 중/완료 비동기 전환 없음). /runner/probe및/runner-agent/{id}/run은 온라인 러너 에이전트가 필요합니다. (그렇지 않으면 502); 로컬 체인은 관리 평면만 다룹니다.- 여러 목록 엔드포인트는
?projectId=가 필요합니다(요구사항 / 스킬 / 기능 케이스 / 케이스 검토). - 생성은 201, 삭제/부분 업데이트는 204 반환 → 정확한
StatusIs(200)대신 일반적인ResponseCode < 400성공 어서션을 사용합니다.
| Env var | 기본값 | 설명 |
|---|---|---|
SHEPHERD_BASE | http://127.0.0.1:9180 | 백엔드 주소 |
SHEPHERD_USER / SHEPHERD_PASS | admin / s3cret | 로그인 자격 증명 (SHEPHERD_ADMIN_PASSWORD) |
SHEPHERD_PROJECT_ID | 자동 확인 | 대상 프로젝트; 기본값은 첫 번째 조직의 첫 번째 프로젝트, 없으면 생성됨 |
스크립트, 환경, 정의, 케이스 및 시나리오는 모두 이름으로 생성 또는 재사용됩니다 —
반복 실행이 누적되지 않습니다.
(기존 리소스 이름(예: 自举环境 / 自举链路)은 중국어로 유지됩니다:
이는 유지되는 이름 기반 재사용 키입니다. 이름을 바꾸면 기존 행이 고립됩니다.)
흐름 (7단계)
- 토큰 로그인(관리자 호출은 리소스 설정 전용)
- 조직 → 프로젝트 확인/생성
- 이 시스템의 OpenAPI 가져오기 (
GET /api-docs/openapi.json) → 멱등성 가져오기 (POST /api/definition/import; 동일한 메소드+경로는 사양을 덮어쓰고 중복되지 않음); 사양이 채워져 있고 각 인터페이스에 어서션이 있는 케이스가 있는지 샘플 확인 - 이 호스트를 가리키는 환경 생성 또는 재사용 (
baseUrl= 이 서버) - 부트스트랩 체인 정의 아래에 실제 케이스 4개 생성 또는 재사용
- 해당 케이스를 단계로 참조하는 시나리오 생성 또는 재사용
(
kind=CASE), 순서 정렬, 환경으로 실행 - 보고서 가져오기; 단계별 ✅/❌ + 추출된 변수 + 어서션 개수 출력
이것은 실제 체인이며 하드코딩된 GET이 아닙니다
시나리오는 하드코딩된 요청을 인라인으로 포함하는 대신 api 케이스를 참조합니다
(kind=CASE). 케이스는 POST + GET + 인증 헤더 + 변수 추출 +
크로스 스텝 체이닝을 다룹니다:
① 로그인 및 토큰 추출 POST /auth/login assert status 200 + contains "token" → extract token = $.token
② 인증된 조직 목록 조회 GET /organization header Authorization: Bearer ${token} → extract orgId = $.items[0].id
③ orgId로 인증된 프로젝트 목록 조회 GET /project?organizationId=${orgId} (토큰 및 orgId 모두 대체됨)
④ 부정: 토큰 없음 거부 GET /organization assert status 401
핵심 실행 메커니즘 (crates/api-test/src/adapters/{plan,local,pg}.rs,
crates/api-runner/src/domain/runner.rs 참조):
- CASE 단계는 인프로세스로 실행되며, 케이스의 전체
메소드/url/본문/헤더/인증/어서션/프로세서를 로드합니다 — 리소스 풀이 필요하지 않음
(인라인
REQUEST단계는 헤더를 삭제하므로 CASE 사용). - EXTRACT 프로세서는
$.token등을 실행 변수에 쓰고, 단계 간에 전달됩니다. ${var}단일 중괄호 대체는 url / 헤더 값 / 본문에 적용됩니다. (참고:{{}}아님).- 환경 baseUrl은 상대 url 앞에 붙습니다; 기본 헤더는 빈 곳을 채웁니다(동일한 이름의 케이스 헤더가 우선).
- 알려진 제한:
Variable어서션은 시나리오 내에서 실행 변수를 볼 수 없습니다. (plan.rs는 어서션 평가에 변수를 전달하지 않음), 따라서 이 스크립트는Variable어서션 대신StatusIs/BodyContains를 사용합니다.
테스트 계획 작업 자체 점검
plans_selftest.py는 HTTP API를 통해 테스트 계획 작업을 종단 간 검증합니다:
계획 생성/재사용(계획 ID는 로컬 상태 파일 .plan_selftest_id에 유지,
계획 목록/삭제 엔드포인트가 없으므로), PUT 업데이트 라운드트립
(설명/태그/passThreshold), 계획 문서 저장 + 링크 동기화,
케이스 링크(시나리오 1개 + API 케이스 1개), 전체 계획 실행(모든 행 SUCCESS,
시나리오 행은 단계가 모두 SUCCESS인 reportId를 전달함),
단일 케이스 재실행, 스케줄 생성/삭제(201/204/404), 케이스 링크 해제(204 + 목록 축소).
멱등성: 연속으로 두 번 실행해도 두 번 모두 완전히 통과해야 합니다.
백엔드 가져오기 개선 사항(함께 제공)
POST /api/definition/import 이제:
- 각 작업의
parameters(쿼리/헤더/경로; 필수 플래그는 비고에 인코딩됨),requestBody($ref/allOf가components에 대해 bodySchema 트리 + 예제로 확인됨) 및responses(상태 코드 + 스키마 예제)를 구문 분석 → 정의spec에 기록; - 각 새 인터페이스에 대해 기본 케이스(상태 코드 + 기본 비즈니스 어서션)를 생성합니다.
- 멱등성을 가집니다: 기존 프로젝트+메소드+경로는 사양만 덮어씁니다.
(사용자가 편집한 케이스는 보존됨);
{created, updated, skipped}를 반환합니다.
코드: crates/api-definition/src/domain/import.rs,
application/import_api_definitions.rs, domain/api_definition.rs (with_spec).
종료 코드
0 모두 통과; 1 일부 단계 실패; 2 부트스트랩 흐름 자체 오류.