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) } }