@@ -135,169 +135,178 @@ class JUnit5MockServerSupport(private val baseMockServer: BaseMockServer) : Mock
135
135
136
136
class PactConsumerTestExt : Extension , BeforeTestExecutionCallback , BeforeAllCallback , ParameterResolver , AfterTestExecutionCallback , AfterAllCallback {
137
137
override fun supportsParameter (parameterContext : ParameterContext , extensionContext : ExtensionContext ): Boolean {
138
- val store = extensionContext.getStore(ExtensionContext .Namespace .create(" pact-jvm" ))
139
- if (store[" providerInfo" ] != null ) {
140
- val providerInfo = store[" providerInfo" ] as ProviderInfo
141
- val type = parameterContext.parameter.type
142
- return when (providerInfo.providerType) {
143
- ProviderType .ASYNCH -> when {
144
- type.isAssignableFrom(List ::class .java) -> true
145
- type.isAssignableFrom(MessagePact ::class .java) -> true
146
- else -> false
147
- }
148
- else -> when {
149
- type.isAssignableFrom(MockServer ::class .java) -> true
150
- type.isAssignableFrom(RequestResponsePact ::class .java) -> true
151
- else -> false
152
- }
138
+ val providerInfo = lookupProviderInfo(extensionContext).first
139
+ val type = parameterContext.parameter.type
140
+ return when (providerInfo.providerType) {
141
+ ProviderType .ASYNCH -> when {
142
+ type.isAssignableFrom(List ::class .java) -> true
143
+ type.isAssignableFrom(MessagePact ::class .java) -> true
144
+ else -> false
145
+ }
146
+ else -> when {
147
+ type.isAssignableFrom(MockServer ::class .java) -> true
148
+ type.isAssignableFrom(RequestResponsePact ::class .java) -> true
149
+ else -> false
153
150
}
154
- } else {
155
- return false
156
151
}
157
152
}
158
153
159
154
override fun resolveParameter (parameterContext : ParameterContext , extensionContext : ExtensionContext ): Any {
160
- val store = extensionContext.getStore(ExtensionContext .Namespace .create(" pact-jvm" ))
161
- if (store[" providerInfo" ] != null ) {
162
- val providerInfo = store[" providerInfo" ] as ProviderInfo
163
- val type = parameterContext.parameter.type
164
- return when (providerInfo.providerType) {
165
- ProviderType .ASYNCH -> {
166
- val pact = store[" pact" ] as MessagePact
167
- when {
168
- type.isAssignableFrom(List ::class .java) -> pact.messages
169
- type.isAssignableFrom(MessagePact ::class .java) -> pact
170
- else -> throw UnsupportedOperationException (" Could not inject parameter $type into test method" )
171
- }
155
+ val providerInfo = lookupProviderInfo(extensionContext)
156
+ val store = extensionContext.getStore(NAMESPACE )
157
+ val type = parameterContext.parameter.type
158
+ return when (providerInfo.first.providerType) {
159
+ ProviderType .ASYNCH -> {
160
+ val pact = lookupPact(providerInfo.first, providerInfo.second, extensionContext) as MessagePact
161
+ when {
162
+ type.isAssignableFrom(List ::class .java) -> pact.messages
163
+ type.isAssignableFrom(MessagePact ::class .java) -> pact
164
+ else -> throw UnsupportedOperationException (" Could not inject parameter $type into test method" )
172
165
}
173
- else -> {
174
- val pact = store[" pact" ] as RequestResponsePact
175
- when {
176
- type.isAssignableFrom(MockServer ::class .java) -> store[" mockServer" ]
177
- type.isAssignableFrom(RequestResponsePact ::class .java) -> pact
178
- else -> throw UnsupportedOperationException (" Could not inject parameter $type into test method" )
179
- }
166
+ }
167
+ else -> {
168
+ when {
169
+ type.isAssignableFrom(MockServer ::class .java) -> setupMockServer(providerInfo.first, providerInfo.second, extensionContext)!!
170
+ type.isAssignableFrom(RequestResponsePact ::class .java) -> store[" pact" ] as RequestResponsePact
171
+ else -> throw UnsupportedOperationException (" Could not inject parameter $type into test method" )
180
172
}
181
173
}
182
- } else {
183
- return false
184
174
}
185
175
}
186
176
187
177
override fun beforeAll (context : ExtensionContext ) {
188
- val store = context.getStore(ExtensionContext . Namespace .create( " pact-jvm " ) )
178
+ val store = context.getStore(NAMESPACE )
189
179
store.put(" executedFragments" , mutableListOf<Method >())
190
180
}
191
181
192
182
override fun beforeTestExecution (context : ExtensionContext ) {
193
183
val (providerInfo, pactMethod) = lookupProviderInfo(context)
194
-
195
184
logger.debug { " providerInfo = $providerInfo " }
196
185
197
- val store = context.getStore(ExtensionContext .Namespace .create(" pact-jvm" ))
198
- val executedFragments = store[" executedFragments" ] as MutableList <Method >
199
- val pact = lookupPact(providerInfo, pactMethod, context, executedFragments)
200
- store.put(" pact" , pact)
201
- store.put(" providerInfo" , providerInfo)
186
+ setupMockServer(providerInfo, pactMethod, context)
187
+ }
202
188
203
- if (providerInfo.providerType != ProviderType .ASYNCH ) {
189
+ private fun setupMockServer (providerInfo : ProviderInfo , pactMethod : String , context : ExtensionContext ): MockServer ? {
190
+ val store = context.getStore(NAMESPACE )
191
+ return if (providerInfo.providerType != ProviderType .ASYNCH && store[" mockServer" ] == null ) {
204
192
val config = providerInfo.mockServerConfig()
205
193
store.put(" mockServerConfig" , config)
206
- val mockServer = mockServer(pact as RequestResponsePact , config) as BaseMockServer
194
+ val mockServer = mockServer(lookupPact(providerInfo, pactMethod, context) as RequestResponsePact , config) as BaseMockServer
207
195
mockServer.start()
208
196
mockServer.waitForServer()
209
197
store.put(" mockServer" , JUnit5MockServerSupport (mockServer))
198
+ mockServer
199
+ } else {
200
+ store[" mockServer" ] as MockServer ?
210
201
}
211
202
}
212
203
213
204
fun lookupProviderInfo (context : ExtensionContext ): Pair <ProviderInfo , String > {
214
- val methodAnnotation = if (AnnotationSupport .isAnnotated(context.requiredTestMethod, PactTestFor ::class .java)) {
215
- logger.debug { " Found @PactTestFor annotation on test method" }
216
- val annotation = AnnotationSupport .findAnnotation(context.requiredTestMethod, PactTestFor ::class .java).get()
217
- ProviderInfo .fromAnnotation(annotation) to annotation.pactMethod
205
+ val store = context.getStore(NAMESPACE )
206
+ return if (store[" providerInfo" ] != null ) {
207
+ (store[" providerInfo" ] as ProviderInfo ) to store[" pactMethod" ].toString()
218
208
} else {
219
- null
220
- }
209
+ val methodAnnotation = if (AnnotationSupport .isAnnotated(context.requiredTestMethod, PactTestFor ::class .java)) {
210
+ logger.debug { " Found @PactTestFor annotation on test method" }
211
+ val annotation = AnnotationSupport .findAnnotation(context.requiredTestMethod, PactTestFor ::class .java).get()
212
+ ProviderInfo .fromAnnotation(annotation) to annotation.pactMethod
213
+ } else {
214
+ null
215
+ }
221
216
222
- val classAnnotation = if (AnnotationSupport .isAnnotated(context.requiredTestClass, PactTestFor ::class .java)) {
223
- logger.debug { " Found @PactTestFor annotation on test class" }
224
- val annotation = AnnotationSupport .findAnnotation(context.requiredTestClass, PactTestFor ::class .java).get()
225
- ProviderInfo .fromAnnotation(annotation) to annotation.pactMethod
226
- } else {
227
- null
228
- }
217
+ val classAnnotation = if (AnnotationSupport .isAnnotated(context.requiredTestClass, PactTestFor ::class .java)) {
218
+ logger.debug { " Found @PactTestFor annotation on test class" }
219
+ val annotation = AnnotationSupport .findAnnotation(context.requiredTestClass, PactTestFor ::class .java).get()
220
+ ProviderInfo .fromAnnotation(annotation) to annotation.pactMethod
221
+ } else {
222
+ null
223
+ }
229
224
230
- return when {
231
- classAnnotation != null && methodAnnotation != null -> Pair (methodAnnotation.first.merge(classAnnotation.first),
232
- if (methodAnnotation.second.isNotEmpty()) methodAnnotation.second else classAnnotation.second)
233
- classAnnotation != null -> classAnnotation
234
- methodAnnotation != null -> methodAnnotation
235
- else -> {
236
- logger.debug { " No @PactTestFor annotation found on test class, using defaults" }
237
- ProviderInfo () to " "
225
+ val providerInfo = when {
226
+ classAnnotation != null && methodAnnotation != null -> Pair (methodAnnotation.first.merge(classAnnotation.first),
227
+ if (methodAnnotation.second.isNotEmpty()) methodAnnotation.second else classAnnotation.second)
228
+ classAnnotation != null -> classAnnotation
229
+ methodAnnotation != null -> methodAnnotation
230
+ else -> {
231
+ logger.debug { " No @PactTestFor annotation found on test class, using defaults" }
232
+ ProviderInfo () to " "
233
+ }
238
234
}
235
+
236
+ store.put(" providerInfo" , providerInfo.first)
237
+ store.put(" pactMethod" , providerInfo.second)
238
+
239
+ providerInfo
239
240
}
240
241
}
241
242
242
243
fun lookupPact (
243
244
providerInfo : ProviderInfo ,
244
245
pactMethod : String ,
245
- context : ExtensionContext ,
246
- executedFragments : MutableList <Method >
246
+ context : ExtensionContext
247
247
): BasePact <out Interaction > {
248
- val providerName = if (providerInfo.providerName.isEmpty()) " default" else providerInfo.providerName
249
- val methods = AnnotationSupport .findAnnotatedMethods(context.requiredTestClass, Pact ::class .java,
250
- HierarchyTraversalMode .TOP_DOWN )
251
-
252
- val method = when {
253
- pactMethod.isNotEmpty() -> {
254
- logger.debug { " Looking for @Pact method named '$pactMethod ' for provider '$providerName '" }
255
- methods.firstOrNull { it.name == pactMethod }
256
- }
257
- providerInfo.providerName.isEmpty() -> {
258
- logger.debug { " Looking for first @Pact method" }
259
- methods.firstOrNull()
260
- }
261
- else -> {
262
- logger.debug { " Looking for first @Pact method for provider '$providerName '" }
263
- methods.firstOrNull {
264
- val annotationProviderName = AnnotationSupport .findAnnotation(it, Pact ::class .java).get().provider
265
- annotationProviderName.isEmpty() || annotationProviderName == providerInfo.providerName
248
+ val store = context.getStore(NAMESPACE )
249
+ if (store[" pact" ] == null ) {
250
+ val providerName = if (providerInfo.providerName.isEmpty()) " default" else providerInfo.providerName
251
+ val methods = AnnotationSupport .findAnnotatedMethods(context.requiredTestClass, Pact ::class .java,
252
+ HierarchyTraversalMode .TOP_DOWN )
253
+
254
+ val method = when {
255
+ pactMethod.isNotEmpty() -> {
256
+ logger.debug { " Looking for @Pact method named '$pactMethod ' for provider '$providerName '" }
257
+ methods.firstOrNull { it.name == pactMethod }
258
+ }
259
+ providerInfo.providerName.isEmpty() -> {
260
+ logger.debug { " Looking for first @Pact method" }
261
+ methods.firstOrNull()
262
+ }
263
+ else -> {
264
+ logger.debug { " Looking for first @Pact method for provider '$providerName '" }
265
+ methods.firstOrNull {
266
+ val annotationProviderName = AnnotationSupport .findAnnotation(it, Pact ::class .java).get().provider
267
+ annotationProviderName.isEmpty() || annotationProviderName == providerInfo.providerName
268
+ }
266
269
}
267
270
}
268
- }
269
271
270
- val providerType = providerInfo.providerType ? : ProviderType .SYNCH
271
- if (method == null ) {
272
- throw UnsupportedOperationException (" No method annotated with @Pact was found on test class " +
273
- context.requiredTestClass.simpleName + " for provider '${providerInfo.providerName} '" )
274
- } else if (providerType == ProviderType .SYNCH && ! JUnitTestSupport .conformsToSignature(method)) {
275
- throw UnsupportedOperationException (" Method ${method.name} does not conform to required method signature " +
276
- " 'public RequestResponsePact xxx(PactDslWithProvider builder)'" )
277
- } else if (providerType == ProviderType .ASYNCH && ! JUnitTestSupport .conformsToMessagePactSignature(method)) {
278
- throw UnsupportedOperationException (" Method ${method.name} does not conform to required method signature " +
279
- " 'public MessagePact xxx(MessagePactBuilder builder)'" )
280
- }
272
+ val providerType = providerInfo.providerType ? : ProviderType .SYNCH
273
+ if (method == null ) {
274
+ throw UnsupportedOperationException (" No method annotated with @Pact was found on test class " +
275
+ context.requiredTestClass.simpleName + " for provider '${providerInfo.providerName} '" )
276
+ } else if (providerType == ProviderType .SYNCH && ! JUnitTestSupport .conformsToSignature(method)) {
277
+ throw UnsupportedOperationException (" Method ${method.name} does not conform to required method signature " +
278
+ " 'public RequestResponsePact xxx(PactDslWithProvider builder)'" )
279
+ } else if (providerType == ProviderType .ASYNCH && ! JUnitTestSupport .conformsToMessagePactSignature(method)) {
280
+ throw UnsupportedOperationException (" Method ${method.name} does not conform to required method signature " +
281
+ " 'public MessagePact xxx(MessagePactBuilder builder)'" )
282
+ }
281
283
282
- val pactAnnotation = AnnotationSupport .findAnnotation(method, Pact ::class .java).get()
283
- logger.debug { " Invoking method '${method.name} ' to get Pact for the test " +
284
- " '${context.testMethod.map { it.name }.orElse(" unknown" )} '" }
285
-
286
- val provider = parseExpression(pactAnnotation.provider).toString()
287
- val providerNameToUse = if (provider.isNotEmpty()) provider else providerName
288
- val pact = when (providerType) {
289
- ProviderType .SYNCH , ProviderType .UNSPECIFIED -> ReflectionSupport .invokeMethod(method, context.requiredTestInstance,
290
- ConsumerPactBuilder .consumer(pactAnnotation.consumer).hasPactWith(providerNameToUse)) as BasePact <* >
291
- ProviderType .ASYNCH -> ReflectionSupport .invokeMethod(method, context.requiredTestInstance,
292
- MessagePactBuilder .consumer(pactAnnotation.consumer).hasPactWith(providerNameToUse)) as BasePact <* >
284
+ val pactAnnotation = AnnotationSupport .findAnnotation(method, Pact ::class .java).get()
285
+ logger.debug {
286
+ " Invoking method '${method.name} ' to get Pact for the test " +
287
+ " '${context.testMethod.map { it.name }.orElse(" unknown" )} '"
288
+ }
289
+
290
+ val provider = parseExpression(pactAnnotation.provider).toString()
291
+ val providerNameToUse = if (provider.isNotEmpty()) provider else providerName
292
+ val pact = when (providerType) {
293
+ ProviderType .SYNCH , ProviderType .UNSPECIFIED -> ReflectionSupport .invokeMethod(method, context.requiredTestInstance,
294
+ ConsumerPactBuilder .consumer(pactAnnotation.consumer).hasPactWith(providerNameToUse)) as BasePact <* >
295
+ ProviderType .ASYNCH -> ReflectionSupport .invokeMethod(method, context.requiredTestInstance,
296
+ MessagePactBuilder .consumer(pactAnnotation.consumer).hasPactWith(providerNameToUse)) as BasePact <* >
297
+ }
298
+ val executedFragments = store[" executedFragments" ] as MutableList <Method >
299
+ executedFragments.add(method)
300
+ store.put(" pact" , pact)
301
+ return pact
302
+ } else {
303
+ return store[" pact" ] as BasePact <out Interaction >
293
304
}
294
- executedFragments.add(method)
295
- return pact
296
305
}
297
306
298
307
override fun afterTestExecution (context : ExtensionContext ) {
299
308
if (! context.executionException.isPresent) {
300
- val store = context.getStore(ExtensionContext . Namespace .create( " pact-jvm " ) )
309
+ val store = context.getStore(NAMESPACE )
301
310
val providerInfo = store[" providerInfo" ] as ProviderInfo
302
311
val pactDirectory = lookupPactDirectory(context)
303
312
if (providerInfo.providerType != ProviderType .ASYNCH ) {
@@ -338,7 +347,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
338
347
339
348
override fun afterAll (context : ExtensionContext ) {
340
349
if (! context.executionException.isPresent) {
341
- val store = context.getStore(ExtensionContext . Namespace .create( " pact-jvm " ) )
350
+ val store = context.getStore(NAMESPACE )
342
351
val executedFragments = store[" executedFragments" ] as MutableList <Method >
343
352
val methods = AnnotationSupport .findAnnotatedMethods(context.requiredTestClass, Pact ::class .java,
344
353
HierarchyTraversalMode .TOP_DOWN )
@@ -355,5 +364,7 @@ class PactConsumerTestExt : Extension, BeforeTestExecutionCallback, BeforeAllCal
355
364
}
356
365
}
357
366
358
- companion object : KLogging ()
367
+ companion object : KLogging () {
368
+ val NAMESPACE = ExtensionContext .Namespace .create(" pact-jvm" )
369
+ }
359
370
}
0 commit comments