Files
kra-new/cmd/channel_http_test.go
T

203 lines
8.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"path/filepath"
"strconv"
"strings"
"testing"
"github.com/gin-gonic/gin"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
businessbiz "kra/internal/biz/business"
"kra/internal/biz/system"
businessdata "kra/internal/data/business"
systemdata "kra/internal/data/system"
"kra/internal/integration/gameplatform"
"kra/internal/server/handler"
"kra/internal/server/router"
businessservice "kra/internal/service/business"
)
type channelHTTPDatabases struct{ platform *gorm.DB }
func (d channelHTTPDatabases) Database(name string) (*gorm.DB, error) {
if name == "lx" {
return d.platform, nil
}
return nil, fmt.Errorf("未配置")
}
func TestChannelHTTPListsMetricsOptionsAndAtomicCreation(t *testing.T) {
open := func(name string) *gorm.DB {
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), name)), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
pool, _ := db.DB()
t.Cleanup(func() { _ = pool.Close() })
return db
}
db, platform := open("main.db"), open("platform.db")
for _, step := range append(systemdata.Migrations(), businessdata.Migrations()...) {
if err := step.Migrate(db); err != nil {
t.Fatal(err)
}
}
for _, sql := range []string{
"INSERT INTO sys_users(id,uuid,username,level,parent_id,id_path,enable) VALUES(1,'root','admin',0,0,'0',1),(7,'owner','owner',1,0,'0',1),(8,'child','child',2,7,'0,7',1),(9,'leaf','leaf',3,8,'0,7,8',1),(99,'other','other',1,0,'0',1)",
"INSERT INTO sys_user_bind_platform(user_id,source_db,platform_busier_id,platform_busier_account,status) VALUES(9,'lx',14,'sdk-account','0'),(99,'hw',14,'other','0')",
"CREATE TABLE tab_promote(id INTEGER,source_db TEXT,account TEXT,nickname TEXT,parent_name TEXT,real_name TEXT,promote_level INTEGER,register_type INTEGER,status INTEGER,lock_status INTEGER,parent_id INTEGER,top_promote_id INTEGER,busier_id INTEGER,create_time INTEGER)",
"INSERT INTO tab_promote VALUES(100,'lx','main-channel','主渠道','','负责人',1,0,1,0,0,0,14,1000),(101,'lx','sub-channel','下级渠道','main-channel','',2,1,1,-1,100,100,14,1000),(100,'hw','other-platform','','','',1,0,1,0,0,0,14,1000)",
"CREATE TABLE tab_promote_apply(source_db TEXT,promote_id INTEGER,game_id INTEGER,status INTEGER)",
"INSERT INTO tab_promote_apply VALUES('lx',100,1,1),('lx',100,1,1),('lx',101,2,1)",
"CREATE TABLE tab_user(source_db TEXT,id INTEGER,promote_id INTEGER,puid INTEGER,idcard TEXT)",
"INSERT INTO tab_user VALUES('lx',1,100,0,'A-X'),('lx',2,101,0,'A-x'),('lx',3,101,0,''),('lx',4,101,2,'sub'),('hw',1,100,0,'other')",
"CREATE TABLE tab_spend(source_db TEXT,promote_id INTEGER,pay_status INTEGER,pay_amount DECIMAL(20,2))",
"INSERT INTO tab_spend VALUES('lx',100,1,10.10),('lx',101,1,20.20),('lx',100,0,999),('hw',100,1,999)",
} {
if err := db.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
for _, sql := range []string{
"CREATE TABLE tab_promote(id INTEGER PRIMARY KEY AUTOINCREMENT,account TEXT UNIQUE,password TEXT,status INTEGER,busier_id INTEGER,create_time INTEGER,register_type INTEGER,parent_id INTEGER,promote_level INTEGER,top_promote_id INTEGER,game_ids2 TEXT)",
"CREATE TABLE tab_promote_settlement_time(id INTEGER PRIMARY KEY AUTOINCREMENT,promote_id INTEGER,promote_account TEXT,time_type INTEGER,day_period INTEGER,create_time INTEGER,update_time INTEGER,next_count_time INTEGER)",
"CREATE TABLE tab_promote_business(id INTEGER PRIMARY KEY,promote_ids TEXT)",
"INSERT INTO tab_promote_business VALUES(14,'5,6')",
} {
if err := platform.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
provider := businessHTTPData{db}
passwords := &gameplatform.Passwords{AuthCode: "test-auth"}
uc := businessbiz.NewChannelUsecase(businessdata.NewChannelRepo(provider), businessdata.NewChannelWriteRepo(channelHTTPDatabases{platform}), businessbiz.NewAccountUsecase(businessdata.NewAccountRepo(provider)), businessbiz.NewUserPreferenceUsecase(businessdata.NewUserPreferenceRepo(provider)), passwords)
engine := gin.New()
engine.Use(func(c *gin.Context) {
id, _ := strconv.ParseUint(c.GetHeader("X-Test-User"), 10, 64)
aid := uint(901)
if id == 1 {
aid = 888
}
c.Request = c.Request.WithContext(system.NewActorContext(c.Request.Context(), system.Actor{UserID: uint(id), AuthorityID: aid}))
c.Next()
})
router.RegisterChannel(engine.Group(""), handler.NewChannel(businessservice.NewChannelService(uc)))
server := httptest.NewServer(engine)
defer server.Close()
call := func(user int, method, path, body string, expected int) any {
t.Helper()
req, _ := http.NewRequest(method, server.URL+path, strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Test-User", strconv.Itoa(user))
res, err := server.Client().Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
var payload map[string]any
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
t.Fatal(err)
}
if payload["code"] != float64(expected) {
t.Fatalf("%s %s 用户%d: %+v", method, path, user, payload)
}
return payload["data"]
}
list := func(user int, query string, total int) map[string]any {
t.Helper()
data := call(user, "GET", "/sw/promote/list"+query, "", 0).(map[string]any)
if data["total"] != float64(total) {
t.Fatalf("范围错误: %+v", data)
}
return data
}
rootRow := func(data map[string]any) map[string]any {
for _, raw := range data["rows"].([]any) {
row := raw.(map[string]any)
if row["id"] == float64(100) && row["sourceDb"] == "lx" {
return row
}
}
t.Fatal("主渠道不见了")
return nil
}
row := rootRow(list(8, "", 2))
if row["gameCount"] != float64(1) || row["playerCount"] != float64(1) || row["totalPayAmount"] != "30.30" || row["busierDisplayName"] != "sdk-account(leaf)" {
t.Fatalf("默认偏好或展示字段错误: %+v", row)
}
if err := db.Exec("INSERT INTO sys_user_preference(user_id,include_sub_promote,idcard_dedup) VALUES(8,1,0)").Error; err != nil {
t.Fatal(err)
}
row = rootRow(list(8, "", 2))
if row["playerCount"] != float64(3) || row["totalPayAmount"] != "30.30" {
t.Fatal("关闭身份证去重不应改变金额")
}
if err := db.Exec("UPDATE sys_user_preference SET include_sub_promote=0 WHERE user_id=8").Error; err != nil {
t.Fatal(err)
}
row = rootRow(list(8, "", 2))
if row["playerCount"] != float64(1) || row["totalPayAmount"] != "10.10" {
t.Fatal("关闭下级没有改变统计范围")
}
list(1, "", 3)
list(8, "?sourceDb=hw", 0)
list(8, "?busierUserId=99", 0)
list(8, "?busierUserId=8", 0)
list(8, "?lockStatus=-1", 1)
list(1, "?busierAccount=leaf", 2)
options := call(8, "GET", "/sw/promote/bindOptions?sourceDb=lx", "", 0).([]any)
if len(options) != 1 || options[0].(map[string]any)["platformBusierId"] != float64(14) {
t.Fatal("上级未获取下级正常绑定")
}
body := `{"sourceDb":"lx","platformBusierId":"14","account":"中文渠道","password":"demo123","registerType":1}`
created := call(8, "POST", "/sw/promote", body, 0).(map[string]any)
if created["sourceDb"] != "lx" {
t.Fatal("返回平台丢失")
}
var persisted struct {
Status, PromoteLevel int
Password string
}
platform.Table("tab_promote").Take(&persisted)
if persisted.Status != -3 || persisted.PromoteLevel != 1 || persisted.Password != "###eef6d9b7160f32a869f3e03b7ea575a5" {
t.Fatalf("源平台创建不兼容: %+v", persisted)
}
call(8, "POST", "/sw/promote", body, 7)
call(99, "POST", "/sw/promote", body, 7)
list(8, "", 2)
call(8, "GET", "/sw/promote/game-distribution?sourceDb=hw&promoteId=100", "", 7)
call(8, "GET", "/sw/promote/game-distribution?sourceDb=lx&promoteId=100", "", 7)
for _, sql := range []string{
"CREATE TABLE tab_game(source_db TEXT,id INTEGER,game_name TEXT)",
"INSERT INTO tab_game VALUES('lx',1,'汇总游戏')",
"CREATE TABLE tab_sw_report_day(source_db TEXT,promote_id INTEGER,game_id INTEGER,dedup_mode INTEGER,stat_date DATE,total_pay DECIMAL(20,2))",
"INSERT INTO tab_sw_report_day VALUES('lx',100,1,0,'2000-01-01',70.00),('lx',100,1,1,'2000-01-01',700.00)",
"CREATE TABLE tab_sw_report_day_key(source_db TEXT,promote_id INTEGER,game_id INTEGER,dedup_mode INTEGER,stat_date DATE,metric INTEGER,identity_key TEXT)",
"INSERT INTO tab_sw_report_day_key VALUES('lx',100,1,0,'2000-01-01',1,'one'),('lx',100,1,0,'2000-01-01',1,'two')",
} {
if err := db.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
games := call(8, "GET", "/sw/promote/game-distribution?sourceDb=lx&promoteId=100", "", 0).([]any)
if len(games) != 1 {
t.Fatal("游戏分布没有按当前渠道的推广游戏过滤")
}
game := games[0].(map[string]any)
if game["gameName"] != "汇总游戏" || game["registerCount"] != float64(2) || game["payAmount"] != "70.00" {
t.Fatalf("游戏分布误用了原始注册/充值或错误金额口径: %+v", game)
}
if err := db.Exec("DROP TABLE tab_promote").Error; err != nil {
t.Fatal(err)
}
data := list(8, "", 0)
if data["available"] != false {
t.Fatal("缺业务表必须明确未接入")
}
}