95 lines
3.8 KiB
Go
95 lines
3.8 KiB
Go
package processor
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
"gorm.io/driver/postgres"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
"gorm.io/gorm/logger"
|
||
|
|
|
||
|
|
"apskel-pos-be/internal/constants"
|
||
|
|
"apskel-pos-be/internal/models"
|
||
|
|
"apskel-pos-be/internal/repository"
|
||
|
|
)
|
||
|
|
|
||
|
|
// fixedOrganizationSettings serves the same organization settings to every caller.
|
||
|
|
type fixedOrganizationSettings struct{ s models.OrganizationLoyaltySettings }
|
||
|
|
|
||
|
|
func (f fixedOrganizationSettings) Organization(context.Context, uuid.UUID) (*models.OrganizationLoyaltySettings, error) {
|
||
|
|
s := f.s
|
||
|
|
return &s, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// walletMoveDB opens TEST_DATABASE_URL and creates an organization with two customers,
|
||
|
|
// removed again when the test ends. See internal/repository/wallet_repository_test.go.
|
||
|
|
func walletMoveDB(t *testing.T) (db *gorm.DB, org, a, b uuid.UUID) {
|
||
|
|
t.Helper()
|
||
|
|
dsn := os.Getenv("TEST_DATABASE_URL")
|
||
|
|
if dsn == "" {
|
||
|
|
t.Skip("TEST_DATABASE_URL not set")
|
||
|
|
}
|
||
|
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
org, a, b = uuid.New(), uuid.New(), uuid.New()
|
||
|
|
phoneA, phoneB := "08"+a.String()[:10], "08"+b.String()[:10]
|
||
|
|
require.NoError(t, db.Exec(`INSERT INTO organizations (id, name, plan_type) VALUES (?, 'wallet move test', 'basic')`, org).Error)
|
||
|
|
require.NoError(t, db.Exec(`INSERT INTO customers (id, organization_id, name, phone_number) VALUES (?, ?, 'Anita', ?), (?, ?, 'Budi Santoso', ?)`,
|
||
|
|
a, org, phoneA, b, org, phoneB).Error)
|
||
|
|
customers := []uuid.UUID{a, b}
|
||
|
|
t.Cleanup(func() {
|
||
|
|
db.Exec(`DELETE FROM wallet_lot_allocations WHERE lot_id IN (SELECT id FROM wallet_lots WHERE customer_id IN ?)`, customers)
|
||
|
|
db.Exec(`DELETE FROM wallet_lots WHERE customer_id IN ? AND origin_lot_id IS NOT NULL`, customers)
|
||
|
|
db.Exec(`DELETE FROM wallet_lots WHERE customer_id IN ?`, customers)
|
||
|
|
db.Exec(`DELETE FROM wallet_transactions WHERE customer_id IN ?`, customers)
|
||
|
|
db.Exec(`DELETE FROM customer_wallets WHERE customer_id IN ?`, customers)
|
||
|
|
db.Exec(`DELETE FROM customers WHERE id IN ?`, customers)
|
||
|
|
db.Exec(`DELETE FROM organizations WHERE id = ?`, org)
|
||
|
|
})
|
||
|
|
return db, org, a, b
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWalletExchange_AgainstPostgres(t *testing.T) {
|
||
|
|
db, _, a, _ := walletMoveDB(t)
|
||
|
|
wallet := NewWalletProcessor(repository.NewWalletRepository(db))
|
||
|
|
txm := repository.NewTxManager(db)
|
||
|
|
settings := fixedOrganizationSettings{models.OrganizationLoyaltySettings{
|
||
|
|
Exchange: models.LoyaltyExchangeSettings{CoinAmount: 10, PointAmount: 3},
|
||
|
|
}}
|
||
|
|
p := NewWalletExchangeProcessor(repository.NewWalletMoveRepository(db), settings, repository.NewWalletQueryRepository(db),
|
||
|
|
&movePinFake{good: "482913"}, wallet, txm)
|
||
|
|
|
||
|
|
expiry := time.Now().Add(24 * time.Hour).Truncate(time.Second)
|
||
|
|
require.NoError(t, txm.WithTransaction(context.Background(), func(ctx context.Context) error {
|
||
|
|
in := earn(a, 30, &expiry)
|
||
|
|
in.Currency = constants.WalletCurrencyCoin
|
||
|
|
_, err := wallet.Credit(ctx, in)
|
||
|
|
return err
|
||
|
|
}))
|
||
|
|
|
||
|
|
res, err := p.Exchange(context.Background(), a, 20, "482913", "db-key", models.CustomerPinRequestInfo{})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, int64(6), res.Points)
|
||
|
|
assert.Equal(t, int64(10), res.CoinBalance)
|
||
|
|
assert.Equal(t, int64(6), res.PointBalance)
|
||
|
|
require.Len(t, res.Lots, 1)
|
||
|
|
require.NotNil(t, res.Lots[0].ExpiresAt)
|
||
|
|
assert.True(t, res.Lots[0].ExpiresAt.Equal(expiry))
|
||
|
|
|
||
|
|
// The retry reads the frozen rate back out of JSONB and replays.
|
||
|
|
again, err := p.Exchange(context.Background(), a, 20, "482913", "db-key", models.CustomerPinRequestInfo{})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, again.Replayed)
|
||
|
|
assert.Equal(t, int64(6), again.Points)
|
||
|
|
|
||
|
|
var rows int64
|
||
|
|
require.NoError(t, db.Raw(`SELECT COUNT(*) FROM wallet_transactions WHERE group_id = ?`, res.GroupID).Scan(&rows).Error)
|
||
|
|
assert.Equal(t, int64(2), rows)
|
||
|
|
}
|