jbwheatley / pact4s Goto Github PK
View Code? Open in Web Editor NEWLicense: Apache License 2.0
License: Apache License 2.0
I'm using "io.github.jbwheatley" %% "pact4s-scalatest" % "0.1.0-java8"
During running test, I got this Info log
[info] Pact4s-Logger - Writing pacts for consumer Consumer(name=FraudBackofficeAPI) and provider Provider(name=FraudMlAPI) to target/pacts
However there is no such file exist in target/pacts like log mentioned. Not in my target/pacts path, and not anywhere else. Seem like it's not generated. What's wrong here?
below is my code for my test class
class PactTest extends AsyncFunSuite with Matchers with RequestResponsePactForger with Mockito with MockWSHelpers {
val clientId = 2
override def pact: RequestResponsePact = ConsumerPactBuilder
.consumer("FraudBackofficeAPI")
.hasPactWith("FraudMlAPI")
.uponReceiving("getAllNameNationalityProbability")
.path("http://test:port/predict-nationality")
.method("POST")
.headers(
Map(
"Content-Type" -> "application/json",
"ClientId" -> clientId.toString,
"RequestId" -> "123e4567-e89b-42d3-a456-556642440000"
)
)
.body(
"""{"name":"John Doe",
|"maxResult":3}
|""".stripMargin,
"application/json"
)
.willRespondWith()
.status(200)
.body("""{
| "ARE": 0.0015790796301290394,
| "ARG": 0.0015750796301290393,
| "AUS": 0.027795471251010895
|}
|""".stripMargin)
.toPact
test("getAllNameNationalityProbability should return response for any name") {
val config = mock[FraudBackofficeConfig]
when(config.fraudMlServerConfig)
.thenReturn(FraudMlServerConfig(Seq("http://test:port"), 2))
val ws = MockWS {
case ("POST", "http://test:port/predict-nationality") =>
Action {
Ok(Json.obj(
"ARE" -> 0.0015790796301290393,
"ARG" -> 0.0015750796301290393,
"AUS" -> 0.027795471251010895
))
}
}
val fraudMlClient = new FraudMlServerClientImpl(config, ws)
val getNameNat = fraudMlClient.getAllNameNationalityProbability("John Doe")
assert(getNameNat != null)
}
}
Upgrading to pact-jvm 4.3.x should be enough to make V4 the default.
I need to start up a server which relies on testcontainers before I can provide the correct port in the ProviderInfoBuilder
-- this forces me to call verifyPacts()
asynchronously (from afterContainersStart
), but this results in the test suite exiting without running any tests.
As a workaround for now, I can just put a dummy test case in there, but I wonder if there is a better solution.
In some simple cases, it would be nice to support automatic generation of a DSL given a case class. Similar to what the Kotlin implementation offers with basedOnRequiredConstructorFields
.
Expected usage would be something like following:
case class MyModel(a: String, b: Int, c: NestedModel)
case class NestedModel(x: Seq[Long])
val dsl = DslJsonBodyBuilder.fromType[MyModel]
// Gives a LambdaDslJsonBody => Unit
// Same as what would be given to:
newJsonObject { rootObj =>
rootObj.stringType("a")
rootObj.integerType("b")
rootObj.newObject("c") { o =>
o.newArray("x") { a =>
a.longType()
}
}
}
We could also provide a helper in ScalaDsl
(#355 ):
newJsonObject[MyModel]
The generated DSL would be using matching types, not values.
To implement that, we will need to use TypeTag
but this won't be available in Scala 3 (there are other alternatives in Scala 3). This would mean a different codebase for Scala 2 & Scala 3 which is perfectly possible but I believe the sbt structure does not allow it for now.
If a consumer defines a pact using provider state callback features like .pathFromProviderState("/endpoint/${id}", "/endpoint/36")
, then how to define the id
value on the provider side?
Pact-JVM Junit state provider methods can return a Map of such values but I don't see an equivalent with pact4s-scalatest.
Please add support for the following keys to be used in the consumer version selectors when fetching pacts for verification:
{ "deployedOrReleased": true }
{ "deployed": true }
{ "released": true }
{ "environment": "<env name>" }
{ "deployed": true }
{ "released": true }
These keys can be used in various combinations ( eg. { "environment": "prod", released: true, consumer: "Foo" }
). Please allow any combination of keys, and do not validate them locally, as the validation rules can change over time as support is added for new selectors - just ensure that any errors returned from the API are displayed clearly to the user.
See https://github.com/pact-foundation/pact_broker/blob/master/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown for the usage docs of each selector.
As more selectors will be added over time, it's my preference that the consumer version selectors are not strongly typed, and are just passed through straight from the configuration object to the API, so that we don't have to make code changes to the Pact clients each time we add new selectors. (eg. there will be new selectors coming for branch support very soon). I understand that this is not compatible with the idioms of every Pact client language however, so do whatever you need to do to make the new selectors work elegantly within your language.
Please update https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors/ for your language once the selectors have been released.
Once this issue is resolved: pact-foundation/pact-jvm#1407
We will likely need to make updates to pact4s
in order to support this new behavior.
what do we need to add to pact4s to support protobufs - pact-jvm already appears to have support, so should be doable
The pending feature has been used for long enough now to show that it works, and that there is little reason to ever have it turned off any more. The Pact Broker now defaults to true
if the includePendingStatus
field is not set, however, this will not take effect if the client side has it set to false by default. Please set enablePending
to true by default now, to ensure it is turned on for all older and future versions of the Pact Broker.
Consider printing a warning message if the user does set it to false explicitly, along the lines of "We recommend setting enablePending to true. For more information, please see https://docs.pact.io/pending"
For example, instead of including a compile-time dependency for "org.scalatest" %% "scalatest" % "3.2.8"
, instead use the Provided
scope: "org.scalatest" %% "scalatest" % "3.2.8 % Provided
-- this way any binary compatible version of the library can be included by consumers of the library (they must specify it explicitly in their compile scope), instead of having to pull in the exact version used by this project.
Would there be a way to not having to add a custom endpoint only for the tests in order to setup the provider state when verifying pacts on the provider side?
With Pact-JVM and Junit, it's only a matter of a dedicated method that runs to setup the provider state.
I believe it would be way easier to do it in a similar way in pact4s. I'm not sure adding an endpoint only for tests is an easy task in all web frameworks and that could discourage people to use pact4s.
The Pact Broker now supports branches as first class entities. You can read more about this here: https://docs.pact.io/pact_broker/branches
Please add support for specifying branch related properties in the consumer version selectors that are sent to the Pact Broker when requesting pacts to verify. Please do not do any verification of the consumer version selectors on the client side - the validation rules are subject to change. Just ensure that any error response is displayed to the user.
branch
property to the consumer version selector (if there is a domain model for this).mainBranch
(or main_branch
for snake case languages) property consumer version selector (if there is a domain model for this).matchingBranch
(or matching_branch
for snake case languages) property consumer version selector (if there is a domain model for this).branch
, mainBranch
(or main_branch
for snake case languages) and matchingBranch
(or matching_branch
) properties in the user facing API.branch
, mainBranch
and matchingBranch
(must be camelcase) through to the relevant implementation (ruby and/or rust)export PACT_BROKER_BASE_URL="https://test.pact.dius.com.au"
export PACT_BROKER_USERNAME="dXfltyFMgNOFZAxr8io9wJ37iUpY42M"
export PACT_BROKER_PASSWORD="O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1"
docker run --rm \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_USERNAME \
-e PACT_BROKER_PASSWORD \
pactfoundation/pact-cli:0.50.0.14 \
publish \
/pact/example/pacts \
--consumer-app-version fake-git-sha-for-demo-$(date +%s) \
--branch main
docker run --rm \
-e PACT_BROKER_BASE_URL \
-e PACT_BROKER_USERNAME \
-e PACT_BROKER_PASSWORD \
pactfoundation/pact-cli:0.50.0.14 \
publish \
/pact/example/pacts \
--consumer-app-version fake-git-sha-for-demo-$(date +%s) \
--branch feat/x
{ "mainBranch": true }
{ "branch": "feat/x" }
{ "matchingBranch": true }
with the provider branch set to feat/x
I tested this with VerificationType.AnnotatedMethod
-- but I assume it's the same for request/response. The VerificationResult.Failed
seems to be swallowing up the exception information by default and just shows a generic, unhelpful message like:
Verification failed due to: Request to provider method failed with an exception
ScalaTestFailureLocation: pact4s.scalatest.PactVerifier at (PactVerifier.scala:31)
org.scalatest.exceptions.TestFailedException: Verification failed due to: Request to provider method failed with an exception
I am guessing this is due to the underlying pact-jvm
implementation. I do see something about an environment variable, PACT_SHOW_STACKTRACE
, here: https://github.com/pact-foundation/pact-jvm/blob/master/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderVerifier.kt#L358 -- perhaps that would provide extra information. Otherwise, we would have to extract it out of the errors list.
The readme mentions
1 support for scala 3 is currently blocked by scala/scala3#12086, as pact-jvm is written in kotlin
is this still the case? The dotty issue is marked as fixed.
I'm asking cause a team member currently doing his bachelor-thesis introduced pact4s to our project and I just figured out now that it pulls a huge amount of dependencies into the project and if it additionally would also block us from upgrading to scala 3, that would be an even bigger problem in the future.
Thanks!
We are still using Scala 2.12 for many of our projects, even though we are in the midst of upgrading to 2.13. Would be nice to cross-compile this to 2.12 so we can use it.
It might help in some cases to be able to set a fixed port for the mock server used when running consumer tests, this is already achievable by overriding mockProviderConfig: MockProviderConfig
from RequestResponsePactForgerResources
but not documented.
Example:
class MyTest ... with RequestResponsePactForger {
override val mockProviderConfig: MockProviderConfig = MockProviderConfig.httpConfig("localhost", 9003)
...
}
The ProviderVerifier
by default has:
override var providerMethodInstance: Function<Method, Any> = Function { m -> m.declaringClass.newInstance() }
I have noticed that sometimes this causes issues with references inside of the annotated method when it gets invoked, especially variables that have been defined on traits outside of the class. I have been able to work around this by assigning a variable to this
inside the PactVerifier
trait, and then using verifier.setProviderMethodInstance
to apply it.
I will work on getting a failing test case up, and then applying the fix and making sure it passes.
Consumer pact using pathFromProviderState (see section "Having values injected from provider state callbacks
" on pact-jvm consumer docs)
.given("a user exists", Map("id" -> "6000"))....
.pathFromProviderState("/api/users/${id}", "/api/users/100")
creates a pact json file with interaction object like
{
"description": "a request to find a user",
"providerStates": [
{
"name": "a user exists",
"params": {
"id": "6000"
}
}
],
"request": {
"generators": {
"path": {
"dataType": "STRING",
"expression": "/api/users/${id}",
"type": "ProviderState"
}
},
"method": "GET",
"path": "/api/users/100"
},
"response": {
"body": {
"id": "6000"
},
"status": 200
}
}
...
Producer verification state change function
...
.withStateChangeFunction({
case ProviderState("a user exists", params) =>
val id = params.getOrElse("id", fail("params missing value id"))
createUserWithId(id)
case _ => ()
}: PartialFunction[ProviderState, Unit])
Expected
Pact verification calls producer with path /api/users/6000
Actual
Pact verification calls producer with path /api/users/
Need help regarding the above scenario. I am not sure if it's a bug, yet to be supported feature or if I am doing something wrong.
I have been able to replicate this on the PactVerifierStateChangeFunctionSuite.scala test by using the following pact json content modified to use generators
Logs from unit test execution
[PACT4S TEST INFO] Request to mock provider server with port 49171 in test suite scalatest/requestresponse/PactVerifierStateChangeFunctionSuite.scala
[PACT4S TEST INFO] Request(method=GET, uri=/anyone-, headers=Headers(Accept-Encoding: gzip, x-gzip, deflate, Host: localhost:49171, Connection: keep-alive, User-Agent: Apache-HttpClient/5.1.1 (Java/11.0.11)))
[PACT4S TEST INFO] Response(status=404, headers=Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 9))
[PACT4S TEST INFO] Duration: 0 millis
2022-05-19 01:44:07,378 [pool-2-thread-1] DEBUG a.c.d.pact.provider.ProviderClient - Received response: 404
2022-05-19 01:44:07,379 [pool-2-thread-1] DEBUG a.c.d.pact.provider.ProviderClient - Response: ProviderResponse(statusCode=404, headers={Date=[Thu, 19 May 2022 00:44:07 GMT], Connection=[keep-alive], Content-Type=[text/plain; charset=UTF-8], Content-Length=[9]}, contentType=text/plain; charset=UTF-8, body=Not found)
returns a response which
has status code 200 (FAILED)
has a matching body (FAILED)
Just wanted to start a discussion here about the best way to implement message verification support in Scala. First, a quick overview of current state:
there is a PactVerifier
trait which works without any modification for request/response pacts
the trait uses ProviderVerifier().runVerificationForConsumer
which supports both message and interaction (request/response) pacts
currently this method always defaults to request/response verification because ProviderInfo
doesn't have an explicit verificationType
-- it is easy to add support for this to the ProviderInfoBuilder
:
final case class ProviderInfoBuilder(
name: String,
protocol: String,
host: String,
port: Int,
path: String,
verificationType: PactVerification,
pactSource: PactSource
) {
private[pact4s] def toProviderInfo: ProviderInfo = {
val p = new ProviderInfo(name, protocol, host, port, path)
p.setVerificationType(verificationType)
pactSource match {
case broker: PactBroker => applyBrokerSourceToProvider(p, broker)
case FileSource(consumer, file) =>
p.hasPactWith(
consumer,
{ consumer =>
consumer.setPactSource(new PactJVMFileSource(file))
kotlin.Unit.INSTANCE
}
)
p
}
}
...
}
however, this will result in verification via annotation (@PactVerifyProvider("message description")
):
@PactVerifyProvider("Resource with name 'example'")
def exampleResource(): MessageAndMetadata = {
val headers = Map("header-name" -> "header-value")
val payload = """{"hello":"world"}""".getBytes
new MessageAndMetadata(payload, headers.asJava)
}
Full example:
class ProviderPactMessageVerificationSpec extends PactVerifier with DecorateAsJava {
def provider: ProviderInfoBuilder = ProviderInfoBuilder(
"provider",
"http",
"localhost",
3456,
"/",
PactVerification.ANNOTATED_METHOD,
FileSource("consumer", new File(getClass.getClassLoader.getResource("consumer_provider.json").getPath))
)
@PactVerifyProvider("Resource with name 'example'")
def exampleResource(): MessageAndMetadata = {
val headers = Map("header-name" -> "header-value")
val payload = """{"hello":"world"}""".getBytes
new MessageAndMetadata(payload, headers.asJava)
}
verifyPacts()
}
There are a few things awkward about this flow:
ProviderInfoBuilder
should probably make defining the provider HTTP information optional -- it could be awkward for message verification where no provider states are needed (otherwise the HTTP information would be used to make requests against the provider application for states)So what kind of test DSL do we want for linking of pact messages to message generators? And how would we integrate that with pact-jvm
? Under the hood, the ProviderVerifier
eventually calls verifyMessage -- we could invoke this directly ourselves. I think in general we should try not to drift too far from the pact-jvm
implementation.
Another option I have seen is requesting of messages via an HTTP proxy: https://github.com/pact-foundation/pact-message-demo (the gist: you add endpoints to the provider to support returning messages based on description and provider state) -- however, pact-jvm
does not support this natively.
While updating our internal library to the latest version of pact4s
, I've noticed a few things:
ProviderTags
is cumbersome when you have multiple tags. In our case, we read tags from configuration, so we get it as a list.PactBrokerWithSelectors
dynamically. For example, we use configuration to dynamically enable/disable certain features like pending pacts or WIP pacts. Previously this just meant passing in an Option
, but now we have to build the configuration in stages in an immutable way, which results in harder to read and maintain code (example shown below).PublishVerificationResults
expects providerTags: List[String]
which means we now have to maintain two different ways of generating provider tags since ProviderTags.toList
is privateHere is an example of updating our business logic for these changes. This is what we had previously:
lazy val pactSource: PactSource = PactBrokerWithSelectors(
brokerUrl = pactVerificationSettings.brokerUrl,
auth = Some(pactVerificationSettings.authentication),
enablePending = pactVerificationSettings.enablePendingPacts,
includeWipPactsSince = pactVerificationSettings.includeWorkInProgressPactsSince,
providerTags = pactVerificationSettings.providerTags.toList,
selectors = pactVerificationSettings.consumerVersionSelectors
)
And here's what we have now:
lazy val pactSource: PactSource = {
val pactSource = PactBrokerWithSelectors(pactVerificationSettings.brokerUrl)
.withAuth(pactVerificationSettings.authentication)
.withSelectors(pactVerificationSettings.consumerVersionSelectors)
val pactSourceMaybePending =
if (pactVerificationSettings.enablePendingPacts)
pactSource.withPendingPactsEnabled(pactVerificationSettings.providerTags)
else
pactSource.withPendingPactsDisabled
pactVerificationSettings.includeWorkInProgressPactsSince
.map(pactSourceMaybePending.withWipPactsSince(_, pactVerificationSettings.providerTags))
.getOrElse(pactSourceMaybePending)
}
In addition to updating pactVerificationSettings.providerTags
:
val tags = ... // reads them from configuration
ProviderTags(
tags.headOption.getOrElse(throw new IllegalArgumentException("At least one provider tag must be set.")),
tags.tail.toList
)
I understand these changes are to ensure the generated settings are type safe and compatible, but it makes the interface harder to use.
For some cases, it could be nice to support multiple providers in a single test, as what is possible with Pact JVM and JUnit: https://github.com/pact-foundation/pact-jvm/blob/master/consumer/junit/src/test/java/au/com/dius/pact/consumer/junit/pactproviderrule/PactMultiProviderTest.java.
Looking at the code, it seems to me that one way to achieve this would be to provide a new trait similar to BasePactForgerResourcesForPlatform
that defines a list of pacts rather than a single one:
trait BasePactForgerResourcesForPlatformMultiProvider[Pact <: BasePact] extends BasePactForgerResources {
// def pact: Pact
def pacts: Seq[Pact]
...
}
The existing BasePactForgerResourcesForPlatform
could actually be inheriting BasePactForgerResourcesForPlatformMultiProvider
with a sequence of a single pact to avoid too much code duplication.
Then this could be implemented "on demand" for each test framework (scalatest/munit/weaver).
Any thought on this?
It will be similar to circe
, it should provide a MessagePactDecoder
that uses play.api.libs.json
.
Hi,
I'm currently stuck implementing the verification on the provider side against the pacts published by the consumer on the pactflow broker.
In my code, I've set up the following:
val provider: ProviderInfoBuilder = ProviderInfoBuilder( "PROVIDER_SERVICE_NAME", PactSource.PactBrokerWithSelectors( "https://tray.pactflow.io", ) .withAuth(TokenAuth(Properties.envOrElse("PACTFLOW_READ_WRITE_TOKEN", ""))) .withConsumerVersionSelectors(ConsumerVersionSelectors() .branch(Properties.envOrElse("CONSUMER_BRANCH", "dev"), Some("CONSUMER_SERVICE_NAME"), None) ) ).withHost("localhost") .withPort(port) .withRequestFiltering {...etc
The tests run locally against a file, however when I change it to pactflow and run the tests on the pipeline I'm getting this error:
munit.FailException: /home/runner/work/api-service/api-service/src/pact/scala/../pact/provider/TEST_FILE.scala:59 Call to fetch pacts from Pact Broker failed with an exception 58: test("Verify cluster service pacts successfully") { 59: verifyPacts( 60: publishVerificationResults = Some(PublishVerificationResults("CONSUMER_ID_FROM_PACTFLOW")),
(Some names are edited for company privacy)
With the tests failing in the pipeline but no errors showing on pactflow, it seems like the verification isn't reaching pactflow at all. We're currently stuck in our implementation, so I'd like to know whether there's something missing from the code, or whether it is expected for pact4s not to connect to pactflow.
Thank you for your time
I'm trying to replace an integration test with contract test. So I need to make a real call here.
Below is code of the class that's going to make a call (FraudMlServerClientImpl) note that it has @Inject annotation right after class name.
@Singleton
class FraudMlServerClientImpl @Inject()(
appConfig: FraudBackofficeConfig,
ws: WSClient
)(implicit ec: ExecutionContext) extends FraudMlServerClient with HealthCheckable with LazyLogging {
val clientId = appConfig.fraudMlServerConfig.clientId
val urls: List[String] = appConfig.fraudMlServerConfig.urls.toList
val retryPolicy = RetryPolicy(maxAttemptsAllowed = 4)()
val roundRobin = WeightedRoundRobin[FraudMlServerResource](
urls.map(u => FraudMlServerResource(u, u, PositiveInt(10000))),
decrementOnError = _ => Some(10),
incrementOnSuccess = Some(10)
)
def getAllNameNationalityProbability(
name: String,
maxResult: Int = 3
): Future[Map[String, Double]] = {
// make a call to another service and receive response
}
and this is my PactTest.scala where I have only 1 test for testing getAllNameNationalityProbability method
As you can see when I declared my PactTest class, I have @Inject() follow along to provide appConfig and ws which points to server instance I expect to test with pacts .
class PactTest @Inject()(
appConfig: FraudBackofficeConfig,
ws: WSClient
) extends AsyncFunSuite with Matchers with RequestResponsePactForger {
val clientId = 2
override def pact: RequestResponsePact = ConsumerPactBuilder
.consumer("FraudBackofficeAPI")
.hasPactWith("FraudMlAPI")
.uponReceiving("getAllNameNationalityProbability")
.path("/predict-nationality")
.method("POST")
.headers(
Map(
"Content-Type" -> "application/json",
"ClientId" -> clientId.toString,
"RequestId" -> "123e4567-e89b-42d3-a456-556642440000"
)
)
.body(
"""{"name":"John Doe",
|"maxResult":3}
|""".stripMargin,
"application/json"
)
.willRespondWith()
.status(200)
.body("""{
| "ARE": 0.0015790796301290394,
| "ARG": 0.0015750796301290393,
| "AUS": 0.027795471251010895
|}
|""".stripMargin)
.toPact
test("getAllNameNationalityProbability should return response for any name") {
val fraudMlClient = new FraudMlServerClientImpl(appConfig, ws)
val getNameNat = fraudMlClient.getAllNameNationalityProbability("John Doe")
assert(getNameNat != null)
}
}
However, when I execute this command in terminal => sbt "test:testOnly *PactTest"
I got No tests were executed. Seem like it doesn't see a test in this file at all. But when I try removing those @Inject out and initiate client by new FraudMlServerClientImpl(null, null) and execute the same test command again, the test is being run.
The result is not what I expected though, as I said I need to make a real call here. But seem like I can't use @Inject with pact for some what reason. How do I deal with this? please help.
FYI. I'm using
"io.github.jbwheatley" %% "pact4s-scalatest-java8" % "0.0.19" % Test
Unless I missing something, there's no "easy" way to define a beforeEach/afterEach logic to run automatically before or after each contract request verification on the provider side.
Take for instance the following code sample:
class PactVerificationsTest extends PactVerifier {
override def provider: ProviderInfoBuilder = ProviderInfoBuilder(...)
...
.withStateChangeFunction {
case ProviderState("State A", params) =>
resetState()
// ... some specific state logic
case ProviderState("State B", params) =>
resetState()
// ... some specific state logic
}
...
}
We have to put the resetState()
call in every state.
Would it make sense to have something like a .withStateChangeBeforeHook { f() }
that would make the verifier automatically call f()
before each request verification?
If you think it make sense, I'll be happy to help implement it.
the tests in the example directory aren't runnable.
depends on scala/scala3#12086
just popping this in an issue to keep track of it
If the mock server has not received requests for all the interactions defined in the consumer pact, then the pact file will not be written. We are still logging that this write is taking place on the pact4s side, which is misleading in the case that the interactions are not complete. We should check whether all interactions have been run and inform the user accordingly for better transparency.
Saw this come up in #178
Instead of writing out pacts at the end of run(testName: Option[String], args: Args)
, it would be more flexible to do it in afterAll(): Unit
of the BeforeAndAfterAll
trait -- that way users can provide custom logic to fail the tests prior to the pact files being written.
In our case, I want to ensure that a test exists for every message defined. If not, I want the suite to fail and pacts to not be written.
We should run CI checks against PRs, and again during the release process prior to publish. Probably we can just use github actions workflows for this, perhaps with https://github.com/djspiewak/sbt-github-actions
The documentation and the actual content received by a provider states that a ProviderState
is of the form {"state" : "the provider state id string", "params": { "id": "bob" } }
but the definition of ProviderState
case class is not up to date and only contains the state
.
we haven't got anything written about how to write message pacts in pact4s ๐ข
This needs to check the status of failed.getPending
. If it's true, we should mark the test as skipped
instead of failure
, since pending pacts should not fail the build.
Originally filed as pact-foundation/pact-jvm#1417
Hello!
I'm not sure if I'm being dense but I can't figure out how to use generators
with pact4s
on the Provider
side of things
Forgive me if I don't use the correct lexicon, I'm super new to pact and inheriting incomplete code
My Consumer
generates a pact that contains something like this:
"generators": {
"header": {
"Authorization": {
"dataType": "STRING",
"expression": "Bearer ${bearerToken}",
"type": "ProviderState"
}
}
},
"headers": {
"Authorization": "Bearer super-secure"
},
"method": "GET",
"path": "/whatever"
},
If I understand this correctly, this allows the Provider
code to inject its bearerToken
to be then used as a param during the contract test, so I expected to be able to return these generated params back in the withStateChangeFunction
function but that function is instead a ProviderState => Unit
so I can't return anything.
I did some changes locally to pact4s
itself and made that function into a ProviderState => ProviderState
so I was able to do the injecting I required, but I wanted to engage here first to understand if what I'm doing makes sense, before sending a PR over
I'm evaluating this as an alternative to scala-pact. The main feature gap I see at the moment is the inability to handle provider states when checking pacts. However, I also notice that pact-jvm has native support for scalatest providers
https://github.com/pact-foundation/pact-jvm/tree/master/provider/scalatest
and that it seems to offer pretty rich support for modeling provider states so it might be worth linking to them.
The Pact Broker now supports branches as first class entities. You can read more about this here: https://docs.pact.io/blog/2021/10/08/why-we-are-getting-rid-of-tags
To allow users to use this feature:
From the documentation of Pact (https://docs.pact.io/implementation_guides/jvm/consumer#examples), a new Lambda DSL is available which allows to represent the following data:
[
["a1", "a2"],
[1, 2],
[{"foo": "Foo"}]
]
With the following syntax (Scala):
newJsonArray((rootArray) => {
rootArray.array((a) => a.stringValue("a1").stringValue("a2"))
rootArray.array((a) => a.numberValue(1).numberValue(2))
rootArray.array((a) => a.object((o) => o.stringValue("foo", "Foo")))
}).build()
Which is quite nice, but there's also a Kotlin Lambda DSL that can express the same with following syntax:
newJsonArray {
newArray {
stringValue("a1")
stringValue("a2")
}
newArray {
numberValue(1)
numberValue(2)
}
newArray {
newObject { stringValue("foo", "Foo") }
}
}
It could be nice to have a Scala Lambda DSL similar to the Kotlin one.
A reminder to myself to set up scala-steward now that the public instance is no longer active.
In some projects I got exception when use pactVerify
method:
java.lang.IllegalAccessError: tried to access method com.google.common.util.concurrent.SimpleTimeLimiter.<init>(Ljava/util/concurrent/ExecutorService;)V from class pact4s.TimeLimiter$
version: 0.5.0
Hi,
I have try to add a header in ProviderResponseBuilder with the below code.
ProviderResponseBuilder(
responseCode,
responseBody
)
.withHeaders(Map("Content-Type" -> List[String]("application/json;charset=UTF-8")))
However, I got pact verification failed with below error.
scala.collection.immutable.$colon$colon cannot be cast to java.util.List
As I try to debug, it seems the type of Header is different where expected response header type is ArrayList
, but the actual response header type is ::
.
Any idea how to fix this?
au.com.dius.pact.consumer.dsl.PactBuilder
is required to construct V4 pacts, and the constructors we currently support (au.com.dius.pact.consumer.ConsumerPactBuilder
and au.com.dius.pact.consumer.MessagePactBuilder
) are now considered legacy.
We should add extension methods to aid in the creation of pacts using this new dsl, similar to what we do in https://github.com/jbwheatley/pact4s/tree/main/shared/src/main/scala/pact4s/syntax
Currently you can publish results by manually setting system properties, e.g.
System.setProperty(ProviderVerifier.PACT_VERIFIER_PUBLISH_RESULTS, "true")
But this is clunky and not a common pattern in Scala. It would be preferable to provide an explicit interface for publishing of verification results. Users can still gather information from the System
properties if they want to, but they will need to be explicit about it.
Sending people to the test classes to look at examples isn't that user-friendly, and lots there is obfuscated for the purpose of brevity. Would be better to create a module with a full example set up for a request-response relationship, and for a messaging relationship.
if the state change function doesn't have a matching case, then the output message will just be something like: State change callback failed with an exception - State Change Request Failed - 400 Bad Request
.
It would be much better if we provided more context on why the callback failed, e.g. "expected state "bla bla", received state "blo blo""
When specifying a provider state with .given()
, the second argument can be a Map of parameters. We should add support for using a scala Map there like we have for .headers
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.