inital commit
This commit is contained in:
138
request_options_test.go
Normal file
138
request_options_test.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package fa
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestRequestOverride_PerCallCookiesAndUA exercises the multi-tenant flow:
|
||||
// one Client built with default creds, two calls in a row each carrying a
|
||||
// different user's cookies via per-call Options. The server records the
|
||||
// Cookie + User-Agent headers it saw on each request; the per-call values
|
||||
// must override the client's, and the client's defaults must come back on
|
||||
// a call that passes no overrides.
|
||||
func TestRequestOverride_PerCallCookiesAndUA(t *testing.T) {
|
||||
type seen struct {
|
||||
cookie string
|
||||
userAgent string
|
||||
}
|
||||
var (
|
||||
mu sync.Mutex
|
||||
hits []seen
|
||||
)
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/view/1/", func(w http.ResponseWriter, r *http.Request) {
|
||||
mu.Lock()
|
||||
hits = append(hits, seen{cookie: r.Header.Get("Cookie"), userAgent: r.Header.Get("User-Agent")})
|
||||
mu.Unlock()
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
_, _ = w.Write([]byte(syntheticSubmissionHTML))
|
||||
})
|
||||
srv := httptest.NewServer(mux)
|
||||
defer srv.Close()
|
||||
|
||||
// Client built with default ("system") creds plus a default UA.
|
||||
client := newE2EClient(t, srv)
|
||||
// Layer the client default cookies in via WithCookies so we can verify
|
||||
// they appear when no override is passed.
|
||||
clientWithDefaults := New(
|
||||
WithHTTPClient(client.http),
|
||||
WithRateLimit(0, 16),
|
||||
WithMaxRetries(0),
|
||||
WithUserAgent("default-ua/1.0"),
|
||||
WithCookies(Cookies{A: "defaultA", B: "defaultB"}),
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Call 1: no override → client defaults must apply.
|
||||
if _, err := clientWithDefaults.GetSubmission(ctx, 1); err != nil {
|
||||
t.Fatalf("call 1: %v", err)
|
||||
}
|
||||
// Call 2: per-user override (user-A creds + user-A UA).
|
||||
if _, err := clientWithDefaults.GetSubmission(ctx, 1,
|
||||
WithCookies(Cookies{A: "userA_a", B: "userA_b"}),
|
||||
WithCloudflare(CFCookies{Clearance: "userA_cf"}),
|
||||
WithUserAgent("userA-browser/1.0"),
|
||||
); err != nil {
|
||||
t.Fatalf("call 2: %v", err)
|
||||
}
|
||||
// Call 3: a different user.
|
||||
if _, err := clientWithDefaults.GetSubmission(ctx, 1,
|
||||
WithCookies(Cookies{A: "userB_a", B: "userB_b"}),
|
||||
); err != nil {
|
||||
t.Fatalf("call 3: %v", err)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if len(hits) != 3 {
|
||||
t.Fatalf("hits = %d; want 3", len(hits))
|
||||
}
|
||||
|
||||
// Call 1: default cookies + default UA.
|
||||
if !strings.Contains(hits[0].cookie, "a=defaultA") || !strings.Contains(hits[0].cookie, "b=defaultB") {
|
||||
t.Errorf("call 1 cookie = %q; want default a/b", hits[0].cookie)
|
||||
}
|
||||
if hits[0].userAgent != "default-ua/1.0" {
|
||||
t.Errorf("call 1 UA = %q; want default-ua/1.0", hits[0].userAgent)
|
||||
}
|
||||
|
||||
// Call 2: user-A creds replace the jar's defaults wholesale.
|
||||
if !strings.Contains(hits[1].cookie, "a=userA_a") || !strings.Contains(hits[1].cookie, "b=userA_b") {
|
||||
t.Errorf("call 2 cookie = %q; want user-A a/b", hits[1].cookie)
|
||||
}
|
||||
if !strings.Contains(hits[1].cookie, "cf_clearance=userA_cf") {
|
||||
t.Errorf("call 2 cookie missing cf_clearance: %q", hits[1].cookie)
|
||||
}
|
||||
if strings.Contains(hits[1].cookie, "defaultA") || strings.Contains(hits[1].cookie, "defaultB") {
|
||||
t.Errorf("call 2 cookie leaked client defaults: %q", hits[1].cookie)
|
||||
}
|
||||
if hits[1].userAgent != "userA-browser/1.0" {
|
||||
t.Errorf("call 2 UA = %q; want userA-browser/1.0", hits[1].userAgent)
|
||||
}
|
||||
|
||||
// Call 3: user-B cookies override, but UA falls back to client default
|
||||
// because the override did not touch it.
|
||||
if !strings.Contains(hits[2].cookie, "a=userB_a") || !strings.Contains(hits[2].cookie, "b=userB_b") {
|
||||
t.Errorf("call 3 cookie = %q; want user-B a/b", hits[2].cookie)
|
||||
}
|
||||
if hits[2].userAgent != "default-ua/1.0" {
|
||||
t.Errorf("call 3 UA = %q; want default-ua/1.0 (no override)", hits[2].userAgent)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRequestOverride_NoOverrideMeansNoCtxValue is a cheap sanity check
|
||||
// that applyRequestOptions short-circuits when nothing request-level
|
||||
// actually changed (e.g. caller passed only client-only options).
|
||||
func TestRequestOverride_NoOverrideMeansNoCtxValue(t *testing.T) {
|
||||
c := New(WithCookies(Cookies{A: "x", B: "y"}))
|
||||
ctx := context.Background()
|
||||
|
||||
// No options at all → same ctx.
|
||||
if got := c.applyRequestOptions(ctx, nil); got != ctx {
|
||||
t.Error("nil opts should pass through ctx unchanged")
|
||||
}
|
||||
// A client-only option that does not touch request-level fields.
|
||||
got := c.applyRequestOptions(ctx, []Option{WithMaxRetries(7)})
|
||||
if got != ctx {
|
||||
t.Error("client-only option should not attach a request override")
|
||||
}
|
||||
// A request-level option that happens to equal the current value.
|
||||
got = c.applyRequestOptions(ctx, []Option{WithCookies(Cookies{A: "x", B: "y"})})
|
||||
if got != ctx {
|
||||
t.Error("override matching client config should not attach")
|
||||
}
|
||||
// A real override.
|
||||
got = c.applyRequestOptions(ctx, []Option{WithCookies(Cookies{A: "z", B: "w"})})
|
||||
if got == ctx {
|
||||
t.Error("real override should produce a new ctx")
|
||||
}
|
||||
if ov := requestOverrideFrom(got); ov == nil || ov.cookies.A != "z" {
|
||||
t.Errorf("override ctx missing or wrong: %+v", ov)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user