#!/usr/bin/env python3
"""Measure same-connection HTTP/2 fairness beside sixteen delayed API requests.

One worker; client, backend, and Superweb on loopback. This is a regression
workload, not a capacity test or a comparison with other servers.
"""
import argparse
import datetime
import hashlib
import json
import os
import pathlib
import platform
import statistics
import sys
import time

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--binary', default='./superweb')
parser.add_argument('--output', required=True)
parser.add_argument('--rounds', type=int, default=5)
args = parser.parse_args()
binary = pathlib.Path(args.binary).resolve()
os.environ['SUPERWEB'] = str(binary)
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / 'test'))
from test_h2_proxy import H2ProxyTests

rows = []
H2ProxyTests.setUpClass()
try:
    case = H2ProxyTests('test_h2_multiplex_and_headers'); case.setUp()
    try:
        port = case.start(True)
        client = case.client(port)
        case.good(client.wait(client.request('/api/warmup')))
        for round_number in range(1, args.rounds + 1):
            case.backend.seen.clear()
            started = time.perf_counter_ns()
            slow = [client.request('/api/delay') for _ in range(16)]
            assert case.backend.seen.wait(2)
            api, assets = [], []
            for _ in range(10):
                begin = time.perf_counter_ns()
                response = case.good(client.wait(client.request('/api/ok')))
                assert json.loads(response)['path'] == '/ok'
                api.append((time.perf_counter_ns() - begin) / 1e6)
                begin = time.perf_counter_ns()
                assert case.good(client.wait(client.request('/hello.txt'))) == b'assets stay responsive'
                assets.append((time.perf_counter_ns() - begin) / 1e6)
            for sid in slow: case.good(client.wait(sid))
            rows.append(dict(round=round_number, fast_api_ms=api, asset_ms=assets,
                             delayed_batch_ms=(time.perf_counter_ns()-started)/1e6, errors=0))
    finally:
        case.tearDown()
finally:
    H2ProxyTests.tearDownClass()

def summary(key):
    values = sorted(v for row in rows for v in row[key])
    return {'median_ms':statistics.median(values), 'p95_ms':values[int(.95*(len(values)-1))],
            'max_ms':max(values), 'samples':len(values)}
result = dict(timestamp_utc=datetime.datetime.now(datetime.timezone.utc).isoformat(),
              binary_sha256=hashlib.sha256(binary.read_bytes()).hexdigest(), platform=platform.platform(),
              protocol='HTTP/2 over TLS to Superweb; cleartext HTTP/1.1 to backend',
              workers=1, connections=1, concurrent_delayed_requests=16, backend_delay_ms=800,
              scope='Client, Superweb and backend on loopback; fairness regression, not throughput or server ranking.',
              fast_api=summary('fast_api_ms'), asset=summary('asset_ms'),
              delayed_batch_median_ms=statistics.median(row['delayed_batch_ms'] for row in rows), errors=0, rounds=rows)
pathlib.Path(args.output).write_text(json.dumps(result, indent=2)+'\n')
print(json.dumps({k:v for k,v in result.items() if k != 'rounds'}, indent=2))
