diff --git a/integration_test_utils.py b/integration_test_utils.py index dd245ef..78af49c 100644 --- a/integration_test_utils.py +++ b/integration_test_utils.py @@ -45,12 +45,17 @@ from ucp_sdk.models.schemas.shopping.types import ( fulfillment_method_create_request, ) +from ucp_sdk.models.schemas.shopping.types.amount import Amount from ucp_sdk.models.schemas.shopping.types import item_create_request from ucp_sdk.models.schemas.shopping.types import item_update_request from ucp_sdk.models.schemas.shopping.types import line_item_create_request from ucp_sdk.models.schemas.shopping.types import line_item_update_request +from ucp_sdk.models.schemas.shopping.types.signed_amount import SignedAmount from ucp_sdk.models.schemas import payment_handler from ucp_sdk.models.schemas.shopping.types import shipping_destination +from ucp_sdk.models.schemas.shopping.types.totals import Totals + +UCP_VERSION = "2026-04-08" import uvicorn @@ -58,6 +63,42 @@ class UnifiedUpdate(CheckoutUpdateRequest): """Client-side unified update model to support extensions.""" +def _patch_sdk_root_models() -> None: + """Make generated April SDK root models test-friendly. + + The April 2026 Python SDK models introduce RootModel wrappers for scalar + amounts and for checkout/order totals. These wrappers are correct at the + schema layer, but direct iteration/comparison is awkward in the existing + conformance assertions. + """ + + def _scalar_eq(self: Any, other: Any) -> bool: + if hasattr(other, "root"): + return self.root == other.root + return self.root == other + + def _scalar_int(self: Any) -> int: + return int(self.root) + + def _scalar_str(self: Any) -> str: + return str(self.root) + + Amount.__eq__ = _scalar_eq + Amount.__int__ = _scalar_int + Amount.__index__ = _scalar_int + Amount.__str__ = _scalar_str + + SignedAmount.__eq__ = _scalar_eq + SignedAmount.__int__ = _scalar_int + SignedAmount.__index__ = _scalar_int + SignedAmount.__str__ = _scalar_str + + Totals.__iter__ = lambda self: iter(self.root) + + +_patch_sdk_root_models() + + FLAGS = flags.FLAGS try: flags.DEFINE_string("server_url", None, "Base URL of the server") @@ -480,7 +521,7 @@ def create_checkout_payload( payment_handler.PaymentHandler( id="google_pay", name="google.pay", - version="2026-01-23", + version=UCP_VERSION, spec="https://example.com/spec", config_schema="https://example.com/schema", instrument_schemas=["https://example.com/instrument_schema"], @@ -540,7 +581,7 @@ def create_checkout_payload( fulfillment=fulfillment, ) checkout_req.status = "incomplete" - checkout_req.ucp = {"version": "2026-01-23"} + checkout_req.ucp = {"version": UCP_VERSION} checkout_req.totals = [] checkout_req.links = [] diff --git a/protocol_test.py b/protocol_test.py index 4ac7d47..21d8263 100644 --- a/protocol_test.py +++ b/protocol_test.py @@ -18,15 +18,20 @@ import integration_test_utils import httpx from pydantic import ValidationError -from ucp_sdk.models.schemas.ucp import BusinessSchema, ReverseDomainName +from ucp_sdk.models.schemas.ucp import BusinessSchema from ucp_sdk.models.schemas.shopping import checkout as checkout from ucp_sdk.models.schemas.shopping.payment import ( Payment, ) +from ucp_sdk.models.schemas.shopping.types.reverse_domain_name import ( + ReverseDomainName, +) # Rebuild models to resolve forward references checkout.Checkout.model_rebuild(_types_namespace={"Payment": Payment}) +UCP_VERSION = "2026-04-08" + class ProtocolTest(integration_test_utils.IntegrationTestBase): """Tests for UCP protocol compliance. @@ -162,7 +167,7 @@ def test_discovery(self): self.assertEqual( data.get("version"), - "2026-01-23", + UCP_VERSION, msg="Unexpected UCP version in discovery doc", ) @@ -223,7 +228,7 @@ def test_discovery(self): if isinstance(shopping_services, list) else shopping_services ) - self.assertEqual(shopping_service.get("version"), "2026-01-23") + self.assertEqual(shopping_service.get("version"), UCP_VERSION) self.assertIsNotNone(shopping_service.get("transport") == "rest") self.assertIsNotNone(shopping_service.get("endpoint")) @@ -265,7 +270,7 @@ def test_version_negotiation(self): # 1. Compatible Version headers = integration_test_utils.get_headers() - headers["UCP-Agent"] = 'profile="..."; version="2026-01-23"' + headers["UCP-Agent"] = f'profile="..."; version="{UCP_VERSION}"' response = self.client.post( checkout_sessions_url, json=create_payload.model_dump( diff --git a/shopping-agent-test.json b/shopping-agent-test.json index 3617648..84fad37 100644 --- a/shopping-agent-test.json +++ b/shopping-agent-test.json @@ -1,13 +1,13 @@ { "ucp": { - "version": "2026-01-23", + "version": "2026-04-08", "capabilities": { "dev.ucp.shopping.order": [ { "name": "dev.ucp.shopping.order", - "version": "2026-01-23", - "spec": "https://ucp.dev/2026-01-23/specification/order/", - "schema": "https://ucp.dev/2026-01-23/schemas/shopping/order.json", + "version": "2026-04-08", + "spec": "https://ucp.dev/2026-04-08/specification/order/", + "schema": "https://ucp.dev/2026-04-08/schemas/shopping/order.json", "config": { "webhook_url": "http://localhost:{webhook_port}/webhooks/partners/test_partner/events/order" }