# 0.6.3 Test Surface Audit

**Status:** Initial classification — Phase 1 deliverable  
**Spec:** 0.6.3 Rust-first test migration requirements/design/tasks package  
**Requirements:** 1.1, 1.2, 1.3, 1.4, 1.5

---

## Purpose

This document is the authoritative classification of every in-scope test file
for the 0.6.3 Rust-first test migration. Each file is assigned exactly one
category and a rationale tied to the concern being tested.

### Categories

| Category | Meaning |
|---|---|
| **Keep as Rust-native** | Already implemented in Rust; no migration needed |
| **Migrate to Rust** | Currently shell or Python; canonical E2E logic should move to the Rust harness |
| **Keep as C** | Tests NGINX module internals, C/NGINX glue, or ABI concerns; must remain in C |
| **Keep as thin shell wrapper** | Shell orchestration that delegates to the Rust harness or preserves a public CLI contract |
| **Remove** | Stale, spec-only, or fully superseded; removal is safe once replacement coverage is confirmed |
| **Defer** | Out of 0.6.3 scope; retained on its current path without migration |

---

## Scope Directories

- `components/nginx-module/tests/` (unit, integration, helpers, make, run.sh, Makefile)
- `components/nginx-module/tests/e2e/`
- `tools/e2e/`
- `tests/property/`

---

## 1. `components/nginx-module/tests/` — Top-level harness files

| File | Category | Concern | Rationale |
|---|---|---|---|
| `Makefile` | **Keep as C** | C test build orchestration | Drives compilation and linking of all C unit and integration tests; NGINX module build system concern |
| `run.sh` | **Keep as thin shell wrapper** | Test mode dispatch | Thin dispatcher that delegates to `make` targets; no scenario logic; preserves the `make test-nginx-unit` public contract |

---

## 2. `components/nginx-module/tests/unit/` — C unit tests

All files in this directory are classified **Keep as C**. They test NGINX module
internals, C/NGINX glue, configuration parsing, header/body filter logic, ABI
boundaries, and metrics structures — concerns that must remain in C per the
C_Test_Boundary definition.

