package orbit import ( "context" "encoding/json" "net/http" "strings" "testing" "time" ) func TestIntegrationWorkflowQuerySDK(t *testing.T) { api, queue, token := integrationWorkerClient(t) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() spec := workflowSDKSpec(queue, "query."+workerTestID(t)) // SIGNAL保持稳定WAITING,不启动Worker或等待短时任务截止。 spec.Body = WorkflowBlock{Steps: []WorkflowStep{{Key: "receipt", Kind: "SIGNAL", Signal: &WorkflowSignal{Name: "done", PayloadVersion: "v1", Correlation: WorkflowValue{Kind: "LITERAL", Literal: json.RawMessage(`"query"`)}, PayloadType: spec.InputType, TimeoutMS: 60000}}}, OutputType: spec.InputType, Output: WorkflowRef("receipt")} in := publishWorkflowSDK(t, ctx, api, spec) in.BusinessKey = "作业 /+%\n " + workerTestID(t) + " " var started []WorkflowInstance for _, key := range []string{in.BusinessKey, in.BusinessKey, strings.TrimSpace(in.BusinessKey)} { in.BusinessKey = key out, err := api.StartWorkflow(ctx, workerTestID(t), in) if err != nil { t.Fatal(err) } started = append(started, out.Instance) } paused, err := api.ControlWorkflow(ctx, started[0].ID, workerTestID(t), WorkflowControlRequest{Operation: "PAUSE", ExpectedControlRevision: started[0].ControlRevision, Reason: "verify paused query"}) if err != nil || !paused.Instance.Paused { t.Fatal(paused, err) } from, before := started[0].CreatedAt, started[2].CreatedAt.Add(time.Microsecond) query := ListWorkflowsRequest{DefinitionID: in.DefinitionID, Version: "v1", State: "WAITING", BusinessKey: started[0].BusinessKey, CreatedFrom: &from, CreatedBefore: &before, Limit: 1} first, err := api.ListWorkflows(ctx, query) if err != nil || len(first.Items) != 1 || first.Items[0].ID != started[1].ID || first.NextCursor == "" { t.Fatal(first, err) } query.Cursor = first.NextCursor last, err := api.ListWorkflows(ctx, query) if err != nil || len(last.Items) != 1 || last.Items[0].ID != started[0].ID || !last.Items[0].Paused || last.NextCursor != "" { t.Fatal(last, err) } query.BusinessKey = strings.TrimSpace(query.BusinessKey) _, err = api.ListWorkflows(ctx, query) workflowAPIError(t, err, "INVALID_ARGUMENT") query.Cursor = "" if page, err := api.ListWorkflows(ctx, query); err != nil || len(page.Items) != 1 || page.Items[0].ID != started[2].ID { t.Fatal("exact business key", page, err) } b := false query.BusinessKey = started[0].BusinessKey query.Paused = &b if page, err := api.ListWorkflows(ctx, query); err != nil || len(page.Items) != 1 || page.Items[0].ID != started[1].ID { t.Fatal("false paused filter", page, err) } for _, suffix := range []string{"?state=WAITING&state=RUNNING", "?paused=1", "?business_key=", "?unknown=x", "?version=v1", "?limit=101"} { req, err := http.NewRequestWithContext(ctx, "GET", api.baseURL+"/v1/workflows"+suffix, nil) if err != nil { t.Fatal(err) } req.Header.Set("Authorization", "Bearer "+token) res, err := http.DefaultClient.Do(req) if err != nil { t.Fatal(err) } res.Body.Close() if res.StatusCode != 400 { t.Fatal("invalid raw query", suffix, res.StatusCode) } } for _, v := range started { current, err := api.GetWorkflow(ctx, v.ID) if err != nil { t.Fatal(err) } if _, err = api.ControlWorkflow(ctx, v.ID, workerTestID(t), WorkflowControlRequest{Operation: "CANCEL", ExpectedControlRevision: current.ControlRevision, Reason: "query regression cleanup"}); err != nil { t.Fatal(err) } waitWorkflowSDK(t, ctx, api, v.ID, "CANCELLED") } t.Log("real HTTP: exact key, time bounds, fixed version, paused false, filtered cursor, malformed query rejection and cancellation cleanup") }