Skip to content

Commit 2ed86d3

Browse files
author
Ronald Holshausen
committedApr 4, 2020
fix: JUnit 5 No values are injected into response headers and response bodies from state callbacks #1060
1 parent 8997d01 commit 2ed86d3

File tree

7 files changed

+227
-6
lines changed

7 files changed

+227
-6
lines changed
 

‎provider/pact-jvm-provider-junit/src/main/kotlin/au/com/dius/pact/provider/junit/target/HttpTarget.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ open class HttpTarget
7575
reportTestResult(failures.isEmpty(), verifier)
7676

7777
try {
78-
if (!failures.isEmpty()) {
78+
if (failures.isNotEmpty()) {
7979
verifier.displayFailures(failures)
8080
throw getAssertionError(failures)
8181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package au.com.dius.pact.provider.junit
2+
3+
import au.com.dius.pact.provider.junit.loader.PactFolder
4+
import au.com.dius.pact.provider.junit.target.HttpTarget
5+
import au.com.dius.pact.provider.junit.target.Target
6+
import au.com.dius.pact.provider.junit.target.TestTarget
7+
import com.github.restdriver.clientdriver.ClientDriverRule
8+
import groovy.util.logging.Slf4j
9+
import org.apache.http.HttpRequest
10+
import org.junit.Before
11+
import org.junit.ClassRule
12+
import org.junit.runner.RunWith
13+
14+
import static com.github.restdriver.clientdriver.RestClientDriver.giveEmptyResponse
15+
import static com.github.restdriver.clientdriver.RestClientDriver.onRequestTo
16+
import static com.github.restdriver.clientdriver.ClientDriverRequest.Method.POST
17+
import static org.hamcrest.Matchers.equalTo
18+
19+
@RunWith(PactRunner)
20+
@Provider('providerInjectedHeaders')
21+
@PactFolder('pacts')
22+
@Slf4j
23+
class InjectedHeadersContractTest {
24+
@ClassRule
25+
@SuppressWarnings('FieldName')
26+
public static final ClientDriverRule embeddedService = new ClientDriverRule(8332)
27+
28+
@TestTarget
29+
@SuppressWarnings(['PublicInstanceField', 'JUnitPublicField'])
30+
public final Target target = new HttpTarget(8332)
31+
32+
@Before
33+
void before() {
34+
embeddedService.addExpectation(
35+
onRequestTo('/accounts').withMethod(POST)
36+
.withHeader('X-ContractTest', equalTo('true')),
37+
38+
giveEmptyResponse().withStatus(201)
39+
.withHeader('Location', 'http://localhost:8332/accounts/1234')
40+
)
41+
}
42+
43+
@TargetRequestFilter
44+
void exampleRequestFilter(HttpRequest request) {
45+
request.addHeader('X-ContractTest', 'true')
46+
}
47+
48+
@State('an active account exists')
49+
Map<String, Object> createAccount() {
50+
[
51+
port: 8332,
52+
accountId: '1234'
53+
]
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"provider" : {
3+
"name" : "providerInjectedHeaders"
4+
},
5+
"consumer" : {
6+
"name" : "consumer"
7+
},
8+
"interactions" : [ {
9+
"providerStates": [
10+
{
11+
"name": "an active account exists",
12+
"params": {
13+
"name": "account 1"
14+
}
15+
}
16+
],
17+
"description" : "Create new account for user",
18+
"request" : {
19+
"method" : "POST",
20+
"path" : "/accounts"
21+
},
22+
"response" : {
23+
"status": 201,
24+
"headers": {
25+
"Location": "http://localhost:8080/accounts/4beb44f1-53f7-4281-a78b-12c06d682067"
26+
},
27+
"generators": {
28+
"header": {
29+
"Location": {
30+
"type": "ProviderState",
31+
"expression": "http://localhost:${port}/accounts/${accountId}"
32+
}
33+
}
34+
}
35+
}
36+
} ],
37+
"metadata" : {
38+
"pact-specification" : {
39+
"version" : "3.0.0"
40+
},
41+
"pact-jvm" : {
42+
"version" : "4.0.8"
43+
}
44+
}
45+
}

‎provider/pact-jvm-provider-junit5/src/main/kotlin/au/com/dius/pact/provider/junit5/PactJUnit5VerificationProvider.kt

+9-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ data class PactVerificationContext @JvmOverloads constructor(
7777
val store = context.getStore(ExtensionContext.Namespace.create("pact-jvm"))
7878
val client = store.get("client")
7979
val request = store.get("request")
80+
val testContext = store.get("interactionContext") as PactVerificationContext
8081
val failures = mutableMapOf<String, Any>()
8182
try {
82-
this.testExecutionResult = validateTestExecution(client, request, failures)
83+
this.testExecutionResult = validateTestExecution(client, request, failures, testContext.executionContext ?: emptyMap())
8384
if (testExecutionResult is TestResult.Failed) {
8485
verifier!!.displayFailures(failures)
8586
throw AssertionError(JUnitProviderTestSupport.generateErrorStringFromMismatches(failures))
@@ -89,13 +90,18 @@ data class PactVerificationContext @JvmOverloads constructor(
8990
}
9091
}
9192

92-
private fun validateTestExecution(client: Any?, request: Any?, failures: MutableMap<String, Any>): TestResult {
93+
private fun validateTestExecution(
94+
client: Any?,
95+
request: Any?,
96+
failures: MutableMap<String, Any>,
97+
context: Map<String, Any>
98+
): TestResult {
9399
if (providerInfo.verificationType == null || providerInfo.verificationType == PactVerification.REQUEST_RESPONSE) {
94100
val interactionMessage = "Verifying a pact between $consumerName and ${providerInfo.name}" +
95101
" - ${interaction.description}"
96102
return try {
97103
val reqResInteraction = interaction as RequestResponseInteraction
98-
val expectedResponse = reqResInteraction.response
104+
val expectedResponse = reqResInteraction.response.generatedResponse(context)
99105
val actualResponse = target.executeInteraction(client, request)
100106

101107
verifier!!.verifyRequestResponsePact(expectedResponse, actualResponse, interactionMessage, failures,

‎provider/pact-jvm-provider-junit5/src/test/groovy/au/com/dius/pact/provider/junit5/PactVerificationContextSpec.groovy

+9-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ class PactVerificationContextSpec extends Specification {
1616
@SuppressWarnings('UnnecessaryGetter')
1717
def 'sets the test result to an error result if the test fails with an exception'() {
1818
given:
19-
ExtensionContext.Store store = Stub()
19+
PactVerificationContext context
20+
ExtensionContext.Store store = Stub {
21+
get(_) >> { args ->
22+
if (args[0] == 'interactionContext') {
23+
context
24+
}
25+
}
26+
}
2027
ExtensionContext extContext = Stub {
2128
getStore(_) >> store
2229
}
@@ -33,7 +40,7 @@ class PactVerificationContextSpec extends Specification {
3340
new Response(), '12345')
3441
TestResult testResult = TestResult.Ok.INSTANCE
3542

36-
def context = new PactVerificationContext(store, extContext, target, verifier, valueResolver,
43+
context = new PactVerificationContext(store, extContext, target, verifier, valueResolver,
3744
provider, consumerName, interaction, testResult)
3845

3946
when:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package au.com.dius.pact.provider.junit5
2+
3+
import au.com.dius.pact.core.model.Interaction
4+
import au.com.dius.pact.core.model.Pact
5+
import au.com.dius.pact.provider.junit.Provider
6+
import au.com.dius.pact.provider.junit.State
7+
import au.com.dius.pact.provider.junit.loader.PactFolder
8+
import com.github.tomakehurst.wiremock.WireMockServer
9+
import groovy.util.logging.Slf4j
10+
import org.apache.http.HttpRequest
11+
import org.junit.jupiter.api.BeforeEach
12+
import org.junit.jupiter.api.TestTemplate
13+
import org.junit.jupiter.api.extension.ExtendWith
14+
import ru.lanwen.wiremock.ext.WiremockResolver
15+
import ru.lanwen.wiremock.ext.WiremockUriResolver
16+
17+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse
18+
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo
19+
import static com.github.tomakehurst.wiremock.client.WireMock.post
20+
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo
21+
22+
@Provider('providerInjectedHeaders')
23+
@PactFolder('pacts')
24+
@ExtendWith([
25+
WiremockResolver,
26+
WiremockUriResolver
27+
])
28+
@Slf4j
29+
class StateInjectedHeadersProviderTest {
30+
31+
@TestTemplate
32+
@ExtendWith(PactVerificationInvocationContextProvider)
33+
void testTemplate(Pact pact, Interaction interaction, HttpRequest request, PactVerificationContext context) {
34+
log.info("testTemplate called: ${pact.provider.name}, ${interaction.description}")
35+
request.addHeader('X-ContractTest', 'true')
36+
37+
context.verifyInteraction()
38+
}
39+
40+
@BeforeEach
41+
void before(PactVerificationContext context, @WiremockResolver.Wiremock WireMockServer server,
42+
@WiremockUriResolver.WiremockUri String uri) throws MalformedURLException {
43+
log.info("BeforeEach - $uri")
44+
45+
context.setTarget(HttpTestTarget.fromUrl(new URL(uri)))
46+
47+
server.stubFor(
48+
post(urlPathEqualTo('/accounts'))
49+
.withHeader('X-ContractTest', equalTo('true'))
50+
.willReturn(aResponse()
51+
.withStatus(201)
52+
.withHeader('Location', 'http://localhost:8090/accounts/1234'))
53+
)
54+
}
55+
56+
@State('an active account exists')
57+
Map<String, Object> createAccount() {
58+
[
59+
port: 8090,
60+
accountId: '1234'
61+
]
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"provider" : {
3+
"name" : "providerInjectedHeaders"
4+
},
5+
"consumer" : {
6+
"name" : "consumer"
7+
},
8+
"interactions" : [ {
9+
"providerStates": [
10+
{
11+
"name": "an active account exists",
12+
"params": {
13+
"name": "account 1"
14+
}
15+
}
16+
],
17+
"description" : "Create new account for user",
18+
"request" : {
19+
"method" : "POST",
20+
"path" : "/accounts"
21+
},
22+
"response" : {
23+
"status": 201,
24+
"headers": {
25+
"Location": "http://localhost:8080/accounts/4beb44f1-53f7-4281-a78b-12c06d682067"
26+
},
27+
"generators": {
28+
"header": {
29+
"Location": {
30+
"type": "ProviderState",
31+
"expression": "http://localhost:${port}/accounts/${accountId}"
32+
}
33+
}
34+
}
35+
}
36+
} ],
37+
"metadata" : {
38+
"pact-specification" : {
39+
"version" : "3.0.0"
40+
},
41+
"pact-jvm" : {
42+
"version" : "4.0.8"
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)
Please sign in to comment.