You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
13 KiB
13 KiB
Phase 1 테스팅 체크리스트
실제 구현 기준 재작성 (2026-03-12).
Stock Oracle(localhost:18001)을 data intermediary로 사용하는 아키텍처 기준.
[x] = 테스트 통과 확인, [ ] = 미커버 또는 미통과.
1. 테스트 레벨
| 레벨 | 실행 명령 | 상태 |
|---|---|---|
| 단위 테스트 | make test-unit |
100 tests pass |
| 리플레이 테스트 | make test-replay |
5 tests pass |
| 통합 테스트 | make test-integration |
Docker postgres 필요 |
| 운영 전 수동 점검 | 아래 섹션 참조 | — |
2. 단위 테스트 체크리스트
2.1 config (tests/unit/test_config.py)
- Settings가 기본값을 올바르게 로드한다 —
test_settings_defaults - log_level이 대문자로 정규화된다 —
test_log_level_normalized - exhibit_cache_dir이 data_root 기반 경로를 반환한다 —
test_exhibit_cache_dir - parquet_dir이 data_root 기반 경로를 반환한다 —
test_parquet_dir - get_symbols가 YAML에서 심볼 목록을 반환한다 —
test_get_symbols
2.2 ids (tests/unit/test_ids.py)
- document_id 포맷이 규칙(DOC::source::issuer_id:📅:acc)을 만족한다 —
test_document_id_format - event_id 포맷이 규칙(EVT::...)을 만족하며 event_type이 포함된다 —
test_event_id_format - CIK에서 issuer_id가 0-padded 10자리로 생성된다 —
test_issuer_id_from_cik - ticker에서 symbol_id가 기본 venue(XNYS)로 생성된다 —
test_symbol_id_from_ticker - ticker가 대문자로 정규화되고 custom venue가 반영된다 —
test_symbol_id_uppercase - sha256_checksum이 동일 입력에 대해 deterministic 하다 —
test_sha256_checksum - 다른 입력에 대해 다른 checksum이 생성된다 —
test_sha256_different - new_job_run_id가 유효한 UUID를 반환한다 —
test_new_job_run_id
2.3 time_utils (tests/unit/test_time_utils.py)
- utc_now()가 tz-aware datetime을 반환한다 —
test_utc_now - UTC → Eastern 변환이 정확하다 (21:05 UTC = 16:05 ET) —
test_to_eastern - Eastern → UTC 변환이 정확하다 —
test_to_utc - naive datetime은 변환 시 ValueError가 발생한다 —
test_naive_datetime_rejected - 21:05 UTC는 "post_market"으로 분류된다 —
test_filing_time_bucket_post_market - 12:00 UTC (07:00 ET)는 "pre_market"으로 분류된다 —
test_filing_time_bucket_pre_market - 15:00 UTC (10:00 ET)는 "regular_hours"로 분류된다 —
test_filing_time_bucket_regular - naive datetime은 "unknown"으로 분류된다 —
test_filing_time_bucket_naive
2.4 file_store (tests/unit/test_file_store.py)
- exhibit 쓰기/읽기가 정상 작동하고 checksum을 반환한다 —
test_write_and_read_exhibit - exists_exhibit이 존재 여부를 정확히 반환한다 —
test_exists_exhibit - get_checksum이 동일 파일에 대해 deterministic 하다 —
test_checksum_deterministic - exhibit 경로에 안전한 파일명(EX-99.1.txt)이 사용된다 —
test_exhibit_path_safe_chars
2.5 retries (tests/unit/test_retries.py)
- 예외 계층 구조(RetryableError/NonRetryableError/ValidationError/DependencyError)가 올바르다 —
test_exception_hierarchy - 에러 필드(source/entity/context)가 올바르게 저장된다 —
test_error_fields - 첫 시도에 성공하면 1회만 호출된다 —
test_with_retry_succeeds_on_first_attempt - RetryableError 발생 시 최대 횟수까지 재시도한다 —
test_with_retry_retries_on_retryable_error - NonRetryableError는 1회만 호출되고 즉시 raise된다 —
test_with_retry_does_not_retry_non_retryable - max_attempts 모두 소진 후 RetryableError가 최종 raise된다 —
test_with_retry_exhaustion
2.6 logging (tests/unit/test_logging.py)
- configure_logging("DEBUG") 호출 시 예외가 발생하지 않는다 —
test_configure_logging_no_error - bind_job_run_id 후 ContextVar에 run_id가 설정된다 —
test_bind_job_run_id_in_context - get_logger가 info/debug/warning/error 메서드를 가진 객체를 반환한다 —
test_get_logger_returns_bound_logger
2.7 oracle_client
기존 테스트 (tests/unit/test_oracle_client.py)
- FilingsService.search_filings가 FilingSearchResponse를 반환한다 —
test_search_filings - FilingsService.get_exhibit가 ExhibitResponse를 반환한다 —
test_get_exhibit - PriceService.get_daily_bars가 PriceDataResponse를 반환한다 —
test_get_daily_bars - 404 응답 시 OracleNotFoundError가 발생한다 —
test_not_found_raises_oracle_not_found - 500 응답 시 OracleServerError가 발생한다 —
test_server_error_raises_oracle_server_error - 일시적 500 후 성공 시 정상 결과를 반환한다 —
test_get_retries_on_transient_error_then_succeeds - FinraService.get_short_volume가 ShortVolumeResponse를 반환한다 —
test_get_short_volume - FinancialService.get_financial_data가 FinancialDataResponse를 반환한다 —
test_get_financial_data - ConnectError 시 OracleConnectionError가 발생한다 (3회 재시도 후) —
test_connection_error_raises_oracle_connection_error - ReadTimeout 시 OracleTimeoutError가 발생한다 (3회 재시도 후) —
test_timeout_raises_oracle_timeout_error - context manager 없이 get() 호출 시 RuntimeError가 발생한다 —
test_client_without_context_manager_raises
FredService (tests/unit/test_fred_service.py)
- FredService.get_observations가 FredProxyResponse(series_id, observations)를 반환한다 —
test_get_observations - FredService.get_series_info가 FredSeriesInfo(id, frequency)를 반환한다 —
test_get_series_info
2.8 parser
text_normalizer (tests/unit/test_text_normalizer.py)
- HTML 태그가 제거된다
- 연속 공백/개행이 정규화된다
- 빈 문자열 입력이 처리된다
rule_parser (tests/unit/test_rule_parser.py)
- Item 2.02가 earnings_release로 분류된다
- Item 7.01이 analyst_day로 분류된다
- Item 1.01이 agreement_signed으로 분류된다
- Item 8.01이 other_disclosure로 분류된다
- 긍정 키워드로 bullish 방향이 감지된다
- 부정 키워드로 bearish 방향이 감지된다
- Guidance raised/lowered 구문이 올바르게 분류된다
- non_gaap_heavy risk flag가 감지된다
- financing_related risk flag가 감지된다
- evidence에 매칭 rule_id가 포함된다
- 메타데이터(filing_date, accepted_at_utc)가 event_date/filing_time_bucket에 반영된다
schema_validator (tests/unit/test_schema_validator.py)
- 유효한 parser output이 validate 통과한다
- 잘못된 event_type enum은 invalid 처리된다
- confidence가 범위(0~1)를 벗어나면 invalid 처리된다
- 필수 필드 누락 시 invalid 처리된다
llm_parser_stub (tests/unit/test_llm_parser_stub.py)
- enabled=False 인 경우 parse()가 None을 반환한다 —
test_disabled_returns_none - enabled=True 인 경우 parse()가 NotImplementedError를 발생시킨다 —
test_enabled_raises_not_implemented
2.9 features
market_features (tests/unit/test_market_features.py)
- event_date 기준 reaction_day_return이 계산된다
- 전일 대비 pre_event_return이 계산된다
- bars가 없으면 빈 dict가 반환된다
- event_date가 bars에 없어도 가장 가까운 날짜로 폴백한다
- avg_volume_20d가 bars 수에 맞게 계산된다
event_features (tests/unit/test_event_features.py)
- bullish 방향 시 guidance_direction_score > 0이다
- bearish 방향 시 guidance_direction_score < 0이다
- risk_flags 비율이 올바르게 계산된다
- confidence.overall이 feature에 포함된다
- signals dict가 올바르게 변환된다
financial_features (tests/unit/test_financial_features.py)
- 최신 period의 eps/gross_margin/operating_margin이 추출된다
- period가 2개 이상일 때 eps_growth_qoq가 계산된다
- period가 2개 이상일 때 revenue_growth_qoq가 계산된다
- periods가 비어 있으면 빈 dict가 반환된다
- prior eps가 0일 때 eps_growth_qoq가 None이다
2.10 db models (tests/unit/test_db_models.py)
- IssuerMaster 필드(issuer_id, issuer_name, ticker, is_active)가 올바르게 설정된다 —
test_issuer_master_fields - Document 기본값(parsed_status="pending")이 올바르게 설정된다 —
test_document_defaults - Event 기본값(status="pending")이 올바르게 설정된다 —
test_event_defaults - JobRun 필드(records_seen, records_written)가 올바르게 설정된다 —
test_job_run_fields - DB enum 값(JobStatus/ParsedStatus/EventDirection/EventType/ParserKind)이 올바르게 정의된다 —
test_enums
3. 통합 테스트 체크리스트
Docker postgres 필요 (docker compose up postgres). make test-integration으로 실행.
3.1 Filing Pipeline (tests/integration/test_filing_pipeline.py)
- Document upsert helper가 중복 없이 idempotent 하다 —
test_document_upsert_idempotency_via_helpers - 동일 document_id 재삽입 시 중복 row가 생기지 않는다 —
test_document_upsert_idempotency - Event + EventParse lifecycle이 정상 작동한다 —
test_event_parse_lifecycle
3.2 Sync Jobs (tests/integration/test_sync_jobs.py)
- MacroSync: macro_observations 테이블에 적재된다 —
test_macro_series_insert - ShortVolumeSync: short_sale_daily 테이블에 적재된다 —
test_short_sale_daily_insert - IssuerSync: issuer_master 테이블이 갱신된다 (테스트 미작성)
3.3 DB Migration (tests/integration/test_db_migration.py)
- 14개 테이블이 모두 생성된다 —
test_all_tables_exist - DB 연결이 정상이다 —
test_db_health
3.4 Feature Pipeline (tests/integration/test_feature_pipeline.py)
- market_v1/event_v1 스냅샷이 정상 생성된다 —
test_feature_snapshot_created - financial_service 제공 시 financial_v1 스냅샷이 추가 생성된다 —
test_financial_v1_snapshot_created
4. 리플레이 테스트 체크리스트 (tests/replay/)
4.1 결정성 (test_determinism.py)
- 동일 텍스트에 대해 동일 parser version이면 event_type/guidance/confidence가 동일하다 —
test_parser_determinism - 부정/혼합 텍스트에서도 동일 결과가 나온다 —
test_parser_determinism_negative_text - event feature 계산이 deterministic 하다 —
test_feature_determinism
4.2 Idempotency (test_idempotency.py)
- 동일 document_id로 parser를 두 번 실행해도 동일한 결과가 나온다
- checksum이 동일 내용에 대해 항상 동일하다
5. 운영 전 수동 점검
5.1 환경
docker compose up postgres후make bootstrap성공make migrate실행 후 14개 테이블 생성 확인python -m apps.pipeline.filing_poller.main --dry-run실행 가능
5.2 관측 가능성
- 모든 job에 job_run_id가 JSON 로그에 찍힌다
- 실패 시 로그만 보고 실패 지점을 식별 가능하다
- records_seen / records_written / records_skipped가 job_runs에 기록된다
5.3 데이터 품질
- Oracle에서 실제 filing 1건을 fetch해 문서 내용 확인
- parser 결과 5건을 수동 검수해 event_type/guidance 품질 확인
- feature snapshot 1건을 조회해 필드값이 합리적인지 확인
5.4 실패 안전성
- Stock Oracle 응답 없을 때 OracleConnectionError → retry → 로그 확인
- parser invalid output이 Event 테이블로 흘러가지 않음을 확인
- DB 장애 시 JobRun status가 "failed"로 기록됨을 확인
6. CI 최소 요구 사항
make test-unit통과 (105 tests)make test-replay통과 (5 tests)ruff check통과 (format check는 기존 파일 formatting 필요)make test-integration통과 (9 tests pass)- migration smoke test 통과
7. Phase 1 승인 기준
| 항목 | 상태 | 비고 |
|---|---|---|
| 단위 테스트 자동화 세트 | ✅ | 105 tests pass |
| 리플레이 테스트 | ✅ | 5 tests pass |
| OracleClient 에러 처리 | ✅ | Connection/Timeout/ServerError 모두 커버 |
| parser schema validation | ✅ | JSON schema 기반 validation 테스트 완료 |
| feature snapshot 생성 | ✅ | market_v1/event_v1/financial_v1 코드 완료 |
| retry/backoff 정책 | ✅ | with_retry exhaustion 테스트 포함 |
| 로깅 구성 | ✅ | configure_logging/bind/get_logger 테스트 완료 |
| 통합 테스트 | ✅ | 9 tests pass (Docker postgres 실제 연동, Oracle은 httpx_mock) |
| 운영 전 수동 점검 | ⬜ | 실제 Oracle 연동 환경에서 수행 필요 |