Repository navigation
Conversation
evoleinik
force-pushed
the
feat/catalog-identity-linking-tests
branch
from
November 11, 2026 10:25
75f8c6a to
a5c2ca5
Compare
evoleinik
marked this pull request as ready for review
November 11, 2026 10:31
4 of 17 tasks
evoleinik
force-pushed
the
feat/catalog-identity-linking-tests
branch
from
November 13, 2026 23:49
a5c2ca5 to
13c68a9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The suite has no tests for catalog or identity linking. This PR adds 12. It follows up on my comment on #120.
catalog_test.pyhas 8 tests for search, lookup and get product over the REST binding.identity_linking_test.pyhas 4. They read the authorization metadata and send one request with a made-up token. They never run an authorization flow or need an account.Each assertion rests on one of three things: a MUST sentence in the specification or in an RFC it cites, an item of the REST binding's Conformance list, or a constraint in the schemas. The table below names the rule behind each test. The rules are the same in the 2026-04-08 and 2026-08-25 releases. The one exception is the
oauth2provider rule, which is new in 2026-08-25 and applies only to a profile that lists such a provider.test_search_returns_products_in_ucp_envelopeucpwithversionand the active capabilities. The search response schema requiresucpandproductstest_search_cursor_returns_next_pagecursorMUST be present whenhas_next_pageis truetest_search_variants_carry_valid_pricesprice, and a Price has an integeramountof at least 0 and acurrencymatching^[A-Z]{3}$test_lookup_unknown_id_returns_no_productinputsentry MUST NOT appeartest_lookup_dedupes_ids_and_correlates_inputsinputsentry MUST NOT appeartest_lookup_over_batch_limit_returns_request_too_largetest_get_product_endpoint_is_available/catalog/lookupand/catalog/productMUST be available. The get product response schema requiresproducttest_get_product_by_variant_id_features_that_varianttest_protected_resource_metadata_matches_its_resourceresourceMUST be identical to the identifier the metadata URL was built fromtest_authorization_server_metadata_issuer_matchesissuerMUST match byte for bytetest_authorization_server_metadata_declares_scopes_and_authscopes_supported. MUST declaretoken_endpoint_auth_methods_supported. With anoauth2provider, MUST include the JWT bearer grant ingrant_types_supportedtest_rejected_token_on_gated_operation_gets_bearer_challengeidentity_required: a gated operation MUST answer an invalid token with 401, aBearerchallenge and anidentity_requiredmessage. The header MUST includerealmset to the issuer, and MUST includeerror="invalid_token"Each test skips when the server does not advertise its capability. The catalog tests send no user token, so they also skip a capability gated by a scope in
config.scopes. Three lookup tests find their product by search, so they also need the search capability. A test that needs a product skips until the merchant setscatalog.search_query. The batch test skips until the merchant setscatalog.max_lookup_ids. The token test needs a gated operation:identity_linking.request, or a catalog search when the profile gates it. The README documents these keys.Other changes:
shopping-agent-test.jsondeclaresdev.ucp.shopping.catalog.searchanddev.ucp.shopping.catalog.lookup. A business computes the intersection of its capabilities and the platform's (Overview, Business Requirements 2), so without them the suite's agent gets no catalog capability. fix: declare exercised capabilities in agent profile #109 added the shopping capabilities for the same reason.runner.pyaddsshopping.catalog.catalog_testto theshoppingsuite andcommon.identity_linking.identity_linking_testto thecommonsuite. The packagesshopping/catalog/andcommon/identity_linking/are new.framework/services.pyreads three things from the profile: a service's REST endpoint, a capability'sconfig, and the gated scopes. It takes the REST entry even when that entry is not listed first.ietfjoins the cspell word list, for the JWT bearer grant URN.ruff check,ruff format, prettier and cspell pass on the changed files.Results
52319df,--suite=all0642adf: 81 passed and 2 skipped. With this PR, the same 81 pass, and the 12 new tests skip because the sample has no catalog or identity linkingThe price test fails because the catalogs our server carries publish no prices. The spec requires a price on every variant today. Universal-Commerce-Protocol/ucp#969 and Universal-Commerce-Protocol/ucp#1042 propose a way to mark a price that is not published. So the failure is the expected result for these catalogs.
Our server fetches the agent profile named in
UCP-Agentand refuses a localhost URL. So I ran it on #123's branch with--agent_profile_url, using the same test files as this PR. Nothing in this PR needs #123 to run against a local server.Each test was also run against defects planted for it. A local proxy sat in front of the first configuration and changed one thing at a time. Each defect failed the tests listed. The price test kept failing in every row, because of the missing prices above.
test_lookup_dedupes_ids_and_correlates_inputsinputs, repeats an entry, loses the product-id entry, or carries the variant-id entry under another variant idtest_lookup_dedupes_ids_and_correlates_inputs(each one separately)test_lookup_unknown_id_returns_no_producthas_next_pagetrue with nocursortest_search_cursor_returns_next_pageucp.capabilitiestest_search_returns_products_in_ucp_envelope,test_search_cursor_returns_next_pageusd, where the same price withUSDpassestest_search_variants_carry_valid_pricesproducttest_get_product_endpoint_is_available,test_get_product_by_variant_id_features_that_varianttest_get_product_by_variant_id_features_that_variantinvalid_requesttest_lookup_over_batch_limit_returns_request_too_largeresourcediffers from its URLtest_protected_resource_metadata_matches_its_resourceissuergains a trailing slashtest_authorization_server_metadata_issuer_matchesscopes_supported, or dropstoken_endpoint_auth_methods_supportedtest_authorization_server_metadata_declares_scopes_and_auth(each one separately)oauth2provider, and no metadata has the JWT bearer granttest_authorization_server_metadata_declares_scopes_and_authtest_authorization_server_metadata_issuer_matches,test_authorization_server_metadata_declares_scopes_and_authtest_rejected_token_on_gated_operation_gets_bearer_challengeerror="invalid_token", has anotherrealm, or has norealmtest_rejected_token_on_gated_operation_gets_bearer_challenge(each one separately)These changes should fail nothing new, and none did:
100.0{"code": "request_too_large", ...}bodyauthorization_serversIn the gated rows the server's 401 is real. The proxy only added the gate to the profile.
Choices a reviewer may question
request_too_largeat the top level or inmessages. The spec does not define the body of that 400./, so both spellings are accepted there. Issuers listed in protected-resource metadata are compared byte for byte.Left out
ucp.status"error"and anunrecoverablemessage. It states no MUST for it.insufficient_scope. Our server gates no operation. So the proxy would have to invent those answers, and these tests wait for a server that really gates one.The new files follow the layout from #121:
shopping/catalog/andcommon/identity_linking/. If #123 lands first, the endpoint lookup can use itsrest_entryhelper instead.Type of change
Is this a Breaking Change or Removal?
No. The change removes no schema file and no field.
Checklist
🤖 Generated with Claude Code