order sagas
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/flow"
|
||||
)
|
||||
|
||||
func fullRegistry(t *testing.T, pub Publisher) *flow.Registry {
|
||||
t.Helper()
|
||||
reg := flow.NewRegistry()
|
||||
flow.RegisterBuiltinHooks(reg)
|
||||
RegisterFlowActions(reg, newPool(t), NewMockProvider())
|
||||
RegisterEmitHook(reg, pub)
|
||||
return reg
|
||||
}
|
||||
|
||||
func TestCapabilitiesIncludesPredicatesAndEmit(t *testing.T) {
|
||||
caps := fullRegistry(t, nil).Capabilities()
|
||||
|
||||
for _, want := range []string{"has_customer_email", "has_items", "is_captured", "not_captured", "has_open_balance"} {
|
||||
if !slices.Contains(caps.Predicates, want) {
|
||||
t.Errorf("predicates missing %q (got %v)", want, caps.Predicates)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(caps.Hooks, "amqp_emit") {
|
||||
t.Errorf("hooks missing amqp_emit (got %v)", caps.Hooks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsCapturedPredicateGatesStep(t *testing.T) {
|
||||
pool := newPool(t)
|
||||
reg := flow.NewRegistry()
|
||||
flow.RegisterBuiltinHooks(reg)
|
||||
RegisterFlowActions(reg, pool, NewMockProvider())
|
||||
eng := flow.NewEngine(reg, nil)
|
||||
|
||||
ran := false
|
||||
reg.Action("mark", func(_ context.Context, _ *flow.State, _ json.RawMessage) error { ran = true; return nil })
|
||||
|
||||
// Capture order 9001 via place-and-pay.
|
||||
def, _ := EmbeddedFlow("place-and-pay")
|
||||
paid := flow.NewState(9001, nil)
|
||||
paid.Vars[PlaceOrderVar] = placeMsg()
|
||||
if _, err := eng.Run(context.Background(), def, paid); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gated := &flow.Definition{Name: "g", Steps: []flow.Step{{Name: "m", Action: "mark", When: "is_captured"}}}
|
||||
if _, err := eng.Run(context.Background(), gated, flow.NewState(9001, nil)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ran {
|
||||
t.Fatal("is_captured should pass for a captured order")
|
||||
}
|
||||
|
||||
// Fresh (unplaced) order → is_captured false → step skipped.
|
||||
ran = false
|
||||
if _, err := eng.Run(context.Background(), gated, flow.NewState(9999, nil)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ran {
|
||||
t.Fatal("is_captured should skip for a new order")
|
||||
}
|
||||
}
|
||||
|
||||
type fakePublisher struct{ msgs []string }
|
||||
|
||||
func (f *fakePublisher) Publish(_, routingKey string, body []byte) error {
|
||||
f.msgs = append(f.msgs, routingKey+":"+string(body))
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestAmqpEmitHookPublishes(t *testing.T) {
|
||||
fp := &fakePublisher{}
|
||||
reg := flow.NewRegistry()
|
||||
RegisterEmitHook(reg, fp)
|
||||
reg.Action("noopact", func(_ context.Context, _ *flow.State, _ json.RawMessage) error { return nil })
|
||||
eng := flow.NewEngine(reg, nil)
|
||||
|
||||
def := &flow.Definition{Name: "e", Steps: []flow.Step{{
|
||||
Name: "s",
|
||||
Action: "noopact",
|
||||
Hooks: flow.Hooks{After: []flow.HookRef{{Type: "amqp_emit", Params: json.RawMessage(`{"routingKey":"k"}`)}}},
|
||||
}}}
|
||||
if _, err := eng.Run(context.Background(), def, flow.NewState(7, nil)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(fp.msgs) != 1 || !strings.HasPrefix(fp.msgs[0], "k:") {
|
||||
t.Fatalf("expected one message routed to k, got %v", fp.msgs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user