owpengram-server/internal/app/stars/service_test.go

137 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package stars
import (
"context"
"errors"
"testing"
"telesrv/internal/domain"
"telesrv/internal/store/memory"
)
func newTestService(grant int64) *Service {
return NewService(memory.NewStarsStore(), WithStartingGrant(grant))
}
// 起始授予幂等:多次 GetBalance 只授予一次。
func TestStartingGrantOnce(t *testing.T) {
svc := newTestService(1000)
ctx := context.Background()
bal, err := svc.GetBalance(ctx, 7)
if err != nil {
t.Fatalf("GetBalance: %v", err)
}
if bal.Balance != 1000 || !bal.Granted {
t.Fatalf("first balance = %+v, want 1000 granted", bal)
}
// 再读不应重复授予。
bal2, err := svc.GetBalance(ctx, 7)
if err != nil {
t.Fatalf("GetBalance#2: %v", err)
}
if bal2.Balance != 1000 {
t.Fatalf("second balance = %d, want 1000 (no double grant)", bal2.Balance)
}
// 流水里应恰有一条 grant。
page, err := svc.ListTransactions(ctx, 7, "", 100)
if err != nil {
t.Fatalf("ListTransactions: %v", err)
}
if len(page.Transactions) != 1 || page.Transactions[0].Reason != domain.StarsReasonGrant || page.Transactions[0].Amount != 1000 {
t.Fatalf("grant txns = %+v, want one +1000 grant", page.Transactions)
}
}
// 关闭授予grant=0时余额为 0、无 grant 流水。
func TestGrantDisabled(t *testing.T) {
svc := newTestService(0)
bal, err := svc.GetBalance(context.Background(), 9)
if err != nil {
t.Fatalf("GetBalance: %v", err)
}
if bal.Balance != 0 || bal.Granted {
t.Fatalf("balance = %+v, want 0 not granted", bal)
}
}
// 借记成功扣减余额并写负流水;余额不足返回 ErrStarsInsufficient 且不动账。
func TestDebitAndInsufficient(t *testing.T) {
svc := newTestService(1000)
ctx := context.Background()
peer := domain.Peer{Type: domain.PeerTypeChannel, ID: 555}
bal, err := svc.Debit(ctx, 7, 300, domain.StarsReasonReaction, peer, "paid reaction", "")
if err != nil {
t.Fatalf("Debit: %v", err)
}
if bal.Balance != 700 {
t.Fatalf("after debit = %d, want 700", bal.Balance)
}
// 余额不足。
if _, err := svc.Debit(ctx, 7, 10_000, domain.StarsReasonReaction, peer, "", ""); !errors.Is(err, domain.ErrStarsInsufficient) {
t.Fatalf("over-debit err = %v, want ErrStarsInsufficient", err)
}
// 余额未被改动。
after, _ := svc.GetBalance(ctx, 7)
if after.Balance != 700 {
t.Fatalf("balance after failed debit = %d, want 700 unchanged", after.Balance)
}
// 非法金额。
if _, err := svc.Debit(ctx, 7, 0, domain.StarsReasonReaction, peer, "", ""); !errors.Is(err, domain.ErrStarsInvalidAmount) {
t.Fatalf("zero debit err = %v, want ErrStarsInvalidAmount", err)
}
}
// 贷记增加余额并写正流水。
func TestCredit(t *testing.T) {
svc := newTestService(0) // 关闭起始授予,单测贷记
ctx := context.Background()
bal, err := svc.Credit(ctx, 7, 250, domain.StarsReasonTopup, domain.Peer{}, "topup", "")
if err != nil {
t.Fatalf("Credit: %v", err)
}
if bal.Balance != 250 {
t.Fatalf("after credit = %d, want 250", bal.Balance)
}
}
// keyset 分页:末页 NextOffset 必须为空(否则客户端死循环)。
func TestListTransactionsPagination(t *testing.T) {
svc := newTestService(0)
ctx := context.Background()
for i := 0; i < 5; i++ {
if _, err := svc.Credit(ctx, 7, int64(10+i), domain.StarsReasonTopup, domain.Peer{}, "", ""); err != nil {
t.Fatalf("Credit#%d: %v", i, err)
}
}
page1, err := svc.ListTransactions(ctx, 7, "", 2)
if err != nil {
t.Fatalf("page1: %v", err)
}
if len(page1.Transactions) != 2 || page1.NextOffset == "" {
t.Fatalf("page1 = %d txns next=%q, want 2 + nonempty next", len(page1.Transactions), page1.NextOffset)
}
// 倒序最新id 最大amount=14在前。
if page1.Transactions[0].Amount != 14 {
t.Fatalf("page1[0].Amount = %d, want 14 (newest first)", page1.Transactions[0].Amount)
}
page2, err := svc.ListTransactions(ctx, 7, page1.NextOffset, 2)
if err != nil {
t.Fatalf("page2: %v", err)
}
if len(page2.Transactions) != 2 {
t.Fatalf("page2 = %d txns, want 2", len(page2.Transactions))
}
page3, err := svc.ListTransactions(ctx, 7, page2.NextOffset, 2)
if err != nil {
t.Fatalf("page3: %v", err)
}
if len(page3.Transactions) != 1 {
t.Fatalf("page3 = %d txns, want 1 (last)", len(page3.Transactions))
}
if page3.NextOffset != "" {
t.Fatalf("last page NextOffset = %q, want empty (no infinite paging)", page3.NextOffset)
}
}