This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/sandbox/routing_module_test.go
Jeffrey Smith e736a27b59
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Has been skipped
CI/CD / e2e-smoke (pull_request) Has been skipped
CI/CD / test-runners (pull_request) Has been skipped
CI/CD / test-go-pg (pull_request) Successful in 2m55s
CI/CD / test-sqlite (pull_request) Successful in 3m17s
CI/CD / build-and-deploy (pull_request) Successful in 1m5s
Feat v0.9.8 conditional routing SDK primitive
Promote workflow branch-rule evaluation to a generic Starlark
routing.evaluate(rules, data) module available to all extensions.
10 operators, first-match-wins, no permission gate. 8 new tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 19:17:03 +00:00

163 lines
5.0 KiB
Go

package sandbox
import (
"testing"
"go.starlark.net/starlark"
)
func runRoutingScript(t *testing.T, script string) starlark.StringDict {
t.Helper()
mod := BuildRoutingModule()
predeclared := starlark.StringDict{"routing": mod}
globals, err := starlark.ExecFile(&starlark.Thread{Name: "test"}, "test.star", script, predeclared)
if err != nil {
t.Fatal(err)
}
return globals
}
func runRoutingScriptErr(t *testing.T, script string) error {
t.Helper()
mod := BuildRoutingModule()
predeclared := starlark.StringDict{"routing": mod}
_, err := starlark.ExecFile(&starlark.Thread{Name: "test"}, "test.star", script, predeclared)
return err
}
func TestRoutingEvaluate_SingleMatch(t *testing.T) {
globals := runRoutingScript(t, `
result = routing.evaluate([
{"field": "priority", "op": "eq", "value": "high", "target": "escalation"},
], {"priority": "high"})
`)
result := globals["result"]
if s, ok := result.(starlark.String); !ok || string(s) != "escalation" {
t.Fatalf("expected 'escalation', got %v", result)
}
}
func TestRoutingEvaluate_FirstMatchWins(t *testing.T) {
globals := runRoutingScript(t, `
result = routing.evaluate([
{"field": "amount", "op": "gt", "value": 100, "target": "big"},
{"field": "amount", "op": "gt", "value": 50, "target": "medium"},
], {"amount": 200})
`)
result := globals["result"]
if s, ok := result.(starlark.String); !ok || string(s) != "big" {
t.Fatalf("expected 'big', got %v", result)
}
}
func TestRoutingEvaluate_NoMatch(t *testing.T) {
globals := runRoutingScript(t, `
result = routing.evaluate([
{"field": "status", "op": "eq", "value": "done", "target": "finish"},
], {"status": "pending"})
`)
if globals["result"] != starlark.None {
t.Fatalf("expected None, got %v", globals["result"])
}
}
func TestRoutingEvaluate_EmptyRules(t *testing.T) {
globals := runRoutingScript(t, `
result = routing.evaluate([], {"x": 1})
`)
if globals["result"] != starlark.None {
t.Fatalf("expected None, got %v", globals["result"])
}
}
func TestRoutingEvaluate_AllOperators(t *testing.T) {
globals := runRoutingScript(t, `
# exists
r1 = routing.evaluate([{"field": "x", "op": "exists", "value": "", "target": "yes"}], {"x": 1})
# not_exists
r2 = routing.evaluate([{"field": "x", "op": "not_exists", "value": "", "target": "yes"}], {"y": 1})
# eq
r3 = routing.evaluate([{"field": "s", "op": "eq", "value": "abc", "target": "yes"}], {"s": "abc"})
# neq
r4 = routing.evaluate([{"field": "s", "op": "neq", "value": "abc", "target": "yes"}], {"s": "xyz"})
# gt
r5 = routing.evaluate([{"field": "n", "op": "gt", "value": 10, "target": "yes"}], {"n": 20})
# lt
r6 = routing.evaluate([{"field": "n", "op": "lt", "value": 10, "target": "yes"}], {"n": 5})
# gte
r7 = routing.evaluate([{"field": "n", "op": "gte", "value": 10, "target": "yes"}], {"n": 10})
# lte
r8 = routing.evaluate([{"field": "n", "op": "lte", "value": 10, "target": "yes"}], {"n": 10})
# in
r9 = routing.evaluate([{"field": "s", "op": "in", "value": ["a", "b", "c"], "target": "yes"}], {"s": "b"})
# contains
r10 = routing.evaluate([{"field": "s", "op": "contains", "value": "ell", "target": "yes"}], {"s": "hello"})
`)
for _, name := range []string{"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10"} {
v := globals[name]
if s, ok := v.(starlark.String); !ok || string(s) != "yes" {
t.Errorf("%s: expected 'yes', got %v", name, v)
}
}
}
func TestRoutingEvaluate_TypeCoercion(t *testing.T) {
globals := runRoutingScript(t, `
# Numeric string vs int
r1 = routing.evaluate([
{"field": "n", "op": "gt", "value": 10, "target": "yes"},
], {"n": "20"})
# Int equality via string normalization
r2 = routing.evaluate([
{"field": "n", "op": "eq", "value": 42, "target": "yes"},
], {"n": 42})
`)
for _, name := range []string{"r1", "r2"} {
v := globals[name]
if s, ok := v.(starlark.String); !ok || string(s) != "yes" {
t.Errorf("%s: expected 'yes', got %v", name, v)
}
}
}
func TestRoutingEvaluate_BadInput(t *testing.T) {
// rules must be a list
err1 := runRoutingScriptErr(t, `routing.evaluate("bad", {})`)
if err1 == nil {
t.Fatal("expected error for non-list rules")
}
// data must be a dict
err2 := runRoutingScriptErr(t, `routing.evaluate([], "bad")`)
if err2 == nil {
t.Fatal("expected error for non-dict data")
}
// rule missing required fields
err3 := runRoutingScriptErr(t, `routing.evaluate([{"field": "x"}], {})`)
if err3 == nil {
t.Fatal("expected error for incomplete rule")
}
}
func TestRoutingEvaluate_MissingFields(t *testing.T) {
globals := runRoutingScript(t, `
# Field not in data — eq should not match
r1 = routing.evaluate([
{"field": "absent", "op": "eq", "value": "x", "target": "bad"},
], {"other": "y"})
# not_exists matches when field is absent
r2 = routing.evaluate([
{"field": "absent", "op": "not_exists", "value": "", "target": "good"},
], {"other": "y"})
`)
if globals["r1"] != starlark.None {
t.Fatalf("r1: expected None for missing field, got %v", globals["r1"])
}
if s, ok := globals["r2"].(starlark.String); !ok || string(s) != "good" {
t.Fatalf("r2: expected 'good', got %v", globals["r2"])
}
}