Skip to content

feat: pact contract for get job by id and post job - #106

Open
duvanmoionq wants to merge 3 commits into
mainfrom
pact/contract
Open

duvanmoionq wants to merge 3 commits into
mainfrom
pact/contract

Conversation

@duvanmoionq

@duvanmoionq duvanmoionq commented Sep 9, 2026

Copy link
Copy Markdown

QTPF-9072

install pact dependency
Adding pact contract for http POST /job
Adding pact contract for http GEt /job/{id}

@duvanmoionq
duvanmoionq requested a review from a team as a code owner September 9, 2026 16:47
@antalszava
antalszava self-requested a review September 10, 2026 12:04
@antalszava

Copy link
Copy Markdown
Collaborator

Thank you @duvanmoionq! before a full review, a question: should the new tests be added to the CI too? or does pact work in a different way?

@duvanmoionq

Copy link
Copy Markdown
Author

Thank you @duvanmoionq! before a full review, a question: should the new tests be added to the CI too? or does pact work in a different way?

Yes! we would do that later for now we are only adding test contracts examples that we can follow to add more contracts. we will add later the CI logic whenever we configure the Broker we need.

@antalszava antalszava left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you so much @duvanmoionq! 👏 Very interesting direction.

I've left a couple of comments, my main feedback is: could we somehow dynamically depend on the API spec that we have in the repo in the pact?

Also, could you further describe what we gain from using pact instead of "simply" writing pytest tests with expected responses?

@@ -0,0 +1,165 @@
"""Pact HTTP contract: ionq-core-python (consumer) -> cloud-job-manager (provider).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is it a convention to have a consumers folder inside the pact folder?

First it seems a bit unnecessary to have two levels of folder nesting atm.

"""Pact HTTP contract: ionq-core-python (consumer) -> cloud-job-manager (provider).

Pins the two jobs-API interactions the SDK depends on, in ONE pact
(ionq-core-python-cloud-job-manager.json):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The mention of ionq-core-python-cloud-job-manager.json seems a bit confusing here since it's not a file in the repo - where does it live?

Pins the two jobs-API interactions the SDK depends on, in ONE pact
(ionq-core-python-cloud-job-manager.json):

1. POST /v0.4/jobs create a circuit job -> 201 {id, status, session_id}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This endpoint can have different inputs: single-circuit,multi-circuit, quantum function and qaoa function. Should that matter here/does that matter for the contract?

Comment on lines +6 to +7
1. POST /v0.4/jobs create a circuit job -> 201 {id, status, session_id}
2. GET /v0.4/jobs/{id} fetch a completed job -> 200 (every SingleCircuitJob

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Imho these should be coming dynamically from this repo's API spec version. Accordingly, I think it would be good to remove/keep the endpoint and payload descriptions minimal here because they need to be changed here each time their spec changes.

artifact DESCRIPTORS)

The SDK carries /v0.4 in its base_url (client config, not contract): the pact
records the WIRE paths the provider serves, so the mock base_url below is the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what's WIRE paths?

Comment on lines +15 to +26
Consumer-driven notes (generated openapi-python-client code: parse IS
consumption — from_dict pops every required key):
- Create response: session_id is REQUIRED-nullable — new vs the retired
python-ionq contract, which read only id + status.
- Get response: SingleCircuitJob.from_dict hard-requires ~23 keys; nullable
ones must be PRESENT (null is fine). results entries are v1 artifact
descriptors {id, format, media_type} KEYED BY FORMAT — the provider also
sends legacy {url} pointer entries alongside (extra keys, allowed by Pact,
ignored by this assertion).
- Client: bare AuthenticatedClient, never the IonQClient factory — the factory
pins a platform-varying User-Agent and warns on non-HTTPS base urls, which
this repo's filterwarnings=error would turn into a failure.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I find this paragraph challenging to understand completely, could it be rephrased a bit?


# The real request model drives the pact request body (never hand-written, so
# it can't drift from what the SDK serializes). Enriched with the optional
# fields the SDK really sends: name, settings.error_mitigation and noise.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think it's good to remove

name, settings.error_mitigation and noise

since these can change and then the comment becomes easily outdated.

Comment on lines +84 to +87
# Every SingleCircuitJob required key, with the values the provider state's
# seed produces; required-nullable keys are asserted as null. results pins the
# format-keyed v1 descriptor the provider synthesizes (its legacy {url}
# entries ride along as unasserted extras).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I find these comments hard to read and understand, could they be rephrased?

Comment on lines +164 to +165
PACT_DIR.mkdir(exist_ok=True)
pact.write_file(PACT_DIR, overwrite=True)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What do these instructions do?

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