Files
2026-05-06 10:14:55 +03:00

151 lines
3.9 KiB
Go

package server
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
"galaxy/backend/internal/geo"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.uber.org/zap/zaptest"
)
type fakeAdminGeoLister struct {
entries []geo.CountryCounter
err error
}
func (f *fakeAdminGeoLister) ListUserCounters(_ context.Context, _ uuid.UUID) ([]geo.CountryCounter, error) {
if f.err != nil {
return nil, f.err
}
return f.entries, nil
}
func newAdminGeoEngine(t *testing.T, fake AdminGeoLister) *gin.Engine {
t.Helper()
gin.SetMode(gin.TestMode)
r := gin.New()
h := NewAdminGeoHandlers(fake, zaptest.NewLogger(t))
r.GET("/api/v1/admin/geo/users/:user_id/countries", h.ListUserCountries())
return r
}
func TestAdminGeoListUserCountriesSuccess(t *testing.T) {
t.Parallel()
now := time.Date(2026, 5, 4, 12, 0, 0, 0, time.UTC)
fake := &fakeAdminGeoLister{entries: []geo.CountryCounter{
{Country: "AU", Count: 3, LastSeenAt: &now},
{Country: "DE", Count: 1, LastSeenAt: nil},
}}
r := newAdminGeoEngine(t, fake)
userID := uuid.New()
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/geo/users/"+userID.String()+"/countries", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status: want 200, got %d (%s)", rec.Code, rec.Body.String())
}
var body adminGeoListWire
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if body.UserID != userID.String() {
t.Errorf("user_id: want %s, got %s", userID, body.UserID)
}
if len(body.Items) != 2 {
t.Fatalf("items: want 2, got %d (%+v)", len(body.Items), body.Items)
}
if body.Items[0].Country != "AU" || body.Items[0].Count != 3 || body.Items[0].LastSeenAt == nil {
t.Errorf("items[0] mismatch: %+v", body.Items[0])
}
if body.Items[1].Country != "DE" || body.Items[1].Count != 1 || body.Items[1].LastSeenAt != nil {
t.Errorf("items[1] mismatch: %+v", body.Items[1])
}
}
func TestAdminGeoListUserCountriesEmpty(t *testing.T) {
t.Parallel()
r := newAdminGeoEngine(t, &fakeAdminGeoLister{})
userID := uuid.New()
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/geo/users/"+userID.String()+"/countries", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status: want 200, got %d", rec.Code)
}
var body adminGeoListWire
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if body.Items == nil {
t.Fatal("items: want non-nil empty slice, got nil")
}
if len(body.Items) != 0 {
t.Fatalf("items: want empty, got %+v", body.Items)
}
}
func TestAdminGeoListUserCountriesInvalidUserID(t *testing.T) {
t.Parallel()
r := newAdminGeoEngine(t, &fakeAdminGeoLister{})
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/geo/users/not-a-uuid/countries", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status: want 400, got %d", rec.Code)
}
}
func TestAdminGeoListUserCountriesStoreError(t *testing.T) {
t.Parallel()
r := newAdminGeoEngine(t, &fakeAdminGeoLister{err: errors.New("boom")})
userID := uuid.New()
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/geo/users/"+userID.String()+"/countries", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("status: want 500, got %d", rec.Code)
}
}
func TestAdminGeoListUserCountriesNilServiceReturns501(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
r := gin.New()
h := NewAdminGeoHandlers(nil, zaptest.NewLogger(t))
r.GET("/api/v1/admin/geo/users/:user_id/countries", h.ListUserCountries())
req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/geo/users/"+uuid.New().String()+"/countries", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusNotImplemented {
t.Fatalf("status: want 501, got %d", rec.Code)
}
}