feat: add generated scene skill platform hardening

This commit is contained in:
木炎
2026-04-21 23:19:06 +08:00
parent 118fc77935
commit 956f0c2b68
439 changed files with 61974 additions and 3645 deletions

View File

@@ -31,7 +31,8 @@ fn make_test_mode(
description: None,
}),
column_defs: vec![("id".to_string(), "ID".to_string())],
request_template: serde_json::json!({}),
request_template: serde_json::json!({ "mode": name }),
request_field_mappings: Vec::new(),
normalize_rules: Some(NormalizeRulesIr {
rules_type: "validate_required".to_string(),
required_fields: vec!["id".to_string()],
@@ -43,6 +44,10 @@ fn make_test_mode(
fn make_test_scene_ir(modes: Vec<ModeIr>) -> SceneIr {
let is_multi = modes.len() > 1;
let api_endpoints = modes
.iter()
.filter_map(|mode| mode.api_endpoint.clone())
.collect::<Vec<_>>();
SceneIr {
scene_id: "test-scene".to_string(),
scene_id_diagnostics: SceneIdDiagnosticsIr::default(),
@@ -71,6 +76,13 @@ fn make_test_scene_ir(modes: Vec<ModeIr>) -> SceneIr {
},
],
workflow_evidence: Default::default(),
main_request: None,
pagination_plan: None,
enrichment_requests: Vec::new(),
join_keys: Vec::new(),
merge_or_dedupe_rules: Vec::new(),
export_plan: None,
merge_plan: None,
request_template: serde_json::Value::Null,
response_path: "".to_string(),
normalize_rules: None,
@@ -78,7 +90,8 @@ fn make_test_scene_ir(modes: Vec<ModeIr>) -> SceneIr {
validation_hints: Default::default(),
evidence: Vec::new(),
readiness: Default::default(),
api_endpoints: Vec::new(),
api_endpoints,
runtime_dependencies: Vec::new(),
static_params: Default::default(),
column_defs: Vec::new(),
confidence: 0.0,
@@ -96,9 +109,9 @@ fn temp_workspace(prefix: &str) -> PathBuf {
path
}
/// Test 1: Single mode generates MODES array (routes through compile_multi_mode_request)
/// Test 1: Single request table uses dedicated simple-request path instead of MODES fallback.
#[test]
fn test_single_mode_generates_modes_array() {
fn test_single_request_table_uses_dedicated_path() {
let output_root = temp_workspace("sgclaw-single-mode-test");
let modes = vec![make_test_mode(
"month",
@@ -108,10 +121,9 @@ fn test_single_mode_generates_modes_array() {
)];
let scene_ir = make_test_scene_ir(modes);
// Use SingleRequestTable archetype - the compile path should auto-wrap into multi-mode
// Use SingleRequestTable archetype - the compile path should stay on the dedicated single-request route.
let mut scene_ir = scene_ir;
scene_ir.workflow_archetype = Some(WorkflowArchetype::SingleRequestTable);
// Provide one api_endpoint so ensure_modes_populated works
scene_ir.api_endpoints = vec![ApiEndpointIr {
name: "default_endpoint".to_string(),
url: "http://example.com/api/data".to_string(),
@@ -138,8 +150,12 @@ fn test_single_mode_generates_modes_array() {
fs::read_to_string(skill_root.join("scripts/collect_single_mode_scene.js")).unwrap();
assert!(
generated_script.contains("const MODES ="),
"Generated JS should contain 'const MODES =' since SingleRequestTable routes through compile_multi_mode_request"
generated_script.contains("const REQUEST_TEMPLATE ="),
"Generated JS should contain REQUEST_TEMPLATE on the dedicated single-request path"
);
assert!(
!generated_script.contains("const MODES ="),
"Generated JS should no longer route SingleRequestTable through MODES fallback"
);
}
@@ -148,18 +164,8 @@ fn test_single_mode_generates_modes_array() {
fn test_multi_mode_generates_mode_routing() {
let output_root = temp_workspace("sgclaw-multi-mode-test");
let modes = vec![
make_test_mode(
"month",
"http://example.com/api/month",
None,
"data",
),
make_test_mode(
"week",
"http://example.com/api/week",
None,
"data",
),
make_test_mode("month", "http://example.com/api/month", None, "data"),
make_test_mode("week", "http://example.com/api/week", None, "data"),
];
let scene_ir = make_test_scene_ir(modes);
@@ -200,7 +206,8 @@ fn test_form_urlencoded_request_body() {
Some("application/x-www-form-urlencoded"),
"data",
)];
let scene_ir = make_test_scene_ir(modes);
let mut scene_ir = make_test_scene_ir(modes);
scene_ir.workflow_archetype = Some(WorkflowArchetype::MultiModeRequest);
generate_scene_package(GenerateSceneRequest {
source_dir: PathBuf::from("tests/fixtures/generated_scene/report_collection"),
@@ -245,7 +252,8 @@ fn test_response_path_extraction_in_template() {
None,
"data.list",
)];
let scene_ir = make_test_scene_ir(modes);
let mut scene_ir = make_test_scene_ir(modes);
scene_ir.workflow_archetype = Some(WorkflowArchetype::MultiModeRequest);
generate_scene_package(GenerateSceneRequest {
source_dir: PathBuf::from("tests/fixtures/generated_scene/report_collection"),
@@ -312,7 +320,9 @@ fn test_process_data_flag_in_ajax() {
);
// processData should be false for form-urlencoded (negated condition)
assert!(
generated_script.contains("processData: request.headers['Content-Type'] !== 'application/x-www-form-urlencoded'"),
generated_script.contains(
"processData: request.headers['Content-Type'] !== 'application/x-www-form-urlencoded'"
),
"Generated JS should set processData to false for form-urlencoded content type"
);
}