旧 external_generation_job 归一化用例改成真断言

- server-rs/crates/spacetime-module/src/migration.rs:provider_kind / provider_task_id 的断言改成先 as_object() 取键再比 null,原先用 Value 索引在键缺失时返回 Null,归一化被删掉也照样通过
This commit is contained in:
2026-09-24 17:48:41 +08:00
parent 14294a2c9b
commit 40c97bf876
2 changed files with 13 additions and 7 deletions
@@ -83,11 +83,13 @@ fn image_source_rejects_ambiguous_and_raw_input() {
});
let error = serde_json::from_value::<Model3dImageToModelRequest>(raw_input)
.expect_err("裸字符串图片输入应被拒绝");
// 拒绝必须发生在 source 本身:错误里点名 Model3dGenerationSource,避免将来
// generation / 落点字段的变化把这条负例“顶替”成通过。
assert!(
error.to_string().contains("Model3dGenerationSource"),
"裸字符串 source 的报错应点名 Model3dGenerationSource,实际为:{error}"
// 拒绝必须发生在 source 本身,不能被 generation / 落点字段的变化“顶替”成通过。
// 这里只锁结构化分类(数据错),不锁 serde 的 Display 文案 —— 文案会随 serde
// 版本与枚举表示法变化,而「拒的是 source 的形状」这个契约不变。
assert_eq!(
error.classify(),
serde_json::error::Category::Data,
"裸字符串 source 的报错应判为数据错误,实际为:{error}"
);
// 同样把 source 单独反序列化一遍,锁死被拒的是图片输入的形状本身。
@@ -1546,8 +1546,12 @@ mod migration_bootstrap_secret_tests {
&serde_json::json!({ "job_id": "task-1" }),
);
assert_eq!(normalized["provider_kind"], serde_json::Value::Null);
assert_eq!(normalized["provider_task_id"], serde_json::Value::Null);
// serde_json 的 `Index<&str>` 在键缺失时返回 `Null` 而不是报错,直接断言
// `normalized["provider_kind"] == Null` 在归一化整段被删掉时也照样通过。
// 先按对象取键,再锁 null 默认值,才真正守住这两列被插进去这件事。
let row = normalized.as_object().expect("归一化后的行必须是对象");
assert_eq!(row.get("provider_kind"), Some(&serde_json::Value::Null));
assert_eq!(row.get("provider_task_id"), Some(&serde_json::Value::Null));
}
#[test]