cart and checkout
This commit is contained in:
+50
-12
@@ -3,14 +3,19 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/actor"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/idempotency"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/flow"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/order"
|
||||
)
|
||||
|
||||
func testApplier(t *testing.T) *orderedApplier {
|
||||
func testServer(t *testing.T) *server {
|
||||
t.Helper()
|
||||
reg := actor.NewMutationRegistry()
|
||||
order.RegisterMutations(reg)
|
||||
@@ -32,23 +37,56 @@ func testApplier(t *testing.T) *orderedApplier {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(pool.Close)
|
||||
return &orderedApplier{pool: pool, storage: storage}
|
||||
|
||||
applier := &orderedApplier{pool: pool, storage: storage}
|
||||
provider := order.NewPassthroughProvider("legacy", "ref", 15000)
|
||||
|
||||
freg := flow.NewRegistry()
|
||||
flow.RegisterBuiltinHooks(freg)
|
||||
order.RegisterFlowActions(freg, applier, provider)
|
||||
order.RegisterEmitHook(freg, nil)
|
||||
engine := flow.NewEngine(freg, slog.New(slog.NewTextHandler(io.Discard, nil)))
|
||||
|
||||
def, err := order.EmbeddedFlow("place-and-pay")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
idem, err := idempotency.Open(filepath.Join(t.TempDir(), "idem.log"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &server{
|
||||
pool: pool, applier: applier, storage: storage, reg: reg,
|
||||
engine: engine, freg: freg,
|
||||
flows: &flowStore{defs: map[string]*flow.Definition{def.Name: def}},
|
||||
provider: provider, taxProvider: order.NewStaticTaxProvider(),
|
||||
defaultFlow: def.Name, idem: idem, logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngestLegacyOrder(t *testing.T) {
|
||||
app := testApplier(t)
|
||||
func TestIngestOrderFromQueue(t *testing.T) {
|
||||
s := testServer(t)
|
||||
ctx := context.Background()
|
||||
body := []byte(`{
|
||||
"order_id":"K-1","purchase_currency":"SEK","purchase_country":"se","locale":"sv-SE",
|
||||
"order_amount":15000,"order_tax_amount":3000,
|
||||
"order_lines":[{"reference":"l1","name":"Widget","quantity":1,"unit_price":15000,"tax_rate":25,"total_amount":15000,"total_tax_amount":3000}]
|
||||
"checkoutId":"K-1","idempotencyKey":"checkout-K-1","cartId":"cart-1",
|
||||
"currency":"SEK","country":"SE","customerEmail":"customer@example.com",
|
||||
"lines":[{"reference":"l1","sku":"l1","name":"Widget","quantity":1,"unitPrice":15000,"taxRate":25}],
|
||||
"payment":{"provider":"klarna","reference":"ref-123","amount":15000}
|
||||
}`)
|
||||
|
||||
if err := ingestLegacyOrder(ctx, app, body); err != nil {
|
||||
if err := ingestOrderFromQueue(ctx, s, body); err != nil {
|
||||
t.Fatalf("ingest: %v", err)
|
||||
}
|
||||
id := legacyOrderID("K-1")
|
||||
g, err := app.Get(ctx, id)
|
||||
|
||||
// Retrieve the created order grain. The new order ID is recorded in idempotency.Store
|
||||
id, ok := s.idem.Get("checkout-K-1")
|
||||
if !ok {
|
||||
t.Fatalf("expected order ID to be stored in idempotency cache")
|
||||
}
|
||||
|
||||
g, err := s.applier.Get(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -60,10 +98,10 @@ func TestIngestLegacyOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
// Redelivery must be idempotent — no double capture, no new payment.
|
||||
if err := ingestLegacyOrder(ctx, app, body); err != nil {
|
||||
if err := ingestOrderFromQueue(ctx, s, body); err != nil {
|
||||
t.Fatalf("re-ingest: %v", err)
|
||||
}
|
||||
g2, _ := app.Get(ctx, id)
|
||||
g2, _ := s.applier.Get(ctx, id)
|
||||
if g2.CapturedAmount != 15000 {
|
||||
t.Fatalf("redelivery double-captured: %d", g2.CapturedAmount)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user