99 lines
4.5 KiB
Go
99 lines
4.5 KiB
Go
package hostorg
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// TestNormalizeListQueryAllowsCoinSellerComputedSorts 锁定币商余额和累充 USDT 排序字段会被后台列表查询接受。
|
||
func TestNormalizeListQueryAllowsCoinSellerComputedSorts(t *testing.T) {
|
||
for _, sortBy := range []string{sortByMerchantBalance, sortByTotalRechargeUSDT} {
|
||
query := normalizeListQuery(listQuery{Page: 1, PageSize: 50, SortBy: sortBy, SortDirection: "asc"})
|
||
if query.SortBy != sortBy || query.SortDirection != "asc" {
|
||
t.Fatalf("expected sort %s asc to be kept, got sort_by=%q direction=%q", sortBy, query.SortBy, query.SortDirection)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestBDRoleFromStatusPathUsesLeaderTableWithAPIPrefix 锁定线上真实 FullPath 带 /api/v1 前缀时,BD Leader 状态仍然写独立负责人表。
|
||
func TestBDRoleFromStatusPathUsesLeaderTableWithAPIPrefix(t *testing.T) {
|
||
role, target := bdRoleFromStatusPath("/api/v1/admin/bd-leaders/:user_id/status")
|
||
if role != "bd_leader" || target != "bd_leader_profiles" {
|
||
t.Fatalf("leader status route must use bd_leader_profiles, got role=%q target=%q", role, target)
|
||
}
|
||
|
||
role, target = bdRoleFromStatusPath("/api/v1/admin/bds/:user_id/status")
|
||
if role != "bd" || target != "bd_profiles" {
|
||
t.Fatalf("bd status route must use bd_profiles, got role=%q target=%q", role, target)
|
||
}
|
||
}
|
||
|
||
// TestUserCountryRegionSQLUsesCountryMapping 锁定组织列表区域展示口径:从用户国家映射 active 区域,不从身份表区域快照取值。
|
||
func TestUserCountryRegionSQLUsesCountryMapping(t *testing.T) {
|
||
joinSQL := userCountryRegionJoin("owner", "owner_country_region", "owner_region")
|
||
for _, want := range []string{
|
||
"LEFT JOIN region_countries owner_country_region",
|
||
"owner_country_region.country_code = owner.country",
|
||
"owner_country_region.status = 'active'",
|
||
"LEFT JOIN regions owner_region",
|
||
"owner_region.region_id = owner_country_region.region_id",
|
||
"owner_region.status = 'active'",
|
||
} {
|
||
if !strings.Contains(joinSQL, want) {
|
||
t.Fatalf("country region join missing %q in %s", want, joinSQL)
|
||
}
|
||
}
|
||
if strings.Contains(joinSQL, "owner.region_id") {
|
||
t.Fatalf("country region join must not read identity or user region snapshots: %s", joinSQL)
|
||
}
|
||
if got := userCountryRegionIDSQL("owner_region"); got != "COALESCE(owner_region.region_id, 0)" {
|
||
t.Fatalf("region id projection mismatch: %s", got)
|
||
}
|
||
if got := userCountryRegionNameSQL("owner_region"); got != "COALESCE(owner_region.name, '')" {
|
||
t.Fatalf("region name projection mismatch: %s", got)
|
||
}
|
||
}
|
||
|
||
// TestSalaryWalletAssetTypeByRole 锁定四个组织身份读取各自工资钱包资产;BD Leader 复用 Admin 工资资产,不能误读普通 BD 资产。
|
||
func TestSalaryWalletAssetTypeByRole(t *testing.T) {
|
||
cases := map[string]string{
|
||
"host": assetHostSalaryUSD,
|
||
"agency": assetAgencySalaryUSD,
|
||
"bd": assetBDSalaryUSD,
|
||
"bd_leader": assetAdminSalaryUSD,
|
||
"admin": assetAdminSalaryUSD,
|
||
}
|
||
for role, want := range cases {
|
||
if got := salaryWalletAssetType(role); got != want {
|
||
t.Fatalf("role %s salary wallet asset mismatch: got %q want %q", role, got, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestNormalizeSalaryWalletHistoryQueryCapsPageSize 避免历史抽屉一次拉太多钱包分录,同时兼容 admin 作为 BD Leader 的旧口径。
|
||
func TestNormalizeSalaryWalletHistoryQueryCapsPageSize(t *testing.T) {
|
||
query := normalizeSalaryWalletHistoryQuery(salaryWalletHistoryQuery{Page: 0, PageSize: 500, Role: "admin", UserID: 7})
|
||
if query.Page != 1 || query.PageSize != 100 || query.Role != salaryWalletRoleBDLeader || query.UserID != 7 {
|
||
t.Fatalf("salary wallet history query normalized incorrectly: %+v", query)
|
||
}
|
||
}
|
||
|
||
// TestSortCoinSellerListItemsComputedFields 验证 wallet 聚合字段排序只改变展示顺序,不改动币商身份数据。
|
||
func TestSortCoinSellerListItemsComputedFields(t *testing.T) {
|
||
items := []*CoinSellerListItem{
|
||
{UserID: 1, MerchantBalance: 100, TotalRechargeUSDTMicro: 30_000_000},
|
||
{UserID: 2, MerchantBalance: 300, TotalRechargeUSDTMicro: 10_000_000},
|
||
{UserID: 3, MerchantBalance: 200, TotalRechargeUSDTMicro: 20_000_000},
|
||
}
|
||
|
||
sortCoinSellerListItems(items, sortByMerchantBalance, "desc")
|
||
if got := []int64{items[0].UserID, items[1].UserID, items[2].UserID}; got[0] != 2 || got[1] != 3 || got[2] != 1 {
|
||
t.Fatalf("merchant balance desc order mismatch: %v", got)
|
||
}
|
||
|
||
sortCoinSellerListItems(items, sortByTotalRechargeUSDT, "asc")
|
||
if got := []int64{items[0].UserID, items[1].UserID, items[2].UserID}; got[0] != 2 || got[1] != 3 || got[2] != 1 {
|
||
t.Fatalf("total recharge usdt asc order mismatch: %v", got)
|
||
}
|
||
}
|