| File | Concern |
|---|---|
| `accept_parser_test.c` | Accept-header parsing logic in C (NGINX module glue) |
| `auth_cache_control_test.c` | Cache-Control header handling in the auth path (C filter internals) |
| `auth_cookie_pattern_test.c` | Auth cookie detection pattern matching (C filter internals) |
| `body_filter_test.c` | NGINX body filter chain and buffer handling (NGINX module glue) |
| `brotli_function_test.c` | Brotli decompression function correctness (C decompression internals) |
| `brotli_standalone_test.c` | Brotli decompression standalone smoke (compiler/toolchain-sensitive C behavior) |
| `conditional_requests_test.c` | Conditional request (ETag/IMS) logic in C (C filter internals) |
| `config_core_impl_test.c` | Core configuration parsing and defaults (configuration parsing and merge logic) |
| `config_handlers_impl_test.c` | Configuration directive handler implementations (configuration parsing and merge logic) |
| `config_merge_test.c` | Configuration merge across location/server/http blocks (configuration parsing and merge logic) |
| `config_parsing_test.c` | Directive value parsing (configuration parsing and merge logic) |
| `conversion_impl_base_url_test.c` | Base URL construction in the conversion implementation (C filter internals) |
| `decision_log_test.c` | Decision log formatting and reason code emission (NGINX module glue) |
| `decompression_detect_test.c` | Content-Encoding detection logic (C filter internals) |
| `decompression_logging_test.c` | Decompression event logging (NGINX module glue) |
| `dynconf_impl_test.c` | Dynamic configuration snapshot, apply, and reload logic (configuration parsing and merge logic) |
| `effective_conf_test.c` | Effective configuration view construction and snapshot isolation (configuration parsing and merge logic) |
| `eligibility_impl_test.c` | Eligibility decision chain implementation (NGINX module glue) |
| `eligibility_test.c` | Eligibility enum and reason code mapping (NGINX module glue) |
| `error_classification_test.c` | Error category classification logic (C filter internals) |
| `error_impl_test.c` | Error handling implementation paths (C filter internals) |
| `failure_strategies_test.c` | Fail-open / fail-closed strategy dispatch (C filter internals) |
| `fast_path_test.c` | Fast-path eligibility short-circuit (NGINX module glue) |
| `gzip_deflate_decompression_test.c` | Gzip/deflate decompression correctness (C decompression internals) |
| `head_request_test.c` | HEAD request handling in the filter (NGINX module glue) |
| `header_compile_test.c` | Header compilation and ABI boundary smoke (ABI and FFI boundary validation) |
| `header_filter_test.c` | NGINX header filter chain behavior (NGINX module glue and lifecycle hooks) |
| `headers_test.c` | Response header manipulation (header and body filter internals) |
| `input_validation_test.c` | Input validation guards (C filter internals) |
| `markdown_filter_runtime_test.c` | Filter runtime state machine (NGINX module glue and lifecycle hooks) |
| `metrics_collection_test.c` | Metrics counter increment paths (metrics internals tied to C structures) |
| `metrics_decompression_test.c` | Decompression metrics accounting (metrics internals tied to C structures) |
| `metrics_endpoint_test.c` | Metrics endpoint handler (metrics internals tied to C structures) |
| `metrics_format_select_test.c` | Metrics format content negotiation in C (metrics internals tied to C structures) |
| `metrics_output_test.c` | Metrics output rendering (JSON/text/Prometheus) (metrics internals tied to C structures) |
| `metrics_snapshot_new_fields_test.c` | Metrics snapshot field coverage for new fields (metrics internals tied to C structures) |
| `otel_impl_test.c` | OpenTelemetry integration implementation (NGINX module glue) |
| `passthrough_test.c` | Pass-through (non-conversion) path correctness (NGINX module glue) |
| `prometheus_format_test.c` | Prometheus text format rendering in C (metrics internals tied to C structures) |
| `prometheus_per_path_test.c` | Per-path Prometheus metric labeling (metrics internals tied to C structures) |
| `prometheus_renderer_test.c` | Prometheus renderer correctness (metrics internals tied to C structures) |
| `protocol_correctness_test.c` | HTTP protocol correctness in filter responses (NGINX module glue) |
| `reason_code_test.c` | Reason code string definitions and accessor functions (NGINX module glue) |
| `skip_counter_test.c` | Skip counter increment logic (metrics internals tied to C structures) |
| `streaming_decomp_test.c` | Streaming decompression path (C decompression internals) |
| `streaming_impl_test.c` | Streaming filter implementation internals (NGINX module glue and lifecycle hooks) |
| `streaming_prometheus_metric_family_test.c` | Streaming-specific Prometheus metric families (metrics internals tied to C structures) |
| `streaming_test.c` | Streaming path correctness and state machine (NGINX module glue and lifecycle hooks) |
| `template_minimal_test.c` | Minimal test template / harness smoke (NGINX stub compatibility) |
| `threshold_router_test.c` | Threshold-based path router (full-buffer vs incremental) (C filter internals) |
| `unsupported_format_fallback_test.c` | Unsupported format fallback behavior (C filter internals) |

---

## 3. `components/nginx-module/tests/integration/` — C integration tests

| File | Category | Concern | Rationale |
|---|---|---|---|
| `nginx_runtime_integration_test.c` | **Keep as C** | NGINX runtime integration (module load, config apply, request lifecycle) | Tests the module against a real NGINX stub runtime; validates NGINX module glue and lifecycle hooks at the integration level |
| `run_integration_tests.sh` | **Keep as thin shell wrapper** | Integration test runner | Thin shell dispatcher that invokes the compiled C integration test binary; no scenario assertion logic |

---

## 4. `components/nginx-module/tests/helpers/` — C test helpers

| File | Category | Concern | Rationale |
|---|---|---|---|
| `headers_standalone.c` | **Keep as C** | Standalone header helper for tests that cannot link the full module (ABI and FFI boundary validation) | Provides a minimal header-manipulation surface for unit tests that need to exercise header logic without the full NGINX stub |
| `headers_standalone_types.h` | **Keep as C** | Type definitions for the standalone header helper | Header companion to `headers_standalone.c`; part of the same ABI boundary validation surface |

---

