Skip to content

Commit 9c88e3a

Browse files
Merge branch 'main' into test-skeleton/reports-specs
2 parents 1c45f0c + 9d84207 commit 9c88e3a

2 files changed

Lines changed: 135 additions & 10 deletions

File tree

tests/test_events_loader.py

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,108 @@
1-
import importlib
1+
from __future__ import annotations
22

3+
from datetime import datetime, timezone
4+
from pathlib import Path
35

4-
def test_import_events_loader():
5-
mod = importlib.import_module("llm_observability_analytics.events.loader")
6-
assert mod is not None
6+
import pytest
77

8+
from llm_observability_analytics.contracts.models import (
9+
LLMInteractionEvent,
10+
ModelExecutionContext,
11+
TokenUsageRecord,
12+
LatencyRecord,
13+
SourceGroundingReference,
14+
RetrievalTraceEvent,
15+
)
16+
from llm_observability_analytics.events.loader import (
17+
load_interaction_events,
18+
load_retrieval_trace_events,
19+
)
20+
21+
22+
def _now_iso() -> str:
23+
return datetime.now(tz=timezone.utc).isoformat()
24+
25+
26+
def _make_interaction(query_id: str, trace_id: str) -> LLMInteractionEvent:
27+
mc = ModelExecutionContext(
28+
query_id=query_id,
29+
trace_id=trace_id,
30+
model_version="m-v",
31+
dataset_version=None,
32+
provider="prov",
33+
model_name="name",
34+
)
35+
tu = TokenUsageRecord(
36+
query_id=query_id,
37+
trace_id=trace_id,
38+
model_version="m-v",
39+
dataset_version=None,
40+
input_tokens=1,
41+
output_tokens=2,
42+
recorded_at=datetime.now(timezone.utc),
43+
)
44+
lat = LatencyRecord(
45+
query_id=query_id,
46+
trace_id=trace_id,
47+
request_timestamp=datetime.now(timezone.utc),
48+
response_timestamp=datetime.now(timezone.utc),
49+
latency_ms=123,
50+
)
51+
ref = SourceGroundingReference(
52+
query_id=query_id, trace_id=trace_id, document_id="doc1", chunk_id="chk1"
53+
)
54+
return LLMInteractionEvent(
55+
query_id=query_id,
56+
trace_id=trace_id,
57+
request_timestamp=datetime.now(timezone.utc),
58+
response_timestamp=datetime.now(timezone.utc),
59+
prompt_text="p",
60+
response_text="r",
61+
model_context=mc,
62+
token_usage=tu,
63+
latency=lat,
64+
retrieval_references=[ref],
65+
)
66+
67+
68+
def _make_retrieval(query_id: str, trace_id: str) -> RetrievalTraceEvent:
69+
ref = SourceGroundingReference(
70+
query_id=query_id, trace_id=trace_id, document_id="doc1", chunk_id="chk1"
71+
)
72+
return RetrievalTraceEvent(
73+
query_id=query_id,
74+
trace_id=trace_id,
75+
retrieval_timestamp=datetime.now(timezone.utc),
76+
query_text="hello",
77+
retrieval_system="r",
78+
top_k=1,
79+
references=[ref],
80+
)
81+
82+
83+
def test_load_interaction_events_success(tmp_path: Path) -> None:
84+
p = tmp_path / "interactions.jsonl"
85+
evt = _make_interaction("q1", "t1")
86+
p.write_text(evt.to_json() + "\n", encoding="utf-8")
87+
88+
out = load_interaction_events(p, max_events=10)
89+
assert len(out) == 1
90+
assert out[0].query_id == "q1"
91+
92+
93+
def test_load_retrieval_trace_events_success(tmp_path: Path) -> None:
94+
p = tmp_path / "retrieval.jsonl"
95+
evt = _make_retrieval("q2", "t2")
96+
p.write_text(evt.to_json() + "\n", encoding="utf-8")
97+
98+
out = load_retrieval_trace_events(p, max_events=10)
99+
assert len(out) == 1
100+
assert out[0].query_id == "q2"
101+
102+
103+
def test_load_invalid_json_raises(tmp_path: Path) -> None:
104+
p = tmp_path / "broken.jsonl"
105+
p.write_text("{not-json}\n", encoding="utf-8")
106+
with pytest.raises(ValueError):
107+
load_interaction_events(p, max_events=10)
8108

9-
# TODO: add file-based loader tests using tmp_path

tests/test_metrics_models.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,35 @@
1-
import importlib
1+
from __future__ import annotations
22

3+
import json
4+
from dataclasses import asdict
35

4-
def test_import_metrics_models():
5-
mod = importlib.import_module("llm_observability_analytics.metrics.models")
6-
assert mod is not None
6+
from llm_observability_analytics.metrics.models import MetricRecord, AnalyticsSummary
77

88

9-
# TODO: add numeric helper tests with small sample inputs
9+
def test_metric_record_basic():
10+
mr = MetricRecord(metric_name="latency", metric_value=12.5, dimension_key="service", dimension_value="svc-a")
11+
assert mr.metric_name == "latency"
12+
assert mr.metric_value == 12.5
13+
14+
15+
def test_analytics_summary_roundtrip():
16+
s = AnalyticsSummary(
17+
request_count=10,
18+
retrieval_trace_count=4,
19+
latency_mean_ms=100.0,
20+
latency_p50_ms=90.0,
21+
latency_p95_ms=150.0,
22+
total_tokens=1234,
23+
average_tokens_per_request=123.4,
24+
retrieval_hit_count=3,
25+
grounded_response_count=7,
26+
ungrounded_response_count=3,
27+
feedback_count=2,
28+
)
29+
d = s.to_dict()
30+
assert d["request_count"] == 10
31+
# JSON roundtrip
32+
j = s.to_json()
33+
parsed = json.loads(j)
34+
assert parsed == asdict(s)
35+

0 commit comments

Comments
 (0)