trashclaw / tests /test_http_bench.py
elyanlabs's picture
Source snapshot of github.com/Scottcjn/trashclaw@6dce9ed
53b2ac9 verified
Raw History Blame Contribute Delete
3.96 kB
# SPDX-License-Identifier: MIT
"""Tests for the http_bench plugin."""
import http.server
import os
import sys
import threading
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "plugins"))
from http_bench import run, _percentile
# ── Fixtures ──
@pytest.fixture(scope="module")
def local_http_server():
"""Start a simple HTTP server on a random port."""
handler = http.server.SimpleHTTPRequestHandler
# Suppress log output
class QuietHandler(handler):
def log_message(self, format, *args):
pass
srv = http.server.HTTPServer(("127.0.0.1", 0), QuietHandler)
port = srv.server_address[1]
t = threading.Thread(target=srv.serve_forever, daemon=True)
t.start()
yield port
srv.shutdown()
# ── _percentile helper ──
def test_percentile_basic():
data = list(range(1, 101)) # 1..100
assert _percentile(data, 50) == pytest.approx(50.5, abs=1)
assert _percentile(data, 95) == pytest.approx(95.05, abs=1)
assert _percentile(data, 99) == pytest.approx(99.01, abs=1)
def test_percentile_single():
assert _percentile([42.0], 50) == 42.0
assert _percentile([42.0], 99) == 42.0
def test_percentile_empty():
assert _percentile([], 50) == 0.0
# ── Basic functionality ──
def test_missing_url():
result = run()
assert "Error" in result
def test_bench_local_server(local_http_server):
result = run(url=f"http://127.0.0.1:{local_http_server}", requests=5, concurrency=2, timeout=5)
assert "Latency" in result
assert "p50" in result
assert "p95" in result
assert "p99" in result
assert "Throughput" in result
assert "Success" in result
def test_bench_reports_failures():
# Port 1 is almost certainly not an HTTP server
result = run(url="http://127.0.0.1:1", requests=2, concurrency=1, timeout=0.5)
assert "Failed" in result
def test_small_request_count(local_http_server):
result = run(url=f"http://127.0.0.1:{local_http_server}", requests=1)
assert "Total:" in result
assert "1" in result
def test_auto_prepend_http(local_http_server):
"""Should auto-prepend http:// if missing."""
result = run(url=f"127.0.0.1:{local_http_server}", requests=2)
assert "Latency" in result or "Failed" in result
def test_clamp_concurrency(local_http_server):
"""Concurrency over 20 should be clamped."""
result = run(url=f"http://127.0.0.1:{local_http_server}", requests=3, concurrency=100)
# Should still work, just clamped to 20
assert "Total:" in result
def test_clamp_requests(local_http_server):
"""Requests over 500 should be clamped."""
result = run(url=f"http://127.0.0.1:{local_http_server}", requests=9999, concurrency=1)
# Should report 500 max
assert "500" in result
# ── TLS verification ──
def _captured_contexts(monkeypatch, **run_kwargs):
import ssl
import urllib.error
import http_bench
contexts = []
def fake_urlopen(req, timeout=None, context=None):
contexts.append(context)
raise urllib.error.URLError("stubbed")
monkeypatch.setattr(http_bench.urllib.request, "urlopen", fake_urlopen)
output = run(url="https://example.invalid", requests=2, concurrency=1, **run_kwargs)
assert len(contexts) == 2
return ssl, contexts, output
def test_tls_verified_by_default(monkeypatch):
ssl, contexts, output = _captured_contexts(monkeypatch)
for ctx in contexts:
assert ctx.verify_mode == ssl.CERT_REQUIRED
assert ctx.check_hostname is True
assert "verification disabled" not in output
@pytest.mark.parametrize("flag", [True, "true"])
def test_tls_insecure_opt_in(monkeypatch, flag):
ssl, contexts, output = _captured_contexts(monkeypatch, insecure=flag)
for ctx in contexts:
assert ctx.verify_mode == ssl.CERT_NONE
assert ctx.check_hostname is False
assert "verification disabled" in output