Another question - hope this is the right place to...
# general
n
Another question - hope this is the right place to ask. When I attempt to run pact tests locally (local pact file, local provider, pact mock host), I get an error that my request headers are different than previously. How does it come to this conclusion? Am I actually pointing it to my real broker somehow?
Copy code
AssertionError: An interaction with same description ("a request for a Data Context") and provider state ("the Data Context exists") but a different request headers has already been used. Please use a different description or provider state, or remove any random data in the interaction.
I think I'm misunderstanding what the pact mock host/port actually represents.
Copy code
pact_test: pact.Pact = pact.Consumer(
        name=CONSUMER_NAME,
        version=version,
        tag_with_git_branch=True,
        auto_detect_version_properties=True,
    ).has_pact_with(
        pact.Provider(name=PROVIDER_NAME),
        broker_base_url=pact_broker_base_url,
        broker_token=broker_token,
        host_name=PACT_MOCK_HOST,
        port=PACT_MOCK_PORT,
        pact_dir=str(PACT_DIR.resolve()),
        publish_to_broker=publish_to_broker,
    )
Everything works fine in CI, and I think the only difference is I'm using the read-only token locally, and the read/write token in CI.
y
Hey @Nathan Farmer So the pact mock, on the consumer side of your testing, will which serve as a stand-in for your real provider. You set up an interaction, which contains the request you expect your client to make, and the response you expect it to return. If your client code issues the correct request you specified, and the pact mock provider receives it, it will send the response that you setup. You can then perform unit test assertions on your system under test, given that is received a particular response from the provider. Pact python additionally has some helper functions to allow it to publish to a broker after a test run, this is why you have options such as • version • tag_with_git_branch • auto_detect_version_properties • publish_to_broker • broken_token These really are a separate activity (publishing pacts to a broker) than the execution of the pact tests. If you are trying to publish to a broker, with the same version as a previously published pact, and the content within that pact has changed (random data perhaps) - the pact broker will inform you that you cannot do so. It may be that
publish_to_broker
is set to true. Also do you have more than one test, do those tests share the same given and when statements?
Copy code
("a request for a Data Context") and provider state ("the Data Context exists"
n
• We have test data in a local version of our provider that we can get the provider states from • We have the ability to convert the pact response bodies with the matchers into unit tests mocks and can run unit tests •
publish_to_broker
is only set to true in CI, because our logic is setup in such a way that the flag only gets set to true if the user has a read/write token (which we only have in CI) • We don't have more than one test that shares the same given. It seems like there is something either different in the request that I can't find, or there is something about how this all works that I don't understand.
y
Okay, sounds like we might need to see some of tests so draw some conclusions, as you may be a bit of the beaten path. I’m about to sign off now for the weekend as its 7pm in the UK, but sharing some of the actual test code would be useful. Not sure why you need to the local version of the provider, is that to get the correct names of provider states they already have mapped, or is that to help in constructing the response bodies for the provider?
👍 1
n
The local version of the provider was already setup for end-to-end tests. > is that to get the correct names of provider states they already have mapped We don't have provider states mapped so maybe that is the issue. We have test data that returns a response and in the given we are just describing the state that we know exists in the test db. > or is that to help in constructing the response bodies for the provider Right now we are just writing consumer-side tests. We are using the response bodies in consumer-side unit tests. It helps with constructing the response bodies because we get the diff for actual (in the test data) vs expected response body. Right now we don't see the diffs locally though, just in CI.
b
Not sure why you need to the local version of the provider
This is probably the point that's being missed, afaict. Consumer tests don't need a provider, that's what Pact provides for you. (The provider needs to exist later in the workflow, for verification)
m
> I think I’m misunderstanding what the pact mock host/port actually represents. I always think it’s helpful to frame Pact as a unit testing tool (it probably technically isn’t, but that’s not relevant just yet). This way, you can understand that: 1. During consumer testing, you’re only testing the smallest possible unit of work in this context - the code that makes an API call to another service. We call this a collaboration test 2. Pact is used in this collaboration test as the API mock - this means it not only is a test double for the API you’re calling, the behaviour is also checked. a. In Pact’s case, calls to the mock are what get recorded into the pact file. This is how we can be confident what is put into the contract is a valid representation of reality 3. On the provider side, once again, we’re going to isolate the provider code. Pact will stand in for the consumer, by replaying the requests in the contract file a. It’s usually a bit wider than a unit test on the provider side, but the mentality should be the same. Stub out external dependencies (e.g. other services) to isolate the bit you need to test
👌 1
n
Ok team. Back in the office here in the US. Thanks for some of the great conversation above about how it all works. I'm going to return to the original error message after we did some debugging and figured out what the issue was.
🙏 1
We are seeing the error message about "An interaction with same description and provider state, but a different request headers has already been used" because for some reason the mock service is not always being stopped (despite using the
pact.stop_service()
pattern in the docs after `yield`ing the pact). I think maybe the debugger is having some sort of undesirable side effects, but I'm not 100% sure if that is the cause. So changes to the test were being run against the same mock service resulting in that error message. Running this fixes the issue:
Copy code
ps aux|grep pact
kill -9 <pid> for each PID listed in the output of
b
Not sure if it's a Python-specific thing, but it feels like you're doing a bunch of manual work that the library should be doing, like
pact.stop_service()
. . .
m
I think the
pact.verify()
command is what clears interactions between tests, if that’s the problem. But the
stop_service()
command should stop the underlying mock. We’d need to understand why that’s not shutting the process down, because you should defnitely not have to
kill
the process manually.
💡 1
If there is a way you can provide a repro build (ideally with a GitHub action that demonstrates the problem), that would help with investigating further. Once you can do that, I’d suggest creating an issue here: https://github.com/pact-foundation/pact-python/issues/new/choose.