package databi import ( "encoding/json" "testing" ) func TestRollupByRegionGroupsCountriesAndRecomputesDerived(t *testing.T) { regions := []RegionInfo{ {AppCode: "aslan", RegionID: 11, RegionCode: "MENA", RegionName: "中东", Countries: []string{"SA", "AE"}}, {AppCode: "aslan", RegionID: 12, RegionCode: "SEA", RegionName: "东南亚", Countries: []string{"ID"}}, } rows := []map[string]any{ {"country_code": "SA", "recharge_usd_minor": int64(10000), "active_users": int64(100), "paid_users": int64(10), "recharge_users": int64(10), "gift_coin_spent": nil}, {"country_code": "AE", "recharge_usd_minor": json.Number("5000"), "active_users": json.Number("50"), "paid_users": json.Number("5"), "recharge_users": json.Number("5"), "gift_coin_spent": nil}, {"country_code": "ID", "recharge_usd_minor": int64(2000), "active_users": int64(40), "paid_users": int64(2), "recharge_users": int64(2), "gift_coin_spent": int64(700)}, {"country_code": "XX", "recharge_usd_minor": int64(1), "active_users": int64(1), "paid_users": int64(0), "recharge_users": int64(0)}, } out := rollupByRegion(rows, regionResolver(regions)) if len(out) != 3 { t.Fatalf("expected 3 region rows (MENA/SEA/未划分), got %d", len(out)) } mena := out[0] if got, _ := rowInt64(mena, "region_id"); got != 11 { t.Fatalf("expected first row to be region 11 by recharge desc, got %d", got) } if got, _ := rowInt64(mena, "recharge_usd_minor"); got != 15000 { t.Fatalf("expected MENA recharge 15000, got %d", got) } if got, _ := rowInt64(mena, "active_users"); got != 150 { t.Fatalf("expected MENA active users 150, got %d", got) } if got, ok := mena["arppu_usd_minor"].(int64); !ok || got != 1000 { t.Fatalf("expected MENA arppu 1000, got %v", mena["arppu_usd_minor"]) } if mena["gift_coin_spent"] != nil { t.Fatalf("expected MENA gift_coin_spent nil when all rows nil, got %v", mena["gift_coin_spent"]) } sea := out[1] if got, _ := rowInt64(sea, "gift_coin_spent"); got != 700 { t.Fatalf("expected SEA gift_coin_spent 700, got %d", got) } unassigned := out[2] if got, _ := rowInt64(unassigned, "region_id"); got != 0 { t.Fatalf("expected unassigned region id 0, got %d", got) } } func TestRollupByRegionPrefersRowRegionID(t *testing.T) { regions := []RegionInfo{{AppCode: "lalu", RegionID: 3, RegionCode: "LATAM", RegionName: "拉美", Countries: []string{"BR"}}} rows := []map[string]any{ {"region_id": json.Number("3"), "country_id": int64(55), "recharge_usd_minor": int64(100)}, {"region_id": int64(3), "country_id": int64(56), "recharge_usd_minor": int64(200)}, } out := rollupByRegion(rows, regionResolver(regions)) if len(out) != 1 { t.Fatalf("expected 1 region row, got %d", len(out)) } if got := out[0]["region_name"]; got != "拉美" { t.Fatalf("expected region name 拉美, got %v", got) } if got, _ := rowInt64(out[0], "recharge_usd_minor"); got != 300 { t.Fatalf("expected recharge 300, got %d", got) } } func TestFilterRowsByRegion(t *testing.T) { regions := []RegionInfo{ {AppCode: "yumi", RegionID: 21, Countries: []string{"SA"}}, {AppCode: "yumi", RegionID: 22, Countries: []string{"EG"}}, } rows := []map[string]any{ {"country_code": "SA"}, {"country_code": "EG"}, {"country_code": "??"}, } out := filterRowsByRegion(rows, regionResolver(regions), int64Set([]int64{21})) if len(out) != 1 || out[0]["country_code"] != "SA" { t.Fatalf("expected only SA row, got %v", out) } } func TestAllowedRegions(t *testing.T) { access := testAccess() if all, _ := allowedRegions(access, "lalu"); !all { t.Fatalf("expected whole-app access for lalu (region 0 scope)") } all, ids := allowedRegions(access, "aslan") if all || len(ids) != 2 { t.Fatalf("expected two region scopes for aslan, got all=%v ids=%v", all, ids) } if all, ids := allowedRegions(access, "yumi"); all || len(ids) != 0 { t.Fatalf("expected no access for yumi, got all=%v ids=%v", all, ids) } } func TestResolveKpiMonthClampsFuture(t *testing.T) { location := mustLocation(t, "Asia/Shanghai") month, start, end, err := resolveKpiMonth("2020-02", 0, location) if err != nil { t.Fatalf("unexpected error: %v", err) } if month != "2020-02" { t.Fatalf("expected month 2020-02, got %s", month) } if start.Format("2006-01-02") != "2020-02-01" || end.Format("2006-01-02") != "2020-03-01" { t.Fatalf("unexpected month window %s ~ %s", start, end) } if _, _, _, err := resolveKpiMonth("2020/02", 0, location); err == nil { t.Fatalf("expected format error for 2020/02") } }