Skip to content

(#4) test: migrate to matrix + remove legacy E2E - #59

Closed
SieDeta wants to merge 6 commits into
shared-configureable-E2E-libfrom
migrate-matrix-remove-legacy
Closed

(#4) test: migrate to matrix + remove legacy E2E#59
SieDeta wants to merge 6 commits into
shared-configureable-E2E-libfrom
migrate-matrix-remove-legacy

Conversation

@SieDeta

@SieDeta SieDeta commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR completes the high-risk migration from legacy E2E tests to the matrix-based execution framework introduced in previous phases. It removes duplicated legacy infrastructure while preserving existing test entry points and behavior.

The primary goal of this migration is to consolidate previously independent E2E implementations behind a single execution engine (tests/e2e_matrix.py), reducing maintenance burden while ensuring that all E2E coverage continues to exercise the same underlying runner and comparator paths.

What's Included

Wrapper Support (tests/e2e_matrix.py)

matrix_argv_from_env()

Translates legacy E2E_* environment variables into a single-cell matrix invocation, ensuring compatibility with existing workflows.

Supported legacy inputs include:

  • Model selection
  • --enforce-eager
  • Dtype configuration
  • Ring transport options
  • Hook selection
  • Tolerance settings
  • Database configuration
  • Other existing E2E parameters

This preserves the behavior of the previous E2E tests while routing execution through the matrix framework.


run_single()

Provides a thin compatibility layer that:

  • Parses matrix arguments
  • Verifies that exactly one matrix cell is requested
  • Executes that cell
  • Returns the resulting CellResult

Any invocation expanding to multiple cells is rejected.

This guarantees that existing pytest tests continue to represent a single logical assertion, matching the semantics of the legacy implementations.

Migration to Matrix-Based Execution

Prior to this PR, each E2E test suite implemented its own orchestration logic, resulting in duplicated code for:

  • Runner invocation
  • Comparator selection
  • Environment translation
  • Result parsing
  • Reporting

The new architecture centralizes these responsibilities in tests/e2e_matrix.py and shared libraries under tests/lib/.

The migrated tests now act as thin wrappers that specify the desired matrix configuration while delegating execution to the common matrix engine.

Conceptually, the migration changes the structure from:

HF tests
├── runner orchestration
├── comparison logic
└── reporting

vLLM tests
├── runner orchestration
├── comparison logic
└── reporting

to:

                    tests/e2e_matrix.py
                             │
           ┌─────────────────┼─────────────────┐
           │                 │                 │
    HF wrappers       vLLM wrappers     Future wrappers

This enables future expansion across:

  • Backends (HF, vLLM)
  • Models
  • Execution modes
  • Hook selections
  • Tensor parallel configurations
  • Comparison standards

without introducing additional duplicated E2E infrastructure.

Legacy E2E Removal

test_e2e_correctness_vs_hf.py

Reduced from approximately 1667 lines → 85 lines.

Active Tests Migrated

The remaining active tests now act as thin wrappers around matrix execution:

  • HF / eager / allclose
  • HF / CUDA graphs / allclose (tol = 0.5)

Removed Legacy Code

Deleted the following obsolete components:

  • Both uncollected _legacy implementations retained "for reference"

  • Permanently disabled:

    @pytest.mark.skipif(True)
    def test_e2e_correctness_hf_cuda_graphs(...)
  • Unused in-process helper functions

Note: The disabled CUDA-graphs test relied on a compiled-rollout reference that had already been superseded. No active assertions or passing coverage were lost.

vLLM Test Migration

test_vllm_identical.py

Reduced from 262 → ~55 lines.

Migrated to a matrix wrapper executing:

vllm / bitwise

comparison cells.


test_vllm_rowcnt.py

Reduced from 117 → ~50 lines.

Migrated to a matrix wrapper executing:

vllm / row_count

comparison cells.

Safety Checks

Public Test Names Preserved

All four externally visible test names remain unchanged.

This preserves compatibility with:

  • Existing shell wrappers
  • CI configurations
  • Node ID–based test invocations

Precise Requirement-Based Skips

Tests now use explicit requirement guards from tests/_requirements.py:

  • require_cuda()
  • require_vllm()
  • require_clickhouse()

This improves failure reporting and prevents ambiguous environment-related failures.


Static Matrix-Parity Verification

Verified that each wrapper dispatches the exact same runner + comparator chain used by the corresponding legacy implementation.

Parity was confirmed using matrix dry-run dispatch output.

This migration intentionally changes the orchestration layer only; the underlying inference runners and comparison logic remain unchanged.

Verification

  • ✅ CPU test suite: 116 passed
  • ✅ Added 6 wrapper translation unit tests
  • ✅ All wrapper translation tests pass
  • ✅ Static dispatch parity verified for all migrated wrappers
  • ✅ No changes to public test node IDs
  • ✅ Zero newly introduced failures

⚠️ Merge Gate

Per the migration plan (PR #58 – PR #59 convention), this PR requires a numeric GPU/ClickHouse parity run before merge.

The purpose of this validation is to demonstrate that the matrix wrappers produce numerically equivalent behavior to the legacy implementations under real GPU execution.

The parity run should compare:

  • Legacy E2E implementation output
  • Matrix-wrapper output

using the same:

  • Model
  • Backend
  • Execution mode
  • Hook selection
  • Tensor-parallel configuration

The comparison should verify:

  • Identical runner dispatch behavior
  • Equivalent ClickHouse transport output
  • Matching comparator verdicts
  • Consistent numeric metrics (max_abs, mean_abs, first-difference position)
  • No unexpected token divergence

This validation provides evidence that the migration changed only the execution framework and not the functional correctness guarantees of the E2E suite.

Note: Static dispatch parity has been verified in this PR. Dynamic GPU/ClickHouse parity execution could not be performed in the current environment and must be completed prior to merge.

Introduce the test-suite categorization foundation from the test-suite
refactor plan (PR #1 of 6).

- pyproject.toml: register the full marker set (cpu, gpu, multi_gpu, e2e,
  clickhouse, vllm, hf, ring_native, slow, manual, numeric); default
  collection excludes `manual` and skips tests/tools, tests/ring, .venv,
  integration, build via norecursedirs.
- tests/_requirements.py: CPU-importable skip guards that fail closed with
  precise reasons (require_cuda, require_gpus, require_clickhouse,
  require_vllm, require_model_cache, require_nvcc).
- Mark every test: pure-CPU contract tests -> `cpu`; GPU/E2E suites ->
  explicit gpu/vllm/clickhouse/e2e/hf marks. test_gpt2_parity pulls real
  gpt2 weights -> `hf` + require_model_cache, not cpu.
- Split test_producer_chunked_schema: op-registration tests stay `cpu`,
  CUDA device-smoke tests become `gpu`.
- test_per_hook_isolation: source-patch unit classes -> `cpu`; the slow
  GPU sweep -> `gpu` (keeps `slow`).
- Relocate manual shell wrappers to tests/tools/ (+ README); fix their
  repo-root path computations and cross-references for the new depth.

Default CPU command:
  python -m pytest -m "not gpu and not e2e and not manual" -q

Verified: markers register without warnings; the CPU selection deselects
32 GPU/E2E tests. Pre-existing (reproduced on base main, unrelated to this
PR): monitoring/ring_transport.py references HOOK_TYPE_ROUTER_LOGITS
(defined only in csrc enum, missing on the Python side), and the vendored
transformers submodule is unbuilt -- these block a fully green CPU run and
must be fixed separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@SieDeta SieDeta changed the title test: migrate to matrix + remove legacy E2E (#4) test: migrate to matrix + remove legacy E2E Jun 11, 2026
@SieDeta
SieDeta force-pushed the shared-configureable-E2E-lib branch from 5ceb2be to 017720d Compare June 11, 2026 16:22
@SieDeta
SieDeta force-pushed the migrate-matrix-remove-legacy branch from a44a932 to 9f06d40 Compare June 11, 2026 17:08
SieDeta and others added 5 commits June 12, 2026 00:29
Phase 1 of the test-suite refactor (plan §2, §6 / PR2).

Env-var normalization — one public hook-selection input:
- E2E_HOOK_SELECTION is now the single public test input; it is
  translated to the internal DMX_HOOK_SELECTION runtime contract (read by
  the runners/adapters) in every subprocess env.
- test_vllm_identical.py: read E2E_HOOK_SELECTION (was E2E_HOOKS); drop
  the duplicate docstring entry.
- test_vllm_rowcnt.py: actually honor the documented E2E_HOOK_SELECTION by
  translating it into DMX_HOOK_SELECTION for the runner/comparator subprocs.
- tools/verify_vllm.sh, tools/identical_vllm.sh,
  tools/run_qwen2_moe_vllm_pipeline.sh: E2E_HOOKS -> E2E_HOOK_SELECTION.
- All E2E_HOOKS usages removed.

Source-patch hardening — single isolation contract:
- Add isolated_hook(framework, model_key, hook) in tests/isolate_hook.py:
  snapshots the vendored _compare source bytes, patches to capture one
  hook, and on exit restores AND asserts byte-identical restoration via a
  SHA-256 compare, raising loudly so a dirty vendored submodule can never
  escape. Invalidates cached bytecode by default so subprocess imports see
  the patched source.
- patch_compare_model kept as a backward-compatible delegating alias.
- Migrate test_per_hook_isolation.py to isolated_hook; add
  test_dirty_restore_raises_loudly covering the loud-failure path.

Acceptance: `pytest -m "not gpu and not e2e and not manual"` — the
per-hook isolation unit suite is green (15 passed, incl. the new restore
test). Pre-existing failures in this checkout stem from the unbuilt
monitoring native layer (HOOK_TYPE_ROUTER_LOGITS) and are unrelated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phases 2-3 of the test-suite refactor (plan §7, §8 / PR3). Additive only:
the matrix runs alongside the existing tests and nothing is deleted.

tests/lib/ — shared E2E library (§7), consolidating logic that
vllm_identical_comparator / compare_disk_vs_ch / vllm_rowcnt_comparator /
hf_comparator each reimplemented:
- compare.py: Check dataclass + the four standards (bitwise, allclose,
  row_count, transport_bitwise) as one interface; records max/mean abs +
  first-diff position even on a pass so "barely passing" stays visible.
- align.py: left-pad strip, EOS trim, request_id "<gid>:<row>" parsing,
  vLLM UUID-suffix normalization, logits head-skip alignment.
- report.py: CellResult dataclass -> JSON record / JSONL artifact + human
  table; legacy comparator result.json adapter.
- clickhouse_io.py: canonical dtype map + short-hook->CH act_name map + row
  decode / per-hook counts / request grouping (clickhouse_driver lazy).
- segments.py: thin re-export of monitoring.segment_merger + a sorted
  per-request chunk merge helper.
- disk_ref.py: parse RefDiskWorker .pt filenames; load HF structured refs.
- hf_reference.py: stable-named re-export of the ROL/GEN HF rollouts (the
  700-line module relocation is deferred to the legacy-removal PR).

tests/e2e_matrix.py — configurable matrix entry point (§8) replacing the
hardcoded shell sweeps:
- Multi-value axes (backend/model/mode/standard/hooks/tp/ring/dtype/
  prompt-set) -> Cartesian product of cells.
- Dispatches each cell to the existing runners + comparators as
  subprocesses (no inference logic reimplemented): vLLM bitwise/transport
  -> ref+monitored+vllm_identical_comparator; vLLM row_count/allclose ->
  monitored+vllm_rowcnt_comparator; HF -> ref+monitored+hf_comparator.
- Translates the public E2E_HOOK_SELECTION input to internal
  DMX_HOOK_SELECTION per subprocess (plan §2).
- One JSONL record per cell; per-cell isolation so one bad cell can't abort
  the matrix; per-subprocess --cell-timeout so a hung runner fails the cell.
- --dry-run prints planned cells + dispatch commands with no CUDA/CH, so
  expansion and env translation are CPU-testable.

tests/test_e2e_lib.py — 37 cpu-marked unit tests covering the four
standards, align helpers, report serialization/round-trip, and matrix cell
expansion / env translation / dispatch planning / dry-run.

Acceptance: `pytest -m "not gpu and not e2e and not manual"` — new suite
green (37 passed; 108 total passing on this checkout). Pre-existing
failures stem from the unbuilt monitoring native layer
(HOOK_TYPE_ROUTER_LOGITS) and are unrelated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 4 of the test-suite refactor (plan §5 / PR4). The high-risk switch:
the vLLM and HF E2E tests become thin wrappers on the configurable matrix
(PR3), and the stale in-process bodies are deleted. Net -1991/+216 lines.

Wrapper support in tests/e2e_matrix.py:
- matrix_argv_from_env(): translate the legacy E2E_* env knobs (model,
  enforce-eager, dtype, ring, hook-selection, tolerance, db, ...) into a
  single-cell matrix argv, so wrappers honor exactly what the old tests did.
- run_single(): parse argv to one cell, run it, return the CellResult
  (refuses anything but a single cell).

test_e2e_correctness_vs_hf.py: 1667 -> ~85 lines.
- test_e2e_correctness_hf  -> matrix hf/eager/allclose cell.
- test_e2e_cuda_graphs_vs_eager_hf -> matrix hf/cuda_graph/allclose cell,
  default tolerance 0.5 (eager ref vs CUDA-graph monitored).
- Deleted: _test_e2e_correctness_hf_legacy and
  _test_e2e_cuda_graphs_vs_eager_hf_legacy (uncollected "kept for reference"
  copies), the permanently-disabled @skipif(True)
  test_e2e_correctness_hf_cuda_graphs (its compiled-rollout reference could
  not replicate generate()'s StaticCache handling and was explicitly
  superseded -- no still-passing assertion lost), and the now-unused
  in-process helpers (_make_ring_cfg, _make_host_cfg,
  get_num_layers_from_config, _canon_layer_and_act, bitwise_equal, ...).

test_vllm_identical.py (262 -> ~55) -> matrix vllm/bitwise cell;
test_vllm_rowcnt.py (117 -> ~50) -> matrix vllm/row_count cell.

All four public test NAMES are preserved (tests/tools/verify_hf.sh,
verify_vllm.sh, identical_vllm.sh invoke them by node id). Skips are now
precise via tests/_requirements (require_cuda/require_vllm/require_clickhouse)
instead of ad-hoc torch.backends.cuda checks.

Matrix-parity (static dispatch) — each wrapper drives the identical
runner+comparator chain the old test did:
- test_e2e_correctness_hf        : hf_reference_runner + hf_monitored_runner(eager) + hf_comparator
- test_e2e_cuda_graphs_vs_eager_hf: hf_reference_runner(eager) + hf_monitored_runner(CG) + hf_comparator(tol=0.5)
- test_vllm_identical            : enable_ref_hooks + vllm_ref_runner + vllm_monitored_runner + vllm_identical_comparator
- test_vllm_rowcnt               : vllm_monitored_runner + vllm_rowcnt_comparator
The numeric GPU/ClickHouse parity run (old result vs new JSONL) must be
pasted on the PR before merge per the plan's PR3-4 gate.

Acceptance: `pytest -m "not gpu and not e2e and not manual"` green
(116 passed; +6 wrapper-translation unit tests). All four wrappers collect
cleanly. Pre-existing failures stem from the unbuilt monitoring native
layer (HOOK_TYPE_ROUTER_LOGITS) and are unrelated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `-m multi_gpu` suite documented in docs/testing.md collected zero
tests -- no test carried the `multi_gpu` marker, so TP coverage existed
only in the CPU shape-math unit test and the manual tests/tools sweeps.

Add tests/test_e2e_tp2.py: two wrappers that drive the configurable
matrix at tp=2 (vLLM transport_bitwise + HF eager allclose), forcing
E2E_TP_SIZE=2 via matrix_argv_from_env's env override. Marked
multi_gpu/gpu/e2e/clickhouse (+vllm/+hf) and skip-guarded with
require_gpus(2)/require_vllm/require_clickhouse so a <2-GPU runner skips
with a reason instead of failing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Samfisheryu

Copy link
Copy Markdown
Collaborator

Closing this as superseded by #58. The migration-wrapper commits from this PR have been cherry-picked into the combined #58 branch for review together with the shared matrix work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants