cart and checkout
This commit is contained in:
@@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -105,6 +107,12 @@ func (a *testProfileApplier) Apply(ctx context.Context, id uint64, msgs ...proto
|
||||
g.Checkouts = append(g.Checkouts, profile.LinkedCheckout{CheckoutId: m.CheckoutId, CartId: m.CartId})
|
||||
case *messages.LinkOrder:
|
||||
g.Orders = append(g.Orders, profile.LinkedOrder{OrderReference: m.OrderReference, CartId: m.CartId, Status: m.Status})
|
||||
case *messages.AnonymizeProfile:
|
||||
g.Name = ""
|
||||
g.Email = ""
|
||||
g.Phone = ""
|
||||
g.AvatarUrl = ""
|
||||
g.Addresses = nil
|
||||
}
|
||||
}
|
||||
return &actor.MutationResult[profile.ProfileGrain]{
|
||||
@@ -138,7 +146,7 @@ func testProfileID(t *testing.T, applier *testProfileApplier) string {
|
||||
func TestGetCustomer(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// Set up some profile data
|
||||
pid, _ := profile.ParseProfileId(id)
|
||||
@@ -173,7 +181,7 @@ func TestGetCustomer(t *testing.T) {
|
||||
|
||||
func TestGetCustomerNotFound(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// "nonexistent" is actually valid base62, so use an ID with characters outside the alphabet.
|
||||
req := httptest.NewRequest("GET", "/!invalid!", nil)
|
||||
@@ -188,7 +196,7 @@ func TestGetCustomerNotFound(t *testing.T) {
|
||||
func TestUpdateCustomer(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
body := `{"name": "Bob", "email": "bob@example.com", "phone": "+46701234567", "language": "sv", "currency": "SEK"}`
|
||||
req := httptest.NewRequest("PUT", fmt.Sprintf("/%s", id), strings.NewReader(body))
|
||||
@@ -224,7 +232,7 @@ func TestUpdateCustomer(t *testing.T) {
|
||||
func TestAddAddress(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
body := `{
|
||||
"label": "Home",
|
||||
@@ -266,7 +274,7 @@ func TestAddAddress(t *testing.T) {
|
||||
func TestAddAddressMissingRequired(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// Missing addressLine1
|
||||
body := `{"city": "Stockholm", "zip": "111 22", "country": "SE"}`
|
||||
@@ -283,7 +291,7 @@ func TestAddAddressMissingRequired(t *testing.T) {
|
||||
func TestUpdateAddress(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// First add an address
|
||||
pid, _ := profile.ParseProfileId(id)
|
||||
@@ -337,7 +345,7 @@ func TestUpdateAddress(t *testing.T) {
|
||||
func TestUpdateAddressInvalidID(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
body := `{"label": "New Home"}`
|
||||
req := httptest.NewRequest("PUT", fmt.Sprintf("/%s/addresses/abc", id), strings.NewReader(body))
|
||||
@@ -353,7 +361,7 @@ func TestUpdateAddressInvalidID(t *testing.T) {
|
||||
func TestRemoveAddress(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// First add an address
|
||||
pid, _ := profile.ParseProfileId(id)
|
||||
@@ -398,7 +406,7 @@ func TestRemoveAddressNotFound(t *testing.T) {
|
||||
applier.Get(context.Background(), uint64(pid))
|
||||
|
||||
id := pid.String()
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
req := httptest.NewRequest("DELETE", fmt.Sprintf("/%s/addresses/999", id), nil)
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
@@ -444,7 +452,7 @@ func TestRemoveAddressNotFoundMutation(t *testing.T) {
|
||||
|
||||
func TestCustomerHandlerInvalidID(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
handler := CustomerHandler(applier)
|
||||
handler := CustomerHandler(applier, "")
|
||||
|
||||
// Path "/" now has POST / registered (create customer), so GET / is 405.
|
||||
// Paths with invalid base62 characters should get 400.
|
||||
@@ -496,3 +504,72 @@ func TestCustomerHandlerThroughCombinedMount(t *testing.T) {
|
||||
t.Fatalf("expected id %q, got %q", id, resp.Id)
|
||||
}
|
||||
}
|
||||
|
||||
type testCredentialDeleter struct {
|
||||
deletedEmail string
|
||||
}
|
||||
|
||||
func (d *testCredentialDeleter) Delete(_ context.Context, email string) (bool, error) {
|
||||
d.deletedEmail = email
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func TestDeleteCustomer(t *testing.T) {
|
||||
applier := newTestProfileApplier()
|
||||
id := testProfileID(t, applier)
|
||||
deleter := &testCredentialDeleter{}
|
||||
auditPath := filepath.Join(t.TempDir(), "audit.log")
|
||||
handler := CustomerHandler(applier, auditPath, deleter)
|
||||
|
||||
// Set up some profile data
|
||||
pid, _ := profile.ParseProfileId(id)
|
||||
applier.Apply(context.Background(), uint64(pid), &messages.SetProfile{
|
||||
Name: proto.String("Alice"),
|
||||
Email: proto.String("alice@example.com"),
|
||||
})
|
||||
applier.Apply(context.Background(), uint64(pid), &messages.AddAddress{
|
||||
Address: &messages.Address{
|
||||
Label: "Home",
|
||||
AddressLine1: "Storgatan 1",
|
||||
City: "Stockholm",
|
||||
Zip: "111 22",
|
||||
Country: "SE",
|
||||
},
|
||||
})
|
||||
|
||||
// DELETE /customers/{id}
|
||||
req := httptest.NewRequest("DELETE", fmt.Sprintf("/%s", id), nil)
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNoContent {
|
||||
t.Fatalf("expected 204 No Content, got %d. Body: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
// Verify credentials deleted
|
||||
if deleter.deletedEmail != "alice@example.com" {
|
||||
t.Fatalf("expected deleted email 'alice@example.com', got %q", deleter.deletedEmail)
|
||||
}
|
||||
|
||||
// Verify profile is anonymized
|
||||
g, _ := applier.Get(context.Background(), uint64(pid))
|
||||
if g.Name != "" || g.Email != "" || g.Addresses != nil {
|
||||
t.Fatalf("expected profile to be anonymized, got Name=%q, Email=%q, Addresses=%v", g.Name, g.Email, g.Addresses)
|
||||
}
|
||||
|
||||
// Verify audit log has the correct entry and no PII
|
||||
logBytes, err := os.ReadFile(auditPath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read audit log: %v", err)
|
||||
}
|
||||
logContent := string(logBytes)
|
||||
if !strings.Contains(logContent, "ACTION=GDPR_ERASURE") {
|
||||
t.Fatal("expected audit log to record erasure action")
|
||||
}
|
||||
if !strings.Contains(logContent, "PROFILE_ID="+id) {
|
||||
t.Fatal("expected audit log to record profile ID")
|
||||
}
|
||||
if strings.Contains(logContent, "Alice") || strings.Contains(logContent, "alice@example.com") {
|
||||
t.Fatal("expected audit log to exclude PII")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user