## 5. `components/nginx-module/tests/make/` — Build infrastructure

| File | Category | Concern | Rationale |
|---|---|---|---|
| `targets.mk` | **Keep as C** | C test build targets (compiler flags, sanitizer targets, clang smoke) | Defines `make test-nginx-unit`, `make test-nginx-unit-clang-smoke`, and `make test-nginx-unit-sanitize-smoke`; sanitizer smoke checks and compiler/toolchain-sensitive C behavior |

---

## 6. `components/nginx-module/tests/e2e/` — Python E2E spec files

| File | Category | Concern | Rationale |
|---|---|---|---|
| `test_streaming_e2e.py` | **Remove** | Streaming runtime E2E (spec-only Python file) | See §8 below for full removal rationale and replacement path |
| `test_streaming_failure_cache_e2e.py` | **Remove** | Streaming failure/cache semantics E2E (spec-only Python file) | See §8 below for full removal rationale and replacement path |

---

## 7. `tools/e2e/` — Shell E2E scenario scripts

| File | Category | Concern | Rationale |
|---|---|---|---|
| `run_e2e_suite.sh` | **Keep as thin shell wrapper** | Suite-level orchestration for `make test-e2e` | Top-level suite entrypoint; will delegate migrated scenarios to `e2e-harness` while retaining non-migrated scenarios on their current path; preserves the public `make test-e2e` contract |
| `verify_conditional_requests_e2e.sh` | **Migrate to Rust** | Conditional request runtime assertions (ETag, IMS, 304, HEAD parity) | One of the five first-batch 0.6.3 migration targets; canonical assertion logic moves to `tools/e2e-harness/src/scenarios/conditional_requests.rs`; shell script becomes a thin wrapper or is removed |
| `verify_metrics_endpoint_e2e.sh` | **Migrate to Rust** | Metrics endpoint runtime assertions (JSON/text/Prometheus format, default behavior) | One of the five first-batch 0.6.3 migration targets; canonical assertion logic moves to `tools/e2e-harness/src/scenarios/metrics_endpoint.rs` |
| `verify_status_codes_e2e.sh` | **Migrate to Rust** | Status code passthrough and redirect runtime assertions | One of the five first-batch 0.6.3 migration targets; canonical assertion logic moves to `tools/e2e-harness/src/scenarios/status_codes.rs` |
| `verify_auth_cache_e2e.sh` | **Migrate to Rust** | Auth cookie detection, Cache-Control, ETag replacement, Vary runtime assertions | One of the five first-batch 0.6.3 migration targets; canonical assertion logic moves to `tools/e2e-harness/src/scenarios/auth_cache.rs` |
| `verify_accept_negotiation_e2e.sh` | **Migrate to Rust** | Accept-header negotiation and wildcard runtime assertions | One of the five first-batch 0.6.3 migration targets; canonical assertion logic moves to `tools/e2e-harness/src/scenarios/accept_negotiation.rs` |
| `verify_chunked_streaming_native_e2e.sh` | **Defer** | Chunked streaming native runtime assertions | Streaming E2E path; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_streaming_e2e.sh` | **Defer** | Streaming conversion runtime assertions | Streaming E2E path; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_streaming_failure_cache_e2e.sh` | **Defer** | Streaming failure/cache semantics runtime assertions | Streaming E2E path; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_config_merge_e2e.sh` | **Defer** | Configuration merge runtime assertions | Configuration merge E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_error_handling_e2e.sh` | **Defer** | Error handling runtime assertions | Error handling E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_huge_body_allowed_native_e2e.sh` | **Defer** | Huge body allowed path runtime assertions | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_huge_body_native_e2e.sh` | **Defer** | Huge body rejection runtime assertions | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_large_markdown_response_e2e.sh` | **Defer** | Large Markdown response runtime assertions | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_proxy_tls_backend_e2e.sh` | **Defer** | TLS backend proxy runtime assertions | TLS/proxy E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `verify_security_e2e.sh` | **Defer** | Security runtime assertions (injection, path traversal, header validation) | Security E2E; not in the 0.6.3 first-batch migration scope; retained on its current canonical path |
| `fixtures/tls_backend_server.py` | **Defer** | TLS fixture backend for `verify_proxy_tls_backend_e2e.sh` | Python fixture server; not in the 0.6.3 first-batch migration scope; retained alongside its parent scenario |

