From 71a17d609668c2efeae90dc80fd23b15c7edd3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 22 Sep 2026 11:46:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20platform-image=20mock=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E4=BD=93=E8=AF=BB=E5=8F=96=E7=AB=9E=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nanobanana 生成用例的 mock server 改为复用同文件 read_http_request,按 Content-Length 读满请求体再断言,消除「只读到 \r\n\r\n 就断言头后 body」的竞态 - pitfalls 新增「测试内 mock HTTP server 必须按 Content-Length 读满请求体再断言」记录现象、原因与变异验证方式 --- docs/project-memory/shared-memory/pitfalls.md | 8 ++++++++ .../crates/platform-image/tests/image_provider.rs | 15 +-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 00a6556df..21be86be3 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -7,6 +7,14 @@ - 处理:客户端画布图标生成只 trim 描述并以单项 `iconDescriptions` 原样提交,保留内部换行;面板与原生入口按 `200` 个 Unicode 码点校验并拒绝空白或超限输入,不静默截断、不机械拆条。服务端共用的提示词流程负责规范图、背景与排布要求;其它图片生成的 `32000` 字符上限保持不变。 - 验证:检查实际请求体与 trim 后的原文一致,并覆盖 `200/201` 码点、补充平面字符、换行和空白输入;不能只断言“请求长度未超限”。完整合同见 [画板图标素材生成入口设计](../../【编辑器】画板图标素材生成入口设计-2026-06-15.md)。 +## 测试内 mock HTTP server 必须按 Content-Length 读满请求体再断言 + +- 现象:`platform-image` 的 `nanobanana_generate_content_posts_native_body_and_reads_inline_data` 在本机(Windows)稳定红、在 CI 上存在偶发红,断言 `request_text.contains("\"imageSize\":\"512\"")` 失败,看起来像实现没有发送请求体。 +- 原因:该 mock 用例自带一版「读到第一个 `\r\n\r\n` 就 break」的读循环,而 `\r\n\r\n` 只代表请求头结束;reqwest 写完头再写 body,TCP 分片下 body 常常还没到。断言实际只看到头和半截 body,是测试脚手架的竞态,与平台 / 网络栈无关,被测代码本身没有问题。 +- 处理:mock server 一律复用同文件已有的 `read_http_request`,先解析 `Content-Length`,读满 `header_end + content_length` 再断言;同文件的 `image_edit_retries_send_timeout_once_and_succeeds` 与 `image_provider_deadline_clips_stalled_attempt_and_prevents_retry` 早已使用该 helper。 +- 验证:把断言期望值临时改成错误值,用例必须失败(证明读到了真实 body);改回后期望连续重跑 8 次全绿,并跑 `cargo test -p platform-image` 全量(22 + 64 + 14 passed)。 +- 关联:`server-rs/crates/platform-image/tests/image_provider.rs`。 + ## 2026-09-21 不同渠道的包体在同一台设备安装会互相顶掉 - **现象**:在一台已经装了某个渠道 AGC 客户端的设备上安装另一个渠道的安装包,装完后旧客户端直接消失(安装目录被覆盖、卸载项被接管),更新端点、平台服务器与本地登录态一起换成新渠道的;两个渠道的客户端无法共存。 diff --git a/server-rs/crates/platform-image/tests/image_provider.rs b/server-rs/crates/platform-image/tests/image_provider.rs index 4ceea0692..be1401272 100644 --- a/server-rs/crates/platform-image/tests/image_provider.rs +++ b/server-rs/crates/platform-image/tests/image_provider.rs @@ -443,20 +443,7 @@ async fn nanobanana_generate_content_posts_native_body_and_reads_inline_data() { let Ok((mut stream, _)) = listener.accept().await else { return; }; - let mut request = Vec::new(); - let mut buffer = [0_u8; 4096]; - loop { - let Ok(read) = stream.read(&mut buffer).await else { - return; - }; - if read == 0 { - return; - } - request.extend_from_slice(&buffer[..read]); - if request.windows(4).any(|window| window == b"\r\n\r\n") { - break; - } - } + let request = read_http_request(&mut stream).await; let request_text = String::from_utf8_lossy(request.as_slice()); assert!( request_text.contains("/v1beta/models/gemini-3.1-flash-image-preview:generateContent")