weopqrst/mooncassette/recorder does not have a README file

    Transport

    被录制的底层调用。

    实现方只需把真实客户端适配到本接口,不必关心录制、匹配、脱敏。

    MockTransport

    pub struct MockTransport {
    scripted : Map[String,
    Response
    ]
    calls : Int
    }

    脚本化的假 Transport,用于测试与示例。

    未配置的请求返回 500:这样在测试里「本不该发生的真实调用」 会立刻表现为可断言的失败,而不是静默通过。

    注意:脚本按规范化请求的指纹索引(注册与查询两侧都会先 normalize),因此调用方可以按业务原样书写请求,不必关心 对象键顺序或易变字段是否已剔除。

    这里刻意做脱敏:真实 Transport 收到的是「保留密钥」的请求, Mock 必须与真实行为一致,否则会掩盖脱敏相关问题。

    MockTransport::call_count

    fn MockTransport::call_count(self : MockTransport) -> Int

    实际被调用的次数。

    MockTransport::new

    创建一个空的 MockTransport。

    MockTransport::on

    为某个请求登记响应。

    Mode

    pub(all) enum Mode {
    Record
    Playback
    Auto
    } derive(Eq)

    会话模式。

    Session

    pub struct Session {
    mode : Mode
    cassette :
    Cassette

    cursor : Int
    hits : Int
    misses : Int
    recorded : Int
    transport : &Transport?
    policy :
    MatchPolicy

    sanitize :
    SanitizePolicy

    }

    录制/回放会话。

    cursor 是回放推进位置:命中的记录会被跳过,从而正确处理 「同一请求被录制多次」的场景。Auto 模式下每次新录制都会把 游标推到末尾。

    Session::cassette

    当前 cassette(录制模式下即为最新结果,可直接交给 @codec.encode 落盘)。

    Session::cursor

    fn Session::cursor(self : Session) -> Int

    当前回放游标。

    Session::diagnose

    诊断「为什么没命中」,不抛错。

    replay 失败时抛出的 NoMatch 消息里已经包含同样的结论;本函数提供给 需要自行格式化输出的场景,例如 CLI、自定义断言,或「先看清楚再决定是 补录制还是改请求」的调试流程。

    调用方传业务原样的请求即可:规范化与脱敏由本函数统一处理,与匹配路径 保持一致。

    Session::new

    创建会话。

    默认模式为 Playback(最安全:不会意外发起真实调用), 默认匹配策略为 Exact,默认脱敏策略为 SanitizePolicy::default()

    Session::record

    手动写入一条录制:把「在别处拿到的响应」并入 cassette。

    主要用途是异步 HTTP 客户端Transport::send 是同步的,而 mizchi/x/http 这类客户端只能在 async 上下文里调用,因此无法实现 Transport;此时在 async 上下文里手工走一遍即可:

    match session.try_replay(request) { Some(response) => response None => { let response = await my_client.send(request) // 只有这一步是异步的 session.record(request, response) } }

    请求与响应都会先经过与 send 完全相同的派生链(规范化 + 脱敏),因此 手工录下的记录与自动录下的记录在 cassette 里形态一致,可以互相回放。 换句话说,本函数绕开了 Transport,但没有绕开任何不变量。

    返回值是已脱敏的响应,与 send 在录制模式下的返回保持一致。保持一致 的原因是确定性:回放返回的必然是 cassette 里存的那一份,若录制时返回未 脱敏的原文,同一段代码在首次运行与后续运行就会看到不同的值。

    本函数不接触任何外部资源,因此在 Playback 模式下调用它也不会破坏 「回放不发起真实调用」这一保证;但它确实会修改 cassette。

    Session::replay

    强制回放。未命中时报 NoMatch

    try_replay 的区别只在于「未命中」的处置: 这里的失败是显式的,适合在测试里断言「录制覆盖完整」。

    Session::send

    发送一次请求。

    这里存在一条关键的不变量:同一次业务请求会被派生成两种形态, 分别走两条不同链路,二者不可混用。

    • live(发给 provider):normalize 后直接发出,保留密钥 若这里也脱敏,真实鉴权会失败。
    • stored(用于匹配与落盘):在 live 之上再 sanitize抹掉密钥

    录制与回放两侧都必须走这条同样的链路,指纹才能对齐。否则会出现 「录得进去、回放不出来」——因为落盘的是脱敏版本,而回放查询的是原版。 这个缺陷在早期版本里真实存在过,现在由本函数与 prepare 共同保证对称。

    • Record:调用真实 Transport,追加记录,返回真实响应;
    • Playback:只从 cassette 取,未命中报 NoMatch
    • Auto:先回放,未命中再录制(即为「首次自动录制」工作流)。

    Session::set_mode

    fn Session::set_mode(self : Session, mode : Mode) -> Unit

    切换模式。

    Session::stats

    fn Session::stats(self : Session) -> Stats

    当前统计。

    Session::try_replay

    尝试回放。命中则推进游标并返回响应,未命中返回 None

    调用方只需原样传入业务请求:规范化与脱敏由 prepare 统一处理, 因此不会出现「直接调用本函数时忘了脱敏导致命中不了」的陷阱。

    Stats

    pub(all) struct Stats {
    hits : Int
    misses : Int
    recorded : Int
    } derive(Eq)

    会话统计。

    Source Files