Skip to content

Commit

Permalink
refactor: support multiple providerinfo in JUnit 5 tests #1342
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed May 8, 2021
1 parent 20da4aa commit 4a6c7df
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@ annotation class PactTestFor(
* The type of mock server implementation to use. The default is to use the Java server for HTTP and the KTor
* server for HTTPS
*/
val mockServerImplementation: MockServerImplementation = MockServerImplementation.Default
val mockServerImplementation: MockServerImplementation = MockServerImplementation.Default,

/**
* Test methods that provides the Pacts to use for the test. This allows multiple providers to be
* used in the same test.
*/
val pactMethods: Array<String> = []
)

data class ProviderInfo @JvmOverloads constructor(
Expand Down Expand Up @@ -183,7 +189,7 @@ class JUnit5MockServerSupport(private val baseMockServer: BaseMockServer) : Abst

class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCallback, ParameterResolver, AfterTestExecutionCallback, AfterAllCallback {
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
val providerInfo = lookupProviderInfo(extensionContext).first
val providerInfo = lookupProviderInfo(extensionContext).first().first
val type = parameterContext.parameter.type
return when (providerInfo.providerType) {
ProviderType.ASYNCH -> if (providerInfo.pactVersion == PactSpecVersion.V4) {
Expand All @@ -208,7 +214,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
}

override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
val providerInfo = lookupProviderInfo(extensionContext)
val providerInfo = lookupProviderInfo(extensionContext).first()
val store = extensionContext.getStore(NAMESPACE)
val type = parameterContext.parameter.type
return when (providerInfo.first.providerType) {
Expand Down Expand Up @@ -246,7 +252,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
}

override fun beforeTestExecution(context: ExtensionContext) {
val (providerInfo, pactMethod) = lookupProviderInfo(context)
val (providerInfo, pactMethod) = lookupProviderInfo(context).first()
logger.debug { "providerInfo = $providerInfo" }

if (providerInfo.providerType != ProviderType.ASYNCH) {
Expand All @@ -270,10 +276,10 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
}
}

fun lookupProviderInfo(context: ExtensionContext): Pair<ProviderInfo, String> {
fun lookupProviderInfo(context: ExtensionContext): List<Pair<ProviderInfo, String>> {
val store = context.getStore(NAMESPACE)
return if (store["providerInfo"] != null) {
(store["providerInfo"] as ProviderInfo) to store["pactMethod"].toString()
listOf((store["providerInfo"] as ProviderInfo) to store["pactMethod"].toString())
} else {
val methodAnnotation = if (AnnotationSupport.isAnnotated(context.requiredTestMethod, PactTestFor::class.java)) {
logger.debug { "Found @PactTestFor annotation on test method" }
Expand Down Expand Up @@ -305,7 +311,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
store.put("providerInfo", providerInfo.first)
store.put("pactMethod", providerInfo.second)

providerInfo
listOf(providerInfo)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package au.com.dius.pact.consumer.junit5

import au.com.dius.pact.consumer.MockServer
import au.com.dius.pact.consumer.dsl.PactDslWithProvider
import au.com.dius.pact.core.model.RequestResponsePact
import au.com.dius.pact.core.model.annotations.Pact
import groovyx.net.http.FromServer
import groovyx.net.http.HttpBuilder
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

import static au.com.dius.pact.consumer.dsl.LambdaDsl.newJsonBody

@SuppressWarnings('UnusedMethodParameter')
@ExtendWith(PactConsumerTestExt)
@Disabled
class MultiProviderTest {

@Pact(provider = 'provider1', consumer= 'consumer')
RequestResponsePact pact1(PactDslWithProvider builder) {
builder
.uponReceiving('a new user')
.path('/some-service/users')
.method('POST')
.body(newJsonBody {
it.stringValue('name', 'bob')
}.build())
.willRespondWith()
.status(201)
.matchHeader('Location', 'http(s)?://\\w+:\\d+//some-service/user/\\w{36}$')
.toPact()
}

@Pact(provider = 'provider2', consumer= 'consumer')
RequestResponsePact pact2(PactDslWithProvider builder) {
builder
.uponReceiving('a new user')
.path('/some-service/users')
.method('POST')
.body(newJsonBody {
it.numberType('id')
}.build())
.willRespondWith()
.status(204)
.toPact()
}

@Test
@PactTestFor(pactMethods = ['pact1', 'pact2'])
void runTest1(MockServer mockServer1, MockServer mockServer2) {
def http = HttpBuilder.configure { request.uri = mockServer1.url }

http.post {
request.uri.path = '/some-service/users'
request.body = user()
request.contentType = 'application/json'

response.success { FromServer fs, Object body ->
assert fs.statusCode == 201
assert fs.headers.find { it.key == 'Location' }?.value?.contains(SOME_SERVICE_USER)
}
}

http.get {
request.uri.path = SOME_SERVICE_USER + EXPECTED_USER_ID
request.contentType = 'application/json'
response.success { FromServer fs, Object body ->
assert fs.statusCode == 200
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,4 @@ class MultiTest {
.status(404)
.toPact()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class PactConsumerTestExtTest {
'getTestMethod': { Optional.of(TestClass.methods.find { it.name == 'pactMethod' }) },
'getStore': { mockStore }
] as ExtensionContext
def providerInfo = subject.lookupProviderInfo(context)
def providerInfo = subject.lookupProviderInfo(context)[0]
assertThat(providerInfo.first.providerName, Matchers.is(''))
assertThat(providerInfo.first.hostInterface, Matchers.is(''))
assertThat(providerInfo.first.port, Matchers.is(''))
Expand All @@ -170,7 +170,7 @@ class PactConsumerTestExtTest {
'getTestMethod': { Optional.of(TestClassWithClassLevelAnnotation.methods.find { it.name == 'pactMethod' }) },
'getStore': { mockStore }
] as ExtensionContext
def providerInfo = subject.lookupProviderInfo(context)
def providerInfo = subject.lookupProviderInfo(context)[0]
assertThat(providerInfo.first.providerName, Matchers.is('TestClassWithClassLevelAnnotation'))
assertThat(providerInfo.first.hostInterface, Matchers.is('localhost'))
assertThat(providerInfo.first.port, Matchers.is('8080'))
Expand All @@ -188,7 +188,7 @@ class PactConsumerTestExtTest {
'getTestMethod': { Optional.of(TestClassWithMethodLevelAnnotation.methods.find { it.name == 'pactMethod' }) },
'getStore': { mockStore }
] as ExtensionContext
def providerInfo = subject.lookupProviderInfo(context)
def providerInfo = subject.lookupProviderInfo(context)[0]
assertThat(providerInfo.first.providerName, Matchers.is('TestClassWithMethodLevelAnnotation'))
assertThat(providerInfo.first.hostInterface, Matchers.is('localhost'))
assertThat(providerInfo.first.port, Matchers.is('8080'))
Expand All @@ -208,7 +208,7 @@ class PactConsumerTestExtTest {
},
'getStore': { mockStore }
] as ExtensionContext
def providerInfo = subject.lookupProviderInfo(context)
def providerInfo = subject.lookupProviderInfo(context)[0]
assertThat(providerInfo.first.providerName, Matchers.is('TestClassWithMethodAndClassLevelAnnotation'))
assertThat(providerInfo.first.hostInterface, Matchers.is('testServer'))
assertThat(providerInfo.first.port, Matchers.is('1234'))
Expand All @@ -228,8 +228,7 @@ class PactConsumerTestExtTest {
},
'getStore': { mockStore }
] as ExtensionContext
def providerInfo = subject.lookupProviderInfo(context)
def providerInfo = subject.lookupProviderInfo(context)[0]
assertThat(providerInfo.first.pactVersion, Matchers.is(PactSpecVersion.V3))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,44 +24,44 @@ class XMLPactTest {
.uponReceiving('a POST request with an XML message')
.method('POST')
.path('/message')
.body(new PactXmlBuilder('Message').build(message -> {
.body(new PactXmlBuilder('Message').build { message ->
message.setAttributes([type: 'Request'])
message.appendElement('Head', [:], head -> {
head.appendElement('Client', [name: 'WebCheck'], client -> {
client.appendElement('Version', regexp(/\d+\.\d+\.\d+\.\d+/, "2.2.8.2"))
})
head.appendElement('Server', [:], server -> {
server.appendElement('Name', [:], "SrvCheck")
server.appendElement('Version', [:], "3.0")
})
head.appendElement('Authentication', [:], authentication -> {
authentication.appendElement('User', [:], regexp(/\w+/, "user_name"))
authentication.appendElement('Password', [:], regexp(/\w+/, "password"))
})
message.appendElement('Head', [:]) { head ->
head.appendElement('Client', [name: 'WebCheck']) { client ->
client.appendElement('Version', regexp(/\d+\.\d+\.\d+\.\d+/, '2.2.8.2'))
}
head.appendElement('Server', [:]) { server ->
server.appendElement('Name', [:], 'SrvCheck')
server.appendElement('Version', [:], '3.0')
}
head.appendElement('Authentication', [:]) { authentication ->
authentication.appendElement('User', [:], regexp(/\w+/, 'user_name'))
authentication.appendElement('Password', [:], regexp(/\w+/, 'password'))
}
head.appendElement('Token', [:], '1234567323211242144')
})
message.appendElement('Body', [:], body -> {
body.appendElement('Call', [method: 'getInfo', service: 'CheckRpcService'], call -> {
call.appendElement('Param', [name: regexp(/exportId|mtpId/, 'exportId')], param -> {
}
message.appendElement('Body', [:]) { body ->
body.appendElement('Call', [method: 'getInfo', service: 'CheckRpcService']) { call ->
call.appendElement('Param', [name: regexp(/exportId|mtpId/, 'exportId')]) { param ->
param.appendElement('ExportId', regexp(/\d+/, '1234567890'))
})
})
})
}))
}
}
}
})
.willRespondWith()
.status(200)
.body(new PactXmlBuilder("Message").build(message -> {
message.appendElement('Head', [:], head -> {
head.appendElement('Server', [:], server -> {
.body(new PactXmlBuilder('Message').build { message ->
message.appendElement('Head', [:]) { head ->
head.appendElement('Server', [:]) { server ->
server.appendElement('Name', [:], regexp(/\w+/, 'server_name'))
server.appendElement('Version', [:], regexp(/.+/, 'server_version'))
server.appendElement('Timestamp', [:], regexp(/.+/, 'server_timestamp'))
})
})
message.appendElement('Body', [:], body -> {
}
}
message.appendElement('Body', [:]) { body ->
body.appendElement('Result', [state: 'SUCCESS'])
})
}))
}
})
.toPact()
}

Expand Down
9 changes: 4 additions & 5 deletions provider/gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -642,16 +642,15 @@ Preemptive Authentication can be enabled by setting the `pact.pactbroker.httpcli
### Allowing just the changed pact specified in a webhook to be verified [4.0.6+]

When a consumer publishes a new version of a pact file, the Pact broker can fire off a webhook with the URL of the changed
pact file. To allow only the changed pact file to be verified, you can override the URL by using the `pact.filter.consumers`
and `pact.filter.pacturl` project properties.
pact file. To allow only the changed pact file to be verified, you can override the URL by using the `pact.filter.pacturl` project properties.

For example, running:

```console
gradle pactVerify -Ppact.filter.consumers='Foo Web Client' -Ppact.filter.pacturl=https://test.pact.dius.com.au/pacts/provider/Activity%20Service/consumer/Foo%20Web%20Client/version/1.0.1
```
gradle pactVerify -Ppact.filter.pacturl=https://test.pact.dius.com.au/pacts/provider/Activity%20Service/consumer/Foo%20Web%20Client/version/1.0.1
```

will only run the verification for Foo Web Client with the given pact file URL.
will only run the verification with the given pact file URL.

## Verifying pact files from a S3 bucket

Expand Down

0 comments on commit 4a6c7df

Please sign in to comment.