---

## 8. `tests/property/` — Python property-based tests

| File | Category | Concern | Rationale |
|---|---|---|---|
| `__init__.py` | **Keep as Rust-native** | Python package marker | Empty package marker; no test logic |
| `test_prometheus_metrics.py` | **Keep as Rust-native** | Prometheus text format renderer properties (round-trip serialization, naming compliance, label boundary enforcement, counter accounting invariants, content negotiation, time series count) | Pure Python property-based tests using Hypothesis; test a Python reference model of the C Prometheus renderer; no NGINX runtime required; provide unique coverage of the renderer's output contract that is not duplicated by C unit tests; these tests are already Rust-first-compatible in the sense that they are pure logic tests with no shell orchestration |
| `test_reason_codes.py` | **Keep as Rust-native** | Reason code system properties (completeness, format, decision chain order, verbosity gating, NGINX log level mapping, request state mapping) | Pure Python property-based tests using Hypothesis; test a Python reference model of the C reason code system; no NGINX runtime required; provide unique coverage of the reason code contract that is not duplicated by C unit tests |

> **Note on `tests/property/` classification:** These files are classified
> **Keep as Rust-native** because they are pure-logic property tests with no
> shell orchestration or NGINX runtime dependency. They are not Python E2E spec
> files in the sense of Requirement 4 (which targets
> `components/nginx-module/tests/e2e/`). They remain on their current path and
> are not in scope for removal or migration in 0.6.3.

---

## 9. Remove and Defer Summary

### Files Classified as Remove

| File | Removal Rationale | Canonical Retained / Planned Replacement |
|---|---|---|
| `components/nginx-module/tests/e2e/test_streaming_e2e.py` | Spec-only Python E2E file. Most test cases are either skipped (`pytest.skip`) or require a streaming-enabled NGINX binary that is not available in standard CI. The two runnable cases (`test_16_1_streaming_conversion_success`, `test_16_4_streaming_fallback`, `test_16_8_head_request_no_streaming`) exercise the same runtime behavior already covered by `tools/e2e/verify_chunked_streaming_native_e2e.sh` and `tools/e2e/verify_streaming_e2e.sh`. The four non-skipped security/validation unit tests (`test_start_nginx_rejects_relative_binary_path`, `test_nginx_bin_returns_canonical_absolute_path`, `test_nginx_bin_rejects_path_outside_allowlist`, `test_nginx_bin_rejects_unexpected_basename`) test internal Python helper logic, not product behavior. Requirement 4.1 mandates removal unless unique runtime coverage is demonstrated. | `tools/e2e/verify_chunked_streaming_native_e2e.sh` (retained canonical streaming path); `tools/e2e/verify_streaming_e2e.sh` (retained canonical streaming path). The four Python-helper unit tests have no product-level equivalent and are not worth migrating. |
| `components/nginx-module/tests/e2e/test_streaming_failure_cache_e2e.py` | Spec-only Python E2E file. All nine test cases are either empty stubs (no assertions) or guarded by `pytest.skip`. Only `test_10_1_streaming_success_etag_not_in_headers` and `test_10_7_streaming_response_headers` contain any assertions, and those assertions (`status == 200`, `Content-Type contains text/markdown`) are a strict subset of what `tools/e2e/verify_streaming_failure_cache_e2e.sh` already validates. No unique assertions exist. Requirement 4.1 mandates removal. | `tools/e2e/verify_streaming_failure_cache_e2e.sh` (retained canonical streaming failure/cache path). |

### Files Classified as Defer

