Files
kra-new/internal/data/business/analytics_test.go
T

112 lines
5.6 KiB
Go

package business
import (
"context"
"testing"
"gorm.io/gorm"
"kra/internal/biz/business"
)
func prepareAnalyticsData(t *testing.T) (*gorm.DB, business.AnalyticsRepo, business.AnalyticsScope, business.AnalyticsFilter) {
t.Helper()
db, _ := prepareChannels(t)
for _, sql := range []string{
"ALTER TABLE tab_sw_report_day ADD COLUMN game_name TEXT",
"ALTER TABLE tab_sw_report_day_key ADD COLUMN game_name TEXT",
"UPDATE tab_sw_report_day SET game_name=CASE WHEN game_id=1 THEN '历史游戏甲' ELSE '游戏乙' END",
"UPDATE tab_sw_report_day_key SET game_name=CASE WHEN game_id=1 THEN '历史游戏甲' ELSE '游戏乙' END",
"UPDATE tab_sw_report_day_key SET identity_key='A' WHERE (source_db='hw' OR promote_id=103) AND metric=1",
"INSERT INTO tab_sw_report_day(source_db,promote_id,game_id,dedup_mode,stat_date,total_pay,game_name) VALUES('lx',0,1,0,'2026-11-01',5,'历史游戏甲'),('lx',999,1,0,'2026-11-01',7,'历史游戏甲')",
"INSERT INTO tab_sw_report_day_key(source_db,promote_id,game_id,dedup_mode,stat_date,metric,identity_key,game_name) VALUES('lx',0,1,1,'2026-11-01',1,'official','历史游戏甲'),('lx',999,1,1,'2026-11-01',1,'orphan','历史游戏甲'),('lx',100,1,1,'2026-11-01',2,'A','历史游戏甲'),('lx',103,1,1,'2026-11-02',2,'A','历史游戏甲'),('hw',100,1,1,'2026-11-01',2,'A','历史游戏甲'),('lx',100,1,1,'2026-11-01',3,'A','历史游戏甲'),('lx',103,1,1,'2026-11-02',3,'A','历史游戏甲'),('hw',100,1,1,'2026-11-01',3,'A','历史游戏甲')",
} {
if err := db.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
scope := business.AnalyticsScope{Viewer: channelTestScope(), IncludeSub: true, IDCardDedup: true}
filter := business.AnalyticsFilter{Sources: []string{"lx", "hw"}, Begin: "2026-11-01", End: "2026-11-03"}
return db, NewAnalyticsRepo(testData{db}), scope, filter
}
func TestAnalyticsChannelTreeAndAdminOfficialRows(t *testing.T) {
_, repo, scope, filter := prepareAnalyticsData(t)
data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil {
t.Fatal(err)
}
if len(data.Rows) != 3 || data.GlobalCounts != nil {
t.Fatalf("普通商务统计范围错误: %+v", data)
}
var lx *business.AnalyticsRow
for _, row := range data.Rows {
if row.SourceDB == "lx" && row.ID == 100 {
lx = row
}
if row.ID == 0 || row.ID == 999 {
t.Fatal("受约束商务看到官方/未知渠道")
}
}
if lx == nil || lx.Counts.Register != 2 || portraitTestMoney(lx.Pay) != "60.60" || lx.Name != "root-channel" || lx.BusinessName() != "lx-business" {
t.Fatalf("渠道树去重、充值或商务展示错误: %+v", lx)
}
scope.Viewer = business.UserScope{All: true}
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || len(data.Rows) != 5 || data.GlobalCounts.Register != 4 || data.GlobalCounts.Active != 2 || data.GlobalCounts.Pay != 1 || portraitTestMoney(data.GlobalPay) != "2070.60" {
t.Fatalf("超管全局去重或官方/历史渠道遗漏: %+v %v", data, err)
}
}
func TestAnalyticsFiltersKeepHierarchyAndSnapshotNames(t *testing.T) {
db, repo, scope, filter := prepareAnalyticsData(t)
filter.PromoteName = "child"
data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || len(data.Rows) != 1 || data.Rows[0].ID != 100 || data.Rows[0].Counts.Register != 2 || portraitTestMoney(data.Rows[0].Pay) != "60.60" {
t.Fatalf("模糊渠道筛选应扩到同树可见渠道: %+v %v", data, err)
}
if err := db.Exec("UPDATE tab_promote SET register_type=1 WHERE source_db='lx' AND id=101").Error; err != nil {
t.Fatal(err)
}
filter.PromoteName = ""
kind := 1
filter.PromoteType = &kind
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || len(data.Rows) != 1 || data.Rows[0].ID != 100 || portraitTestMoney(data.Rows[0].Pay) != "20.20" || data.Rows[0].PromoteType == nil || *data.Rows[0].PromoteType != 0 {
t.Fatalf("类型筛选应限制参与渠道,同时显示归根后的当前资料: %+v %v", data, err)
}
filter.PromoteType = nil
filter.GameNames = []string{"历史游戏甲"}
data, err = repo.Aggregate(context.Background(), business.GameAnalytics, scope, filter)
if err != nil || len(data.Rows) != 2 {
t.Fatalf("按游戏快照名筛选错误: %+v %v", data, err)
}
for _, row := range data.Rows {
if row.SourceDB == "lx" && (row.ID != 1 || row.Name != "游戏甲" || row.Counts.Register != 1) {
t.Fatalf("应按报表快照筛选、用当前游戏名展示: %+v", row)
}
}
filter.GameNames = []string{"游戏甲"}
data, err = repo.Aggregate(context.Background(), business.GameAnalytics, scope, filter)
if err != nil || len(data.Rows) != 0 {
t.Fatal("不能用当前游戏表名替代报表快照过滤")
}
}
func TestAnalyticsMissingScopeAndTablesDoNotBroaden(t *testing.T) {
db, repo, scope, filter := prepareAnalyticsData(t)
scope.IncludeSub = false
data, err := repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || len(data.Rows) != 2 {
t.Fatal("关闭下级仅保留一级渠道统计")
}
if err := db.Exec("DROP TABLE tab_sw_report_day_key").Error; err != nil {
t.Fatal(err)
}
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || data.Available {
t.Fatal("缺身份键表不能返回零汇总")
}
scope.Viewer = business.UserScope{SelfID: 500, OnlySelf: true}
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
if err != nil || !data.Available || len(data.Rows) != 0 {
t.Fatal("无绑定应为确定空范围")
}
}