Allow zero coin game outbox events
This commit is contained in:
parent
d2dbc88e5f
commit
1b8241c3d2
@ -40,18 +40,8 @@ type GameOutboxMessage struct {
|
|||||||
// EncodeGameOutboxMessage serializes a game fact for fanout through RocketMQ.
|
// EncodeGameOutboxMessage serializes a game fact for fanout through RocketMQ.
|
||||||
func EncodeGameOutboxMessage(message GameOutboxMessage) ([]byte, error) {
|
func EncodeGameOutboxMessage(message GameOutboxMessage) ([]byte, error) {
|
||||||
message.MessageType = MessageTypeGameOutboxEvent
|
message.MessageType = MessageTypeGameOutboxEvent
|
||||||
if strings.TrimSpace(message.AppCode) == "" ||
|
if err := validateGameOutboxMessage(message); err != nil {
|
||||||
strings.TrimSpace(message.EventID) == "" ||
|
return nil, err
|
||||||
strings.TrimSpace(message.EventType) == "" ||
|
|
||||||
strings.TrimSpace(message.GameID) == "" ||
|
|
||||||
message.OccurredAtMS <= 0 {
|
|
||||||
return nil, errors.New("game outbox message is incomplete")
|
|
||||||
}
|
|
||||||
if message.EventType == EventTypeGameOrderSettled && (strings.TrimSpace(message.OrderID) == "" ||
|
|
||||||
message.UserID <= 0 ||
|
|
||||||
strings.TrimSpace(message.OpType) == "" ||
|
|
||||||
message.CoinAmount <= 0) {
|
|
||||||
return nil, errors.New("game order outbox message is incomplete")
|
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(message.PayloadJSON) == "" {
|
if strings.TrimSpace(message.PayloadJSON) == "" {
|
||||||
message.PayloadJSON = "{}"
|
message.PayloadJSON = "{}"
|
||||||
@ -68,21 +58,30 @@ func DecodeGameOutboxMessage(body []byte) (GameOutboxMessage, error) {
|
|||||||
if message.MessageType != MessageTypeGameOutboxEvent {
|
if message.MessageType != MessageTypeGameOutboxEvent {
|
||||||
return GameOutboxMessage{}, errors.New("unexpected game outbox message_type")
|
return GameOutboxMessage{}, errors.New("unexpected game outbox message_type")
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(message.AppCode) == "" ||
|
if err := validateGameOutboxMessage(message); err != nil {
|
||||||
strings.TrimSpace(message.EventID) == "" ||
|
return GameOutboxMessage{}, err
|
||||||
strings.TrimSpace(message.EventType) == "" ||
|
|
||||||
strings.TrimSpace(message.GameID) == "" ||
|
|
||||||
message.OccurredAtMS <= 0 {
|
|
||||||
return GameOutboxMessage{}, errors.New("game outbox message is incomplete")
|
|
||||||
}
|
|
||||||
if message.EventType == EventTypeGameOrderSettled && (strings.TrimSpace(message.OrderID) == "" ||
|
|
||||||
message.UserID <= 0 ||
|
|
||||||
strings.TrimSpace(message.OpType) == "" ||
|
|
||||||
message.CoinAmount <= 0) {
|
|
||||||
return GameOutboxMessage{}, errors.New("game order outbox message is incomplete")
|
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(message.PayloadJSON) == "" {
|
if strings.TrimSpace(message.PayloadJSON) == "" {
|
||||||
message.PayloadJSON = "{}"
|
message.PayloadJSON = "{}"
|
||||||
}
|
}
|
||||||
return message, nil
|
return message, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateGameOutboxMessage(message GameOutboxMessage) error {
|
||||||
|
if strings.TrimSpace(message.AppCode) == "" ||
|
||||||
|
strings.TrimSpace(message.EventID) == "" ||
|
||||||
|
strings.TrimSpace(message.EventType) == "" ||
|
||||||
|
strings.TrimSpace(message.GameID) == "" ||
|
||||||
|
message.OccurredAtMS <= 0 {
|
||||||
|
return errors.New("game outbox message is incomplete")
|
||||||
|
}
|
||||||
|
if message.EventType == EventTypeGameOrderSettled && (strings.TrimSpace(message.OrderID) == "" ||
|
||||||
|
message.UserID <= 0 ||
|
||||||
|
strings.TrimSpace(message.OpType) == "" ||
|
||||||
|
message.CoinAmount < 0) {
|
||||||
|
// 厂商可能发送 0 金额派奖或 0 金额结算确认;这类订单是已落库事实,必须允许 MQ 投递。
|
||||||
|
// 负数仍然不是合法订单金额,扣减方向必须由 op_type=debit 表达,不能把符号塞进金额字段。
|
||||||
|
return errors.New("game order outbox message is incomplete")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
67
pkg/gamemq/messages_test.go
Normal file
67
pkg/gamemq/messages_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package gamemq
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestEncodeGameOutboxMessageAllowsZeroCoinGameOrder(t *testing.T) {
|
||||||
|
message := GameOutboxMessage{
|
||||||
|
AppCode: "lalu",
|
||||||
|
EventID: "GameOrderSettled:gord_zero_credit",
|
||||||
|
EventType: EventTypeGameOrderSettled,
|
||||||
|
OrderID: "gord_zero_credit",
|
||||||
|
UserID: 42,
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
GameID: "1021",
|
||||||
|
OpType: "credit",
|
||||||
|
CoinAmount: 0,
|
||||||
|
OccurredAtMS: 1781199149295,
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := EncodeGameOutboxMessage(message)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("zero coin game order should be publishable: %v", err)
|
||||||
|
}
|
||||||
|
decoded, err := DecodeGameOutboxMessage(body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("zero coin game order should be decodable: %v", err)
|
||||||
|
}
|
||||||
|
if decoded.CoinAmount != 0 || decoded.PayloadJSON != "{}" {
|
||||||
|
t.Fatalf("decoded zero coin order mismatch: %+v", decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeGameOutboxMessageRejectsNegativeGameOrderAmount(t *testing.T) {
|
||||||
|
_, err := EncodeGameOutboxMessage(GameOutboxMessage{
|
||||||
|
AppCode: "lalu",
|
||||||
|
EventID: "GameOrderSettled:gord_negative",
|
||||||
|
EventType: EventTypeGameOrderSettled,
|
||||||
|
OrderID: "gord_negative",
|
||||||
|
UserID: 42,
|
||||||
|
PlatformCode: "zeeone",
|
||||||
|
GameID: "1021",
|
||||||
|
OpType: "credit",
|
||||||
|
CoinAmount: -1,
|
||||||
|
OccurredAtMS: 1781199149295,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("negative game order amount should be rejected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeGameOutboxMessageAllowsSelfGameEventWithoutOrderFields(t *testing.T) {
|
||||||
|
body, err := EncodeGameOutboxMessage(GameOutboxMessage{
|
||||||
|
AppCode: "lalu",
|
||||||
|
EventID: "SelfGameMatchSettled:match_1",
|
||||||
|
EventType: EventTypeSelfGameMatchSettled,
|
||||||
|
UserID: 42,
|
||||||
|
PlatformCode: "self",
|
||||||
|
GameID: "dice",
|
||||||
|
PayloadJSON: `{"match_id":"match_1"}`,
|
||||||
|
OccurredAtMS: 1781199149295,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("self game fact should not require order fields: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := DecodeGameOutboxMessage(body); err != nil {
|
||||||
|
t.Fatalf("self game fact should decode: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user