test_openai_serving_harness.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python3
  2. """Host-side tests for the OpenAI serving harness helpers."""
  3. import importlib.util
  4. from pathlib import Path
  5. import io
  6. import itertools
  7. import json
  8. import os
  9. import sys
  10. from unittest.mock import patch
  11. sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
  12. from benchmarks import decode_window as decode
  13. ROOT = Path(__file__).resolve().parents[1]
  14. spec = importlib.util.spec_from_file_location(
  15. "openai_serving", ROOT / "benchmarks" / "openai_serving.py"
  16. )
  17. assert spec is not None and spec.loader is not None
  18. mod = importlib.util.module_from_spec(spec)
  19. spec.loader.exec_module(mod)
  20. def test_env_url_strips_slash(monkeypatch=None):
  21. import os
  22. old = os.environ.get("BASE_URL")
  23. os.environ["BASE_URL"] = "http://127.0.0.1:8888/"
  24. try:
  25. assert mod.env_url() == "http://127.0.0.1:8888"
  26. finally:
  27. if old is None:
  28. os.environ.pop("BASE_URL", None)
  29. else:
  30. os.environ["BASE_URL"] = old
  31. def test_prose_topics_cover_c8():
  32. assert len(mod.PROSE) >= 8
  33. class Response(io.BytesIO):
  34. status = 200
  35. def test_benchmark_auth_header_and_no_secret_in_result():
  36. calls = []
  37. def urlopen(req, timeout):
  38. calls.append(req)
  39. return Response(b'{"choices": [{"message": {"content": "42"}, "finish_reason": "stop"}], "usage": {"completion_tokens": 1}}')
  40. with patch.dict(os.environ, {"API_KEY": "fixture-token"}), patch.object(mod.urllib.request, "urlopen", urlopen):
  41. row = mod.chat("http://127.0.0.1:8888", [], max_tokens=32)
  42. assert calls[0].get_header("Authorization") == "Bearer fixture-token"
  43. assert "fixture-token" not in json.dumps(row)
  44. with patch.dict(os.environ, {"API_KEY": "off"}):
  45. assert "Authorization" not in mod.request_headers()
  46. def stream(events, done=True):
  47. data = b"".join(b"data: " + json.dumps(event).encode() + b"\n\n" for event in events)
  48. return Response(data + (b"data: [DONE]\n\n" if done else b""))
  49. def test_stream_ttft_uses_first_content_and_labels_window_estimate():
  50. events = [
  51. {"choices": [{"delta": {"role": "assistant"}}]},
  52. {"choices": [{"delta": {"content": "x" * 200}}]},
  53. {"choices": [{"delta": {"content": "y" * 500}}]},
  54. {"choices": [{"delta": {}, "finish_reason": "stop"}]},
  55. {"choices": [], "usage": {"completion_tokens": 700}},
  56. ]
  57. ticks = itertools.count()
  58. with patch.object(decode.urllib.request, "urlopen", lambda *a, **k: stream(events)), patch.object(decode.time, "monotonic", lambda: next(ticks)):
  59. row = decode.stream_one(0, 1)
  60. assert row["ttft_s"] == 2
  61. assert row["window_129_641_tps"] == 512
  62. assert row["window_method"] == "character_scaled_estimate"
  63. assert row["completion_tokens"] == 700
  64. def test_stream_rejects_errors_truncation_and_missing_usage():
  65. finished = {"choices": [{"delta": {"content": "42"}, "finish_reason": "stop"}]}
  66. usage = {"choices": [], "usage": {"completion_tokens": 2}}
  67. for events, done in (([{"error": {"message": "failed"}}], True), ([finished, usage], False), ([finished], True)):
  68. with patch.object(decode.urllib.request, "urlopen", lambda *a, **k: stream(events, done)):
  69. try:
  70. decode.stream_one(0, 1)
  71. except RuntimeError:
  72. pass
  73. else:
  74. raise AssertionError("broken stream counted as success")
  75. def test_loads_rejects_unknown_idle_state():
  76. with patch.object(decode.urllib.request, "urlopen", lambda *a, **k: Response(b'{"loads": []}')):
  77. try:
  78. decode.require_idle()
  79. except RuntimeError:
  80. pass
  81. else:
  82. raise AssertionError("missing counters treated as idle")
  83. def test_raw_benchmark_aggregates_match_final_usage():
  84. report = json.loads((ROOT / "docs/results/tp4-switchless-ring-20260915.json").read_text())
  85. for wave in report["decode_window_idle"]["waves"]:
  86. assert abs(wave["aggregate_tok_s"] - wave["completion_tokens"] / wave["wall_seconds"]) < 0.02
  87. assert wave["successes"] == wave["concurrency"]
  88. if __name__ == "__main__":
  89. tests = [v for k, v in list(globals().items()) if k.startswith("test_")]
  90. failed = 0
  91. for fn in tests:
  92. try:
  93. fn()
  94. print(f"[OK] {fn.__name__}")
  95. except Exception as exc:
  96. failed += 1
  97. print(f"[FAIL] {fn.__name__}: {exc}")
  98. print(f"{len(tests) - failed}/{len(tests)} passed")
  99. raise SystemExit(1 if failed else 0)