Hello Pact Python Team, I am trying to write Provi...
# pact-python
j
Hello Pact Python Team, I am trying to write Provider Test as below, it is able to communicate with pactbroker but not able to get the request body from pact so getting 400 error, Am I missing anything?
Copy code
from pact import Verifier

PACT_BROKER_URL = "<http://pactbroker.service.xxx.xxx.xxx.com/>"
# I am spinning up our provider service(my-service) in docker-compose on 5002 port
PROVIDER_HOST = "my-service"
PROVIDER_PORT = 5002
PROVIDER_URL = f"http://{PROVIDER_HOST}:{PROVIDER_PORT}"

@pytest.fixture
def broker_opts():
    return {
        "broker_url": PACT_BROKER_URL,
        "publish_version": "3",
        "publish_verification_results": False,
    }


def test_service_provider_against_broker(broker_opts):
    headers=["Authorization: Bearer my_jwt_token"]
    headers.append("Content-Type:application/json")
    verifier = Verifier(provider="my_provider_python_service", provider_base_url=PROVIDER_URL)
    success, logs = verifier.verify_with_broker(
        **broker_opts,
        verbose=True,
        provider_states_setup_url=f"{PROVIDER_URL}/my_path",
        enable_pending=False,
        headers=headers
    )
    assert success == 0
@Matt (pactflow.io / pact-js / pact-go) I know you are vacationing but your quick feedback on this would really help to unblock me
m
Going to need a lot more info to be able to diagnose this.
but not able to get the request body from pact
what do you mean by this? The request body comes from your provider, not Pact. Pact checks the response from your provider is correct
I can’t see where your provider is starting there, and why it might be failing.
the log output would be helpful here, ideally at debug level
I believe there should be an option to specify the provider log info
j
Copy code
Given metadata, upon receiving return created metadata object id from myconsumer-service, with

{
  "method": "post",
  "path": "/metadata/",
  "headers": {
    "Authorization": "Bearer token",
    "content-type": "application/json"
  },
  "body": {
    "datasource_id": 11111,
    "metadata": {
      "schema_id": 3,
      "schema_tags": [
        {
          "schema_tag_id": 2,
          "schema_tag_values": [
            "1"
          ]
        }
      ]
    }
  }
}
myprovider-service will respond with:

{
  "status": 200,
  "body": {
    "metadata_object_id": 222222222,
    "version_id": 1,
    "validation_errors": {
      "hard": {
      },
      "soft": {
      }
    }
  }
}
This is my pact
I don’t have provider states defined in my provider service
m
what’s the actual issue though?
j
Copy code
4) Verifying a pact between myconsumer-service and myprovider-service Given metadata return created metadata object id with POST /metadata/ returns a response which has a matching body
     Failure/Error: set_up_provider_states interaction.provider_states, options[:consumer]

     Pact::ProviderVerifier::SetUpProviderStateError:
       Error setting up provider state 'metadata' for consumer 'myconsumer-service' at <http://mats-service:5002/metadata/>. response status=400 response body={"title":"Client Input Validation Error","message":[{"loc":["body","datasource_id"],"msg":"field required","type":"value_error.missing"},{"loc":["body","metadata"],"msg":"field required","type":"value_error.missing"},{"loc":["body","consumer"],"msg":"extra fields not permitted","type":"value_error.extra"},{"loc":["body","params"],"msg":"extra fields not permitted","type":"value_error.extra"},{"loc":["body","state"],"msg":"extra fields not permitted","type":"value_error.extra"},{"loc":["body","states"],"msg":"extra fields not permitted","type":"value_error.extra"}],"mats_error_code":2000}

2 interactions, 2 failures
here is the error
there is big stacktrace of ruby below this
which I can send if needed
m
right. So you need the provider state endpoint to be there, and it needs to respond with a
200
whether or not you actually setup a state is a whole other thing
(an important thing, but a different thing)
j
thats awesome I tried with this and it worked but still want to check if this looks good?
Copy code
@pact_router.post("/_pact/provider_states")
async def provider_states(provider_state: ProviderState):
    mapping = {
        "metadata": {},
        "get schema tag enums": {},
    }

    return {"result": mapping[provider_state.state]}
m
Well, that doesn’t actually do anything. It doesn’t need a body, it just needs a 200
if you’re not actually doing anything with the states, my guess is you could just have an empty methed
but at some point, you will need to do something with the states
j
I might get back to you on understanding what needs to be done with the provider states
But I have another question on Provider tests - I think I saw you mentioning that all DB,KAFKA and Aerospike dependencies should be mocked for contract tests which sounds reasonable but as I am spinning up the service in another docker container than contract tests, I am unable to mock those dependencies as service is running in separate container. Is it advisable to spin up MSSQL, Aerospike and Kafka in their own containers and let service talk to them?
I am not sure if I am clear but let me know I can explain more specific usecase for my needs
m
So yeah, this is why running them in a docker container isn’t ideal
as much as possible, try to think of these as a unit test
j
we have buildkite pipelines for test, lint, build and deploy, so all our unit tests, contract tests, integration tests run in pipeline. That’s why we run it in docker container
we have base python images which serve as basic image for services, we pull it from dockerfile and then install all dependencies
easy to manage this with docker
Also @Matt (pactflow.io / pact-js / pact-go) for unit tests we use Python TestClient
from fastapi.testclient import TestClient
, but pact verifier needs a provider base url which we cannot pass if we are using Test Client
m
we have buildkite pipelines for test, lint, build and deploy, so all our unit tests, contract tests, integration tests run in pipeline. That’s why we run it in docker container (edited)
I’m not saying don’t run them in a docker container, I’m suggesting you don’t run the provider tests against a docker container (that doesn’t have stubbed dependencies).
for unit tests we use Python TestClient
from fastapi.testclient import TestClient
, but pact verifier needs a provider base url which we cannot pass if we are using Test Client
I understand. The verification isn’t a unit test, but you try your best to think of it as one - this includes being able to stub dependencies in a granular fashion, so that your pact tests are easy to manage and run.