Skip to content

Commit

Permalink
feat: Support system properties or environment variables for consumer…
Browse files Browse the repository at this point in the history
… and provider annotation with JUnit4 provider tests #528 #1616
  • Loading branch information
rholshausen committed Oct 26, 2022
1 parent aabee8c commit 86813ba
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package au.com.dius.pact.provider.junit

import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.support.expressions.DataType
import au.com.dius.pact.core.support.expressions.ExpressionParser
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
import au.com.dius.pact.core.support.expressions.ValueResolver
import au.com.dius.pact.core.support.json.JsonException
import au.com.dius.pact.provider.ProviderUtils
import au.com.dius.pact.provider.ProviderUtils.findAnnotation
Expand Down Expand Up @@ -56,7 +59,8 @@ import java.io.IOException
open class PactRunner(private val clazz: Class<*>) : ParentRunner<InteractionRunner>(clazz) {

private val children = mutableListOf<InteractionRunner>()
private var valueResolver = SystemPropertyResolver
private var valueResolver: ValueResolver = SystemPropertyResolver
private val ep: ExpressionParser = ExpressionParser()
private var initialized = false

private fun initialize() {
Expand All @@ -67,16 +71,8 @@ open class PactRunner(private val clazz: Class<*>) : ParentRunner<InteractionRun
if (clazz.getAnnotation(Ignore::class.java) != null) {
logger.info("Ignore annotation detected, exiting")
} else {
val providerInfo = findAnnotation(clazz, Provider::class.java) ?: throw InitializationError(
"Provider name should be specified by using ${Provider::class.java.simpleName} annotation")
logger.debug { "Found annotation $providerInfo" }
val serviceName = providerInfo.value

val consumerInfo = findAnnotation(clazz, Consumer::class.java)
if (consumerInfo != null) {
logger.debug { "Found annotation $consumerInfo" }
}
val consumerName = consumerInfo?.value
val (providerInfo, serviceName) = lookupProviderInfo()
val (consumerInfo, consumerName) = lookupConsumerInfo()

val testClass = TestClass(clazz)
val ignoreNoPactsToVerify = findAnnotation(clazz, IgnoreNoPactsToVerify::class.java)
Expand Down Expand Up @@ -121,6 +117,31 @@ open class PactRunner(private val clazz: Class<*>) : ParentRunner<InteractionRun
initialized = true
}

private fun lookupConsumerInfo(): Pair<Consumer?, String?> {
val consumerInfo = findAnnotation(clazz, Consumer::class.java)
return if (consumerInfo != null) {
logger.debug { "Found annotation $consumerInfo" }
val consumerName = ep.parseExpression(consumerInfo.value, DataType.STRING, valueResolver)?.toString()
Pair(consumerInfo, consumerName)
} else {
Pair(null, null)
}
}

private fun lookupProviderInfo(): Pair<Provider, String> {
val providerInfo = findAnnotation(clazz, Provider::class.java) ?: throw InitializationError(
"Provider name should be specified by using ${Provider::class.java.simpleName} annotation"
)
logger.debug { "Found annotation $providerInfo" }
val serviceName = ep.parseExpression(providerInfo.value, DataType.STRING, valueResolver)?.toString()
if (serviceName.isNullOrEmpty()) {
throw InitializationError(
"Provider name specified by ${Provider::class.java.simpleName} annotation is null or empty"
)
}
return Pair(providerInfo, serviceName)
}

private fun checkIgnoreIoException(ignoreIoErrors: String, e: Exception) = if (ignoreIoErrors == "true") {
logger.warn { "\n" + WARNING_ON_IGNORED_IOERROR.trimIndent() }
logger.debug(e) { "Failed to load pact files" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package au.com.dius.pact.provider.junit
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.model.RequestResponsePact
import au.com.dius.pact.core.model.UrlSource
import au.com.dius.pact.provider.junitsupport.Consumer
import au.com.dius.pact.provider.junitsupport.IgnoreNoPactsToVerify
import au.com.dius.pact.provider.junitsupport.Provider
import au.com.dius.pact.provider.junitsupport.loader.PactFolder
Expand All @@ -14,7 +15,9 @@ import au.com.dius.pact.provider.junitsupport.target.Target
import au.com.dius.pact.provider.junitsupport.target.TestTarget
import org.junit.runner.notification.RunNotifier
import org.junit.runners.model.InitializationError
import spock.lang.Issue
import spock.lang.Specification
import spock.util.environment.RestoreSystemProperties

@SuppressWarnings('UnusedObject')
class PactRunnerSpec extends Specification {
Expand Down Expand Up @@ -116,6 +119,21 @@ class PactRunnerSpec extends Specification {
Target target
}

@Provider('${provider.name}')
@PactFolder('pacts')
class ProviderFromSystemPropTestClass {
@TestTarget
Target target
}

@Provider('myAwesomeService')
@Consumer('${consumer.name}')
@PactFolder('pacts')
class ConsumerFromSystemPropTestClass {
@TestTarget
Target target
}

def 'PactRunner throws an exception if there is no @Provider annotation on the test class'() {
when:
new PactRunner(PactRunnerSpec).run(new RunNotifier())
Expand Down Expand Up @@ -219,4 +237,31 @@ class PactRunnerSpec extends Specification {
!runner.children.empty
}

@Issue('#528')
@RestoreSystemProperties
def 'PactRunner supports getting the provider name from a system property or environment variable'() {
given:
System.setProperty('provider.name', 'myAwesomeService')

when:
def runner = new PactRunner(ProviderFromSystemPropTestClass)
runner.run(new RunNotifier())

then:
!runner.children.empty
}

@Issue('#528')
@RestoreSystemProperties
def 'PactRunner supports getting the consumer name from a system property or environment variable'() {
given:
System.setProperty('consumer.name', 'anotherService')

when:
def runner = new PactRunner(ConsumerFromSystemPropTestClass)
runner.run(new RunNotifier())

then:
!runner.children.empty
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import java.lang.annotation.Inherited
import kotlin.annotation.Retention

/**
* Used to pass consumer name to Pact runner
* Used to pass consumer name to Pact runner. Can use expressions (in `${}` form) to get the value from Java system
* properties or environment variables.
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package au.com.dius.pact.provider.junitsupport

import java.lang.annotation.Inherited
import kotlin.annotation.Retention

/**
* Used to pass provider name to Pact runner. Can use expressions (in `${}` form) to get the value from Java system
* properties or environment variables.
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
@Inherited
annotation class Provider(
/**
* @return provider name for pact test running
*/
val value: String
)

0 comments on commit 86813ba

Please sign in to comment.