package appconfig import ( "testing" "time" "hyapp-admin-server/internal/model" ) func TestH5LinkModelFromPayloadValidatesDynamicConfig(t *testing.T) { item, err := h5LinkModelFromPayload(h5LinkPayload{ Key: "host-center.v2", Label: "Host Center", URL: "https://h5.example.com/host", }) if err != nil { t.Fatalf("h5 config should be valid: %v", err) } if item.Group != h5LinkGroup || item.Key != "host-center.v2" || item.Description != "Host Center" || item.Value != "https://h5.example.com/host" { t.Fatalf("h5 config model mismatch: %+v", item) } } func TestH5LinkModelFromPayloadRejectsInvalidKey(t *testing.T) { _, err := h5LinkModelFromPayload(h5LinkPayload{ Key: "host center", Label: "Host Center", URL: "https://h5.example.com/host", }) if err == nil { t.Fatal("expected invalid key to fail") } } func TestBannerModelFromRequestRequiresRoomSmallImageForRoomScope(t *testing.T) { _, err := bannerModelFromRequest("lalu", bannerRequest{ CoverURL: "https://cdn.example.com/banner.png", BannerType: "h5", DisplayScope: bannerDisplayScopeRoom, Param: "https://h5.example.com/activity", Status: bannerStatusActive, Platform: "android", EndsAtMs: time.Now().UTC().Add(time.Hour).UnixMilli(), }) if err == nil { t.Fatal("expected room scope without room small image to fail") } } func TestBannerModelFromRequestKeepsRoomScopeScheduleFields(t *testing.T) { startsAtMs := time.Now().UTC().Add(time.Hour).UnixMilli() endsAtMs := startsAtMs + int64(time.Hour/time.Millisecond) item, err := bannerModelFromRequest("lalu", bannerRequest{ CoverURL: "https://cdn.example.com/banner.png", RoomSmallImageURL: "https://cdn.example.com/banner-small.png", BannerType: "h5", DisplayScopes: []string{bannerDisplayScopeHome, bannerDisplayScopeRoom}, Param: "https://h5.example.com/activity", Status: bannerStatusActive, Platform: "android", StartsAtMs: startsAtMs, EndsAtMs: endsAtMs, }) if err != nil { t.Fatalf("banner model should be valid: %v", err) } if item.DisplayScope != "home,room" || item.RoomSmallImageURL == "" { t.Fatalf("room display fields mismatch: %+v", item) } if item.StartsAtMS != startsAtMs || item.EndsAtMS != endsAtMs || item.Status != bannerStatusActive { t.Fatalf("schedule fields mismatch: %+v", item) } } func TestBannerModelFromRequestExpiresEndedActiveBanner(t *testing.T) { item, err := bannerModelFromRequest("lalu", bannerRequest{ CoverURL: "https://cdn.example.com/banner.png", RoomSmallImageURL: "https://cdn.example.com/ignored.png", BannerType: "app", DisplayScope: bannerDisplayScopeHome, Status: bannerStatusActive, Platform: "ios", EndsAtMs: 1, }) if err != nil { t.Fatalf("banner model should accept ended active banner: %v", err) } if item.Status != bannerStatusExpired { t.Fatalf("ended active banner must become expired: %+v", item) } if item.RoomSmallImageURL != "" { t.Fatalf("non-room banner must not retain room small image: %+v", item) } } func TestAppBannerFromModelReturnsDisplayScopes(t *testing.T) { item := appBannerFromModel(bannerModel("home,room,recharge")) if item.DisplayScope != "home,room,recharge" { t.Fatalf("display scope should keep stored value: %+v", item) } if len(item.DisplayScopes) != 3 || item.DisplayScopes[0] != bannerDisplayScopeHome || item.DisplayScopes[1] != bannerDisplayScopeRoom || item.DisplayScopes[2] != bannerDisplayScopeRecharge { t.Fatalf("display scopes mismatch: %+v", item.DisplayScopes) } } func TestSplashScreenModelFromRequestValidatesH5Config(t *testing.T) { startsAtMs := time.Now().UTC().Add(time.Hour).UnixMilli() endsAtMs := startsAtMs + int64(time.Hour/time.Millisecond) item, err := splashScreenModelFromRequest("lalu", splashScreenRequest{ CoverURL: "https://cdn.example.com/splash.png", SplashType: "h5", Param: "https://h5.example.com/splash", Status: bannerStatusActive, Platform: "android", SortOrder: 7, RegionID: 1001, CountryCode: "us", Description: "launch campaign", StartsAtMs: startsAtMs, EndsAtMs: endsAtMs, }) if err != nil { t.Fatalf("splash screen model should be valid: %v", err) } if item.AppCode != "lalu" || item.SplashType != "h5" || item.CountryCode != "US" || item.StartsAtMS != startsAtMs || item.EndsAtMS != endsAtMs { t.Fatalf("splash screen model mismatch: %+v", item) } } func TestSplashScreenModelFromRequestRequiresH5Link(t *testing.T) { _, err := splashScreenModelFromRequest("lalu", splashScreenRequest{ CoverURL: "https://cdn.example.com/splash.png", SplashType: "h5", Status: bannerStatusActive, Platform: "android", }) if err == nil { t.Fatal("expected h5 splash screen without link to fail") } } func TestSplashScreenModelFromRequestExpiresEndedActiveConfig(t *testing.T) { item, err := splashScreenModelFromRequest("lalu", splashScreenRequest{ CoverURL: "https://cdn.example.com/splash.png", SplashType: "app", Status: bannerStatusActive, Platform: "ios", EndsAtMs: 1, }) if err != nil { t.Fatalf("ended app splash screen should be accepted: %v", err) } if item.Status != bannerStatusExpired { t.Fatalf("ended active splash screen must become expired: %+v", item) } } func TestAppSplashScreenFromModelMapsDTOFields(t *testing.T) { item := appSplashScreenFromModel(model.AppSplashScreen{ ID: 9, AppCode: "lalu", CoverURL: "https://cdn.example.com/splash.png", SplashType: "app", Param: "profile", Status: bannerStatusDisabled, Platform: "ios", SortOrder: 3, RegionID: 2002, CountryCode: "BR", Description: "disabled campaign", StartsAtMS: 1700000000000, EndsAtMS: 1800000000000, CreatedAtMS: 1690000000000, UpdatedAtMS: 1700000002000, }) if item.ID != 9 || item.SplashType != "app" || item.Param != "profile" || item.RegionID != 2002 || item.UpdatedAtMs != 1700000002000 { t.Fatalf("splash screen dto mismatch: %+v", item) } } func bannerModel(displayScope string) model.AppBanner { return model.AppBanner{ ID: 1, AppCode: "lalu", CoverURL: "https://cdn.example.com/banner.png", BannerType: "h5", DisplayScope: displayScope, Param: "https://h5.example.com/activity", Status: bannerStatusActive, Platform: "android", } } func TestExploreTabModelFromRequestValidatesRequiredFields(t *testing.T) { item, err := exploreTabModelFromRequest("lalu", exploreTabRequest{ Enabled: true, H5URL: "https://h5.example.com/explore/live", SortOrder: 3, Tab: "Live", }) if err != nil { t.Fatalf("explore tab should be valid: %v", err) } if item.AppCode != "lalu" || item.Tab != "Live" || item.H5URL != "https://h5.example.com/explore/live" || !item.Enabled || item.SortOrder != 3 { t.Fatalf("explore tab model mismatch: %+v", item) } } func TestExploreTabModelFromRequestRejectsWhitespaceURL(t *testing.T) { _, err := exploreTabModelFromRequest("lalu", exploreTabRequest{ Enabled: true, H5URL: "https://h5.example.com/explore live", Tab: "Live", }) if err == nil { t.Fatal("expected whitespace h5 url to fail") } }