litellm/tests/rust-python-harness/shared/tracing/test_steps.py
yujonglee ee08c36fc0
refactor(tests): restructure rust python harness around strategy definitions (#39628)
* wip

* refactor(tests): move sdk function tracing into rust python harness

* dead code

* fix: handle harness keyboard interrupts

* refactor(tests): deduplicate rust python harness helpers

* fix(harness): expose validated strategy choices

* wip

* refactor(harness): let strategies own parity reports

* docs(harness): update strategy structure

* refactor(harness): localize strategy report views

* wip

* fix(harness): satisfy mapping runner type checks

* fix(harness): clarify trace parity output

* wip

* fix(harness): clarify unit mapping report

* fix(harness): finalize trace parity contracts

* refactor(harness): structure parity contracts

* feat: derive unit test mapping from traces

* feat(harness): map rstest test families

* feat(ocr): port Azure document intelligence tests

* feat(harness): enforce complete unit mappings

* feat(ocr): add reducto core transforms

* feat(harness): classify host-only unit tests

* fix(ocr): complete Rust provider plumbing

* fix(harness): reuse OCR parity workers
2026-09-03 21:15:01 -07:00

157 lines
6.4 KiB
Python

from __future__ import annotations
from typing import Final
import pytest
from .profiler import FunctionTraceEvent
from .steps import Engine, TraceContract, mapping, pipeline_projection, trace_depths, trace_diff
MAPPINGS: Final = (
mapping(rust_span="route", python_frame=r"entry$"),
mapping(rust_span="provider", python_frame=r"provider$"),
mapping(rust_span="request", python_frame=r"request$"),
mapping(rust_span="http", python_frame=r"post$"),
mapping(rust_span="response", python_frame=r"response$"),
)
def event(event_id: int, function: str, parent_id: int | None = None) -> FunctionTraceEvent:
return FunctionTraceEvent(event_id, parent_id, function)
def test_python_projection_collapses_unmapped_parents_and_counts_noise() -> None:
events: Final = (
event(0, "module.py:1 entry"),
event(1, "noise", 0),
event(2, "module.py:2 provider", 1),
event(3, "module.py:3 request", 0),
event(4, "client.py:4 post", 3),
event(5, "module.py:5 response", 0),
)
projection: Final = pipeline_projection("python", events, MAPPINGS)
assert projection.unmatched == 1
assert [(step.id, step.parent_id, step.span, step.raw) for step in projection.steps] == [
(0, None, "route", "module.py:1 entry"),
(2, 0, "provider", "module.py:2 provider"),
(3, 0, "request", "module.py:3 request"),
(4, 3, "http", "client.py:4 post"),
(5, 0, "response", "module.py:5 response"),
]
def test_rust_projection_keeps_unknown_spans() -> None:
projection: Final = pipeline_projection("rust", (event(0, "route"), event(1, "new_span", 0)), MAPPINGS)
assert [(step.span, step.parent_id) for step in projection.steps] == [("route", None), ("new_span", 0)]
def test_projection_preserves_repeated_occurrences() -> None:
projection: Final = pipeline_projection(
"rust",
(event(0, "route"), event(1, "http", 0), event(2, "http", 0)),
MAPPINGS,
)
assert [step.span for step in projection.steps] == ["route", "http", "http"]
def test_projection_preserves_multiple_roots() -> None:
projection: Final = pipeline_projection("rust", (event(0, "route"), event(1, "request")), MAPPINGS)
assert trace_depths(projection.steps) == {0: 0, 1: 0}
def test_projection_rejects_duplicate_and_unknown_parent_ids() -> None:
with pytest.raises(ValueError, match="duplicate trace event id"):
pipeline_projection("rust", (event(0, "route"), event(0, "request")), MAPPINGS)
with pytest.raises(ValueError, match="unknown or later parent"):
pipeline_projection("rust", (event(1, "request", 0),), MAPPINGS)
@pytest.mark.parametrize("engine", ("python", "rust"))
def test_rust_only_mappings_do_not_swallow_python_frames(engine: Engine) -> None:
projection: Final = pipeline_projection(
engine,
(event(0, "anything"),),
(mapping(rust_span="rust_only_span"),),
)
if engine == "python":
assert projection.unmatched == 1
assert projection.steps == ()
else:
assert projection.unmatched == 0
assert projection.steps[0].span == "anything"
def test_mapping_builder_rejects_empty_and_ambiguous_declarations() -> None:
with pytest.raises(ValueError, match="mapping needs"):
mapping()
with pytest.raises(ValueError, match="python-only mapping needs"):
mapping(python_frame=r"frame$")
with pytest.raises(ValueError, match="disagrees with"):
mapping(rust_span="span_a", python_frame=r"frame$", span="span_b")
def test_projection_rejects_ambiguous_python_mapping() -> None:
mappings: Final = (
mapping(rust_span="first", python_frame=r"same$"),
mapping(rust_span="second", python_frame=r"same$"),
)
with pytest.raises(ValueError, match="multiple trace mappings"):
pipeline_projection("python", (event(0, "module.py:1 same"),), mappings)
def test_trace_diff_matches_identical_occurrence_trees() -> None:
mappings: Final = (MAPPINGS[0], MAPPINGS[2])
steps: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "request", 0), event(2, "request", 0)), mappings
).steps
assert trace_diff(steps, steps, mappings).matches
def test_trace_diff_rejects_missing_occurrence_and_parent_drift() -> None:
python: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "request", 0), event(2, "request", 0)), MAPPINGS
).steps
missing: Final = pipeline_projection("rust", (event(0, "route"), event(1, "request", 0)), MAPPINGS).steps
reparented: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "request", 0), event(2, "request", 1)), MAPPINGS
).steps
assert trace_diff(python, missing, MAPPINGS).python_only == ("request",)
assert not trace_diff(python, reparented, MAPPINGS).matches
def test_trace_diff_rejects_sequential_reorder() -> None:
first: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "request", 0), event(2, "response", 0)), MAPPINGS
).steps
second: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "response", 0), event(2, "request", 0)), MAPPINGS
).steps
diff: Final = trace_diff(first, second, MAPPINGS)
assert not diff.matches
assert diff.first_difference == "root/child[1]/route/child[1]: Python='request', Rust='response'"
def test_trace_diff_allows_reordered_concurrent_children() -> None:
mappings: Final = (MAPPINGS[0], MAPPINGS[2], MAPPINGS[4])
first: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "request", 0), event(2, "response", 0)), mappings
).steps
second: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "response", 0), event(2, "request", 0)), mappings
).steps
contract: Final = TraceContract(frozenset({"route"}))
assert trace_diff(first, second, mappings, contract).matches
def test_trace_diff_prunes_declared_engine_only_nodes_but_requires_them() -> None:
mappings: Final = (MAPPINGS[0], mapping(rust_span="rust_prepare"))
python: Final = pipeline_projection("python", (event(0, "module.py:1 entry"),), mappings).steps
rust: Final = pipeline_projection(
"rust", (event(0, "route"), event(1, "rust_prepare", 0)), mappings
).steps
assert trace_diff(python, rust, mappings).matches
assert trace_diff(python, rust[:1], mappings).missing_mappings == ("rust_prepare",)
def test_trace_diff_does_not_claim_empty_traces_match() -> None:
assert not trace_diff((), ()).matches