Skip to content

feat: extract core/ and gate the suites on advertised capabilities (RFC #520, 3/3) - #122

Draft
segiodongo wants to merge 6 commits into
Universal-Commerce-Protocol:mainfrom
segiodongo:split/3-core-common-suites
Draft

segiodongo wants to merge 6 commits into
Universal-Commerce-Protocol:mainfrom
segiodongo:split/3-core-common-suites

Conversation

@segiodongo

Copy link
Copy Markdown
Contributor

Stacked on #121. This branch carries #121's two file-move commits, so the Files changed tab shows both PRs until #121 merges and this branch is rebased onto main. This PR's own change is the last four commits; its exact diff is segiodongo/conformance@split/2-move-shopping-tests...split/3-core-common-suites.

Last of three PRs replacing #107 (after #120 and #121). All test-content changes live here, after the moves have landed:

  • core/ — protocol_test.py (discovery document: required ucp wrapper, version, capability and handler names, URLs) and binding_test.py (transport headers / JSON content type). shopping/checkout/protocol_test.py keeps the service-advertisement checks and the version negotiation test, which asserts the 422 on POST /checkout-sessions.
  • Capability gating — every suite declares what it exercises with @requires_capability; common/payments/ gates on dev.ucp.common.payment.ap2_mandate (the pre-2026-08-25 name is recognised via framework.discovery.FORMER_NAMES) and on the checkout endpoint for card credentials and token binding.
  • Imports — tests use shopping.base directly; integration_test_utils becomes a deprecated facade for external users.
  • Discount tests grouped under shopping/discount/ (moved from the business-logic and validation modules, bodies unchanged).

Review feedback from #107 addressed here: capability names that no server advertises, TokenBindingTest placement, shopping-dependent tests kept out of core/, the ucp wrapper assertion, and the two core/ tests that could not observe what they claimed (GET-based negotiation, Content-Type on a GET-only route) are not reintroduced.

Verification (sample server): 79 tests, 77 passed, 2 skipped (test_discovery_urls; AP2, which the sample server does not advertise), 0 failed — the same result as #107's final head, whose content this branch reproduces.

…oves only)

Second step of the RFC #520 split of Universal-Commerce-Protocol#107. Every test module moves to the
package that owns it, with no content changes, so git tracks each file as
a 100% rename and open pull requests rebase onto the new paths:

- checkout, discount, fulfillment, order and validation tests go under
  `shopping/<domain>/`; `test_data/flower_shop` becomes
  `shopping/fixtures/flower_shop` (a symlink keeps the old path working).
- the payment credential tests (`ap2_test`, `card_credential_test`,
  `binding_test` as `token_binding_test`) go under `common/payments/`.

The tests still import `integration_test_utils`; the runner registry, CI
and README follow the files.
`integration_test_utils.py` becomes `shopping/base.py` (git shows it as a
94% copy because a facade keeps the old path). The facade re-exports every
name tests import from `integration_test_utils`, so the moved tests and
any open pull request keep working unchanged; it is not yet marked
deprecated because the in-tree tests still use it.

The shopping fixtures default to `shopping/fixtures/flower_shop`, and the
wheel lists the `common` and `shopping` packages instead of the former
top-level test modules.
Third step of the RFC #520 split of Universal-Commerce-Protocol#107. Every shopping test now imports
`ShoppingIntegrationTestBase` from `shopping.base` instead of the
`integration_test_utils` facade, calls `self.get_headers()`, tolerates the
SDK's older and newer locations for the payment models, and declares the
capability it exercises with `@requires_capability`, so a server that does
not advertise, say, `dev.ucp.shopping.discount` skips those tests instead
of failing them. Test bodies are unchanged.

`conftest.py` takes `FLAGS` from the framework for the same reason.
The three payment credential tests under `common/payments/` were gated on
capability names no server advertises, so they always skipped. Now:

- `Ap2MandateTest` requires `dev.ucp.common.payment.ap2_mandate`, the name
  the schema defines. Releases before 2026-08-25 advertised it as
  `dev.ucp.shopping.ap2_mandate`; `framework.discovery` records that rename
  (`FORMER_NAMES`) so the test runs against either generation of server.
- `CardCredentialTest` and `TokenBindingTest` are gated on the checkout
  endpoint they drive: card credentials and token binding are payment data
  types, not advertised capabilities.

They import `shopping.base` directly, which leaves `integration_test_utils`
without in-tree users; it now emits a DeprecationWarning for external ones.
`core/` holds the tests any UCP server must pass regardless of the
verticals it implements, which is everything observable from the
discovery document alone:

- `core/protocol_test.py`: the discovery checks from the former shopping
  protocol test (required `ucp` wrapper, date-based version matching the
  conformance input, reverse-DNS capability and handler names, payment
  handler structure, published spec/schema URLs).
- `core/binding_test.py`: the standard transport headers are accepted and
  discovery answers with `application/json`.

`shopping/checkout/protocol_test.py` keeps what needs the shopping vertical:
the service advertisement checks and version negotiation, which can only
be observed on `POST /checkout-sessions` (422 for an unsupported version).

The runner gains the `core` suite and the README documents the tiers.
The discount flow tests (`test_discount_flow`, `test_multiple_discounts_*`,
`test_fixed_amount_discount`) move from the checkout business-logic module
to `shopping/discount/discount_test.py`, and `test_unknown_discount_code`
joins them from the validation suite, so every discount test lives with
the capability it exercises and is gated on `dev.ucp.shopping.discount`.
`shopping/discount/semantics_test.py` (the former `discount_test.py`) is
unchanged. Test bodies are unchanged; only their module and gate move.
@segiodongo
segiodongo force-pushed the split/3-core-common-suites branch from 8d84e15 to 55a9994 Compare November 9, 2026 18:11

@niranjanmanjunath niranjanmanjunath left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to rebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants