118 lines
3.4 KiB
Python
118 lines
3.4 KiB
Python
import json
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from sglang.srt.debug_utils.comparator.log_sink import LogSink
|
|
from sglang.srt.debug_utils.comparator.output_types import (
|
|
ErrorLog,
|
|
InfoLog,
|
|
)
|
|
from sglang.srt.debug_utils.comparator.report_sink import report_sink
|
|
from sglang.test.ci.ci_register import register_cpu_ci
|
|
|
|
register_cpu_ci(est_time=10, suite="stage-a-test-cpu", nightly=True)
|
|
|
|
|
|
def _make_error_log(**overrides) -> ErrorLog:
|
|
defaults: dict = dict(
|
|
category="test",
|
|
message="test warning",
|
|
)
|
|
defaults.update(overrides)
|
|
return ErrorLog(**defaults)
|
|
|
|
|
|
class TestLogSink:
|
|
def test_basic_collection(self) -> None:
|
|
sink = LogSink()
|
|
log = _make_error_log()
|
|
|
|
with sink.context() as collected:
|
|
sink.add(log)
|
|
|
|
assert len(collected) == 1
|
|
assert collected[0] is log
|
|
|
|
def test_nested_contexts(self) -> None:
|
|
sink = LogSink()
|
|
outer_log = _make_error_log(message="outer")
|
|
inner_log = _make_error_log(message="inner")
|
|
|
|
with sink.context() as outer:
|
|
sink.add(outer_log)
|
|
with sink.context() as inner:
|
|
sink.add(inner_log)
|
|
assert len(inner) == 1
|
|
assert inner[0] is inner_log
|
|
|
|
assert len(outer) == 1
|
|
assert outer[0] is outer_log
|
|
|
|
def test_empty_context(self) -> None:
|
|
sink = LogSink()
|
|
with sink.context() as collected:
|
|
pass
|
|
assert collected == []
|
|
|
|
def test_add_outside_context_prints(self, capsys) -> None:
|
|
sink = LogSink()
|
|
report_sink.configure(output_format="text")
|
|
|
|
sink.add(_make_error_log())
|
|
|
|
captured = capsys.readouterr()
|
|
assert "test warning" in captured.out
|
|
|
|
def test_context_captures_instead_of_printing(self, capsys) -> None:
|
|
sink = LogSink()
|
|
report_sink.configure(output_format="text")
|
|
|
|
with sink.context() as collected:
|
|
sink.add(_make_error_log())
|
|
|
|
assert len(collected) == 1
|
|
captured = capsys.readouterr()
|
|
assert captured.out == ""
|
|
|
|
def test_json_output_outside_context(self, capsys) -> None:
|
|
sink = LogSink()
|
|
report_sink.configure(output_format="json")
|
|
|
|
sink.add(_make_error_log())
|
|
|
|
captured = capsys.readouterr()
|
|
parsed: dict = json.loads(captured.out.strip())
|
|
assert "errors" in parsed
|
|
assert len(parsed["errors"]) == 1
|
|
|
|
def test_info_log_outside_context_routes_to_infos(self, capsys) -> None:
|
|
"""InfoLog added outside context populates LogRecord.infos, not errors."""
|
|
sink = LogSink()
|
|
report_sink.configure(output_format="json")
|
|
|
|
sink.add(InfoLog(category="test", message="info msg"))
|
|
|
|
parsed: dict = json.loads(capsys.readouterr().out.strip())
|
|
assert len(parsed["infos"]) == 1
|
|
assert len(parsed["errors"]) == 0
|
|
|
|
def test_exception_in_context_cleans_stack(self, capsys) -> None:
|
|
sink = LogSink()
|
|
report_sink.configure(output_format="text")
|
|
|
|
with pytest.raises(RuntimeError):
|
|
with sink.context() as collected:
|
|
sink.add(_make_error_log())
|
|
raise RuntimeError("boom")
|
|
|
|
assert len(collected) == 1
|
|
|
|
sink.add(_make_error_log(message="after exception"))
|
|
captured = capsys.readouterr()
|
|
assert "after exception" in captured.out
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(pytest.main([__file__]))
|