223 lines
7.7 KiB
Go

package dashboard
import (
"context"
"database/sql"
"testing"
"time"
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/shopspring/decimal"
)
type walletMapperTestStore struct {
users map[int64]UserCountry
}
func (s walletMapperTestStore) WithTx(context.Context, func(*sql.Tx) error) error { return nil }
func (s walletMapperTestStore) WithDashboardLock(context.Context, time.Duration, func() error) error {
return nil
}
func (s walletMapperTestStore) MarkEventApplied(context.Context, *sql.Tx, string, string) (bool, error) {
return true, nil
}
func (s walletMapperTestStore) SaveCheckpoint(context.Context, mysql.Position) error { return nil }
func (s walletMapperTestStore) LoadCheckpoint(context.Context) (mysql.Position, bool, error) {
return mysql.Position{}, false, nil
}
func (s walletMapperTestStore) Cleanup(context.Context) (int64, error) { return 0, nil }
func (s walletMapperTestStore) UpsertUserCountry(context.Context, *sql.Tx, UserCountry) error {
return nil
}
func (s walletMapperTestStore) UserCountry(_ context.Context, userID int64) (UserCountry, bool, error) {
user, ok := s.users[userID]
return user, ok, nil
}
func (s walletMapperTestStore) ResolveWalletGame(context.Context, string, string, string) (string, string, string, error) {
return "TEST", "1", "Test", nil
}
func (s walletMapperTestStore) ApplyDailyContribution(context.Context, *sql.Tx, Contribution, string) error {
return nil
}
func (s walletMapperTestStore) ApplyPeriodContribution(context.Context, *sql.Tx, Contribution, string) error {
return nil
}
func (s walletMapperTestStore) ApplyGamePeriodContribution(context.Context, *sql.Tx, Contribution, string) error {
return nil
}
func (s walletMapperTestStore) ApplyContributionBatch(context.Context, *sql.Tx, []Contribution, string, []string) error {
return nil
}
func TestWalletLuckyGiftIsNotMappedAsGiftConsume(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{users: map[int64]UserCountry{
1001: {UserID: 1001, SysOrigin: "LIKEI", Country: Country{Code: "BD", Name: "Bangladesh"}},
}}, []string{"LIKEI"}, "UNKNOWN", 0)
row := Row{
"id": int64(11),
"user_id": int64(1001),
"sys_origin": "LIKEI",
"event_type": "LUCKY_GIFT",
"type": int64(1),
"penny_amount": decimal.NewFromInt(10000),
"create_time": time.Now().UnixMilli(),
}
contributions, err := mapper.Map(context.Background(), "likei_wallet", "wallet_gold_asset_record_1", "insert", row)
if err != nil {
t.Fatal(err)
}
if len(contributions) != 0 {
t.Fatalf("expected wallet LUCKY_GIFT to be ignored, got %#v", contributions)
}
}
func TestWalletGiveGiftIsNotMappedAsGiftConsume(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{users: map[int64]UserCountry{
1001: {UserID: 1001, SysOrigin: "LIKEI", Country: Country{Code: "BD", Name: "Bangladesh"}},
}}, []string{"LIKEI"}, "UNKNOWN", 0)
row := Row{
"id": int64(12),
"user_id": int64(1001),
"sys_origin": "LIKEI",
"event_type": "GIVE_GIFT_V3",
"type": int64(1),
"penny_amount": decimal.NewFromInt(10000),
"create_time": time.Now().UnixMilli(),
}
contributions, err := mapper.Map(context.Background(), "likei_wallet", "wallet_gold_asset_record_1", "insert", row)
if err != nil {
t.Fatal(err)
}
if len(contributions) != 0 {
t.Fatalf("expected wallet GIVE_GIFT to be ignored, got %#v", contributions)
}
}
func TestUserCreateTimeDisplayOffsetIsApplied(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{}, []string{"LIKEI"}, "UNKNOWN", 8*time.Hour)
createdAt := time.Date(2026, 5, 26, 16, 2, 51, 0, time.UTC)
contributions, err := mapper.Map(context.Background(), "likei", "user_base_info", "insert", Row{
"id": int64(2059304265087774722),
"origin_sys": "LIKEI",
"is_del": int64(0),
"country_code": "PH",
"country_name": "Philippines",
"create_time": createdAt,
})
if err != nil {
t.Fatal(err)
}
if len(contributions) != 1 {
t.Fatalf("expected one user contribution, got %d", len(contributions))
}
expected := createdAt.Add(8 * time.Hour)
if !contributions[0].EventTime.Equal(expected) {
t.Fatalf("expected event time %s, got %s", expected, contributions[0].EventTime)
}
if contributions[0].CountryNewUser != 1 {
t.Fatalf("expected country new user contribution, got %d", contributions[0].CountryNewUser)
}
}
func TestSourceTimeOffsetIsAppliedToAmountEvents(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{users: map[int64]UserCountry{
1001: {UserID: 1001, SysOrigin: "LIKEI", Country: Country{Code: "BD", Name: "Bangladesh"}},
}}, []string{"LIKEI"}, "UNKNOWN", 0, 8*time.Hour)
decodedCreateTime := time.Date(2026, 5, 27, 19, 36, 0, 0, time.UTC)
contributions, err := mapper.Map(context.Background(), "likei", "game_lucky_gift_count", "insert", Row{
"id": int64(31),
"user_id": int64(1001),
"sys_origin": "LIKEI",
"pay_amount": decimal.NewFromInt(50),
"award_amount": decimal.NewFromInt(100),
"create_time": decodedCreateTime,
})
if err != nil {
t.Fatal(err)
}
if len(contributions) != 1 {
t.Fatalf("expected one contribution, got %d", len(contributions))
}
expected := decodedCreateTime.Add(8 * time.Hour)
if !contributions[0].EventTime.Equal(expected) {
t.Fatalf("expected event time %s, got %s", expected, contributions[0].EventTime)
}
}
func TestGoogleRechargeContributesToUserRecharge(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{users: map[int64]UserCountry{
1001: {
UserID: 1001,
SysOrigin: "LIKEI",
Country: Country{Code: "BD", Name: "Bangladesh"},
CreatedAt: time.Date(2026, 5, 27, 8, 0, 0, 0, time.UTC),
},
}}, []string{"LIKEI"}, "UNKNOWN", 0)
contributions, err := mapper.Map(context.Background(), "likei", "order_purchase_history", "insert", Row{
"id": int64(21),
"user_id": int64(1001),
"sys_origin": "LIKEI",
"evn": "PROD",
"status": "COMPLETE",
"is_trial_period": int64(0),
"unit_price": decimal.NewFromInt(99),
"pay_platform": "GOOGLE",
"create_time": time.Date(2026, 5, 27, 9, 0, 0, 0, time.UTC),
})
if err != nil {
t.Fatal(err)
}
if len(contributions) != 1 {
t.Fatalf("expected one contribution, got %d", len(contributions))
}
if !contributions[0].GoogleRecharge.Equal(decimal.NewFromInt(99)) {
t.Fatalf("expected google recharge 99, got %s", contributions[0].GoogleRecharge)
}
if !contributions[0].UserRecharge.Equal(decimal.NewFromInt(99)) {
t.Fatalf("expected user recharge 99, got %s", contributions[0].UserRecharge)
}
}
func TestThirdPartyRechargeContributesToUserRechargeForAnyFactory(t *testing.T) {
mapper := NewMapper(walletMapperTestStore{users: map[int64]UserCountry{
1001: {
UserID: 1001,
SysOrigin: "LIKEI",
Country: Country{Code: "BD", Name: "Bangladesh"},
CreatedAt: time.Date(2026, 5, 27, 8, 0, 0, 0, time.UTC),
},
}}, []string{"LIKEI"}, "UNKNOWN", 0)
contributions, err := mapper.Map(context.Background(), "likei", "order_user_purchase_pay", "insert", Row{
"id": int64(22),
"user_id": int64(1001),
"sys_origin": "LIKEI",
"evn": "PROD",
"factory_code": "OTHER_PAY",
"pay_status": "SUCCESSFUL",
"receipt_type": "PAYMENT",
"refund_status": "NONE",
"compute_usd_amount": decimal.NewFromInt(12),
"create_time": time.Date(2026, 5, 27, 9, 0, 0, 0, time.UTC),
})
if err != nil {
t.Fatal(err)
}
if len(contributions) != 1 {
t.Fatalf("expected one contribution, got %d", len(contributions))
}
if !contributions[0].UserRecharge.Equal(decimal.NewFromInt(12)) {
t.Fatalf("expected user recharge 12, got %s", contributions[0].UserRecharge)
}
if !contributions[0].MifapayRecharge.IsZero() {
t.Fatalf("expected non MifaPay recharge to keep mifapay zero, got %s", contributions[0].MifapayRecharge)
}
}