Files
iqudo-top1/internal/scenario/contract_test.go
2026-08-18 16:27:02 +08:00

72 lines
3.0 KiB
Go

package scenario
import (
"strings"
"testing"
)
func TestValidateContractInput(t *testing.T) {
valid := contractInput{
OutputSchema: map[string]interface{}{"fields": []interface{}{
map[string]interface{}{"key": "matched_topics", "source": "derived", "source_field": "topics"},
}},
ResultSchema: map[string]interface{}{"fields": []interface{}{
map[string]interface{}{"key": "selected_products", "name": "成交商品", "type": "array", "items": map[string]interface{}{"type": "string"}},
}},
Rules: []ruleInput{{
RuleKey: "match_topic", Name: "匹配主题",
Condition: map[string]interface{}{"field": "product_tags", "operator": "contains", "value": "hot"},
Actions: []map[string]interface{}{{"operation": "append", "field": "topics", "value": "topic_hot"}},
}},
AllowedOrigins: []string{"https://crm.example.com"},
}
if err := validateContractInput(valid); err != nil {
t.Fatalf("valid contract rejected: %v", err)
}
tests := []struct {
name string
edit func(*contractInput)
want string
}{
{name: "duplicate output", edit: func(input *contractInput) {
input.OutputSchema["fields"] = append(input.OutputSchema["fields"].([]interface{}), map[string]interface{}{"key": "matched_topics"})
}, want: "输出字段标识"},
{name: "invalid source", edit: func(input *contractInput) {
input.OutputSchema["fields"].([]interface{})[0].(map[string]interface{})["source"] = "script"
}, want: "不支持的来源"},
{name: "invalid condition", edit: func(input *contractInput) { input.Rules[0].Condition = map[string]interface{}{"all": []interface{}{}} }, want: "非空数组"},
{name: "invalid action", edit: func(input *contractInput) { input.Rules[0].Actions[0]["operation"] = "execute" }, want: "不支持的动作"},
{name: "invalid origin", edit: func(input *contractInput) { input.AllowedOrigins = []string{"crm.example.com"} }, want: "完整的 http/https Origin"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
input := cloneContractInput(valid)
test.edit(&input)
if err := validateContractInput(input); err == nil || !strings.Contains(err.Error(), test.want) {
t.Fatalf("error = %v, want containing %q", err, test.want)
}
})
}
}
func cloneContractInput(input contractInput) contractInput {
field := input.OutputSchema["fields"].([]interface{})[0].(map[string]interface{})
fieldCopy := map[string]interface{}{}
for key, value := range field {
fieldCopy[key] = value
}
rule := input.Rules[0]
condition := map[string]interface{}{}
for key, value := range rule.Condition {
condition[key] = value
}
action := map[string]interface{}{}
for key, value := range rule.Actions[0] {
action[key] = value
}
rule.Condition = condition
rule.Actions = []map[string]interface{}{action}
return contractInput{OutputSchema: map[string]interface{}{"fields": []interface{}{fieldCopy}}, ResultSchema: input.ResultSchema, Rules: []ruleInput{rule}, AllowedOrigins: append([]string{}, input.AllowedOrigins...)}
}