Files
kra-new/cmd/ledger_http_test.go
T

181 lines
8.3 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 (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"net/url"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/glebarez/sqlite"
"github.com/xuri/excelize/v2"
"gorm.io/gorm"
businessbiz "kra/internal/biz/business"
"kra/internal/biz/system"
businessdata "kra/internal/data/business"
systemdata "kra/internal/data/system"
"kra/internal/server/handler"
"kra/internal/server/router"
businessservice "kra/internal/service/business"
)
func TestLedgerHTTPQueriesAndExcelExports(t *testing.T) {
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "ledger.db")), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
pool, _ := db.DB()
t.Cleanup(func() { _ = pool.Close() })
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','root',0,0,'0',1),(7,'owner','owner',1,0,'0',1),(9,'leaf','leaf',3,7,'0,7',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','0'),(99,'hw',20,'other','0')",
"CREATE TABLE tab_promote(id INTEGER,source_db TEXT,account TEXT,promote_level INTEGER,top_promote_id INTEGER,busier_id INTEGER)",
"INSERT INTO tab_promote VALUES(100,'lx','root-channel',1,0,14),(101,'lx','child-channel',2,100,14),(100,'hw','outside',1,0,20)",
"CREATE TABLE tab_game(id INTEGER,source_db TEXT,game_name TEXT)",
"INSERT INTO tab_game VALUES(1,'lx','当前游戏'),(1,'hw','同号其他游戏')",
"CREATE TABLE tab_user(id INTEGER,source_db TEXT,register_time TEXT,fgame_id INTEGER,fgame_name TEXT,register_ip TEXT,device_name TEXT,promote_id INTEGER,puid INTEGER)",
"CREATE TABLE tab_spend(id INTEGER,source_db TEXT,user_id INTEGER,pay_order_number TEXT,game_id INTEGER,game_name TEXT,server_id TEXT,server_name TEXT,game_player_name TEXT,pay_amount DECIMAL(20,2),pay_time INTEGER,pay_way INTEGER,pay_status INTEGER,spend_ip TEXT,promote_id INTEGER,promote_account TEXT)",
} {
if err := db.Exec(sql).Error; err != nil {
t.Fatal(err)
}
}
now := time.Now().In(time.FixedZone("CST", 8*3600))
day := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location())
stamp := day.Unix() + 43200
if err := db.Exec("INSERT INTO tab_user VALUES(1,'lx',?,1,'历史游戏','192.0.2.1','设备甲',100,0),(2,'lx',?,1,'历史游戏','','设备乙',101,NULL),(3,'lx',?,1,'历史游戏','','设备丙',101,0),(1,'hw',?,1,'外服游戏','','外服',100,0)", strconv.FormatInt(stamp, 10), strconv.FormatInt(stamp, 10), strconv.FormatInt(stamp, 10), strconv.FormatInt(stamp, 10)).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec("INSERT INTO tab_spend VALUES(101,'lx',1,'000000000001',1,'当前游戏','s1','区服','角色',12.34,?,3,1,'192.0.2.2',100,''),(102,'lx',3,'00002',1,'当前游戏','s1','区服','角色',3.00,?,4,1,'',101,''),(103,'lx',1,'fail',1,'当前游戏','s1','区服','角色',20.00,?,3,0,'',100,''),(104,'lx',1,'history',1,'当前游戏','s1','区服','角色',1000,0,3,1,'',999,'历史渠道'),(105,'lx',5,'official',1,'当前游戏','s1','区服','角色',5,?,3,1,'',0,'')", stamp, stamp, stamp, stamp).Error; err != nil {
t.Fatal(err)
}
provider := businessHTTPData{db}
uc := businessbiz.NewLedgerUsecase(businessdata.NewLedgerRepo(provider), businessbiz.NewAccountUsecase(businessdata.NewAccountRepo(provider)), businessbiz.NewUserPreferenceUsecase(businessdata.NewUserPreferenceRepo(provider)))
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.RegisterLedger(engine.Group(""), handler.NewLedger(businessservice.NewLedgerService(uc)))
server := httptest.NewServer(engine)
defer server.Close()
request := func(user int, method, path, body string) ([]byte, http.Header) {
t.Helper()
req, _ := http.NewRequest(method, server.URL+path, strings.NewReader(body))
req.Header.Set("X-Test-User", strconv.Itoa(user))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
res, err := server.Client().Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
data, err := io.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
return data, res.Header
}
call := func(user int, method, path, body string, code int) any {
t.Helper()
raw, _ := request(user, method, path, body)
var result map[string]any
if err := json.Unmarshal(raw, &result); err != nil {
t.Fatal(err)
}
if result["code"] != float64(code) {
t.Fatalf("%s %s: %s", method, path, raw)
}
return result["data"]
}
data := call(7, "GET", "/sw/register/list?sourceDb=lx&sortField=totalPayAmount", "", 0).(map[string]any)
rows := data["rows"].([]any)
first := rows[0].(map[string]any)
if data["total"] != float64(2) || first["userId"] != float64(1) || first["totalPayAmount"] != "1012.34" || first["fgameName"] != "历史游戏" || first["busierName"] != "sdk(leaf)" {
t.Fatalf("注册明细口径或字段错误: %+v", data)
}
games := call(7, "GET", "/sw/serverAnalysis/games?sourceDb=lx&limit=50", "", 0).([]any)
if len(games) != 1 || games[0].(map[string]any)["gameName"] != "当前游戏" {
t.Fatal("游戏下拉平台范围错误")
}
filtered := call(7, "GET", "/sw/register/list?sourceDb=lx&gameName="+url.QueryEscape("同号其他游戏"), "", 0).(map[string]any)
if filtered["total"] != float64(0) {
t.Fatal("游戏筛选跨平台串号")
}
data = call(7, "GET", "/sw/spend/list?sourceDb=lx&payStatus=0", "", 0).(map[string]any)
if data["total"] != float64(1) || data["totalPayAmount"] != "15.34" {
t.Fatal("失败列表的合计仍须取对应成功订单")
}
data = call(1, "GET", "/sw/spend/list?sourceDb=lx", "", 0).(map[string]any)
if data["total"] != float64(4) || data["totalPayAmount"] != "20.34" {
t.Fatal("超管全平台遗漏官方订单")
}
data = call(99, "GET", "/sw/register/list?sourceDb=lx", "", 0).(map[string]any)
if data["total"] != float64(0) {
t.Fatal("其他商务看到了 lx 明细")
}
if err := db.Exec("INSERT INTO sys_user_preference(user_id,include_sub_promote,idcard_dedup) VALUES(7,1,0)").Error; err != nil {
t.Fatal(err)
}
data = call(7, "GET", "/sw/register/list?sourceDb=lx", "", 0).(map[string]any)
if data["total"] != float64(2) {
t.Fatal("身份证开关不应改变明细行")
}
form := url.Values{"sourceDb": {"lx"}, "beginRegisterTime": {day.Format("2006-01-02")}, "endRegisterTime": {day.Format("2006-01-02")}}.Encode()
raw, header := request(7, "POST", "/sw/register/export", form)
if header.Get("success") != "true" {
t.Fatalf("导出失败: %s", raw)
}
f, err := excelize.OpenReader(bytes.NewReader(raw))
if err != nil {
t.Fatal(err)
}
xlsRows, err := f.GetRows("注册明细")
f.Close()
if err != nil || len(xlsRows) != 3 || xlsRows[0][7] != "累计充值" {
t.Fatal("注册 XLSX 字段或行数错误")
}
raw, header = request(7, "POST", "/sw/spend/export", "sourceDb=lx&payStatus=1&sortField=payAmount")
if header.Get("success") != "true" {
t.Fatalf("充值导出失败: %s", raw)
}
f, err = excelize.OpenReader(bytes.NewReader(raw))
if err != nil {
t.Fatal(err)
}
order, _ := f.GetCellValue("充值明细", "E2")
f.Close()
if order != "000000000001" {
t.Fatal("订单号导出丢失前导零")
}
call(7, "GET", "/sw/register/list?beginRegisterTime=bad&endRegisterTime=2026-11-04", "", 7)
if err := db.Exec("WITH RECURSIVE seq(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM seq WHERE n<10001) INSERT INTO tab_user(id,source_db,register_time,fgame_id,fgame_name,promote_id,puid) SELECT 1000+n,'lx',?,1,'游戏',100,0 FROM seq", strconv.FormatInt(stamp, 10)).Error; err != nil {
t.Fatal(err)
}
call(7, "POST", "/sw/register/export", form, 7)
if err := db.Exec("DROP TABLE tab_promote").Error; err != nil {
t.Fatal(err)
}
data = call(7, "GET", "/sw/spend/list", "", 0).(map[string]any)
if data["available"] != false || data["totalPayAmount"] != nil {
t.Fatal("缺表不能返回伪造零合计")
}
call(7, "POST", "/sw/spend/export", "sourceDb=lx", 7)
}