Skip to content

Commit 4c32e19

Browse files
committed
fix: validate payment handler structure from profile instead of hardcoded list
Replace hardcoded expected handler IDs (google_pay, mock_payment_handler, shop_pay) with structural validation that: - Discovers handlers from the business profile dynamically - Validates required fields (id, version) are present - Validates handler group names follow reverse-DNS convention - Works against any UCP merchant, not just the Flower Shop This makes the protocol conformance tests server-agnostic. Addresses #13
1 parent 7ca5aee commit 4c32e19

1 file changed

Lines changed: 34 additions & 27 deletions

File tree

protocol_test.py

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from absl.testing import absltest
1818
import integration_test_utils
1919
import httpx
20-
from ucp_sdk.models.schemas.ucp import BusinessSchema
20+
from ucp_sdk.models.schemas.ucp import BusinessSchema, ReverseDomainName
2121
from ucp_sdk.models.schemas.shopping import checkout as checkout
2222
from ucp_sdk.models.schemas.shopping.payment import (
2323
Payment,
@@ -180,32 +180,39 @@ def test_discovery(self):
180180
f"Missing expected capabilities in discovery: {missing_caps}",
181181
)
182182

183-
# Verify Payment Handlers
184-
handlers = {
185-
h.get("id")
186-
for handlers in data.get("payment_handlers", {}).values()
187-
for h in (handlers if isinstance(handlers, list) else [handlers])
188-
}
189-
expected_handlers = {"google_pay", "mock_payment_handler", "shop_pay"}
190-
missing_handlers = expected_handlers - handlers
191-
self.assertFalse(
192-
missing_handlers,
193-
f"Missing expected payment handlers: {missing_handlers}",
194-
)
195-
196-
# Specific check for Shop Pay config
197-
shop_pay = next(
198-
(
199-
h
200-
for handlers in data.get("payment_handlers", {}).values()
201-
for h in (handlers if isinstance(handlers, list) else [handlers])
202-
if h.get("id") == "shop_pay"
203-
),
204-
None,
205-
)
206-
self.assertIsNotNone(shop_pay, "Shop Pay handler not found")
207-
self.assertEqual(shop_pay.get("name"), "com.shopify.shop_pay")
208-
self.assertIn("shop_id", shop_pay.get("config"))
183+
# Verify Payment Handlers - structural validation (server-agnostic)
184+
if data.get("payment_handlers"):
185+
handler_count = 0
186+
for handler_name, handler_list in data.get(
187+
"payment_handlers", {}
188+
).items():
189+
# Validate handler group name using the SDK's ReverseDomainName
190+
# model, which enforces the pattern defined in the UCP spec.
191+
try:
192+
ReverseDomainName(root=str(handler_name))
193+
except Exception as e:
194+
self.fail(
195+
f"Payment handler group name '{handler_name}' "
196+
f"does not follow reverse-DNS convention: {e}"
197+
)
198+
for h in (
199+
handler_list if isinstance(handler_list, list) else [handler_list]
200+
):
201+
handler_count += 1
202+
# Validate required fields are present and non-empty
203+
self.assertTrue(
204+
h.get("id"),
205+
"Payment handler missing 'id'",
206+
)
207+
self.assertTrue(
208+
h.get("version"),
209+
f"Payment handler '{h.get('id')}' missing 'version'",
210+
)
211+
self.assertGreater(
212+
handler_count,
213+
0,
214+
"payment_handlers is present but contains no handlers",
215+
)
209216

210217
# Verify shopping capability
211218
shopping_services = data.get("services", {}).get("dev.ucp.shopping")

0 commit comments

Comments
 (0)