pact-foundation / pact-python

Python version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
http://pact.io
MIT License
573 stars 138 forks source link

Mapping provider/customer with description #829

Open ramondepieri opened 1 week ago

ramondepieri commented 1 week ago

Have you read the Contributing Guidelines on issues?

Prerequisites

Description

I am trying to create a message contract test, but something is going wrong:

RuntimeError:
       An error was raised while verifying the message. The response body is: {"detail":"No matched handler."}

According to tests, the problem is happening in reason of mapping is being made by provider state instead of description

Reproducible demo

No response

Steps to reproduce

Run the consumer:

# consumer.py
from pact import MessageConsumer, Provider

def run_consumer():
    contract = MessageConsumer(
        "my_contract Consumer"
    ).has_pact_with(
        Provider("my_contract Provider"),
        pact_dir="pacts",
    )

    event_data = {
        "invoice_id": "12345",
        "amount": 100.00,
        "currency": "USD"
    }

    contract.given("Create contract").expects_to_receive(
        "An event of contract").with_content(event_data)

    with contract:
        pass

if __name__ == "__main__":
    run_consumer()

Now run the provider:

# provider.py
from pact import MessageProvider

def process_invoice_event(event):
    invoice_id = event.get("invoice_id")
    amount = event.get("amount")
    currency = event.get("currency")

    # Validação simples
    if not invoice_id or amount <= 0:
        return {"status": "error", "message": "Invalid invoice data"}

    print(f"Processing invoice: ID = {invoice_id}, Amount = {amount} {currency}")
    return event

def run_provider():
    simulated_event = {
        "invoice_id": "12345",
        "amount": 100.00,
        "currency": "USD"
    }

    provider = MessageProvider(
        message_providers={
            "An event of contract": lambda: process_invoice_event(simulated_event),
        },
        provider="my_contract Provider",
        pact_dir="pacts",
        consumer="my_contract Consumer",
    )

    with provider:
        provider.verify()

if __name__ == "__main__":
    run_provider()

This error will happens: RuntimeError: An error was raised while verifying the message. The response body is: {"detail":"No matched handler."}

Now change the message_providers, to use "Create contract" string instead of "An event of contract"

Note that now is working

Expected behavior

The mapping should use the description instead of provider state

Actual behavior

RuntimeError: An error was raised while verifying the message. The response body is: {"detail":"No matched handler."}

Your environment

No response

Self-service

mefellows commented 1 week ago

I think if we do fix it, to preserve backwards compatibility we may need to check (map) both the states and the description, and only error if one is not found.

YOU54F commented 3 days ago

This has always been a long-standing bug in the pact-python message pact implementation. You will need to map providerStates to message handlers in Pact-python at the moment.

It is also present in the v3 pact examples.

The consumer side

https://github.com/pact-foundation/pact-python/blob/34f686ff3fc57d48284092925bd5b5ac0b8507c6/examples/tests/test_02_message_consumer.py#L114

These should be swapped.

        pact.given("a request to read test.txt")
        .expects_to_receive("test.txt exists")

to be

        pact.given("test.txt exists")
        .expects_to_receive("a request to read test.txt")

In the message provider, we are incorrectly using the provider state, instead of the description

https://github.com/pact-foundation/pact-python/blob/34f686ff3fc57d48284092925bd5b5ac0b8507c6/examples/tests/v3/test_03_message_provider.py#L35-L44

in the message provider proxy, that is shown in the examples, it does not provide a mechanism to pass the message description

https://github.com/pact-foundation/pact-python/blob/34f686ff3fc57d48284092925bd5b5ac0b8507c6/examples/tests/v3/provider_server.py#L88

Those examples should be updated in V3 as well, to use the description, and not the provider state, for the handler mappings