package orbit import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "sync/atomic" "testing" ) func TestWorkflowHistoryIdentityBoundsAndResponseValidation(t *testing.T) { const id = "11111111111111111111111111111111" const child = "22222222222222222222222222222222" ctx := context.Background() var calls atomic.Int32 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls.Add(1) if r.Method != "GET" || r.Header.Get("Idempotency-Key") != "" || r.Header.Get("Authorization") != "Bearer test-token" { t.Error("invalid read request") } if r.URL.Query().Get("cursor") != "opaque+cursor/=" || r.URL.Query().Get("limit") != "1" { t.Error("query changed") } // 合法响应信封中的错误父资源,SDK不得将其作为请求资源的数据返回。 json.NewEncoder(w).Encode(map[string]any{"request_id": id, "data": map[string]any{"instance_id": child, "workflow_id": child, "step_id": child, "revision": "1", "items": []any{}}}) })) defer server.Close() c, err := NewClient(server.URL, Options{Token: "test-token"}) if err != nil { t.Fatal(err) } for _, bad := range []string{"../other", strings.Repeat("A", 32), "a?x=b"} { if _, err = c.ListWorkflowActivations(ctx, bad, "work", HistoryPageRequest{}); err == nil { t.Fatal("bad workflow accepted") } if _, err = c.GetWorkflowActivation(ctx, id, "work", bad); err == nil { t.Fatal("bad activation accepted") } if _, err = c.ListWorkflowPollRounds(ctx, id, "work", bad, HistoryPageRequest{}); err == nil { t.Fatal("bad round scope accepted") } if _, err = c.ListWorkflowSignals(ctx, bad, HistoryPageRequest{}); err == nil { t.Fatal("bad signal parent accepted") } if _, err = c.ListWorkflowSignalOperations(ctx, id, bad, HistoryPageRequest{}); err == nil { t.Fatal("bad signal accepted") } if _, err = c.GetWorkflowSignalOperation(ctx, id, child, bad); err == nil { t.Fatal("bad operation accepted") } } for _, key := range []string{"$root", "../other", "", strings.Repeat("x", 65)} { if _, err = c.ListWorkflowActivations(ctx, id, key, HistoryPageRequest{}); err == nil { t.Fatal("bad key accepted") } } for _, in := range []HistoryPageRequest{{Limit: -1}, {Limit: 101}, {Cursor: strings.Repeat("x", 1025)}} { if _, err = c.ListWorkflowActivations(ctx, id, "work", in); err == nil { t.Fatal("bad activation page") } if _, err = c.ListWorkflowPollRounds(ctx, id, "work", child, in); err == nil { t.Fatal("bad round page") } if _, err = c.ListWorkflowSignals(ctx, id, in); err == nil { t.Fatal("bad signal page") } if _, err = c.ListWorkflowSignalOperations(ctx, id, child, in); err == nil { t.Fatal("bad operation page") } } if calls.Load() != 0 { t.Fatal("invalid arguments reached transport") } page := HistoryPageRequest{Limit: 1, Cursor: "opaque+cursor/="} if _, err = c.ListWorkflowActivations(ctx, id, "work", page); err == nil { t.Fatal("foreign activation page accepted") } if _, err = c.ListWorkflowPollRounds(ctx, id, "work", child, page); err == nil { t.Fatal("foreign round page accepted") } if _, err = c.ListWorkflowSignals(ctx, id, page); err == nil { t.Fatal("foreign signal page accepted") } if calls.Load() != 3 { t.Fatal("unexpected automatic read retry") } }