Skip to content

Commit

Permalink
feat: Add tests for supportingmultiple test targets with JUnit 5 #1708
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Dec 16, 2023
1 parent 4687d96 commit 9a8d121
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.UnknownPactSource
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.generators.GeneratorTestMode
import au.com.dius.pact.core.support.*
import au.com.dius.pact.core.support.MetricEvent
import au.com.dius.pact.core.support.Metrics
import au.com.dius.pact.core.support.Result
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
import au.com.dius.pact.core.support.expressions.ValueResolver
import au.com.dius.pact.provider.IConsumerInfo
Expand All @@ -20,7 +22,6 @@ import au.com.dius.pact.provider.ProviderVerifier
import au.com.dius.pact.provider.VerificationFailureType
import au.com.dius.pact.provider.VerificationResult
import au.com.dius.pact.provider.junitsupport.TestDescription
import io.pact.plugins.jvm.core.PluginConfiguration
import org.junit.jupiter.api.extension.ExtensionContext
import kotlin.collections.isNotEmpty

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

import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.messaging.Message
import spock.lang.Specification

class HttpTestTargetSpec extends Specification {
def 'supports any HTTP interaction'() {
expect:
new HttpTestTarget().supportsInteraction(interaction) == result

where:
interaction | result
new RequestResponseInteraction('test') | true
new Message('test') | false
new V4Interaction.AsynchronousMessage('test') | false
new V4Interaction.SynchronousMessages('test') | false
new V4Interaction.SynchronousHttp('test') | true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package au.com.dius.pact.provider.junit5

import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.messaging.Message
import spock.lang.Specification

class MessageTestTargetSpec extends Specification {
def 'supports any message interaction'() {
expect:
new MessageTestTarget().supportsInteraction(interaction) == result

where:
interaction | result
new RequestResponseInteraction('test') | false
new Message('test') | true
new V4Interaction.AsynchronousMessage('test') | true
new V4Interaction.SynchronousMessages('test') | true
new V4Interaction.SynchronousHttp('test') | false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,82 @@ class PactVerificationContextSpec extends Specification {
1 * verifier.verifyResponseByInvokingProviderMethods(provider, consumer, interaction,
interaction.description, [:], true, _) >> new VerificationResult.Ok()
}

def 'currentTarget - returns the current target if it supports the interaction'() {
given:
def expectedTarget = new HttpTestTarget()
ExtensionContext.Store store = Stub()
ExtensionContext extContext = Stub()
IProviderVerifier verifier = Mock()
ValueResolver valueResolver = Stub()
IProviderInfo provider = Stub()
IConsumerInfo consumer = Stub()
Interaction interaction = new RequestResponseInteraction('test')
def pact = new RequestResponsePact(new Provider(), new Consumer(), [interaction])
List<VerificationResult> testResults = []

def context = new PactVerificationContext(store, extContext, expectedTarget, verifier, valueResolver,
provider, consumer, interaction, pact, testResults)

when:
def result = context.currentTarget()

then:
result == expectedTarget
}

@SuppressWarnings('LineLength')
def 'currentTarget - searches for a target in the additional ones if the current target does not support the interaction'() {
given:
def expectedTarget = new HttpTestTarget()
ExtensionContext.Store store = Stub()
ExtensionContext extContext = Stub()
IProviderVerifier verifier = Mock()
ValueResolver valueResolver = Stub()
IProviderInfo provider = Stub()
IConsumerInfo consumer = Stub()
Interaction interaction = new RequestResponseInteraction('test')
def pact = new RequestResponsePact(new Provider(), new Consumer(), [interaction])
List<VerificationResult> testResults = []
TestTarget otherTarget = Mock {
supportsInteraction(_) >> false
}

def context = new PactVerificationContext(store, extContext, new MessageTestTarget(), verifier, valueResolver,
provider, consumer, interaction, pact, testResults)
context.addAdditionalTarget(otherTarget)
context.addAdditionalTarget(expectedTarget)

when:
def result = context.currentTarget()

then:
result == expectedTarget
}

def 'currentTarget - returns null if no target can be found that supports the interaction'() {
given:
ExtensionContext.Store store = Stub()
ExtensionContext extContext = Stub()
IProviderVerifier verifier = Mock()
ValueResolver valueResolver = Stub()
IProviderInfo provider = Stub()
IConsumerInfo consumer = Stub()
Interaction interaction = new RequestResponseInteraction('test')
def pact = new RequestResponsePact(new Provider(), new Consumer(), [interaction])
List<VerificationResult> testResults = []
TestTarget otherTarget = Mock {
supportsInteraction(_) >> false
}

def context = new PactVerificationContext(store, extContext, new MessageTestTarget(), verifier, valueResolver,
provider, consumer, interaction, pact, testResults)
context.addAdditionalTarget(otherTarget)

when:
def result = context.currentTarget()

then:
result == null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,41 @@ class PactVerificationExtensionSpec extends Specification {
RequestData | new PluginTestTarget() | true
}

def 'supports parameter test with mutiple test targets'() {
given:
def interaction = new V4Interaction.SynchronousHttp(null, 'interaction2')
context = new PactVerificationContext(store, extContext, target, Stub(IProviderVerifier),
Stub(ValueResolver), Stub(IProviderInfo), Stub(IConsumerInfo), interaction, pact, [])
context.addAdditionalTarget(new MessageTestTarget())

extension = new PactVerificationExtension(pact, pactSource, interaction, 'service', 'consumer',
mockValueResolver)
Parameter parameter = mock(Parameter)
when(parameter.getType()).thenReturn(parameterType)
ParameterContext parameterContext = Stub {
getParameter() >> parameter
}

expect:
extension.supportsParameter(parameterContext, extContext) == true

where:

parameterType | target
Pact | new HttpTestTarget()
Interaction | new HttpTestTarget()
ClassicHttpRequest | new HttpTestTarget()
ClassicHttpRequest | new HttpsTestTarget()
ClassicHttpRequest | new MessageTestTarget()
HttpRequest | new HttpTestTarget()
HttpRequest | new HttpsTestTarget()
HttpRequest | new MessageTestTarget()
PactVerificationContext | new HttpTestTarget()
ProviderVerifier | new HttpTestTarget()
RequestData | new HttpTestTarget()
RequestData | new PluginTestTarget()
}

def 'resolve parameter test'() {
given:
extension = new PactVerificationExtension(pact, pactSource, interaction1, 'service', 'consumer',
Expand Down Expand Up @@ -234,4 +269,19 @@ class PactVerificationExtensionSpec extends Specification {
String | null
RequestData | data
}

def 'beforeTestExecution - throws an exception if there is no valid test target for the interaction'() {
given:
context = new PactVerificationContext(store, extContext, new MessageTestTarget(), Stub(IProviderVerifier),
Stub(ValueResolver), Stub(IProviderInfo), Stub(IConsumerInfo), interaction1, pact, [])
extension = new PactVerificationExtension(pact, pactSource, interaction1, 'service', 'consumer',
mockValueResolver)

when:
extension.beforeTestExecution(extContext)

then:
def ex = thrown(UnsupportedOperationException)
ex.message == 'No test target has been configured for RequestResponseInteraction interactions'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package au.com.dius.pact.provider.junit5

import au.com.dius.pact.core.model.V4Interaction
import spock.lang.Specification
import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.messaging.Message

class PluginTestTargetSpec extends Specification {
def 'supports any V4 interaction'() {
expect:
new PluginTestTarget().supportsInteraction(interaction) == result

where:
interaction | result
new RequestResponseInteraction('test') | false
new Message('test') | false
new V4Interaction.AsynchronousMessage('test') | true
new V4Interaction.SynchronousMessages('test') | true
new V4Interaction.SynchronousHttp('test') | true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package au.com.dius.pact.provider.junit5;

import au.com.dius.pact.provider.MessageAndMetadata;
import au.com.dius.pact.provider.PactVerifyProvider;
import au.com.dius.pact.provider.junitsupport.Provider;
import au.com.dius.pact.provider.junitsupport.State;
import au.com.dius.pact.provider.junitsupport.loader.PactFolder;
import com.github.tomakehurst.wiremock.WireMockServer;
import org.apache.hc.core5.http.HttpRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
import ru.lanwen.wiremock.ext.WiremockResolver;
import ru.lanwen.wiremock.ext.WiremockUriResolver;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static java.lang.String.format;

@Provider("test_provider_combined")
@PactFolder("pacts")
@ExtendWith({
WiremockResolver.class,
WiremockUriResolver.class
})
public class CombinedHttpAndMessageTest {
@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider.class)
void testTemplate(HttpRequest request, PactVerificationContext context) {
if (request != null) {
request.addHeader("X-ContractTest", "true");
}

context.verifyInteraction();
}

@BeforeEach
void before(PactVerificationContext context,
@WiremockResolver.Wiremock WireMockServer server,
@WiremockUriResolver.WiremockUri String uri) throws MalformedURLException {
context.setTarget(HttpTestTarget.fromUrl(new URL(uri)));
context.addAdditionalTarget(new MessageTestTarget());

server.stubFor(
get(urlPathEqualTo("/data"))
.withHeader("X-ContractTest", equalTo("true"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("content-type", "application/json")
.withBody("{}")
)
);
}

@State("message exists")
public void messageExits() { }

@PactVerifyProvider("Test Message")
public MessageAndMetadata message() {
return new MessageAndMetadata("{\"a\": \"1234-1234\"}".getBytes(), Map.of("destination", "a/b/c"));
}
}
61 changes: 61 additions & 0 deletions provider/junit5/src/test/resources/pacts/v4-combined-pact.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"provider": {
"name": "test_provider_combined"
},
"consumer": {
"name": "test_consumer"
},
"interactions": [
{
"type": "Synchronous/HTTP",
"key": "001",
"description": "test http interaction",
"request": {
"method": "GET",
"path": "/data"
},
"response": {
"status": 200,
"body": {
"contentType": "application/json",
"encoded": false,
"content": {

}
}
}
}, {
"type": "Asynchronous/Messages",
"key": "m_001",
"metadata": {
"contentType": "application/json",
"destination": "a/b/c"
},
"providerStates": [
{
"name": "message exists"
}
],
"contents": {
"contentType": "application/json",
"encoded": false,
"content": {
"a": "1234-1234"
}
},
"generators": {
"content": {
"a": {
"type": "Uuid"
}
}
},
"description": "Test Message"
}
],
"metadata": {
"pactSpecification": {
"version": "4.0"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package au.com.dius.pact.provider.spring.junit5

import au.com.dius.pact.core.model.*
import au.com.dius.pact.core.model.ContentType
import au.com.dius.pact.core.model.IRequest
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.model.PactSource
import au.com.dius.pact.core.model.Interaction
import au.com.dius.pact.core.model.SynchronousRequestResponse
import au.com.dius.pact.provider.IProviderVerifier
import au.com.dius.pact.provider.ProviderInfo
import au.com.dius.pact.provider.ProviderResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.model.Request
import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.messaging.Message
import org.springframework.http.MediaType
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.function.BodyInserters
Expand Down Expand Up @@ -83,4 +85,17 @@ class WebFluxTargetSpec extends Specification {
response.contentType.toString() == 'application/json'
response.body.valueAsString() == '{"id":1234}'
}

def 'supports any HTTP interaction'() {
expect:
new WebFluxTarget(routerFunction).supportsInteraction(interaction) == result

where:
interaction | result
new RequestResponseInteraction('test') | true
new Message('test') | false
new V4Interaction.AsynchronousMessage('test') | false
new V4Interaction.SynchronousMessages('test') | false
new V4Interaction.SynchronousHttp('test') | true
}
}
Loading

0 comments on commit 9a8d121

Please sign in to comment.