Hi, I am currently using the C++ FFI to generate ...
# general
s
Hi, I am currently using the C++ FFI to generate PACT contracts for some synchronous interactions and trying to understand why I am seeing multiple entries in the contract for identical request-responses. Have posted example interactions below
Copy code
auto syncInteraction1 = pactffi_new_sync_message_interaction( pact, "Interaction");
pactffi_given( syncInteraction1, "Given" );
pactffi_upon_receiving( syncInteraction1, "Upon receiving" );
pactffi_with_body( syncInteraction1, InteractionPart::InteractionPart_Request, "application/json", R"({"jsonrpc":"2.0","id":{"value":3,"pact:matcher:type":"type"}});
pactffi_with_body( syncInteraction3, InteractionPart::InteractionPart_Response, "application/json", R"#({"jsonrpc":"2.0","id":{"value":3,"pact:matcher:type":"type"}})#");

auto syncInteraction2 = pactffi_new_sync_message_interaction( pact, "Interaction");
pactffi_given( syncInteraction2, "Given" );
pactffi_upon_receiving( syncInteraction2, "Upon receiving" );
pactffi_with_body( syncInteraction2, InteractionPart::InteractionPart_Request, "application/json", R"({"jsonrpc":"2.0","id":{"value":4,"pact:matcher:type":"type"}});
pactffi_with_body( syncInteraction2, InteractionPart::InteractionPart_Response, "application/json", R"#({"jsonrpc":"2.0","id":{"value":4,"pact:matcher:type":"type"}})#");
The above 2 interactions are the same except that the id field(in the request/response) has different values but is matched by type. So, I was expecting this to generate only 1 entry in the contract for both interactions which the provider can verify. But in the contract, there are 2 entries. I suppose this is because there are 2 unique keys generated for each of the 2 interactions? Any ideas how we can get around this so we can have only 1 entry in the contract for such duplicated interactions when using the C++ FFI to write PACT consumer tests would be much appreciated.
ralph wave 1
y
why do you need only 1 entry? I imagine you want a state handler with a param, and that param being the id used in the test (if you really need to fix for the provided id) so you would have two interactions, given there are two states, one where there is a product with id 3, and one where there is a product with id 4
Also Pact not PACT πŸ™‚
πŸ™‚ 1
πŸ˜† 1
Thanks for sharing the code snippet, could you confirm which client library? (link to the codebase?) is it this? https://github.com/pact-foundation/pact-cplusplus
s
@Yousaf Nabi (pactflow.io) We need 1 entry because both the interactions(response/request pair) is the same to the provider who is verifying the contract. We were hoping the provider would not be replayed the same request multiple times with different ID`s. So my question was more along the lines that if Pact is creating the key from the interactions, should it not be ignoring the fact that we are looking to match the ID by value type only and not the actual value itself? Which means the generated key should be the same for both interactions? Also we are not using the pact-cplusplus library, we are using the following C++ FFI because we need v4 contracts as we have written our own websocket plugin.
y
We were hoping the provider would not be replayed the same request multiple times with different ID`s.
I don't understand why you have two tests, that cover the same scenario, with the same description and state. these tests don't seem different, if they are different, they should be named as such. It might be scope creep into functional testing, it just seems an odd case. Anyway that aside, maybe it should dedupe in this instance, but the interaction key that the pact core adds, might be stopping that. I would raise this in the pact-reference repo I think as a question. Ahhh SkyComcast and the WS Plugin I presume? @Adam Cox mentioned engineers were using the FFI directly
There is also
pactffi_given_with_param
for using a given state, with parameters
Copy code
/**
 * Adds a provider state to the Interaction with a parameter key and value. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `description` - The provider state description. It needs to be unique.
 * * `name` - Parameter name.
 * * `value` - Parameter value.
 */
bool pactffi_given_with_param(InteractionHandle interaction,
                              const char *description,
                              const char *name,
                              const char *value);
The notes state for
pactffi_given
that the
description
must be unique
Copy code
/**
 * Adds a provider state to the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `description` - The provider state description. It needs to be unique.
 */
bool pactffi_given(InteractionHandle interaction, const char *description);
If they should be unique, I wonder if Pact should clobber one of them and warn the user
It's plausible that its an incorrect use of the library, I would check out one of the implemented versions of a client library (pact-net, pact-js-core, pact-go@v2 etc that use the FFI, to determine what they do)
s
I don't understand why you have two tests, that cover the same scenario, with the same description and state.
So we have multiple unit tests for testing a single API/Method for ensuring code coverage for every statement/condition in the method. Which means the websocket request would be called multiple times with different ID`s depending on the state of the object under test.
Ahhh SkyComcast and the WS Plugin I presume? @Adam Cox mentioned engineers were using the FFI directly
Yes thats right πŸ™‚
y
ok so you want the full coverage on the consumer side, using the pact ffi to facilitate the unit testing, but only want to selectively verify some of them in the provider, as otherwise there is duplication
s
Copy code
The notes state for pactffi_given

that the description must be unique
I tried this as well, but dont think it matters in what we are trying to acheive here. I mean having a unique description for each interaction will not create the 1 entry in the contract right?
y
1. Pact tradtionally is used in a unit testing framework and you would use Pact for capturing cases that have semantic meaning to a consumer, and you might use another mocking tool for testing all the code paths. There is duplication here and I think there could be value is marking a test as not to encode a contract file, as you just want to use Pacts powerful mock server functionality to replace any other types of mocks 2. You could filter by description or something on the verifier side, so despite several contracts being created you only pick specific interactions to verify
I remember there being an issue about it tracking, going to do some digging πŸ™‚
πŸ‘ 1
s
ok so you want the full coverage on the consumer side, using the pact ffi to facilitate the unit testing, but only want to selectively verify some of them in the provider, as otherwise there is duplication
Yes we are writing unit tests which use the pact framework to standup a mock websocket server and respond to requests as the tests progress. Which is why there might be multiple requests which are similar except they differ in ID value`s. So the provider does not have to verify redundant requests which differ only in ID`s.
a
It would be possible to argue that the function under test is doing too much and should be broken up into smaller functions which could be unit tested separately and we would avoid this issue. However this is the state of the code we are trying to test at the moment and we have the following two scenarios: Scenario 1 uses Request A, B and C Scenario 2 use Request D, E, F, G and C The request and response payloads have an id field in them to correlate a request with a response. This id is incremental in the order in which they are sent. As scenario 2 uses request C in position 5 instead of position 3 we end up with a "duplicate" interaction for request C.
y
I can't find the issue at the moment, but the simple answer, is Pact is a contract testing, not unit testing framework, therefore you wouldn't expect to cover these types of duplicate cases. Quickest way would be to give a unique description and verify by that description, or exclude certain interactions from being uploaded (you might need to manually remove)
But worth raising as a discussion point somewhere πŸ™‚ as there are additional use cases out there, and maybe it makes sense to cover them
Thanks for the additional context Adam, that seems like a wild ride for a Friday afternoon πŸ˜„
a
Haha, every day is a wild ride at the moment πŸ˜‰
πŸ„ 1
y
I found this issue whilst hunting, I love the idea of api fuzzing, so if I could do it with Pact, but agree with Ron, it blurs the lines β€’ https://github.com/pact-foundation/pact-jvm/issues/432 and contract testing already is a confusing topic (suppose its highly overloaded as a term)
a
We really do want contracts for requests A-G so I think for now if the provider has to verify request C twice then that might be the current state we have to accept.
If they should be unique, I wonder if Pact should clobber one of them and warn the user
This would solve our current use case I think. Might cause issues for other people elsewhere but if it should be unique then there should be only one
y
Yeah I think that is something that should be addressed in the core, I'll raise something to track to find out what the correct behaviour should be then (if there isn't one already) I note the ffi exposes this function to filter verifications, there isn't an exclude filter (I don't think), but you can include by consumer name
Copy code
void pactffi_verifier_set_filter_info(VerifierHandle *handle,
                                      const char *filter_description,
                                      const char *filter_state,
                                      unsigned char filter_no_state);
It would probably be easy to add an exclude filter method into the codebase, which would allow your verification runs just to exclude certain states or descriptions (unit test / xyz)
a
For the verification side we are using the Pact Standalone Verifier which I think does expose filtering options
t
I confess I’m not following completely, but can’t you inject the ID with provider state?