Skip to content

Commit

Permalink
fix: bug in how the @MockServerConfig annotation is being resolved #1641
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Jan 4, 2023
1 parent 25c0ed6 commit 58b6982
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
return when {
store[key] != null -> store[key] as AbstractBaseMockServer
else -> {
val config = mockServerConfigFromAnnotation(context) ?: providerInfo.mockServerConfig()
val config = providerInfo.mockServerConfig()
store.put("mockServerConfig:${providerInfo.providerName}", config)
val mockServer = mockServer(lookupPact(providerInfo, pactMethod, context), config)
store.put(key, JUnit5MockServerSupport(mockServer))
Expand All @@ -247,14 +247,15 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
}

private fun mockServerConfigFromAnnotation(context: ExtensionContext): MockProviderConfig? {
val mockServerConfigMethod = AnnotationSupport.findAnnotation(context.requiredTestMethod,
MockServerConfig::class.java)
return if (mockServerConfigMethod != null) {
val mockServerConfigMethod = if (context.testMethod.isPresent)
AnnotationSupport.findAnnotation(context.testMethod.get(), MockServerConfig::class.java)
else null
return if (mockServerConfigMethod != null && mockServerConfigMethod.isPresent) {
MockProviderConfig.fromMockServerAnnotation(mockServerConfigMethod)
} else {
val mockServerConfig = AnnotationSupport.findAnnotation(context.requiredTestClass,
MockServerConfig::class.java)
if (mockServerConfig != null) {
if (mockServerConfig != null && mockServerConfig.isPresent) {
MockProviderConfig.fromMockServerAnnotation(mockServerConfig)
} else {
null
Expand Down Expand Up @@ -291,10 +292,13 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
null
}

val mockServerConfig = mockServerConfigFromAnnotation(context)

val providers = when {
classAnnotation != null && methodAnnotation != null -> {
val provider = ProviderInfo.fromAnnotation(methodAnnotation)
.merge(ProviderInfo.fromAnnotation(classAnnotation))
.withMockServerConfig(mockServerConfig)
when {
methodAnnotation.pactMethods.isNotEmpty() -> {
methodAnnotation.pactMethods.map {
Expand All @@ -311,23 +315,31 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
else -> listOf(provider to methodAnnotation.pactMethod.ifEmpty { classAnnotation.pactMethod })
}
}
classAnnotation != null -> if (classAnnotation.pactMethods.isNotEmpty()) {

classAnnotation != null -> {
val annotation = ProviderInfo.fromAnnotation(classAnnotation)
classAnnotation.pactMethods.map {
val providerName = providerNameFromPactMethod(it, context)
annotation.copy(providerName = providerName) to it
.withMockServerConfig(mockServerConfig)
if (classAnnotation.pactMethods.isNotEmpty()) {
classAnnotation.pactMethods.map {
val providerName = providerNameFromPactMethod(it, context)
annotation.copy(providerName = providerName) to it
}
} else {
listOf(annotation to classAnnotation.pactMethod)
}
} else {
listOf(ProviderInfo.fromAnnotation(classAnnotation) to classAnnotation.pactMethod)
}
methodAnnotation != null -> if (methodAnnotation.pactMethods.isNotEmpty()) {

methodAnnotation != null -> {
val annotation = ProviderInfo.fromAnnotation(methodAnnotation)
methodAnnotation.pactMethods.map {
val providerName = providerNameFromPactMethod(it, context)
annotation.copy(providerName = providerName) to it
.withMockServerConfig(mockServerConfig)
if (methodAnnotation.pactMethods.isNotEmpty()) {
methodAnnotation.pactMethods.map {
val providerName = providerNameFromPactMethod(it, context)
annotation.copy(providerName = providerName) to it
}
} else {
listOf(annotation to methodAnnotation.pactMethod)
}
} else {
listOf(ProviderInfo.fromAnnotation(methodAnnotation) to methodAnnotation.pactMethod)
}
else -> {
logger.warn { "No @PactTestFor annotation found on test class, using defaults" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ data class ProviderInfo @JvmOverloads constructor(
)
}

fun withMockServerConfig(mockServerConfig: MockProviderConfig?): ProviderInfo {
return if (mockServerConfig != null) {
this.copy(hostInterface = mockServerConfig.hostname,
port = if (mockServerConfig.port > 0) mockServerConfig.port.toString() else "",
pactVersion = mockServerConfig.pactVersion.or(pactVersion), https = mockServerConfig.scheme == "https",
mockServerImplementation = mockServerConfig.mockServerImplementation.merge(mockServerImplementation))
} else {
this
}
}

companion object {
fun fromAnnotation(annotation: PactTestFor): ProviderInfo {
val providerName = ExpressionParser().parseExpression(annotation.providerName, DataType.STRING)?.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package au.com.dius.pact.consumer.junit5
import au.com.dius.pact.consumer.MockServer
import au.com.dius.pact.consumer.dsl.PactDslJsonBody
import au.com.dius.pact.consumer.dsl.PactDslWithProvider
import au.com.dius.pact.consumer.junit.MockServerConfig
import au.com.dius.pact.consumer.model.MockServerImplementation
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.RequestResponsePact
Expand All @@ -16,8 +17,8 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(PactConsumerTestExt)
@PactTestFor(providerName = 'ProviderThatAcceptsGZippedBodies', port = '42567',
mockServerImplementation = MockServerImplementation.KTorServer, pactVersion = PactSpecVersion.V3)
@PactTestFor(providerName = 'ProviderThatAcceptsGZippedBodies', pactVersion = PactSpecVersion.V3)
@MockServerConfig(port = '42567', implementation = MockServerImplementation.KTorServer)
class KTorGZippedBodyTest {
@Pact(consumer = 'KTorGZippedBodyTestConsumer')
RequestResponsePact pact(PactDslWithProvider builder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package au.com.dius.pact.consumer.junit5

import au.com.dius.pact.consumer.BaseMockServer
import au.com.dius.pact.consumer.PactVerificationResult
import au.com.dius.pact.consumer.junit.MockServerConfig
import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.core.model.Consumer
import au.com.dius.pact.core.model.PactSpecVersion
Expand All @@ -20,7 +21,9 @@ import spock.lang.Specification
import spock.lang.Unroll
import spock.util.environment.RestoreSystemProperties

@SuppressWarnings(['EmptyMethod', 'UnusedMethodParameter'])
@SuppressWarnings(['EmptyMethod', 'UnusedMethodParameter', 'UnnecessaryGetter',
'UnnecessaryParenthesesForMethodCallWithClosure'])
@PactTestFor(providerName = 'PactConsumerTestExtSpecProvider', pactVersion = PactSpecVersion.V3)
class PactConsumerTestExtSpec extends Specification {

private PactConsumerTestExt testExt
Expand Down Expand Up @@ -118,4 +121,156 @@ class PactConsumerTestExtSpec extends Specification {
json.interactions[0].description == 'first'
json.interactions[1].description == 'second'
}

def 'lookupProviderInfo - returns data from the class level PactTestFor annotation'() {
given:
def mockStoreData = [:]
def mockStore = Mock(ExtensionContext.Store) {
get(_) >> { p -> mockStoreData.get(p[0]) }
put(_, _) >> { k, v -> mockStoreData.put(k, v) }
}
ExtensionContext mockContext = Mock() {
getRequiredTestClass() >> PactConsumerTestExtSpec
getTestClass() >> Optional.of(PactConsumerTestExtSpec)
getTestMethod() >> Optional.empty()
getStore(_) >> mockStore
}

when:
def providerInfo = testExt.lookupProviderInfo(mockContext)

then:
providerInfo.size() == 1
providerInfo.first().first.providerName == 'PactConsumerTestExtSpecProvider'
providerInfo.first().first.pactVersion == PactSpecVersion.V3
providerInfo.first().second == ''
}

static class TestClass {
@PactTestFor(providerName = 'PactConsumerTestExtSpecMethodProvider', pactVersion = PactSpecVersion.V1)
def pactTestForMethod() { }
}

def 'lookupProviderInfo - returns data from the method level PactTestFor annotation'() {
given:
def mockStoreData = [:]
def mockStore = Mock(ExtensionContext.Store) {
get(_) >> { p -> mockStoreData.get(p[0]) }
put(_, _) >> { k, v -> mockStoreData.put(k, v) }
}
def method = TestClass.getMethod('pactTestForMethod')
ExtensionContext mockContext = Mock() {
getRequiredTestClass() >> TestClass
getTestClass() >> Optional.of(TestClass)
getRequiredTestMethod() >> method
getTestMethod() >> Optional.of(method)
getStore(_) >> mockStore
}

when:
def providerInfo = testExt.lookupProviderInfo(mockContext)

then:
providerInfo.size() == 1
providerInfo.first().first.providerName == 'PactConsumerTestExtSpecMethodProvider'
providerInfo.first().first.pactVersion == PactSpecVersion.V1
providerInfo.first().second == ''
}

@PactTestFor(providerName = 'PactConsumerTestExtSpecClassProvider', pactVersion = PactSpecVersion.V3)
static class TestClass2 {
@PactTestFor(providerName = 'PactConsumerTestExtSpecMethodProvider')
def pactTestForMethod() { }
}

def 'lookupProviderInfo - returns data from both the method and class level PactTestFor annotation'() {
given:
def mockStoreData = [:]
def mockStore = Mock(ExtensionContext.Store) {
get(_) >> { p -> mockStoreData.get(p[0]) }
put(_, _) >> { k, v -> mockStoreData.put(k, v) }
}
def method = TestClass2.getMethod('pactTestForMethod')
ExtensionContext mockContext = Mock() {
getRequiredTestClass() >> TestClass2
getTestClass() >> Optional.of(TestClass2)
getRequiredTestMethod() >> method
getTestMethod() >> Optional.of(method)
getStore(_) >> mockStore
}

when:
def providerInfo = testExt.lookupProviderInfo(mockContext)

then:
providerInfo.size() == 1
providerInfo.first().first.providerName == 'PactConsumerTestExtSpecMethodProvider'
providerInfo.first().first.pactVersion == PactSpecVersion.V3
providerInfo.first().second == ''
}

@PactTestFor(providerName = 'PactConsumerTestExtSpecClassProvider', pactVersion = PactSpecVersion.V3)
@MockServerConfig(port = '1234', tls = true)
static class TestClass3 { }

def 'lookupProviderInfo - merges data from the class level MockServerConfig annotation'() {
given:
def mockStoreData = [:]
def mockStore = Mock(ExtensionContext.Store) {
get(_) >> { p -> mockStoreData.get(p[0]) }
put(_, _) >> { k, v -> mockStoreData.put(k, v) }
}
ExtensionContext mockContext = Mock() {
getRequiredTestClass() >> TestClass3
getTestClass() >> Optional.of(TestClass3)
getTestMethod() >> Optional.empty()
getStore(_) >> mockStore
}

when:
def providerInfo = testExt.lookupProviderInfo(mockContext)

then:
providerInfo.size() == 1
providerInfo.first().first.providerName == 'PactConsumerTestExtSpecClassProvider'
providerInfo.first().first.pactVersion == PactSpecVersion.V3
providerInfo.first().first.https
providerInfo.first().first.port == '1234'
providerInfo.first().second == ''
}

@PactTestFor(providerName = 'PactConsumerTestExtSpecClassProvider', pactVersion = PactSpecVersion.V3)
static class TestClass4 {
@PactTestFor(providerName = 'PactConsumerTestExtSpecMethodProvider')
@MockServerConfig(port = '1234', tls = true)
def pactTestForMethod() { }
}

def 'lookupProviderInfo - merges data from the method level MockServerConfig annotation'() {
given:
def mockStoreData = [:]
def mockStore = Mock(ExtensionContext.Store) {
get(_) >> { p -> mockStoreData.get(p[0]) }
put(_, _) >> { k, v -> mockStoreData.put(k, v) }
}
def method = TestClass4.getMethod('pactTestForMethod')
ExtensionContext mockContext = Mock() {
getRequiredTestClass() >> TestClass4
getTestClass() >> Optional.of(TestClass4)
getRequiredTestMethod() >> method
getTestMethod() >> Optional.of(method)
getStore(_) >> mockStore
}

when:
def providerInfo = testExt.lookupProviderInfo(mockContext)

then:
providerInfo.size() == 1
providerInfo.first().first.providerName == 'PactConsumerTestExtSpecMethodProvider'
providerInfo.first().first.pactVersion == PactSpecVersion.V3
providerInfo.first().first.https
providerInfo.first().first.port == '1234'
providerInfo.first().second == ''
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.Provider
import au.com.dius.pact.core.model.RequestResponsePact
import au.com.dius.pact.core.model.annotations.Pact
import org.apache.commons.lang3.JavaVersion
import org.apache.commons.lang3.SystemUtils
import org.hamcrest.Matchers
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtensionContext
import spock.lang.Requires

import java.lang.reflect.Method

import static org.hamcrest.MatcherAssert.assertThat
import static org.junit.jupiter.api.Assertions.assertThrows

// TODO: Groovy mocks don't work on JDK 16
@Disabled
@Requires(reason = "Groovy mocks don't work on JDK 16",
value = { SystemUtils.isJavaVersionAtMost(JavaVersion.JAVA_15) })
class PactConsumerTestExtTest {

private final subject = new PactConsumerTestExt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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.consumer.junit.MockServerConfig
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.RequestResponsePact
import au.com.dius.pact.core.model.annotations.Pact
Expand All @@ -11,7 +12,8 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(PactConsumerTestExt)
@PactTestFor(providerName = 'PathWithValueWithSlashTest', port = '1234', pactVersion = PactSpecVersion.V3)
@PactTestFor(providerName = 'PathWithValueWithSlashTest', pactVersion = PactSpecVersion.V3)
@MockServerConfig(port = '1234')
class PathWithValueWithSlashTest {
@Pact(consumer = 'Consumer')
RequestResponsePact filesPact(PactDslWithProvider builder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit.MockServerConfig;
import au.com.dius.pact.consumer.model.MockServerImplementation;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
Expand Down Expand Up @@ -30,7 +32,8 @@
import static org.hamcrest.Matchers.startsWith;

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "ArticlesProvider", https = true, pactVersion = PactSpecVersion.V3)
@PactTestFor(providerName = "ArticlesProvider", pactVersion = PactSpecVersion.V3)
@MockServerConfig(tls = true)
public class ArticlesHttpsTest {
private Map<String, String> headers = MapUtils.putAll(new HashMap<>(), new String[] {
"Content-Type", "application/json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit.MockServerConfig;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
Expand Down Expand Up @@ -30,12 +31,12 @@
import static org.hamcrest.Matchers.startsWith;

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "ArticlesProvider", https = true,
keyStorePath = "src/test/resources/keystore/pact-jvm-2048.jks",
keyStoreAlias = "localhost",
keyStorePassword = "coderswerehere",
privateKeyPassword = "coderswerehere",
pactVersion = PactSpecVersion.V3)
@PactTestFor(providerName = "ArticlesProvider", pactVersion = PactSpecVersion.V3)
@MockServerConfig(tls = true,
keyStorePath = "src/test/resources/keystore/pact-jvm-2048.jks",
keyStoreAlias = "localhost",
keyStorePassword = "coderswerehere",
privateKeyPassword = "coderswerehere")
public class ArticlesHttpsWithKeyStoreTest {
private Map<String, String> headers = MapUtils.putAll(new HashMap<>(), new String[] {
"Content-Type", "application/json"
Expand Down
Loading

0 comments on commit 58b6982

Please sign in to comment.