99 lines
3.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 mysql
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"hyapp/pkg/walletmq"
)
func TestResourceOutboxEventsUseStableEventIDAsTransactionID(t *testing.T) {
// 这些是当前所有通过 resourceOutboxEvent 创建的资源事实helper 对事件类型
// 本身无分支,因此该约束也自动覆盖以后接入同一入口的新资源事实。
eventTypes := []string{
"GiftConfigChanged",
"ResourceChanged",
"ResourceGrantRevoked",
"ResourceGranted",
"ResourceGroupChanged",
"ResourceGroupGranted",
"UserResourceChanged",
"VipEffectiveChanged",
"VipTrialCardGranted",
}
for _, eventType := range eventTypes {
t.Run(eventType, func(t *testing.T) {
first := resourceOutboxEvent(eventType, "command-1", 1001, 2001, map[string]any{"source": "test"}, 1_700_000_000_000)
second := resourceOutboxEvent(eventType, "command-1", 1001, 2001, map[string]any{"source": "retry"}, 1_700_000_000_999)
if first.TransactionID == "" || first.TransactionID != first.EventID {
t.Fatalf("resource correlation ids mismatch: event_id=%q transaction_id=%q", first.EventID, first.TransactionID)
}
if second.EventID != first.EventID || second.TransactionID != first.TransactionID {
t.Fatalf("resource correlation id changed on retry: first=%+v second=%+v", first, second)
}
if len(first.TransactionID) > 96 {
t.Fatalf("resource transaction_id exceeds wallet_outbox column: %d", len(first.TransactionID))
}
if _, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{
AppCode: "lalu",
EventID: first.EventID,
EventType: first.EventType,
TransactionID: first.TransactionID,
CommandID: first.CommandID,
UserID: first.UserID,
AssetType: first.AssetType,
PayloadJSON: `{"source":"test"}`,
OccurredAtMS: first.CreatedAtMS,
}); err != nil {
t.Fatalf("resource event is still rejected by wallet MQ encoder: %v", err)
}
})
}
}
func TestResourceOutboxHistoricalRetryIsOptInAndNarrowlyScoped(t *testing.T) {
_, file, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("resolve test source path")
}
path := filepath.Join(filepath.Dir(file), "../../../deploy/mysql/maintenance/20260711_retry_incomplete_resource_outbox.sql")
body, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read resource outbox maintenance SQL: %v", err)
}
sql := string(body)
for _, required := range []string{
"COALESCE(@execute_wallet_resource_outbox_retry, 0)",
"WHERE @execute_wallet_resource_outbox_retry = 1",
"AND wo.asset_type = 'RESOURCE'",
"AND wo.transaction_id = ''",
"AND BINARY wo.last_error = BINARY 'wallet outbox message is incomplete'",
"AND wo.status IN ('failed', 'retryable')",
"LIMIT 100",
"SET wo.transaction_id = wo.event_id",
"wo.status = 'pending'",
} {
if !strings.Contains(sql, required) {
t.Fatalf("maintenance SQL misses safety contract %q", required)
}
}
for _, eventType := range []string{
"GiftConfigChanged",
"ResourceChanged",
"ResourceGrantRevoked",
"ResourceGranted",
"ResourceGroupChanged",
"ResourceGroupGranted",
"UserResourceChanged",
"VipEffectiveChanged",
"VipTrialCardGranted",
} {
if !strings.Contains(sql, "'"+eventType+"'") {
t.Fatalf("maintenance SQL misses resource event type %q", eventType)
}
}
}