diff --git a/pkg/cart/mutation_test.go b/pkg/cart/mutation_test.go index 0ef7063..302045c 100644 --- a/pkg/cart/mutation_test.go +++ b/pkg/cart/mutation_test.go @@ -2,6 +2,8 @@ package cart import ( "context" + "encoding/json" + "fmt" "reflect" "slices" "strings" @@ -9,7 +11,6 @@ import ( "time" "github.com/gogo/protobuf/proto" - anypb "google.golang.org/protobuf/types/known/anypb" "git.tornberg.me/go-cart-actor/pkg/actor" messages "git.tornberg.me/go-cart-actor/pkg/messages" @@ -462,12 +463,12 @@ func TestSubscriptionDetailsJSONValidation(t *testing.T) { g := newTestGrain() // Valid JSON on create - validCreate := &messages.UpsertSubscriptionDetails{ - OfferingCode: "OFFJSON", - SigningType: "TYPEJSON", - Data: &anypb.Any{Value: []byte(`{"ok":true}`)}, + jsonStr := `{"offeringCode": "OFFJSON", "signingType": "TYPEJSON", "data": {"value": "eyJvayI6dHJ1ZX0="}}` + var validCreate messages.UpsertSubscriptionDetails + if err := json.Unmarshal([]byte(jsonStr), &validCreate); err != nil { + t.Fatal(err) } - applyOK(t, reg, g, validCreate) + applyOK(t, reg, g, &validCreate) if len(g.SubscriptionDetails) != 1 { t.Fatalf("expected one subscription detail after valid create, got %d", len(g.SubscriptionDetails)) } @@ -480,41 +481,45 @@ func TestSubscriptionDetailsJSONValidation(t *testing.T) { } // Update with valid JSON replaces meta - updateValid := &messages.UpsertSubscriptionDetails{ - Id: &id, - Data: &anypb.Any{Value: []byte(`{"changed":123}`)}, + jsonStr2 := fmt.Sprintf(`{"id": "%s", "data": {"value": "eyJjaGFuZ2VkIjoxMjN9"}}`, id) + var updateValid messages.UpsertSubscriptionDetails + if err := json.Unmarshal([]byte(jsonStr2), &updateValid); err != nil { + t.Fatal(err) } - applyOK(t, reg, g, updateValid) + applyOK(t, reg, g, &updateValid) if string(g.SubscriptionDetails[id].Meta) != `{"changed":123}` { t.Fatalf("expected meta updated to new json, got %s", string(g.SubscriptionDetails[id].Meta)) } // Invalid JSON on create - invalidCreate := &messages.UpsertSubscriptionDetails{ - OfferingCode: "BAD", - Data: &anypb.Any{Value: []byte(`{"broken":}`)}, + jsonStr3 := `{"offeringCode": "BAD", "signingType": "TYPE", "data": {"value": "eyJicm9rZW4iO30="}}` + var invalidCreate messages.UpsertSubscriptionDetails + if err := json.Unmarshal([]byte(jsonStr3), &invalidCreate); err != nil { + t.Fatal(err) } - res := applyOne(t, reg, g, invalidCreate) + res := applyOne(t, reg, g, &invalidCreate) if res.Error == nil || !strings.Contains(res.Error.Error(), "invalid json") { t.Fatalf("expected invalid json error on create, got %v", res.Error) } // Invalid JSON on update - badUpdate := &messages.UpsertSubscriptionDetails{ - Id: &id, - Data: &anypb.Any{Value: []byte(`{oops`)}, + jsonStr4 := fmt.Sprintf(`{"id": "%s", "data": {"value": "e29vcHM="}}`, id) + var badUpdate messages.UpsertSubscriptionDetails + if err := json.Unmarshal([]byte(jsonStr4), &badUpdate); err != nil { + t.Fatal(err) } - res2 := applyOne(t, reg, g, badUpdate) + res2 := applyOne(t, reg, g, &badUpdate) if res2.Error == nil || !strings.Contains(res2.Error.Error(), "invalid json") { t.Fatalf("expected invalid json error on update, got %v", res2.Error) } - // Empty Data.Value should not overwrite existing meta - emptyUpdate := &messages.UpsertSubscriptionDetails{ - Id: &id, - Data: &anypb.Any{Value: []byte{}}, + // Empty Data should not overwrite existing meta + jsonStr5 := fmt.Sprintf(`{"id": "%s", "data": {"value": ""}}`, id) + var emptyUpdate messages.UpsertSubscriptionDetails + if err := json.Unmarshal([]byte(jsonStr5), &emptyUpdate); err != nil { + t.Fatal(err) } - applyOK(t, reg, g, emptyUpdate) + applyOK(t, reg, g, &emptyUpdate) if string(g.SubscriptionDetails[id].Meta) != `{"changed":123}` { t.Fatalf("empty update should not change meta, got %s", string(g.SubscriptionDetails[id].Meta)) } diff --git a/pkg/cart/mutation_upsert_subscriptiondetails.go b/pkg/cart/mutation_upsert_subscriptiondetails.go index 102e547..308f0a7 100644 --- a/pkg/cart/mutation_upsert_subscriptiondetails.go +++ b/pkg/cart/mutation_upsert_subscriptiondetails.go @@ -5,6 +5,7 @@ import ( "fmt" messages "git.tornberg.me/go-cart-actor/pkg/messages" + "google.golang.org/protobuf/types/known/anypb" ) func UpsertSubscriptionDetails(g *CartGrain, m *messages.UpsertSubscriptionDetails) error { @@ -12,15 +13,33 @@ func UpsertSubscriptionDetails(g *CartGrain, m *messages.UpsertSubscriptionDetai return nil } + // Helper to get data bytes from Data field + getDataBytes := func(data *anypb.Any) ([]byte, error) { + if data == nil { + return nil, nil + } + if len(data.Value) > 0 { + return data.Value, nil + } + if data.TypeUrl != "" { + return []byte(data.TypeUrl), nil + } + return nil, nil + } + // Create new subscription details when Id is nil. if m.Id == nil { // Validate JSON if provided. var meta json.RawMessage - if m.Data != nil && len(m.Data.Value) > 0 { - if !json.Valid(m.Data.Value) { + dataBytes, err := getDataBytes(m.Data) + if err != nil { + return err + } + if dataBytes != nil { + if !json.Valid(dataBytes) { return fmt.Errorf("subscription details invalid json") } - meta = json.RawMessage(m.Data.Value) + meta = json.RawMessage(dataBytes) } id := MustNewCartId().String() @@ -49,15 +68,16 @@ func UpsertSubscriptionDetails(g *CartGrain, m *messages.UpsertSubscriptionDetai existing.SigningType = m.SigningType changed = true } - if m.Data != nil { - // Only validate & assign if there is content; empty -> leave as-is. - if len(m.Data.Value) > 0 { - if !json.Valid(m.Data.Value) { - return fmt.Errorf("subscription details invalid json") - } - existing.Meta = m.Data.Value - changed = true + dataBytes, err := getDataBytes(m.Data) + if err != nil { + return err + } + if dataBytes != nil { + if !json.Valid(dataBytes) { + return fmt.Errorf("subscription details invalid json") } + existing.Meta = dataBytes + changed = true } if changed { existing.Version++