Files
orbit/sdk/go/tasks_test.go

73 lines
2.9 KiB
Go

package orbit
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
)
func TestTaskClientContractAndNoSilentRetry(t *testing.T) {
const id = "11111111111111111111111111111111"
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
calls.Add(1)
if r.Header.Get("Authorization") != "Bearer example-token" || r.Header.Get("Idempotency-Key") != "stable" {
t.Error("lost authorization or identity")
}
raw, _ := io.ReadAll(r.Body)
if !strings.Contains(string(raw), "9007199254740993") {
t.Error("payload lost integer precision")
}
if calls.Load() == 1 {
w.WriteHeader(503)
_, _ = io.WriteString(w, `{"request_id":"`+id+`","error":{"code":"UNAVAILABLE","message":"retry original identity"}}`)
return
}
_, _ = io.WriteString(w, `{"request_id":"`+id+`","data":{"deduplicated":true,"task":{"id":"`+id+`","revision":"9007199254740993","payload":{"sequence":9007199254740993}}}}`)
}))
defer srv.Close()
client, err := NewClient(srv.URL, Options{Token: "example-token"})
if err != nil {
t.Fatal(err)
}
request := SubmitTaskRequest{QueueID: id, Payload: json.RawMessage(`{"sequence":9007199254740993}`)}
_, err = client.SubmitTask(context.Background(), "stable", request)
var apiErr *APIError
var httpErr *HTTPError
if !errors.As(err, &apiErr) || apiErr.Code != "UNAVAILABLE" || apiErr.RequestID != id || !errors.As(err, &httpErr) || httpErr.StatusCode != 503 || calls.Load() != 1 {
t.Fatalf("error/retry contract: %v, calls=%d", err, calls.Load())
}
out, err := client.SubmitTask(context.Background(), "stable", request)
if err != nil || !out.Deduplicated || out.Task.Revision != 9007199254740993 || string(out.Task.Payload) != `{"sequence":9007199254740993}` {
t.Fatalf("response: %+v %v", out, err)
}
}
func TestBusinessClientRedirectAndPathBoundaries(t *testing.T) {
var reached atomic.Bool
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reached.Store(true) }))
defer target.Close()
source := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, target.URL, 307) }))
defer source.Close()
client, _ := NewClient(source.URL, Options{Token: "example-token"})
_, err := client.GetTask(context.Background(), strings.Repeat("1", 32))
var failure *HTTPError
if !errors.As(err, &failure) || failure.StatusCode != 307 || reached.Load() {
t.Fatalf("redirect leaked request: %v", err)
}
for _, id := range []string{"../queues", "abc?token=bad", strings.Repeat("A", 32)} {
if _, err := client.GetTask(context.Background(), id); err == nil {
t.Fatal("accepted unsafe ID")
}
}
missing, _ := NewClient(source.URL, Options{})
if _, err := missing.GetQueue(context.Background(), strings.Repeat("1", 32)); err == nil {
t.Fatal("missing token allowed")
}
}