181 lines
8.3 KiB
Go
181 lines
8.3 KiB
Go
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)
|
||
}
|