Skip to content

Instantly share code, notes, and snippets.

@siwater
Last active October 16, 2019 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save siwater/5b00fadb788f46200c3f31aac96676e2 to your computer and use it in GitHub Desktop.
Save siwater/5b00fadb788f46200c3f31aac96676e2 to your computer and use it in GitHub Desktop.
This code loses a Pact in PactRunner.kt
The attached file shows the logging I added to PactRunner.kt (lines 101, 129-132)
Here is a sample log output:
2019-10-16 15:50:10.382 DEBUG 4228 --- [ main] a.c.d.p.p.junit.loader.PactBrokerLoader : Loading pacts from pact broker for provider cas-app-actions and tag latest
2019-10-16 15:50:10.502 DEBUG 4228 --- [ main] a.c.dius.pact.core.pactbroker.HalClient : Fetching: /
2019-10-16 15:50:12.871 DEBUG 4228 --- [ main] a.c.dius.pact.core.pactbroker.HalClient : Fetching: https://cas-pact-broker.eng.citrite.net/pacts/provider/cas-app-actions/latest
2019-10-16 15:50:13.051 DEBUG 4228 --- [ main] a.c.dius.pact.core.pactbroker.HalClient : Fetching: https://cas-pact-broker.eng.citrite.net/pacts/provider/cas-app-actions/consumer/sf-action-adapter/version/1.0.0
2019-10-16 15:50:13.302 DEBUG 4228 --- [ main] a.c.dius.pact.provider.junit.PactRunner : filterPacts input: 1
2019-10-16 15:50:13.309 DEBUG 4228 --- [ main] a.c.dius.pact.provider.junit.PactRunner : filterPacts output: 1
2019-10-16 15:50:13.314 DEBUG 4228 --- [ main] a.c.dius.pact.provider.junit.PactRunner : Loaded 0 pacts in java.util.ArrayList
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 40.394 s <<< FAILURE! - in com.citrix.apf.contract.ApfProviderVerificationTest
[ERROR] initializationError(com.citrix.apf.contract.ApfProviderVerificationTest) Time elapsed: 0.014 s <<< ERROR!
java.lang.Exception: Did not find any pact files for provider cas-app-actions
INFO:2019-10-16 15:50:13.417 [Thread-5] org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler.shutdown - Shutting down ExecutorService 'taskScheduler'
INFO:2019-10-16 15:50:13.420 [Thread-5] org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.shutdown - Shutting down ExecutorService 'casOkHttpClientExecutor'
INFO:2019-10-16 15:50:13.421 [Thread-5] org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.shutdown - Shutting down ExecutorService 'httpClientExecutor'
[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR] ApfProviderVerificationTest.initializationError ▒ Did not find any pact files...
package au.com.dius.pact.provider.junit
import au.com.dius.pact.core.model.Interaction
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
import au.com.dius.pact.provider.junit.JUnitProviderTestSupport.filterPactsByAnnotations
import au.com.dius.pact.provider.junit.loader.NoPactsFoundException
import au.com.dius.pact.provider.junit.loader.PactBroker
import au.com.dius.pact.provider.junit.loader.PactFolder
import au.com.dius.pact.provider.junit.loader.PactLoader
import au.com.dius.pact.provider.junit.loader.PactSource
import au.com.dius.pact.provider.junit.target.HttpTarget
import au.com.dius.pact.provider.junit.target.Target
import au.com.dius.pact.provider.junit.target.TestTarget
import com.google.gson.JsonSyntaxException
import mu.KLogging
import org.junit.Ignore
import org.junit.runner.notification.RunNotifier
import org.junit.runners.ParentRunner
import org.junit.runners.model.InitializationError
import org.junit.runners.model.TestClass
import java.io.IOException
import kotlin.reflect.full.createInstance
import kotlin.reflect.full.findAnnotation
/**
* JUnit Runner runs pacts against provider
* To set up name of tested provider use [Provider] annotation
* To point on pact's source use [PactBroker], [PactFolder] or [PactSource] annotations
*
*
* To point provider for testing use combination of [Target] interface and [TestTarget] annotation
* There is out-of-the-box implementation of [Target]:
* [HttpTarget] that will play interaction from pacts as http request and check http responses
*
*
* Runner supports:
* - [org.junit.BeforeClass], [org.junit.AfterClass] and [org.junit.ClassRule] annotations,
* that will be run once - before/after whole contract test suite
*
*
* - [org.junit.Before], [org.junit.After] and [org.junit.Rule] annotations,
* that will be run before/after each test of interaction
* **WARNING:** please note, that only [org.junit.rules.TestRule] is possible to use with this runner,
* i.e. [org.junit.rules.MethodRule] **IS NOT supported**
*
*
* - [State] - before each interaction that require state change,
* all methods annotated by [State] with appropriate state listed will be invoked
*/
open class PactRunner<I>(clazz: Class<*>) : ParentRunner<InteractionRunner<I>>(clazz) where I : Interaction {
private val child = mutableListOf<InteractionRunner<I>>()
private var valueResolver = SystemPropertyResolver()
init {
if (clazz.getAnnotation(Ignore::class.java) != null) {
logger.info("Ignore annotation detected, exiting")
} else {
val providerInfo = clazz.getAnnotation(Provider::class.java) ?: throw InitializationError(
"Provider name should be specified by using ${Provider::class.java.name} annotation")
val serviceName = providerInfo.value
val consumerInfo = clazz.getAnnotation(Consumer::class.java)
val consumerName = consumerInfo?.value
val testClass = TestClass(clazz)
val ignoreNoPactsToVerify = clazz.getAnnotation(IgnoreNoPactsToVerify::class.java)
val ignoreIoErrors = try {
valueResolver.resolveValue(ignoreNoPactsToVerify?.ignoreIoErrors)
} catch (e: RuntimeException) {
logger.debug(e) { "Failed to resolve property value" }
ignoreNoPactsToVerify?.ignoreIoErrors
} ?: "false"
val pactLoader = getPactSource(testClass)
val pacts = try {
filterPacts(pactLoader.load(serviceName)
.filter { p -> consumerName == null || p.consumer.name == consumerName } as List<Pact<I>>)
} catch (e: IOException) {
if (ignoreIoErrors == "true") {
logger.warn { "\n" + WARNING_ON_IGNORED_IOERROR.trimIndent() }
logger.debug(e) { "Failed to load pact files" }
emptyList<Pact<I>>()
} else {
throw InitializationError(e)
}
} catch (e: JsonSyntaxException) {
if (ignoreIoErrors == "true") {
logger.warn { "\n" + WARNING_ON_IGNORED_IOERROR.trimIndent() }
logger.debug(e) { "Failed to load pact files" }
emptyList<Pact<I>>()
} else {
throw InitializationError(e)
}
} catch (e: NoPactsFoundException) {
logger.debug(e) { "No pacts found" }
emptyList<Pact<I>>()
}
logger.debug("Loaded " + pacts.size + " pacts in ${pacts::class.qualifiedName}")
if (pacts.isEmpty()) {
if (ignoreNoPactsToVerify != null) {
logger.warn { "Did not find any pact files for provider ${providerInfo.value}" }
} else {
throw InitializationError("Did not find any pact files for provider ${providerInfo.value}")
}
}
setupInteractionRunners(testClass, pacts, pactLoader)
}
}
protected open fun setupInteractionRunners(testClass: TestClass, pacts: List<Pact<I>>, pactLoader: PactLoader) {
for (pact in pacts) {
this.child.add(newInteractionRunner(testClass, pact, pactLoader.pactSource))
}
}
protected open fun newInteractionRunner(
testClass: TestClass,
pact: Pact<I>,
pactSource: au.com.dius.pact.core.model.PactSource
): InteractionRunner<I> {
return InteractionRunner(testClass, pact, pactSource)
}
protected open fun filterPacts(pacts: List<Pact<I>>): List<Pact<I>> {
logger.debug("filterPacts input: ${pacts.size}")
val result = filterPactsByAnnotations(pacts, testClass.javaClass)
logger.debug("filterPacts output: ${result.size}")
return result
}
override fun getChildren() = child
override fun describeChild(child: InteractionRunner<I>) = child.description
override fun runChild(interaction: InteractionRunner<I>, notifier: RunNotifier) {
interaction.run(notifier)
}
protected open fun getPactSource(clazz: TestClass): PactLoader {
val pactSource = clazz.getAnnotation(PactSource::class.java)
val pactLoaders = clazz.annotations
.filter { annotation -> annotation.annotationClass.findAnnotation<PactSource>() != null }
if ((if (pactSource == null) 0 else 1) + pactLoaders.size != 1) {
throw InitializationError("Exactly one pact source should be set")
}
try {
if (pactSource != null) {
val pactLoaderClass = pactSource.value
return try {
// Checks if there is a constructor with one argument of type Class.
val constructorWithClass = pactLoaderClass.java.getDeclaredConstructor(Class::class.java)
if (constructorWithClass != null) {
constructorWithClass.isAccessible = true
constructorWithClass.newInstance(clazz.javaClass)
} else {
pactLoaderClass.createInstance()
}
} catch (e: NoSuchMethodException) {
logger.error(e) { e.message }
pactLoaderClass.createInstance()
}
} else {
val annotation = pactLoaders.first()
return annotation.annotationClass.findAnnotation<PactSource>()!!.value.java
.getConstructor(annotation.annotationClass.java).newInstance(annotation)
}
} catch (e: ReflectiveOperationException) {
logger.error(e) { "Error while creating pact source" }
throw InitializationError(e)
}
}
companion object : KLogging() {
const val WARNING_ON_IGNORED_IOERROR = """
---------------------------------------------------------------------------
| WARNING! Ignoring IO Exception received when loading Pact files as |
| WARNING! the @IgnoreNoPactsToVerify annotation is present and |
| WARNING! ignoreIoErrors is set to true. Make sure this is not happening |
| WARNING! on your CI server, as this could result in your build passing |
| WARNING! with no providers having been verified due to a configuration |
| WARNING! error. |
-------------------------------------------------------------------------"""
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment