better ucp conformance
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
package ucp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/actor"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/cart"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/checkout"
|
||||
checkoutMessages "git.k6n.net/mats/go-cart-actor/proto/checkout"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type testCheckoutApplier struct {
|
||||
grains map[uint64]*checkout.CheckoutGrain
|
||||
}
|
||||
|
||||
func newTestCheckoutApplier() *testCheckoutApplier {
|
||||
return &testCheckoutApplier{
|
||||
grains: make(map[uint64]*checkout.CheckoutGrain),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *testCheckoutApplier) Get(_ context.Context, id uint64) (*checkout.CheckoutGrain, error) {
|
||||
g, ok := a.grains[id]
|
||||
if !ok {
|
||||
g = checkout.NewCheckoutGrain(id, 0, 0, time.UnixMilli(1000000), nil)
|
||||
a.grains[id] = g
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (a *testCheckoutApplier) Apply(ctx context.Context, id uint64, msgs ...proto.Message) (*actor.MutationResult[checkout.CheckoutGrain], error) {
|
||||
g, err := a.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
switch m := msg.(type) {
|
||||
case *checkoutMessages.InitializeCheckout:
|
||||
g.CartId = cart.CartId(m.CartId)
|
||||
}
|
||||
}
|
||||
return &actor.MutationResult[checkout.CheckoutGrain]{
|
||||
Result: *g,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestCheckoutHandler_CreateWithCartId(t *testing.T) {
|
||||
// Start a mock Cart server.
|
||||
mockCartServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.URL.Path, "/cart/byid/") {
|
||||
t.Errorf("expected path to contain /cart/byid/, got %q", r.URL.Path)
|
||||
}
|
||||
// Return dummy cart state bytes.
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{}`))
|
||||
}))
|
||||
defer mockCartServer.Close()
|
||||
|
||||
os.Setenv("CART_INTERNAL_URL", mockCartServer.URL)
|
||||
defer os.Unsetenv("CART_INTERNAL_URL")
|
||||
|
||||
applier := newTestCheckoutApplier()
|
||||
handler := CheckoutHandler(applier)
|
||||
|
||||
// Create a dummy cart ID.
|
||||
dummyCartId, _ := cart.NewCartId()
|
||||
|
||||
reqBody := fmt.Sprintf(`{"cartId": %q}`, dummyCartId.String())
|
||||
req := httptest.NewRequest("POST", "/", strings.NewReader(reqBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("expected 201 Created, got %d. Body: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
var resp CheckoutResponse
|
||||
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
if resp.Id == "" {
|
||||
t.Fatal("expected non-empty checkout session id")
|
||||
}
|
||||
if resp.CartId != dummyCartId.String() {
|
||||
t.Fatalf("expected cartId %q, got %q", dummyCartId.String(), resp.CartId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckoutHandler_CreateWithLineItemsFallback(t *testing.T) {
|
||||
// Start a mock Cart server that supports both creating a cart and getting it.
|
||||
var createdCartId cart.CartId
|
||||
mockCartServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "POST" && strings.Contains(r.URL.Path, "/ucp/v1/carts/") {
|
||||
var err error
|
||||
createdCartId, err = cart.NewCartId()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(fmt.Sprintf(`{"id": %q, "status": "active"}`, createdCartId.String())))
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == "GET" && strings.Contains(r.URL.Path, "/cart/byid/") {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{}`))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
defer mockCartServer.Close()
|
||||
|
||||
os.Setenv("CART_INTERNAL_URL", mockCartServer.URL)
|
||||
defer os.Unsetenv("CART_INTERNAL_URL")
|
||||
|
||||
applier := newTestCheckoutApplier()
|
||||
handler := CheckoutHandler(applier)
|
||||
|
||||
// POST with line_items and no cartId.
|
||||
reqBody := `{"line_items": [{"sku": "SKU123", "quantity": 2}]}`
|
||||
req := httptest.NewRequest("POST", "/", strings.NewReader(reqBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("expected 201 Created, got %d. Body: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
var resp CheckoutResponse
|
||||
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
if resp.Id == "" {
|
||||
t.Fatal("expected non-empty checkout session id")
|
||||
}
|
||||
if resp.CartId != createdCartId.String() {
|
||||
t.Fatalf("expected cartId %q to match created implicit cart %q", resp.CartId, createdCartId.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user