package router import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "chatapp3-golang/internal/common" "chatapp3-golang/internal/integration" "chatapp3-golang/internal/service/gameprovider" "github.com/gin-gonic/gin" ) func TestPublicRoomGameListResponseKeepsLegacyProviderFields(t *testing.T) { resp := publicRoomGameListResponse(&gameprovider.RoomGameListResponse{ Items: []gameprovider.RoomGameListItem{ { ID: 9527, GameID: "bs_1046", GameType: "BAISHUN", Provider: "BAISHUN", ProviderGameID: "1046", Name: "Lucky77Pro", }, }, }) if len(resp.Items) != 1 { t.Fatalf("items = %d, want 1", len(resp.Items)) } item := resp.Items[0] if item.Provider != "BAISHUN" { t.Fatalf("provider = %q, want BAISHUN", item.Provider) } if item.VendorType != "BAISHUN" { t.Fatalf("vendorType = %q, want BAISHUN", item.VendorType) } if item.ProviderGameID != "1046" { t.Fatalf("providerGameId = %q, want 1046", item.ProviderGameID) } if item.VendorGameID != "1046" { t.Fatalf("vendorGameId = %q, want 1046", item.VendorGameID) } } func TestPublicRoomGameListResponseMapsLingxianToLeaderForOldClients(t *testing.T) { resp := publicRoomGameListResponse(&gameprovider.RoomGameListResponse{ Items: []gameprovider.RoomGameListItem{ { ID: 9528, GameID: "1090", GameType: "LINGXIAN", Provider: "LINGXIAN", ProviderGameID: "1090", Name: "Lingxian Game", LaunchParams: map[string]any{"gameType": "LINGXIAN", "screenMode": "half"}, }, }, }) if len(resp.Items) != 1 { t.Fatalf("items = %d, want 1", len(resp.Items)) } item := resp.Items[0] if item.Provider != "LEADER" { t.Fatalf("provider = %q, want LEADER", item.Provider) } if item.GameType != "LEADER" { t.Fatalf("gameType = %q, want LEADER", item.GameType) } if item.VendorType != "LEADER" { t.Fatalf("vendorType = %q, want LEADER", item.VendorType) } if got := item.LaunchParams["gameType"]; got != "LEADER" { t.Fatalf("launchParams.gameType = %v, want LEADER", got) } if got := item.LaunchParams["screenMode"]; got != "half" { t.Fatalf("launchParams.screenMode = %v, want half", got) } } func TestPublicLaunchKeepsLegacyBridgeAndProviderFields(t *testing.T) { launchConfig := map[string]any{"code": "launch-code"} resp := publicLaunch(&gameprovider.LaunchResponse{ ID: 9527, GameSessionID: "bs_room_1", Provider: "BAISHUN", GameID: "bs_1046", ProviderGameID: "1046", LaunchConfig: launchConfig, RoomState: gameprovider.RoomStateResponse{ RoomID: "room-1", State: "PLAYING", Provider: "BAISHUN", CurrentProviderGameID: "1046", }, }) if resp.Provider != "BAISHUN" { t.Fatalf("provider = %q, want BAISHUN", resp.Provider) } if resp.VendorType != "BAISHUN" { t.Fatalf("vendorType = %q, want BAISHUN", resp.VendorType) } if resp.VendorGameID != "1046" { t.Fatalf("vendorGameId = %q, want 1046", resp.VendorGameID) } bridgeConfig, ok := resp.BridgeConfig.(map[string]any) if !ok { t.Fatalf("bridgeConfig type = %T, want map[string]any", resp.BridgeConfig) } if got := bridgeConfig["code"]; got != "launch-code" { t.Fatalf("bridgeConfig[code] = %v, want launch-code", got) } if resp.RoomState.Provider != "BAISHUN" { t.Fatalf("roomState.provider = %q, want BAISHUN", resp.RoomState.Provider) } if resp.RoomState.CurrentVendorGameID != "1046" { t.Fatalf("roomState.currentVendorGameId = %q, want 1046", resp.RoomState.CurrentVendorGameID) } } func TestPublicLaunchMapsLingxianToLeaderForOldClients(t *testing.T) { resp := publicLaunch(&gameprovider.LaunchResponse{ ID: 9528, GameSessionID: "lx_1_1090", Provider: "LINGXIAN", GameID: "1090", ProviderGameID: "1090", LaunchConfig: map[string]any{"uid": "user-1"}, RoomState: gameprovider.RoomStateResponse{ RoomID: "room-1", State: "PLAYING", Provider: "LINGXIAN", CurrentProviderGameID: "1090", }, }) if resp.Provider != "LEADER" { t.Fatalf("provider = %q, want LEADER", resp.Provider) } if resp.VendorType != "LEADER" { t.Fatalf("vendorType = %q, want LEADER", resp.VendorType) } if resp.RoomState.Provider != "LEADER" { t.Fatalf("roomState.provider = %q, want LEADER", resp.RoomState.Provider) } } func TestGameProviderRoutesReturnEmptyWhenVisibilityPolicyDenies(t *testing.T) { gin.SetMode(gin.TestMode) provider := &routeStubProvider{} engine := gin.New() registerGameProviderRoutes( engine, routeStubAuthGateway{}, gameprovider.NewRegistry(provider), gameprovider.NewVisibilityPolicy( routeStubVisibilityGateway{ region: integration.UserRegion{RegionID: "2046066409959649281", RegionCode: "TR"}, level: integration.UserLevel{WealthLevel: 1}, targetRegionCode: "TR", }, routeStubIPCountryResolver{countryCode: "TR"}, ), ) req := httptest.NewRequest(http.MethodGet, "/app/game/room/list?roomId=1", nil) req.Header.Set("Authorization", "Bearer token") rec := httptest.NewRecorder() engine.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String()) } var payload struct { Body struct { Items []publicRoomGameItem `json:"items"` } `json:"body"` } if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { t.Fatalf("response json error = %v: %s", err, rec.Body.String()) } if len(payload.Body.Items) != 0 { t.Fatalf("items = %d, want 0", len(payload.Body.Items)) } if provider.listRoomCalls != 0 { t.Fatalf("provider list calls = %d, want 0", provider.listRoomCalls) } } func TestGameProviderRoutesReturnProvidersWhenVisibilityPolicyAllows(t *testing.T) { gin.SetMode(gin.TestMode) engine := gin.New() registerGameProviderRoutes( engine, routeStubAuthGateway{}, gameprovider.NewRegistry(&routeStubProvider{}), gameprovider.NewVisibilityPolicy( routeStubVisibilityGateway{ region: integration.UserRegion{RegionID: "2046066409959649281", RegionCode: "TR"}, level: integration.UserLevel{WealthLevel: 2}, targetRegionCode: "TR", }, routeStubIPCountryResolver{countryCode: "TR"}, ), ) req := httptest.NewRequest(http.MethodGet, "/app/game/providers", nil) req.Header.Set("Authorization", "Bearer token") req.Header.Set("X-Real-IP", "88.255.1.1") rec := httptest.NewRecorder() engine.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String()) } var payload struct { Body struct { Items []gameprovider.ProviderSummary `json:"items"` } `json:"body"` } if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { t.Fatalf("response json error = %v: %s", err, rec.Body.String()) } if len(payload.Body.Items) != 1 { t.Fatalf("providers = %d, want 1", len(payload.Body.Items)) } if payload.Body.Items[0].Key != "TEST" { t.Fatalf("provider key = %q, want TEST", payload.Body.Items[0].Key) } } type routeStubAuthGateway struct{} func (routeStubAuthGateway) AuthenticateToken(context.Context, string) (integration.UserCredential, error) { return integration.UserCredential{UserID: integration.Int64Value(1001), SysOrigin: "LIKEI"}, nil } func (routeStubAuthGateway) AuthenticateConsoleToken(context.Context, string) (integration.ConsoleAccount, error) { return integration.ConsoleAccount{}, nil } type routeStubVisibilityGateway struct { region integration.UserRegion level integration.UserLevel targetRegionCode string } func (s routeStubVisibilityGateway) GetUserRegion(context.Context, int64, string) (integration.UserRegion, error) { return s.region, nil } func (s routeStubVisibilityGateway) GetUserLevel(context.Context, string, int64) (integration.UserLevel, error) { return s.level, nil } func (s routeStubVisibilityGateway) ResolveRegionCodeByCountryCode(context.Context, string, string) (string, error) { return s.targetRegionCode, nil } type routeStubIPCountryResolver struct { countryCode string } func (s routeStubIPCountryResolver) CountryCode(context.Context, string) (string, error) { return s.countryCode, nil } type routeStubProvider struct { listRoomCalls int } func (p *routeStubProvider) Key() string { return "TEST" } func (p *routeStubProvider) DisplayName() string { return "Test Provider" } func (p *routeStubProvider) SupportsLaunch(context.Context, gameprovider.AuthUser, gameprovider.LaunchRequest) (bool, error) { return false, nil } func (p *routeStubProvider) ListShortcutGames(context.Context, gameprovider.AuthUser, string) ([]gameprovider.RoomGameListItem, error) { return []gameprovider.RoomGameListItem{{ID: 1, GameID: "test_1", Provider: "TEST", ProviderGameID: "1", Name: "Test Game"}}, nil } func (p *routeStubProvider) ListRoomGames(context.Context, gameprovider.AuthUser, string, string) (*gameprovider.RoomGameListResponse, error) { p.listRoomCalls++ return &gameprovider.RoomGameListResponse{ Items: []gameprovider.RoomGameListItem{{ID: 1, GameID: "test_1", Provider: "TEST", ProviderGameID: "1", Name: "Test Game"}}, }, nil } func (p *routeStubProvider) GetRoomState(context.Context, gameprovider.AuthUser, string) (*gameprovider.RoomStateResponse, error) { return &gameprovider.RoomStateResponse{}, nil } func (p *routeStubProvider) LaunchGame(context.Context, gameprovider.AuthUser, gameprovider.LaunchRequest, string) (*gameprovider.LaunchResponse, error) { return nil, common.NewAppError(http.StatusBadRequest, "unsupported", "unsupported") } func (p *routeStubProvider) CloseGame(context.Context, gameprovider.AuthUser, gameprovider.CloseRequest) (*gameprovider.RoomStateResponse, error) { return &gameprovider.RoomStateResponse{}, nil }