"""回放传输:把既有演练日志作为服务器响应原样回放给客户端。 用于 P1 验收"本地状态机与官方响应一致":官方演练记录 (output/q1/practice/*_actions.json)逐条喂给客户端,客户端重建的 状态必须与当时服务器返回的虚拟时刻逐步吻合。 按录制顺序匹配(客户端的 request_id 生成规则与采集器不同, 故不参与匹配;故障重试场景请用 ScriptedFaultTransport)。 """ from __future__ import annotations import json from urllib.parse import urlsplit from ..protocol.transport import Transport, TransportResponse class PlaybackTransport(Transport): """events: 演练日志 [{path, request, response, ...}, ...]。""" def __init__(self, events: list[dict]): self.events = list(events) self.index = 0 self.served: list[dict] = [] def post(self, url, body, headers, timeout): if self.index >= len(self.events): raise AssertionError("回放日志已耗尽仍有请求") event = self.events[self.index] path = urlsplit(url).path if path != event["path"]: raise AssertionError( f"回放顺序不一致: 客户端请求 {path}, 录制预期 {event['path']}") self.index += 1 self.served.append(event) return TransportResponse( 200, json.dumps(event["response"], ensure_ascii=False).encode("utf-8"))