142 lines
5.8 KiB
Go
142 lines
5.8 KiB
Go
package hostwithdrawal
|
|
|
|
import (
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func TestNormalizeListQueryMapsIdentityAndRejectsBadInput(t *testing.T) {
|
|
query, err := normalizeListQuery(listQuery{
|
|
Page: -1,
|
|
PageSize: 1000,
|
|
AppCode: " LaLu ",
|
|
RecordType: "all",
|
|
Identity: "BD_LEADER",
|
|
Status: "all",
|
|
Keyword: " 168557 ",
|
|
StartAtMS: 100,
|
|
EndAtMS: 200,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("normalize query failed: %v", err)
|
|
}
|
|
if query.Page != 1 || query.PageSize != 100 || query.AppCode != "lalu" || query.RecordType != "" || query.Status != "" || query.Keyword != "168557" {
|
|
t.Fatalf("normalized basic fields mismatch: %+v", query)
|
|
}
|
|
if query.SalaryAssetType != assetAdminSalary || query.Identity != "bd_leader_admin" {
|
|
t.Fatalf("identity mapping mismatch: %+v", query)
|
|
}
|
|
|
|
if _, err := normalizeListQuery(listQuery{Status: "done"}); err == nil {
|
|
t.Fatal("expected invalid status to fail")
|
|
}
|
|
if _, err := normalizeListQuery(listQuery{StartAtMS: 200, EndAtMS: 200}); err == nil {
|
|
t.Fatal("expected closed time range to fail")
|
|
}
|
|
}
|
|
|
|
func TestSalaryTransferWhereUsesIdentityStatusTimeAndKeywordUsers(t *testing.T) {
|
|
where, args := salaryTransferWhere(listQuery{
|
|
AppCode: "lalu",
|
|
SalaryAssetType: assetHostSalary,
|
|
Keyword: "cmd",
|
|
StartAtMS: 100,
|
|
EndAtMS: 200,
|
|
}, []int64{11, 22})
|
|
|
|
wantWhere := "WHERE e.app_code = ? AND e.asset_type = ? AND wt.biz_type = ? AND wt.status = ? AND JSON_UNQUOTE(JSON_EXTRACT(wt.metadata_json, '$.salary_asset_type')) = ? AND e.created_at_ms >= ? AND e.created_at_ms < ? AND (e.user_id IN (?,?) OR e.counterparty_user_id IN (?,?) OR e.transaction_id LIKE ? OR wt.command_id LIKE ? OR CAST(e.user_id AS CHAR) LIKE ? OR CAST(e.counterparty_user_id AS CHAR) LIKE ?)"
|
|
if where != wantWhere {
|
|
t.Fatalf("where mismatch:\nwant %s\n got %s", wantWhere, where)
|
|
}
|
|
wantArgs := []any{"lalu", assetCoinSellerCoin, bizSalaryTransfer, transactionSucceeded, assetHostSalary, int64(100), int64(200), int64(11), int64(22), int64(11), int64(22), "%cmd%", "%cmd%", "%cmd%", "%cmd%"}
|
|
if !reflect.DeepEqual(args, wantArgs) {
|
|
t.Fatalf("args mismatch:\nwant %#v\n got %#v", wantArgs, args)
|
|
}
|
|
}
|
|
|
|
func TestWithdrawalWhereUsesStatusIdentityTimeAndKeywordUsers(t *testing.T) {
|
|
where, args := withdrawalWhere(listQuery{
|
|
AppCode: "lalu",
|
|
SalaryAssetType: assetBDSalary,
|
|
Status: statusPending,
|
|
Keyword: "upi",
|
|
StartAtMS: 100,
|
|
EndAtMS: 200,
|
|
}, []int64{77})
|
|
|
|
wantWhere := "WHERE a.app_code = ? AND a.salary_asset_type = ? AND a.status = ? AND a.created_at_ms >= ? AND a.created_at_ms < ? AND (a.user_id IN (?) OR CAST(a.id AS CHAR) LIKE ? OR a.user_id LIKE ? OR a.withdraw_method LIKE ? OR a.withdraw_address LIKE ? OR a.freeze_transaction_id LIKE ? OR a.audit_transaction_id LIKE ? OR a.approver_name LIKE ?)"
|
|
if where != wantWhere {
|
|
t.Fatalf("where mismatch:\nwant %s\n got %s", wantWhere, where)
|
|
}
|
|
wantArgs := []any{"lalu", assetBDSalary, statusPending, int64(100), int64(200), "77", "%upi%", "%upi%", "%upi%", "%upi%", "%upi%", "%upi%", "%upi%"}
|
|
if !reflect.DeepEqual(args, wantArgs) {
|
|
t.Fatalf("args mismatch:\nwant %#v\n got %#v", wantArgs, args)
|
|
}
|
|
}
|
|
|
|
func TestPageMergedItemsSortsAndSlicesStableMixedSources(t *testing.T) {
|
|
items := []itemDTO{
|
|
{ID: "salary_transfer:8", RecordType: recordTypeSalaryTransfer, CreatedAtMS: 100},
|
|
{ID: "withdrawal:7", RecordType: recordTypeWithdrawal, ApplicationID: "7", CreatedAtMS: 100},
|
|
{ID: "salary_transfer:9", RecordType: recordTypeSalaryTransfer, CreatedAtMS: 100},
|
|
{ID: "withdrawal:11", RecordType: recordTypeWithdrawal, ApplicationID: "11", CreatedAtMS: 90},
|
|
{ID: "salary_transfer:1", RecordType: recordTypeSalaryTransfer, CreatedAtMS: 80},
|
|
}
|
|
|
|
page := pageMergedItems(items, 1, 4)
|
|
gotIDs := []string{page[0].ID, page[1].ID, page[2].ID, page[3].ID}
|
|
wantIDs := []string{"salary_transfer:9", "salary_transfer:8", "withdrawal:7", "withdrawal:11"}
|
|
if !reflect.DeepEqual(gotIDs, wantIDs) {
|
|
t.Fatalf("page sort mismatch:\nwant %#v\n got %#v", wantIDs, gotIDs)
|
|
}
|
|
|
|
secondPage := pageMergedItems(items, 2, 2)
|
|
gotIDs = []string{secondPage[0].ID, secondPage[1].ID}
|
|
wantIDs = []string{"withdrawal:7", "withdrawal:11"}
|
|
if !reflect.DeepEqual(gotIDs, wantIDs) {
|
|
t.Fatalf("second page mismatch:\nwant %#v\n got %#v", wantIDs, gotIDs)
|
|
}
|
|
}
|
|
|
|
func TestRegisterRoutesExposesHostWithdrawalsEndpoint(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
engine := gin.New()
|
|
group := engine.Group("/api/v1")
|
|
RegisterRoutes(group, &Handler{})
|
|
|
|
for _, route := range engine.Routes() {
|
|
if route.Method == "GET" && route.Path == "/api/v1/admin/host-withdrawals" {
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("host withdrawals route was not registered")
|
|
}
|
|
|
|
func TestHostWithdrawalIndexSQLKeepsRequiredReadPaths(t *testing.T) {
|
|
adminSQL, err := os.ReadFile("../../../migrations/072_host_withdrawal_navigation.sql")
|
|
if err != nil {
|
|
t.Fatalf("read admin migration failed: %v", err)
|
|
}
|
|
walletSQL, err := os.ReadFile("../../../../../scripts/mysql/054_wallet_entries_asset_counterparty_time_index.sql")
|
|
if err != nil {
|
|
t.Fatalf("read wallet migration failed: %v", err)
|
|
}
|
|
for _, snippet := range []string{
|
|
"idx_admin_withdrawal_app_time (app_code, created_at_ms, id)",
|
|
"idx_admin_withdrawal_app_asset_time (app_code, salary_asset_type, created_at_ms, id)",
|
|
"idx_admin_withdrawal_app_status_asset_time (app_code, status, salary_asset_type, created_at_ms, id)",
|
|
"idx_admin_withdrawal_app_user_time (app_code, user_id, created_at_ms, id)",
|
|
} {
|
|
if !strings.Contains(string(adminSQL), snippet) {
|
|
t.Fatalf("admin migration missing index snippet %q", snippet)
|
|
}
|
|
}
|
|
if !strings.Contains(string(walletSQL), "idx_wallet_entries_asset_counterparty_time (app_code, asset_type, counterparty_user_id, created_at_ms, entry_id)") {
|
|
t.Fatal("wallet migration missing counterparty index")
|
|
}
|
|
}
|