|
17 | 17 | from absl.testing import absltest |
18 | 18 | import integration_test_utils |
19 | 19 | import httpx |
20 | | -from ucp_sdk.models.schemas.ucp import BusinessSchema |
| 20 | +from ucp_sdk.models.schemas.ucp import BusinessSchema, ReverseDomainName |
21 | 21 | from ucp_sdk.models.schemas.shopping import checkout as checkout |
22 | 22 | from ucp_sdk.models.schemas.shopping.payment import ( |
23 | 23 | Payment, |
@@ -180,32 +180,39 @@ def test_discovery(self): |
180 | 180 | f"Missing expected capabilities in discovery: {missing_caps}", |
181 | 181 | ) |
182 | 182 |
|
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 | + ) |
209 | 216 |
|
210 | 217 | # Verify shopping capability |
211 | 218 | shopping_services = data.get("services", {}).get("dev.ucp.shopping") |
|
0 commit comments