pactcontractpactflow

Why no PACT is returned when calling path /pacts/provider/<name>/for-verification


I have a strange issue, I am creating a 2nd pact for consumer A, the first provider is B, and now I just uploaded the pact for provider C. The issue is that although I see the pact on the UI, when the curling/calling.

Using:

pact for junit5 4.6.3

pact-broker 2.110.0-pactbroker2.107.1

https://brokerurl/pacts/provider/C/for-verification

I see this

{"_embedded":{"pacts":[]},"_links":{"self":{"href":"https://brokerurl/pacts/provider/C/for-verification","title":"Pacts to be verified"}}}

I dont know what the issue is as I upload the contract from the same class in the consumer side.

Any ideas?

import au.com.dius.pact.consumer.MessagePactBuilder
import au.com.dius.pact.consumer.dsl.PactDslJsonBody
import au.com.dius.pact.consumer.junit5.PactConsumerTest
import au.com.dius.pact.consumer.junit5.PactTestFor
import au.com.dius.pact.consumer.junit5.ProviderType
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.annotations.Pact
import au.com.dius.pact.core.model.messaging.Message
import au.com.dius.pact.core.model.messaging.MessagePact
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.traderepublic.schemas.avro4k.resolve.core.ConversationCreatedEvent
import com.traderepublic.schemas.avro4k.resolve.core.CustomerCreatedEvent
import org.junit.jupiter.api.Test
import kotlin.test.assertNull

@PactConsumerTest
class TestPactConsumerTest {
    @Pact(
        provider = "B",
        consumer = "A",
    )
    fun bAsyncEvent(builder: MessagePactBuilder): MessagePact {
        val body =
            with(PactDslJsonBody()) {
                uuid("id")
                `object`("context")
                    .uuid("correlationId")
                    .closeObject()
                `object`("payload")
                    .uuid("id")
                    .closeObject()

                return@with this
            }

        return builder.expectsToReceive("create B created event")
            .withContent(body)
            .toPact()
    }

    @Test
    @PactTestFor(
        pactMethod = "bAsyncEvent",
        providerType = ProviderType.ASYNCH,
        pactVersion = PactSpecVersion.V3,
    )
    fun bCreatedAsyncEventTest(messages: List<Message>) {
        val testObjectMapper = jacksonObjectMapper().registerModule(JavaTimeModule())

        val message =
            testObjectMapper.readValue(
                messages.single().contentsAsString(),
                CustomerCreatedEvent::class.java,
            )

        assertNull(message.context!!.trigger, "If the trigger is not set, it should be null")
    }


    @Pact(
        provider = "C",
        consumer = "A",
    )
    fun cCreatedAsyncEvent(builder: MessagePactBuilder): MessagePact {
        val body =
            with(PactDslJsonBody()) {
                uuid("id")
                `object`("payload")
                    .uuid("Id")
                    .closeObject()

                return@with this
            }

        return builder.expectsToReceive("create C created event")
            .withContent(body)
            .toPact()
    }

    @Test
    @PactTestFor(
        pactMethod = "cCreatedAsyncEvent",
        providerType = ProviderType.ASYNCH,
        pactVersion = PactSpecVersion.V3,
    )
    fun cCreatedAsyncEventTest(messages: List<Message>) {
        val testObjectMapper = jacksonObjectMapper().registerModule(JavaTimeModule())

        val message =
            testObjectMapper.readValue(
                messages.single().contentsAsString(),
                ConversationCreatedEvent::class.java,
            )

        assertNull(message.context, "If the context is not set, it should be null")
    }
}

I also tried use a random name for the new service C like (test-provider) and I get the same error, so I am wondering if the issue is the name of the expectation. Please any help is welcome.


Solution

  • So I found that the query for the latest pact searchs for main branch on the pact_publications "branch_heads"."branch_name" AS "branch_name".

    Here is the full query:

    SELECT "pact_publications".* FROM (SELECT "pact_publications".*, "branch_heads"."branch_name" AS "branch_name" FROM "pact_publications" INNER JOIN "pacticipants" AS "consumers" ON ("pact_publications"."consumer_id" = "consumers"."id") 
    INNER JOIN "branch_heads" ON (("pact_publications"."consumer_version_id" = "branch_heads"."version_id")
    # The issue was on this inner join on the second conditional
    AND ("consumers"."main_branch" = "branch_heads"."branch_name")) WHERE (("pact_publications"."provider_id" = 15) AND ("pact_publications"."consumer_id" IN (SELECT "pacticipants"."id" FROM "pacticipants" WHERE (("name" = 'resolve-core-ticket-service-async') AND ("pacticipants"."id" IS NOT NULL)))))) AS "pact_publications" INNER JOIN "latest_pact_publication_ids_for_consumer_versions" AS "lp" ON ("lp"."pact_publication_id" = "pact_publications"."id")
    

    Long story short, if you dont tag it with main, it won’t return it. This break a bit the flow we thought for onboarding an application but we found a workaround.

    Also if you main branch is master you might need to update your CI or run a command to update the main branch of a pacticipant.

    pact-broker create-or-update-pacticipant --name Foo --main-branch dev