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") }