| File | Defer Rationale | Canonical Retained Path |
|---|---|---|
| `tools/e2e/verify_chunked_streaming_native_e2e.sh` | Streaming E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_chunked_streaming_native_e2e.sh` (unchanged) |
| `tools/e2e/verify_streaming_e2e.sh` | Streaming E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_streaming_e2e.sh` (unchanged) |
| `tools/e2e/verify_streaming_failure_cache_e2e.sh` | Streaming failure/cache E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_streaming_failure_cache_e2e.sh` (unchanged) |
| `tools/e2e/verify_config_merge_e2e.sh` | Configuration merge E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_config_merge_e2e.sh` (unchanged) |
| `tools/e2e/verify_error_handling_e2e.sh` | Error handling E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_error_handling_e2e.sh` (unchanged) |
| `tools/e2e/verify_huge_body_allowed_native_e2e.sh` | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_huge_body_allowed_native_e2e.sh` (unchanged) |
| `tools/e2e/verify_huge_body_native_e2e.sh` | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_huge_body_native_e2e.sh` (unchanged) |
| `tools/e2e/verify_large_markdown_response_e2e.sh` | Performance/boundary E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_large_markdown_response_e2e.sh` (unchanged) |
| `tools/e2e/verify_proxy_tls_backend_e2e.sh` | TLS/proxy E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_proxy_tls_backend_e2e.sh` (unchanged) |
| `tools/e2e/verify_security_e2e.sh` | Security E2E; not in the 0.6.3 first-batch migration scope | `tools/e2e/verify_security_e2e.sh` (unchanged) |
| `tools/e2e/fixtures/tls_backend_server.py` | TLS fixture backend for deferred scenario; not in the 0.6.3 first-batch migration scope | `tools/e2e/fixtures/tls_backend_server.py` (unchanged) |

---

## 10. Classification Summary

| Category | Count |
|---|---|
| Keep as C | 57 |
| Keep as thin shell wrapper | 3 |
| Migrate to Rust | 5 |
| Keep as Rust-native | 3 |
| Remove | 2 |
| Defer | 11 |
| **Total** | **81** |

---

## 11. Mandatory Scope Coverage Verification

All four mandatory audit scope directories are represented:

- [x] `components/nginx-module/tests/` — unit (51 files), integration (2), helpers (2), make (1), run.sh (1), Makefile (1)
- [x] `components/nginx-module/tests/e2e/` — represented by 2 removed Python E2E spec files (no remaining tracked Python E2E spec files)
- [x] `tools/e2e/` — 16 shell scripts + 1 fixture (5 Migrate to Rust, 1 thin wrapper, 11 Defer)
- [x] `tests/property/` — 3 files (2 Keep as Rust-native, 1 package marker)

---

## 12. Planned Replacement Paths for Migrated Scenarios

| Current canonical path | Planned Rust replacement |
|---|---|
| `tools/e2e/verify_conditional_requests_e2e.sh` | `tools/e2e-harness/src/scenarios/conditional_requests.rs` |
| `tools/e2e/verify_metrics_endpoint_e2e.sh` | `tools/e2e-harness/src/scenarios/metrics_endpoint.rs` |
| `tools/e2e/verify_status_codes_e2e.sh` | `tools/e2e-harness/src/scenarios/status_codes.rs` |
| `tools/e2e/verify_auth_cache_e2e.sh` | `tools/e2e-harness/src/scenarios/auth_cache.rs` |
| `tools/e2e/verify_accept_negotiation_e2e.sh` | `tools/e2e-harness/src/scenarios/accept_negotiation.rs` |

After migration, each shell script is either converted to a thin wrapper that
delegates to `e2e-harness scenario <name>` or removed if the Rust harness
provides a complete replacement for all documented flags and environment
variables.

---

*This document satisfies Requirements 1.1–1.5 of the 0.6.3 Rust-first test
migration spec. Python E2E cleanup has been completed and recorded below.*

---

## 13. Phase 5 — Python E2E Cleanup Result (2026-05-12)

**Result**: Python E2E spec files were removed from
`components/nginx-module/tests/e2e/`:

- `test_streaming_e2e.py`
- `test_streaming_failure_cache_e2e.py`

**Removal rationale**:

- no unique product-level runtime assertions remained;
- streaming/runtime assertions are covered by retained canonical shell paths
  (`verify_chunked_streaming_native_e2e.sh`,
  `verify_streaming_failure_cache_e2e.sh`,
  `verify_streaming_e2e.sh`);
- Python-only helper assertions were not product runtime behavior and were not
  in-scope to preserve as canonical E2E.

This completes Requirement 4 cleanup without changing the deferred streaming
scenario scope in 0.6.3.
