6
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
"""接口边界(与传输无关):handle_raw 承载附件2 §5 的全部语法层规则。
|
||||
|
||||
参赛队的内存传输与本包 HTTP 服务器共用这一实现,两条路径行为一致。
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from referee import LocalSimulator, SimulatorClosed
|
||||
from referee.interface import handle_raw
|
||||
|
||||
|
||||
def payload(id="e", **extra):
|
||||
return dict(arena_id="default", robot_id="2026001", request_id=id, **extra)
|
||||
|
||||
|
||||
def post(sim, path, body=None, headers=None, method="POST", target=None):
|
||||
raw = json.dumps(body if body is not None else payload()).encode("utf-8")
|
||||
return handle_raw(sim, method, target or path,
|
||||
headers or [("Content-Type", "application/json")], raw)
|
||||
|
||||
|
||||
def test_raw_json_format_errors():
|
||||
sim = LocalSimulator([])
|
||||
cases = [
|
||||
(b'{"request_id":"a","request_id":"b"}', 400), # 重复键
|
||||
(b'{"position":{"x":1,"x":2}}', 400), # 嵌套重复键
|
||||
(b'{}' + b' ' * 65535, 413), # 超 65536 字节
|
||||
(b'\xef\xbb\xbf{}', 400), (b'\xff', 400), (b'{', 400), # BOM/坏编码/语法
|
||||
(b'[]', 400), (b'{"x":NaN}', 400), (b'{"x":Infinity}', 400),
|
||||
(b'{"a":' + b'[' * 16 + b'0' + b']' * 16 + b'}', 400), # 深度 17
|
||||
]
|
||||
for raw, expected in cases:
|
||||
result = handle_raw(sim, "POST", "/enter", [("Content-Type", "application/json")], raw)
|
||||
assert result.status == expected, (raw[:40], result.status)
|
||||
body = json.loads(result.body)
|
||||
assert body["accepted"] is False
|
||||
assert set(body) >= {"accepted", "real_timestamp_ms", "virtual_time_s"}
|
||||
assert not sim.entered
|
||||
|
||||
|
||||
def test_raw_size_and_depth_boundaries_are_inclusive():
|
||||
sim = LocalSimulator([])
|
||||
headers = [("Content-Type", "application/json")]
|
||||
deep = b'{"extra":' + b'[' * 15 + b'0' + b']' * 15 + b'}' # 深度 16 合法
|
||||
body = json.dumps({**payload(), **json.loads(deep)}).encode()
|
||||
assert handle_raw(sim, "POST", "/enter", headers, body).status == 200
|
||||
exact = json.dumps(payload()).encode().ljust(65536) # 恰好 65536 字节
|
||||
result = handle_raw(sim, "POST", "/enter", headers, exact)
|
||||
assert result.status == 200 and json.loads(result.body)["accepted"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method,path,headers,status", [
|
||||
("POST", "/enter?x=1", None, 404),
|
||||
("POST", "/enter?", None, 404),
|
||||
("POST", "/enter/", None, 404),
|
||||
("POST", "/measure/x", None, 404),
|
||||
("GET", "/enter", None, 405),
|
||||
("PUT", "/clear", None, 405),
|
||||
("POST", "/enter", [("Content-Type", "text/plain")], 415),
|
||||
("POST", "/enter", [("Content-Type", "application/json;foo=bar")], 415),
|
||||
("POST", "/enter", [("Content-Type", "application/json"), ("Content-Type", "application/json")], 415),
|
||||
("POST", "/enter", [("Content-Type", "application/json"), ("Content-Encoding", "gzip")], 415),
|
||||
("POST", "/enter", [("content-type", "Application/JSON; charset=UTF-8")], 200),
|
||||
("POST", "/enter", [("content-type", 'application/json;charset="utf-8"')], 200),
|
||||
])
|
||||
def test_http_boundary(method, path, headers, status):
|
||||
sim = LocalSimulator([])
|
||||
raw = json.dumps(payload()).encode()
|
||||
result = handle_raw(sim, method, path, headers or [("Content-Type", "application/json")], raw)
|
||||
assert result.status == status
|
||||
|
||||
|
||||
def test_closed_simulator_raises_connection_level_error():
|
||||
sim = LocalSimulator([], clock=lambda: 9999, window_started_at=0)
|
||||
with pytest.raises(SimulatorClosed):
|
||||
handle_raw(sim, "POST", "/enter",
|
||||
[("Content-Type", "application/json")], json.dumps(payload()).encode())
|
||||
|
||||
|
||||
def test_on_request_callback_receives_parsed_payload():
|
||||
sim = LocalSimulator([])
|
||||
seen = []
|
||||
raw = json.dumps(payload("enter-1")).encode()
|
||||
handle_raw(sim, "POST", "/enter", [("Content-Type", "application/json")], raw,
|
||||
on_request=lambda path, payload_dict, result: seen.append((path, payload_dict, result)))
|
||||
assert seen[0][0] == "/enter"
|
||||
assert seen[0][1]["request_id"] == "enter-1"
|
||||
assert seen[0][2].status == 200
|
||||
Reference in New Issue
Block a user