Skip to content

Commit

Permalink
Merge pull request #731 from danile42/main
Browse files Browse the repository at this point in the history
Document that port cannot be set in parallel tests
  • Loading branch information
jbwheatley authored Nov 14, 2024
2 parents 1ad8fbf + 072f4dd commit cbcdc0a
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 25 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Mostly dependency-free wrapper of [pact-jvm](https://github.com/pact-foundation/
- [Using Pact Matching DSL](#using-pact-matching-dsl)
- [Using JSON bodies](#using-json-bodies)
+ [Request/Response Pacts](#requestresponse-pacts)
- [Choosing a port](#choosing-a-port)
- [Choosing an address and/or port](#choosing-an-address-andor-port)
- ['Inline' Style of Processing Request/Response Pacts](#inline-style-of-processing-requestresponse-pacts)
+ [Message Pacts](#message-pacts)
+ [Mixed Pacts](#mixed-pacts)
Expand Down Expand Up @@ -263,12 +263,12 @@ Examples:
- [weaver](./example/consumer/src/test/scala/http/consumer/WeaverPact.scala)
- [ziotest](./example/consumer/src/test/scala/http/consumer/ZiotestPact.scala)

#### Choosing a port
#### Choosing an address and/or port

If your consumer test need that the provider mock server runs on a specific port, you can override `mockProviderConfig` from `RequestResponsePactForger` like:
If your consumer test needs the provider mock server to run on a specific address and/or port, you can override `mockProviderConfig` from `RequestResponsePactForger` like:

```scala
// Mock server will run on port 9003
// Mock server will run on localhost, port 9003
override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 9003)
```

Expand Down Expand Up @@ -330,9 +330,16 @@ class TestWithInlinePactDefinitions extends AnyFunSpec with InlineRequestRespons
}
```

This style may be useful when it is impractical to write all interactions for all test cases in one single pact. While in this approach the `BaseMockServer` is created and started for each test case individually, it does not
This style may be useful when it is impractical to write all interactions for all test cases in one single pact.
While in this approach the `BaseMockServer` is created and started for each test case individually, it does not
appear to have a noticeable performance impact.

Note that if you want to set a specific port while using the "inline" style, you cannot use parallel test execution, as
the same port cannot be used by multiple parallel instances of the mock server.
See e.g. [WeaverInlinePactSequential](./example/consumer/src/test/scala/http/consumer/WeaverInlinePact.scala) and [ZiotestInlinePactSequential](./example/consumer/src/test/scala/http/consumer/ZiotestInlinePact.scala)
(MUnit and ScalaTest execute tests sequentially by default).


### Message Pacts

Message pacts use the `MessagePactForger` trait. This trait requires that you provide a `MessagePact`. While the general principles of message forging and verification are the same as with request/response pacts, the guidance here will be a bit more abstract as actual implementations will vary by application and messaging framework. That said, at a high level you will want to generate a message and then feed it to your message handling function, which should expect a concrete class type. You do not want to verify what the message handling function does, only that it can receive the message payload without exception.
Expand Down
3 changes: 3 additions & 0 deletions example/consumer/src/test/scala/http/consumer/MunitPact.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package http.consumer

import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.consumer.{ConsumerPactBuilder, PactTestExecutionContext}
import au.com.dius.pact.core.model.RequestResponsePact
import cats.effect.IO
Expand All @@ -32,6 +33,8 @@ import pact4s.munit.RequestResponsePactForger
class MunitPact extends RequestResponsePactForger with ExamplePactCommons {
override val pactTestExecutionContext: PactTestExecutionContext = executionContext

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)

val pact: RequestResponsePact =
ConsumerPactBuilder
.consumer("munit-consumer")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package http.consumer

import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.consumer.{ConsumerPactBuilder, PactTestExecutionContext}
import au.com.dius.pact.core.model.RequestResponsePact
import cats.effect.IO
Expand All @@ -29,9 +30,10 @@ import pact4s.circe.implicits._
import pact4s.scalatest.RequestResponsePactForger

class ScalaTestPact extends AnyFlatSpec with Matchers with ExamplePactCommons with RequestResponsePactForger {

override val pactTestExecutionContext: PactTestExecutionContext = executionContext

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)

val pact: RequestResponsePact =
ConsumerPactBuilder
.consumer("scalatest-consumer")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@ import pact4s.circe.implicits._
import pact4s.weaver.InlineRequestResponsePactForging
import weaver.IOSuite

object WeaverInlinePact extends IOSuite with InlineRequestResponsePactForging[IO] with ExamplePactCommons {
object WeaverInlinePactParallel extends WeaverInlinePact {
override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost")
}

object WeaverInlinePactSequential extends WeaverInlinePact {
override def maxParallelism = 1

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)
}

abstract class WeaverInlinePact extends IOSuite with InlineRequestResponsePactForging[IO] with ExamplePactCommons {

override type Res = Client[IO]

Expand All @@ -39,8 +49,6 @@ object WeaverInlinePact extends IOSuite with InlineRequestResponsePactForging[IO
"../resources/pacts"
)

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost")

private def pact: PactDslWithProvider =
ConsumerPactBuilder
.consumer("weaver-consumer")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package http.consumer

import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.consumer.{ConsumerPactBuilder, PactTestExecutionContext}
import au.com.dius.pact.core.model.RequestResponsePact
import cats.effect.{IO, Resource}
Expand All @@ -33,6 +34,8 @@ object WeaverPact extends IOSuite with RequestResponsePactForger[IO] with Exampl
"../resources/pacts"
)

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)

override type Resources = Client[IO]

override def additionalSharedResource: Resource[IO, Client[IO]] = EmberClientBuilder.default[IO].build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,24 @@ import org.http4s.{BasicCredentials, Uri}
import pact4s.circe.implicits._
import pact4s.ziotest.InlineRequestResponsePactForging
import zio.interop.catz._
import zio.test.{Spec, TestEnvironment, assertTrue}
import zio.test.{Spec, TestAspect, TestEnvironment, assertTrue}
import zio.{Scope, Task, ZIO, ZLayer}

import scala.annotation.nowarn

object ZiotestInlinePact extends InlineRequestResponsePactForging with ExamplePactCommons {
object ZiotestInlinePactParallel extends ZiotestInlinePact {
override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost")
}

override val pactTestExecutionContext: PactTestExecutionContext = executionContext
object ZiotestInlinePactSequential extends ZiotestInlinePact {
override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost")
override def spec: Spec[TestEnvironment with Scope, Any] = super.spec @@ TestAspect.sequential
}

abstract class ZiotestInlinePact extends InlineRequestResponsePactForging with ExamplePactCommons {

override val pactTestExecutionContext: PactTestExecutionContext = executionContext

private def pact: PactDslWithProvider =
ConsumerPactBuilder
Expand Down Expand Up @@ -182,4 +190,4 @@ object ZiotestInlinePact extends InlineRequestResponsePactForging with ExamplePa
}
}
).provideSomeLayerShared[Scope](resources)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package http.consumer

import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.consumer.{BaseMockServer, ConsumerPactBuilder, PactTestExecutionContext}
import au.com.dius.pact.core.model.RequestResponsePact
import io.circe.Json
Expand All @@ -34,6 +35,8 @@ import scala.annotation.nowarn
object ZiotestPact extends RequestResponsePactForgerWith[Client[Task]] with ExamplePactCommons {
override val pactTestExecutionContext: PactTestExecutionContext = executionContext

override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 1234)

val pact: RequestResponsePact =
ConsumerPactBuilder
.consumer("zio-consumer")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ trait InlineRequestResponsePactForging[F[_]] extends MutableFSuite[F] with Inlin
private val F = effect
private[weaver] def serverResource(self: RequestResponsePactForgerResources): Resource[F, BaseMockServer] = {
import self._
val server = createServer
Resource.make[F, BaseMockServer] {
{
for {
_ <- validatePactVersion(mockProviderConfig.getPactVersion).liftTo[F]
_ <- F.delay(server.start())
_ <- F.delay(server.waitForServer())
} yield server
}.onError { case _: Throwable => F.delay(server.stop()) }
} { s =>
F.delay(s.stop())
Resource.eval(F.delay(createServer)).flatMap { server =>
Resource.make[F, BaseMockServer] {
{
for {
_ <- validatePactVersion(mockProviderConfig.getPactVersion).liftTo[F]
_ <- F.delay(server.start())
_ <- F.delay(server.waitForServer())
} yield server
}.onError { case _: Throwable => F.delay(server.stop()) }
} { s =>
F.delay(s.stop())
}
}
}

Expand Down

0 comments on commit cbcdc0a

Please sign in to comment.