package worker import ( "context" "reflect" "testing" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcfg" ) func TestLoadMonthlyUsageTemplateQPS(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() adapter, err := gcfg.NewAdapterContent(` trafficUsageFullSync: consumer: templateQPS: sim_yd_v5: 30 sim_dx_v1: 25 qibin_direct: 1.5 `) if err != nil { t.Fatalf("create config adapter: %v", err) } g.Cfg().SetAdapter(adapter) defer g.Cfg().SetAdapter(oldAdapter) got := loadMonthlyUsageTemplateQPS(context.Background()) if got["sim_yd_v5"] != 30 || got["sim_dx_v1"] != 25 || got["qibin_direct"] != 1.5 { t.Fatalf("template QPS = %#v, want configured values", got) } } func TestLoadSimStatusRunPrefix(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() defer g.Cfg().SetAdapter(oldAdapter) for _, test := range []struct { name, config, want string invalid bool }{ {"default", "simStatusQueueSync:\n enabled: true\n", "sim-status:", false}, {"custom", "simStatusQueueSync:\n redisKeyPrefix: 'status:'", "status:", false}, {"empty", "simStatusQueueSync:\n redisKeyPrefix: ''", "", true}, } { t.Run(test.name, func(t *testing.T) { adapter, err := gcfg.NewAdapterContent(test.config) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) got, err := loadSimStatusRunPrefix(context.Background()) if got != test.want || (err != nil) != test.invalid { t.Fatalf("prefix=%q err=%v", got, err) } }) } } func TestLoadDailyUsageTemplateQPS(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() adapter, err := gcfg.NewAdapterContent(` trafficUsageDailySync: consumer: templateQPS: sim_yd_v5: 30 sim_dx_v1: 25 `) if err != nil { t.Fatalf("create config adapter: %v", err) } g.Cfg().SetAdapter(adapter) defer g.Cfg().SetAdapter(oldAdapter) got := loadDailyUsageTemplateQPS(context.Background()) if got["sim_yd_v5"] != 30 || got["sim_dx_v1"] != 25 { t.Fatalf("daily usage template QPS = %#v, want the daily-configured values", got) } // The daily chain must not silently inherit the monthly chain's rates; the // two run against the same carrier quota and must be tuned independently. monthly := loadMonthlyUsageTemplateQPS(context.Background()) if len(monthly) != 0 { t.Fatalf("monthly template QPS = %#v, want it unaffected by the daily block", monthly) } } func TestLoadDailyUsageRunPrefix(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() defer g.Cfg().SetAdapter(oldAdapter) for _, test := range []struct { name, config, want string invalid bool }{ {"default", "trafficUsageDailySync:\n enabled: true\n", "daily:", false}, {"custom", "trafficUsageDailySync:\n redisKeyPrefix: 'daily-usage:'", "daily-usage:", false}, {"empty", "trafficUsageDailySync:\n redisKeyPrefix: ''", "", true}, } { t.Run(test.name, func(t *testing.T) { adapter, err := gcfg.NewAdapterContent(test.config) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) got, err := loadDailyUsageRunPrefix(context.Background()) if got != test.want || (err != nil) != test.invalid { t.Fatalf("prefix=%q err=%v", got, err) } }) } } func TestLoadMonthlyHistoryRunPrefix(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() defer g.Cfg().SetAdapter(oldAdapter) for _, test := range []struct { name, config, want string invalid bool }{ {"default", "trafficUsageMonthlyHistorySync:\n enabled: true\n", "monthly-history:", false}, {"custom", "trafficUsageMonthlyHistorySync:\n redisKeyPrefix: 'mh:'", "mh:", false}, {"empty", "trafficUsageMonthlyHistorySync:\n redisKeyPrefix: ''", "", true}, } { t.Run(test.name, func(t *testing.T) { adapter, err := gcfg.NewAdapterContent(test.config) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) got, err := loadMonthlyHistoryRunPrefix(context.Background()) if got != test.want || (err != nil) != test.invalid { t.Fatalf("prefix=%q err=%v", got, err) } }) } } // TestMonthlyHistoryPrefixIsIsolatedFromCurrentMonthSync pins the separation of // the two monthly chains: trafficUsageFullSync fills the MySQL current-month // snapshot, while trafficUsageMonthlyHistorySync fills the TDengine monthly // table. Sharing a prefix would let one chain's producer lock block the other. func TestMonthlyHistoryPrefixIsIsolatedFromCurrentMonthSync(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() defer g.Cfg().SetAdapter(oldAdapter) adapter, err := gcfg.NewAdapterContent(` trafficUsageFullSync: redisKeyPrefix: 'flow:' trafficUsageMonthlyHistorySync: redisKeyPrefix: 'monthly-history:' `) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) prefixes, err := loadFullSyncArchivePrefixes(context.Background()) if err != nil { t.Fatal(err) } seen := map[string]bool{} for _, p := range prefixes { seen[p] = true } if !seen["flow:"] || !seen["monthly-history:"] { t.Fatalf("prefixes=%q, want both the current-month and monthly-history chains present", prefixes) } } func TestLoadFullSyncArchivePrefixes(t *testing.T) { oldAdapter := g.Cfg().GetAdapter() defer g.Cfg().SetAdapter(oldAdapter) for _, test := range []struct { name, config string want []string }{ {"defaults", "{}", []string{"flow:", "sim-status:", "daily:", "monthly-history:", "imei:"}}, {"disabled IMEI remains visible", "imeiFullSync:\n enabled: false", []string{"flow:", "sim-status:", "daily:", "monthly-history:", "imei:"}}, {"custom", "trafficUsageFullSync:\n redisKeyPrefix: 'usage:'\nsimStatusQueueSync:\n redisKeyPrefix: 'status:'\ntrafficUsageDailySync:\n redisKeyPrefix: 'daily-usage:'\ntrafficUsageMonthlyHistorySync:\n redisKeyPrefix: 'monthly-history:'\nimeiFullSync:\n redisKeyPrefix: 'imei-usage:'", []string{"usage:", "status:", "daily-usage:", "monthly-history:", "imei-usage:"}}, // Duplicate prefixes would make Catalog and SimpleReplay read the same // run hash twice, so the list is deduplicated with the first occurrence // keeping its position. {"shared prefix", "trafficUsageFullSync:\n redisKeyPrefix: 'sync:'\nsimStatusQueueSync:\n redisKeyPrefix: 'sync:'\ntrafficUsageDailySync:\n redisKeyPrefix: 'sync:'\ntrafficUsageMonthlyHistorySync:\n redisKeyPrefix: 'sync:'\nimeiFullSync:\n redisKeyPrefix: 'sync:'", []string{"sync:"}}, {"daily shares the status prefix", "simStatusQueueSync:\n redisKeyPrefix: 'daily:'\ntrafficUsageDailySync:\n redisKeyPrefix: 'daily:'", []string{"flow:", "daily:", "monthly-history:", "imei:"}}, {"monthly history shares the daily prefix", "trafficUsageDailySync:\n redisKeyPrefix: 'usage:'\ntrafficUsageMonthlyHistorySync:\n redisKeyPrefix: 'usage:'", []string{"flow:", "sim-status:", "usage:", "imei:"}}, } { t.Run(test.name, func(t *testing.T) { adapter, err := gcfg.NewAdapterContent(test.config) if err != nil { t.Fatal(err) } g.Cfg().SetAdapter(adapter) got, err := loadFullSyncArchivePrefixes(context.Background()) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(got, test.want) { t.Fatalf("prefixes=%q, want %q", got, test.want) } }) } }