yumi-golang/internal/router/game_provider_routes_test.go
2026-06-09 16:26:03 +08:00

307 lines
9.7 KiB
Go

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: "土耳其"},
level: integration.UserLevel{WealthLevel: 2},
targetRegionCode: "土耳其",
},
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: "土耳其"},
level: integration.UserLevel{WealthLevel: 3},
targetRegionCode: "土耳其",
},
routeStubIPCountryResolver{countryCode: "ZA"},
),
)
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
}