internal/app/help/service_premium_test.go
Rama main · réplica de lectura del repositorio original.
package help
import (
"context"
"encoding/json"
"testing"
"telesrv/internal/domain"
)
// TestAppConfigPremiumKeys asserts that premium / Stars related keys are fully delivered
// with an incremented hash: premium_purchase_blocked must be explicitly false — the client
// couples the star gift "Send a Gift" entry with premiumCanBuy()=!premium_purchase_blocked,
// so setting true also hides the gifting entry; reactions_user_max_premium must match the
// server-side enforcement tier.
func TestAppConfigPremiumKeys(t *testing.T) {
cfg, notModified, err := (*Service)(nil).GetAppConfig(context.Background(), 0, 0)
if err != nil || notModified {
t.Fatalf("GetAppConfig = notModified %v err %v", notModified, err)
}
if cfg.Hash != defaultAppConfigHash || cfg.Hash < 10 {
t.Fatalf("hash = %d, want defaultAppConfigHash(≥10)", cfg.Hash)
}
oldCfg, oldNotModified, err := (*Service)(nil).GetAppConfig(context.Background(), 0, defaultAppConfigHash-1)
if err != nil || oldNotModified || oldCfg.Hash != defaultAppConfigHash {
t.Fatalf("GetAppConfig(old hash) = hash %d notModified %v err %v, want refreshed config", oldCfg.Hash, oldNotModified, err)
}
var decoded map[string]any
if err := json.Unmarshal(cfg.JSON, &decoded); err != nil {
t.Fatalf("app config json invalid: %v", err)
}
if got := decoded["ephemeral_welcome_messages_max"]; got != float64(domain.MaxWelcomeMessagesPerPeer) {
t.Fatalf("ephemeral_welcome_messages_max = %v, want %d", got, domain.MaxWelcomeMessagesPerPeer)
}
if period, ok := decoded["no_forwards_request_expire_period"].(float64); !ok || int(period) != domain.PrivateNoForwardsRequestExpirePeriod {
t.Fatalf("no_forwards_request_expire_period = %v, want %d", decoded["no_forwards_request_expire_period"], domain.PrivateNoForwardsRequestExpirePeriod)
}
if blocked, ok := decoded["premium_purchase_blocked"].(bool); !ok || blocked {
t.Fatalf("premium_purchase_blocked = %v, want false (star gift gifting entry is coupled to this flag)", decoded["premium_purchase_blocked"])
}
if username, ok := decoded["premium_bot_username"].(string); !ok || username != "premiumbot" {
t.Fatalf("premium_bot_username = %v, want premiumbot", decoded["premium_bot_username"])
}
for _, key := range []string{"premium_gift_attach_menu_icon", "premium_gift_text_field_icon"} {
if enabled, ok := decoded[key].(bool); !ok || !enabled {
t.Fatalf("%s = %v, want true", key, decoded[key])
}
}
// DrKLO defaults starsLocked=true; when the key is missing and the balance is insufficient for gifting it wrongly pops "cannot purchase stars in your country".
if blocked, ok := decoded["stars_purchase_blocked"].(bool); !ok || blocked {
t.Fatalf("stars_purchase_blocked = %v, want false (DrKLO starsPurchaseAvailable unlocks the top-up entry based on this)", decoded["stars_purchase_blocked"])
}
// DrKLO defaults stargiftsBlocked=true, which hides the star gift grid; false must be sent explicitly.
if blocked, ok := decoded["stargifts_blocked"].(bool); !ok || blocked {
t.Fatalf("stargifts_blocked = %v, want false (DrKLO GiftSheet hides the gift grid based on this)", decoded["stargifts_blocked"])
}
if available, ok := decoded["giveaway_gifts_purchase_available"].(bool); !ok || !available {
t.Fatalf("giveaway_gifts_purchase_available = %v, want true", decoded["giveaway_gifts_purchase_available"])
}
directCurrencies, ok := decoded["premium_playmarket_direct_currency_list"].([]any)
if !ok || len(directCurrencies) == 0 || !containsJSONCurrency(directCurrencies, "USD") {
t.Fatalf("premium_playmarket_direct_currency_list = %#v, want non-empty list containing USD", decoded["premium_playmarket_direct_currency_list"])
}
if posting, ok := decoded["rich_message_posting"].(string); !ok || posting != "enabled" {
t.Fatalf("rich_message_posting = %v, want enabled (TDesktop rich-text editing entry is on by default)", decoded["rich_message_posting"])
}
fragmentPrefixes, ok := decoded["fragment_prefixes"].([]any)
if !ok || len(fragmentPrefixes) != 1 || fragmentPrefixes[0] != "888" {
t.Fatalf("fragment_prefixes = %#v, want [\"888\"]", decoded["fragment_prefixes"])
}
wantNumbers := map[string]float64{
"giveaway_boosts_per_premium": 4,
"giveaway_countries_max": 10,
"giveaway_add_peers_max": 10,
"giveaway_period_max": 604800,
"reactions_user_max_default": 1,
"reactions_user_max_premium": 3,
"boosts_channel_level_max": 100,
"stargifts_pinned_to_top_limit": 6,
"stars_stargift_resale_amount_min": float64(domain.MinStarGiftResaleStars),
"gift_text_length_max": domain.MaxPremiumGiftMessageRunes,
"about_length_limit_default": 70,
"about_length_limit_premium": 140,
"bot_verification_description_length_limit": domain.MaxCustomVerificationDescriptionLength,
"dialogs_pinned_limit_default": 5,
"dialogs_pinned_limit_premium": 10,
"dialogs_folder_pinned_limit_default": 100,
"dialogs_folder_pinned_limit_premium": 200,
"saved_dialogs_pinned_limit_default": 5,
"saved_dialogs_pinned_limit_premium": 100,
"caption_length_limit_default": 1024,
"caption_length_limit_premium": 4096,
"channels_limit_default": 500,
"channels_limit_premium": 1000,
"dialog_filters_limit_default": 10,
"dialog_filters_limit_premium": 20,
"chatlist_update_period": 3600,
"chatlist_invites_limit_default": 3,
"chatlist_invites_limit_premium": 20,
"chatlists_joined_limit_default": 2,
"chatlists_joined_limit_premium": 20,
"upload_max_fileparts_default": 4000,
"upload_max_fileparts_premium": 8000,
"aicompose_tone_examples_num": 3,
"aicompose_tone_title_length_max": 12,
"aicompose_tone_prompt_length_max": 1024,
"aicompose_tone_saved_limit_default": 5,
"aicompose_tone_saved_limit_premium": 20,
"stories_stealth_future_period": 1500,
"stories_stealth_past_period": 300,
"stories_stealth_cooldown_period": 10800,
}
for key, want := range wantNumbers {
got, ok := decoded[key].(float64)
if !ok || got != want {
t.Errorf("appConfig[%q] = %v, want %v", key, decoded[key], want)
}
}
// Keys of unimplemented feature families must not be sent (they would lure clients into unimplemented paths).
for _, forbidden := range []string{"stories_sent_weekly_limit_default", "premium_invoice_slug"} {
if _, ok := decoded[forbidden]; ok {
t.Errorf("appConfig must not contain %q", forbidden)
}
}
}
func containsJSONCurrency(values []any, want string) bool {
for _, value := range values {
if value == want {
return true
}
}
return false
}
func TestAppConfigUsesConfiguredPremiumBotUsername(t *testing.T) {
svc := NewService(nil, nil, WithPremiumBotUsername("storefront_bot"))
cfg, _, err := svc.GetAppConfig(context.Background(), 0, 0)
if err != nil {
t.Fatalf("GetAppConfig: %v", err)
}
var decoded map[string]any
if err := json.Unmarshal(cfg.JSON, &decoded); err != nil {
t.Fatalf("decode app config: %v", err)
}
if got := decoded["premium_bot_username"]; got != "storefront_bot" {
t.Fatalf("premium_bot_username = %v, want storefront_bot", got)
}
if cfg.Hash == defaultAppConfigHash {
t.Fatalf("custom premium bot hash = %d, want deployment-specific hash", cfg.Hash)
}
}
func TestAppConfigOmitsMapboxTokenByDefault(t *testing.T) {
cfg, notModified, err := (*Service)(nil).GetAppConfig(context.Background(), 0, 0)
if err != nil || notModified {
t.Fatalf("GetAppConfig = notModified %v err %v", notModified, err)
}
var decoded map[string]any
if err := json.Unmarshal(cfg.JSON, &decoded); err != nil {
t.Fatalf("app config json invalid: %v", err)
}
if _, ok := decoded["tdesktop_config_map"]; ok {
t.Fatal("tdesktop_config_map present without configured Mapbox token")
}
}
func TestAppConfigUsesConfiguredMapboxTokenAndHash(t *testing.T) {
svc := NewService(nil, nil, WithMapboxToken("pk.test-token"))
cfg, notModified, err := svc.GetAppConfig(context.Background(), 0, 0)
if err != nil || notModified {
t.Fatalf("GetAppConfig = notModified %v err %v", notModified, err)
}
if cfg.Hash == defaultAppConfigHash {
t.Fatalf("hash = %d, want token-specific hash", cfg.Hash)
}
if _, notModified, err := svc.GetAppConfig(context.Background(), 0, cfg.Hash); err != nil || !notModified {
t.Fatalf("GetAppConfig(hash) = notModified %v err %v, want notModified", notModified, err)
}
var decoded map[string]any
if err := json.Unmarshal(cfg.JSON, &decoded); err != nil {
t.Fatalf("app config json invalid: %v", err)
}
configMap, ok := decoded["tdesktop_config_map"].(map[string]any)
if !ok {
t.Fatalf("tdesktop_config_map = %T, want object", decoded["tdesktop_config_map"])
}
for _, key := range []string{"maps", "geo", "bmaps", "bgeo"} {
if got := configMap[key]; got != "pk.test-token" {
t.Fatalf("tdesktop_config_map[%q] = %v, want token", key, got)
}
}
}