package httpserver import ( "encoding/json" "net/http/httptest" "strings" "testing" "git.yuntuo.hk/k2safe/orbit/internal/fault" "git.yuntuo.hk/k2safe/orbit/weave/instance" "git.yuntuo.hk/k2safe/orbit/weave/recovery" ) func TestWorkflowRecoveryEmbeddedJSON(t *testing.T) { valid := `{"expected_revision":"9007199254740993","reason":"核查","evidence_ref":"evidence:1","step_key":"query","activation_id":"11111111111111111111111111111111","expected_step_revision":"3","pending_confirmed":true}` for _, tc := range []struct { name, body string valid bool }{ {"flat embedded fields", valid, true}, {"unknown parent", strings.Replace(valid, `"reason"`, `"Reason"`, 1), false}, {"unknown step", strings.Replace(valid, `"step_key"`, `"StepKey"`, 1), false}, {"nested decision", `{"Decision":{"expected_revision":"1"},"pending_confirmed":true}`, false}, {"missing confirmation", strings.Replace(valid, `,"pending_confirmed":true`, "", 1), false}, {"null confirmation", strings.Replace(valid, `"pending_confirmed":true`, `"pending_confirmed":null`, 1), false}, {"numeric revision", strings.Replace(valid, `"9007199254740993"`, `9007199254740993`, 1), false}, {"duplicate inherited field", strings.Replace(valid, `"reason":"核查"`, `"reason":"核查","reason":"改写"`, 1), false}, } { t.Run(tc.name, func(t *testing.T) { r := httptest.NewRequest("POST", "/", strings.NewReader(tc.body)) r.Header.Set("Content-Type", "application/json") var in recovery.ContinuePollInput err := decodeBody(r, &in) if (err == nil) != tc.valid { t.Fatal(err) } if tc.valid && (in.ExpectedRevision != 9007199254740993 || in.ExpectedStepRevision != 3 || in.StepKey != "query") { t.Fatal("embedded fields lost") } }) } for _, raw := range []string{`{"execution_settled":true,"result":null}`, `{"execution_settled":true,"result":{"n":9007199254740993}}`} { r := httptest.NewRequest("POST", "/", strings.NewReader(raw)) r.Header.Set("Content-Type", "application/json") var in recovery.ResolveStepInput if err := decodeBody(r, &in); err != nil { t.Fatal(err) } if !json.Valid(in.Result) { t.Fatal("result lost") } } r := httptest.NewRequest("POST", "/", strings.NewReader(`{"definition_id":"11111111111111111111111111111111","version":"v1","input":null}`)) r.Header.Set("Content-Type", "application/json") var in instance.StartInput if err := decodeBody(r, &in); err != nil || string(in.Input) != "null" { t.Fatal("explicit null input", err) } } func TestWorkflowLimitsAreExplicitConflicts(t *testing.T) { for _, code := range []string{"WORKFLOW_INSTANCE_LIMIT", "WORKFLOW_SIGNAL_LIMIT"} { w := httptest.NewRecorder() writeError(w, "request", fault.New(code, "limit reached")) if w.Code != 409 { t.Fatal(code, w.Code) } } }