Some checks failed
CI / skinny-install (aco) (push) Successful in 1m18s
CI / skinny-install (api) (push) Successful in 40s
CI / skinny-install (bcda) (push) Successful in 35s
CI / skinny-install (bib) (push) Successful in 38s
CI / skinny-install (cli) (push) Successful in 46s
CI / skinny-install (conf) (push) Successful in 36s
CI / skinny-install (opps) (push) Successful in 38s
CI / skinny-install (pfs) (push) Successful in 47s
CI / skinny-install (rex) (push) Successful in 35s
Infra CI / notebooks (push) Successful in 3m17s
CI / lint-test (push) Failing after 3m30s
CI / skinny-install (bls) (push) Successful in 34s
CI / skinny-install (ccw) (push) Successful in 45s
CI / skinny-install (cms) (push) Successful in 32s
CI / skinny-install (perf) (push) Successful in 43s
Deploy / build-scan-report (push) Has been cancelled
Infra CI / docs (push) Failing after 20s
Infra CI / api (push) Successful in 16s
Infra CI / mc (push) Successful in 12s
Package Supply Chain / pkg-supply-chain (push) Successful in 1m27s
Infra CI / zotero (push) Successful in 6m10s
121 lines
3.7 KiB
Python
121 lines
3.7 KiB
Python
"""Tests for FileSpanExporter fallback and CLI show command."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from unittest.mock import MagicMock
|
|
|
|
from perf.export import FileSpanExporter
|
|
|
|
|
|
def _mock_span(name="test", trace_id=0xABCD, span_id=0x1234, attrs=None):
|
|
ctx = MagicMock()
|
|
ctx.trace_id = trace_id
|
|
ctx.span_id = span_id
|
|
status = MagicMock()
|
|
status.status_code.name = "OK"
|
|
span = MagicMock()
|
|
span.get_span_context.return_value = ctx
|
|
span.name = name
|
|
span.start_time = 1_000_000_000
|
|
span.end_time = 2_000_000_000
|
|
span.status = status
|
|
span.attributes = attrs or {}
|
|
return span
|
|
|
|
|
|
class TestFileExporter:
|
|
def test_creates_directory(self, tmp_path):
|
|
out = tmp_path / "deep" / "dir" / "spans.jsonl"
|
|
exporter = FileSpanExporter(path=out)
|
|
exporter.export([_mock_span()])
|
|
assert out.exists()
|
|
|
|
def test_appends_multiple_exports(self, tmp_path):
|
|
out = tmp_path / "spans.jsonl"
|
|
exporter = FileSpanExporter(path=out)
|
|
exporter.export([_mock_span("a")])
|
|
exporter.export([_mock_span("b"), _mock_span("c")])
|
|
|
|
lines = out.read_text().strip().split("\n")
|
|
assert len(lines) == 3
|
|
names = [json.loads(l)["name"] for l in lines]
|
|
assert names == ["a", "b", "c"]
|
|
|
|
def test_attributes_preserved(self, tmp_path):
|
|
out = tmp_path / "spans.jsonl"
|
|
exporter = FileSpanExporter(path=out)
|
|
exporter.export([_mock_span(attrs={"rows.out": 42, "cache.hit": True})])
|
|
|
|
record = json.loads(out.read_text().strip())
|
|
assert record["attributes"]["rows.out"] == 42
|
|
assert record["attributes"]["cache.hit"] is True
|
|
|
|
def test_shutdown_noop(self, tmp_path):
|
|
exporter = FileSpanExporter(path=tmp_path / "spans.jsonl")
|
|
exporter.shutdown() # should not raise
|
|
|
|
def test_force_flush(self, tmp_path):
|
|
exporter = FileSpanExporter(path=tmp_path / "spans.jsonl")
|
|
assert exporter.force_flush() is True
|
|
|
|
|
|
class TestFallbackPath:
|
|
def test_returns_default_when_conf_unavailable(self):
|
|
from perf.export import _fallback_path
|
|
|
|
result = _fallback_path()
|
|
assert result.name == "spans.jsonl"
|
|
assert "traces" in str(result)
|
|
|
|
def test_returns_conf_path_when_available(self, monkeypatch):
|
|
from pathlib import Path
|
|
|
|
import perf.export
|
|
|
|
def fake_fallback():
|
|
return Path("/custom/traces/spans.jsonl")
|
|
|
|
monkeypatch.setattr(perf.export, "_fallback_path", fake_fallback)
|
|
exporter = FileSpanExporter()
|
|
assert "custom" in str(exporter._path)
|
|
|
|
|
|
class TestCLIShow:
|
|
def test_show_with_data(self, tmp_path):
|
|
from typer.testing import CliRunner
|
|
|
|
from cli.perf import app
|
|
|
|
runner = CliRunner()
|
|
trace_file = tmp_path / "spans.jsonl"
|
|
exporter = FileSpanExporter(path=trace_file)
|
|
exporter.export(
|
|
[
|
|
_mock_span("pipeline.run", attrs={"rows.out": 100}),
|
|
_mock_span(
|
|
"step.core.encounter",
|
|
attrs={
|
|
"rows.out": 50,
|
|
"cache.hit": False,
|
|
"memory.delta_mb": 2.5,
|
|
},
|
|
),
|
|
]
|
|
)
|
|
|
|
result = runner.invoke(app, ["--path", str(trace_file)])
|
|
assert result.exit_code == 0
|
|
assert "pipeline.run" in result.output
|
|
assert "step.core.encounter" in result.output
|
|
assert "rows=50" in result.output
|
|
|
|
def test_show_missing_file(self, tmp_path):
|
|
from typer.testing import CliRunner
|
|
|
|
from cli.perf import app
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(app, ["--path", str(tmp_path / "nope.jsonl")])
|
|
assert result.exit_code == 1
|