2026-04-28 18:05:13 +08:00

330 lines
9.9 KiB
Go

package lingxian
import (
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/model"
"chatapp3-golang/internal/service/gameprovider"
"context"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestSyncAdminGamesFetchesCatalogAndImportsUnifiedList(t *testing.T) {
ctx := context.Background()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(
&model.LingxianProviderConfig{},
&model.LingxianGameCatalog{},
&model.SysGameListConfig{},
&model.SysGameListVendorExt{},
); err != nil {
t.Fatalf("migrate: %v", err)
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[{"gameId":"1","name":"Fruit Party","title":"水果奇缘","ver":11,"full_url":"https://example.test/full.html","half_url":"https://example.test/half.html"}]`))
}))
defer server.Close()
now := time.Now()
if err := db.Create(&model.LingxianProviderConfig{
ID: 1,
SysOrigin: "LIKEI",
Profile: profileProd,
Active: true,
GameListURL: server.URL,
AppKey: "test-key",
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed provider: %v", err)
}
service := NewService(config.Config{HTTP: config.HTTPConfig{Timeout: time.Second}}, db, nil)
resp, err := service.SyncAdminGames(ctx, SyncCatalogRequest{SysOrigin: "LIKEI", Profile: profileProd})
if err != nil {
t.Fatalf("SyncAdminGames: %v", err)
}
if resp.Imported != 1 {
t.Fatalf("imported = %d, want 1", resp.Imported)
}
var cfg model.SysGameListConfig
if err := db.Where("sys_origin = ? AND game_origin = ? AND game_id = ?", "LIKEI", vendorType, "1").First(&cfg).Error; err != nil {
t.Fatalf("unified config missing: %v", err)
}
var ext model.SysGameListVendorExt
if err := db.Where("game_list_config_id = ? AND vendor_type = ? AND profile = ?", cfg.ID, vendorType, profileProd).First(&ext).Error; err != nil {
t.Fatalf("vendor ext missing: %v", err)
}
if ext.VendorGameID != "1" || ext.PackageURL != "https://example.test/full.html" {
t.Fatalf("vendor ext = %#v", ext)
}
if !cfg.Showcase {
t.Fatalf("showcase = false, want true by default")
}
}
func TestImportCatalogGamesCanDefaultToHidden(t *testing.T) {
ctx := context.Background()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(
&model.LingxianProviderConfig{},
&model.LingxianGameCatalog{},
&model.SysGameListConfig{},
&model.SysGameListVendorExt{},
); err != nil {
t.Fatalf("migrate: %v", err)
}
now := time.Now()
if err := db.Create(&model.LingxianProviderConfig{
ID: 11,
SysOrigin: "LIKEI",
Profile: profileProd,
Active: true,
AppKey: "test-key",
TestUID: "test-uid",
TestToken: "test-token",
TestRoomID: "test-room",
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed provider: %v", err)
}
if err := db.Create(&model.LingxianGameCatalog{
ID: 12,
SysOrigin: "LIKEI",
Profile: profileProd,
InternalGameID: "lx_2",
VendorGameID: "2",
Name: "Hidden Lingxian",
Status: catalogEnabled,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed catalog: %v", err)
}
service := NewService(config.Config{HTTP: config.HTTPConfig{Timeout: time.Second}}, db, nil)
resp, err := service.ImportCatalogGames(ctx, "LIKEI", profileProd, []string{"2"}, false)
if err != nil {
t.Fatalf("ImportCatalogGames: %v", err)
}
if resp.Imported != 1 {
t.Fatalf("imported = %d, want 1", resp.Imported)
}
var cfg model.SysGameListConfig
if err := db.Where("sys_origin = ? AND game_origin = ? AND game_id = ?", "LIKEI", vendorType, "lx_2").First(&cfg).Error; err != nil {
t.Fatalf("unified config missing: %v", err)
}
if cfg.Showcase {
t.Fatalf("showcase = true, want false")
}
}
func TestSaveProviderConfigPersistsTestRoomID(t *testing.T) {
ctx := context.Background()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(&model.LingxianProviderConfig{}); err != nil {
t.Fatalf("migrate: %v", err)
}
service := NewService(config.Config{HTTP: config.HTTPConfig{Timeout: time.Second}}, db, nil)
saved, err := service.SaveProviderConfig(ctx, SaveProviderConfigRequest{
SysOrigin: "LIKEI",
Profile: profileProd,
GameListURL: "https://example.test/list.json",
AppKey: "test-key",
TestUID: "test-uid",
TestToken: "test-token",
TestRoomID: "test-room",
})
if err != nil {
t.Fatalf("SaveProviderConfig: %v", err)
}
if saved.TestRoomID != "test-room" {
t.Fatalf("saved testRoomId = %q, want test-room", saved.TestRoomID)
}
runtimeCfg, err := service.resolveRuntimeConfigForProfile(ctx, "LIKEI", profileProd)
if err != nil {
t.Fatalf("resolveRuntimeConfigForProfile: %v", err)
}
if runtimeCfg.TestRoomID != "test-room" {
t.Fatalf("runtime testRoomId = %q, want test-room", runtimeCfg.TestRoomID)
}
}
func TestAppProviderUsesHalfURLForHalfScreenGames(t *testing.T) {
ctx := context.Background()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(
&model.LingxianProviderConfig{},
&model.LingxianGameCatalog{},
&model.SysGameListConfig{},
&model.SysGameListVendorExt{},
); err != nil {
t.Fatalf("migrate: %v", err)
}
now := time.Now()
if err := db.Create(&model.LingxianProviderConfig{
ID: 21,
SysOrigin: "LIKEI",
Profile: profileProd,
Active: true,
AppKey: "test-key",
TestUID: "test-uid",
TestToken: "test-token",
TestRoomID: "test-room",
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed provider: %v", err)
}
if err := db.Create(&model.LingxianGameCatalog{
ID: 22,
SysOrigin: "LIKEI",
Profile: profileProd,
InternalGameID: "1",
VendorGameID: "1",
Name: "Half Lingxian",
PreviewURL: "https://example.test/half.html",
DownloadURL: "https://example.test/full.html",
PackageVersion: "11",
Status: catalogEnabled,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed catalog: %v", err)
}
if err := db.Create(&model.SysGameListConfig{
ID: 23,
SysOrigin: "LIKEI",
GameOrigin: vendorType,
GameID: "1",
Name: "Half Lingxian",
Category: roomCategory,
GameCode: "1",
Showcase: true,
Sort: 1,
FullScreen: false,
ClientOrigin: "COMMON",
GameMode: "[3]",
}).Error; err != nil {
t.Fatalf("seed config: %v", err)
}
orientation := 1
if err := db.Create(&model.SysGameListVendorExt{
ID: 24,
GameListConfigID: 23,
SysOrigin: "LIKEI",
Profile: profileProd,
VendorType: vendorType,
VendorGameID: "1",
LaunchMode: launchModeH5,
PackageVersion: "11",
PackageURL: "https://example.test/full.html",
PreviewURL: "https://example.test/half.html",
Orientation: &orientation,
SafeHeight: 640,
BridgeSchemaVersion: "1.0",
ExtraJSON: `{"gameType":"LINGXIAN"}`,
Enabled: true,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed vendor ext: %v", err)
}
service := NewService(config.Config{HTTP: config.HTTPConfig{Timeout: time.Second}}, db, nil)
provider := NewAppProvider(service)
user := gameprovider.AuthUser{UserID: 1001, SysOrigin: "LIKEI", Token: "user-token"}
list, err := provider.ListRoomGames(ctx, user, "room-1", roomCategory)
if err != nil {
t.Fatalf("ListRoomGames: %v", err)
}
if len(list.Items) != 1 {
t.Fatalf("items = %d, want 1", len(list.Items))
}
item := list.Items[0]
if item.FullScreen {
t.Fatalf("fullScreen = true, want false")
}
if item.SafeHeight != 640 {
t.Fatalf("safeHeight = %d, want 640", item.SafeHeight)
}
if item.Orientation != 1 {
t.Fatalf("orientation = %d, want 1", item.Orientation)
}
if got := item.LaunchParams["screenMode"]; got != "half" {
t.Fatalf("screenMode = %v, want half", got)
}
launch, err := provider.LaunchGame(ctx, user, gameprovider.LaunchRequest{RoomID: "room-1", GameID: "1"}, "")
if err != nil {
t.Fatalf("LaunchGame: %v", err)
}
if !strings.HasPrefix(launch.Entry.EntryURL, "https://example.test/half.html?") {
t.Fatalf("entryUrl = %q, want half url with query", launch.Entry.EntryURL)
}
if strings.Contains(launch.Entry.EntryURL, "full.html") {
t.Fatalf("entryUrl = %q, should not use full url", launch.Entry.EntryURL)
}
if launch.Entry.SafeHeight != 640 {
t.Fatalf("launch safeHeight = %d, want 640", launch.Entry.SafeHeight)
}
parsed, err := url.Parse(launch.Entry.EntryURL)
if err != nil {
t.Fatalf("parse entry url: %v", err)
}
query := parsed.Query()
if got := query.Get("uid"); got != "test-uid" {
t.Fatalf("query uid = %q, want test-uid", got)
}
if got := query.Get("token"); got != "test-token" {
t.Fatalf("query token = %q, want test-token", got)
}
if got := query.Get("lang"); got != defaultLaunchLang {
t.Fatalf("query lang = %q, want %s", got, defaultLaunchLang)
}
if got := query.Get("roomid"); got != "test-room" {
t.Fatalf("query roomid = %q, want test-room", got)
}
if got := query.Get("roomId"); got != "test-room" {
t.Fatalf("query roomId = %q, want test-room", got)
}
if got := launch.LaunchConfig.(map[string]any)["roomid"]; got != "test-room" {
t.Fatalf("launchConfig.roomid = %v, want test-room", got)
}
if got := launch.LaunchConfig.(map[string]any)["lang"]; got != defaultLaunchLang {
t.Fatalf("launchConfig.lang = %v, want %s", got, defaultLaunchLang)
}
if got := launch.RoomState.RoomID; got != "room-1" {
t.Fatalf("roomState.roomId = %q, want real room room-1", got)
}
}