hey I'm new to Contract Testing and concretely to ...
# pact-rust
j
hey I'm new to Contract Testing and concretely to Pact. I'm trying my very first consumer pact test in Rust. Since my application is event-driven I'm trying to use message interactions. One thing that I would like to do in a test is to use
Provider state
(with the given keyword) but I could not find any documentation about it except the basic example here. Do you guys know how to use Provider state to set some data before the execution of the test (if I understood correctly what Provider state is for)?
r
Provider state is used with a callback when verifying the provider, it is only defined in the consumer test.
j
Thanks a lot! So if I understand your answer, I would need to create a pact verifier test that defines such a callback?
r
Yes
j
Ah this helps, thanks a lot.
any documentation on how to create such tests?
r
j
I'm somehow not getting it. So in order to verify the provider, I need to take the pacts generated with the consumer driven tests (this I already achieved). But now I have to create a provider that will received the pacts and basically execute the provider logic. This whole process is triggered by the pact verifier right? And I could basically deploy a pact broker to push and pull the pacts. If everything said before holds true, I'm somehow force to have a running version of the provider? I though that one of the points of contract testing is to not have to deploy anything in a virtual environment to perform the tests...so I have the impression that I'm missing something
r
You don't need to deploy the provider, it is enough to just run it in the local environment and verify against that.
j
is this something that I can do like with the consumer pact tests? (I mean with the Rust testing framework)?
r
No, there is no Rust support for running a provider test using the Rust test framework.
You would need some mechanism to handle the state change calls. I have used Rocket for that.
j
Thanks for the hint. do you have a link to Rocket? I can only find some IT stuff under that name.
r
Axum is another one you can use
j
ah I see, but I'm using a message-based (AMQP) system, not HTTP-based.
r
It still needs an HTTP server to handle the state change calls, that's why you can use one of those ones to create one
j
ah, ok. This is now the last part that I'm still missing. I manage to have the pact tests (consumer driven), a pact-broker running where I push the tests. But now I need the Provider verify. Here I'm still quite lost.
The verifier CLI will not know how to get the messages generated to verify them. A local HTTP server is used. So you need to: 1. Create a local HTTP server that can return the messages and handle the state change calls 2. Run the verifier CLI and point it at that HTTP server
j
Do i have to use the Pact Verifier Library in this HTTP server?
Or what interface do I have to expose via HTTP?
I believe I'm almost there:
Copy code
#[test_log::test(tokio::test)]
async fn when_instrument_state_switched_to_starting_up_then_example_unit_starts_up_itself() {
    // Arrange
    let provider = PactBuilder::new_v4("instrument-state-unit", "example-unit")
        .interaction("Instrument State changes to Starting Up and triggers units to startup", "", |mut i| {
            i.test_name("test_unit_reacts_to_instrument_state_starting_up");
            i.request.content_type("application/json");
            i.request.json_body(json_pattern!({
                "origin": like!("simulated-instrument-sn555"),
                "version": like!("1.0.0"),
                "name": like!("InstrumentStateChanged"),
                "old_state": like!("PoweredOff"),
                "new_state": like!("StartingUp")
            }));

            i.response.ok().content_type("application/json").json_body(json_pattern!({
                "result": "hello"
            }));

            i
        }).start_mock_server(None);

    let provider_info = ProviderInfo {
        name: "example-unit".to_string(),
        host: provider.url().host_str().unwrap().to_string(),
        transports: vec![ ProviderTransport {
            transport: "HTTP".to_string(),
            port: provider.url().port(),
            path: None,
            scheme: Some("http".to_string())
        } ],
        .. ProviderInfo::default()
    };

    // Create the pact source to pull pacts from the pact-broker
    let pact_source = PactSource::BrokerUrl("example-unit".to_string(), "<http://localhost:9292>".to_string(), None, vec![]);

    // Arrange
    let verification_options: VerificationOptions<NullRequestFilterExecutor> = VerificationOptions::default();
    let provider_state_executor = Arc::new(DummyProviderStateExecutor{});
    let publish_options = PublishOptions {
        provider_version: Some("1.0.0".to_string()),
        build_url: None,
        provider_tags: vec![],
        provider_branch: None,
    };

    let result = verify_provider_async(
        provider_info,
        vec![ pact_source ],
        FilterInfo::None,
        vec![ "instrument-state-unit".to_string() ],
        &verification_options,
        Some(&publish_options),
        &provider_state_executor,
        None
    ).await;

    // Assert
    expect!(result.unwrap().result).to(be_true());
}
The results of it is:
Failures:
1) Verifying a pact between instrument-state-unit and example-unit Given Unit is powered off And Hardware units works normally - Instrument State changes to Starting Up and triggers units to startup - error sending request for url (http://127.0.0.1:8080/)
Any ideas of what am I doing wrong?
r
That test was written to test the Pact verifier by using the Pact mock server to pretend to be a provider. It is not really what you want to so.
Also, the
DummyProviderStateExecutor
doesn't do anything. It won't execute the provider states.