package run import ( "encoding/json" "testing" "git.iwork-ai.com/xdc/iqudo-top1/internal/model" "gorm.io/datatypes" ) func TestValidateKnowledgeSelectionsRejectsUnrelatedPlan(t *testing.T) { config := map[string]interface{}{ "knowledge_selector": map[string]interface{}{"derived_field": "matched"}, "knowledge_collection": map[string]interface{}{"steps": []map[string]interface{}{ {"field_key": "segments", "name": "客户分群", "root": true, "required": true, "multiple": true}, {"field_key": "strategies", "name": "推荐策略", "from_field": "segments", "relation_type": "matched_strategy", "required": true, "multiple": true}, {"field_key": "offers", "name": "推荐内容", "from_field": "strategies", "relation_type": "recommended_offer", "required": true, "multiple": true}, }}, } configRaw, _ := json.Marshal(config) snapshotRaw, _ := json.Marshal(knowledgeSnapshot{ Items: []model.KnowledgeItem{ {Base: model.Base{ID: 1}, ItemKey: "vip", Name: "高价值客户", Status: "active"}, {Base: model.Base{ID: 2}, ItemKey: "renewal", Name: "续费策略", Status: "active"}, {Base: model.Base{ID: 3}, ItemKey: "annual", Name: "年度套餐", Status: "active"}, {Base: model.Base{ID: 4}, ItemKey: "trial", Name: "试用课程", Status: "active"}, }, Relations: []model.KnowledgeRelation{ {FromKnowledgeID: 1, ToKnowledgeID: 2, RelationType: "matched_strategy"}, {FromKnowledgeID: 2, ToKnowledgeID: 3, RelationType: "recommended_offer"}, }, }) derivedRaw, _ := json.Marshal(map[string]interface{}{"matched": []string{"高价值客户"}}) run := model.SOPRun{Derived: datatypes.JSON(derivedRaw), KnowledgeSnapshot: datatypes.JSON(snapshotRaw)} node := model.SOPNode{Type: "knowledge", Config: datatypes.JSON(configRaw)} valid := map[string]interface{}{"segments": []interface{}{"高价值客户"}, "strategies": []interface{}{"续费策略"}, "offers": []interface{}{"年度套餐"}} if err := validateKnowledgeSelections(node, run, valid); err != nil { t.Fatalf("valid selection rejected: %v", err) } invalid := map[string]interface{}{"segments": []interface{}{"高价值客户"}, "strategies": []interface{}{"续费策略"}, "offers": []interface{}{"试用课程"}} if err := validateKnowledgeSelections(node, run, invalid); err == nil { t.Fatal("unrelated plan should be rejected") } } func TestValidateKnowledgeSelectionsAllowsAdditionalRootFromConfiguredKnowledgeType(t *testing.T) { configRaw := datatypes.JSON([]byte(`{"knowledge_selector":{"derived_field":"matched"},"knowledge_collection":{"steps":[{"field_key":"symptoms","name":"症状","root":true,"candidate_scope":"all","knowledge_types":["symptom"],"required":true,"multiple":true}]}}`)) snapshotRaw, _ := json.Marshal(knowledgeSnapshot{Items: []model.KnowledgeItem{ {Base: model.Base{ID: 1}, ItemKey: "diarrhea", Name: "腹泻", Type: "symptom", Status: "active"}, {Base: model.Base{ID: 2}, ItemKey: "vomiting", Name: "呕吐", Type: "symptom", Status: "active"}, {Base: model.Base{ID: 3}, ItemKey: "disease", Name: "胃肠炎", Type: "disease", Status: "active"}, }}) derivedRaw, _ := json.Marshal(map[string]interface{}{"matched": []string{"腹泻"}}) run := model.SOPRun{Derived: datatypes.JSON(derivedRaw), KnowledgeSnapshot: datatypes.JSON(snapshotRaw)} node := model.SOPNode{Type: "knowledge", Config: configRaw} if err := validateKnowledgeSelections(node, run, map[string]interface{}{"symptoms": []interface{}{"腹泻", "呕吐"}}); err != nil { t.Fatalf("additional symptom should be accepted: %v", err) } if err := validateKnowledgeSelections(node, run, map[string]interface{}{"symptoms": []interface{}{"胃肠炎"}}); err == nil { t.Fatal("knowledge item of another type should be rejected") } }