feat: backend service
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"galaxy/integration/testenv"
|
||||
)
|
||||
|
||||
// TestGeoCounterIncrements asserts that authenticated requests
|
||||
// produce per-country counter rows in `user_country_counters`.
|
||||
// Gateway does not propagate the original `X-Forwarded-For` to
|
||||
// backend on REST forwarding, so the test calls backend's user
|
||||
// surface directly with a public IP that the synthetic GeoLite2
|
||||
// fixture knows. Calling backend HTTP with `X-User-ID` mirrors the
|
||||
// path gateway takes after the authenticated verification pipeline.
|
||||
func TestGeoCounterIncrements(t *testing.T) {
|
||||
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
||||
defer cancel()
|
||||
|
||||
sess := testenv.RegisterSession(t, plat, "pilot+geocounter@example.com")
|
||||
userID, err := sess.LookupUserID(ctx, plat)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve user_id: %v", err)
|
||||
}
|
||||
|
||||
// Direct backend call mimicking gateway forwarding.
|
||||
user := testenv.NewBackendUserClient(plat.Backend.HTTPURL, userID)
|
||||
for i := 0; i < 3; i++ {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, user.BaseURL+"/api/v1/user/account", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("new request: %v", err)
|
||||
}
|
||||
req.Header.Set("X-User-ID", userID)
|
||||
// 81.2.69.142 is a UK IP present in MaxMind's reference
|
||||
// Country test database (GeoIP2-Country-Test.mmdb).
|
||||
req.Header.Set("X-Forwarded-For", "81.2.69.142")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("execute #%d: %v", i, err)
|
||||
}
|
||||
_ = resp.Body.Close()
|
||||
}
|
||||
|
||||
admin := testenv.NewBackendAdminClient(plat.Backend.HTTPURL, plat.Backend.AdminUser, plat.Backend.AdminPassword)
|
||||
deadline := time.Now().Add(5 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
raw, resp, err := admin.Do(ctx, http.MethodGet, "/api/v1/admin/geo/users/"+userID+"/countries", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("admin geo lookup: %v", err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("admin geo lookup: status %d body=%s", resp.StatusCode, string(raw))
|
||||
}
|
||||
var body struct {
|
||||
Items []struct {
|
||||
Country string `json:"country"`
|
||||
Count int64 `json:"count"`
|
||||
} `json:"items"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &body); err != nil {
|
||||
t.Fatalf("decode geo response: %v", err)
|
||||
}
|
||||
if len(body.Items) > 0 && body.Items[0].Count > 0 {
|
||||
return
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("user_country_counters did not record an increment within 5 s")
|
||||
}
|
||||
Reference in New Issue
Block a user