package au.com.dius.pact.provider.spring.target; import au.com.dius.pact.model.Interaction; import au.com.dius.pact.model.RequestResponseInteraction; import au.com.dius.pact.provider.ConsumerInfo; import au.com.dius.pact.provider.PactVerification; import au.com.dius.pact.provider.ProviderInfo; import au.com.dius.pact.provider.ProviderVerifier; import au.com.dius.pact.provider.junit.Provider; import au.com.dius.pact.provider.junit.TargetRequestFilter; import au.com.dius.pact.provider.junit.target.BaseTarget; import au.com.dius.pact.provider.junit.target.Target; import au.com.dius.pact.provider.spring.MvcProviderVerifier; import org.apache.http.HttpRequest; import org.codehaus.groovy.runtime.MethodClosure; import org.junit.runners.model.FrameworkMethod; import org.springframework.test.web.servlet.MockMvc; import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.function.Consumer; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; /** * Out-of-the-box implementation of {@link Target}, * that run {@link RequestResponseInteraction} against Spring MockMVC controllers and verify response */ public class MockMvcTarget extends BaseTarget { private List<Object> controllers; private List<Object> controllerAdvice; private boolean printRequestResponse; private int runTimes; public MockMvcTarget() { this(Collections.emptyList()); } public MockMvcTarget(List<Object> controllers) { this(controllers, false); } public MockMvcTarget(List<Object> controllers, boolean printRequestResponse) { this(controllers, new ArrayList<Object>() {}, printRequestResponse); } public MockMvcTarget(List<Object> controllers, List<Object> controllerAdvice, boolean printRequestResponse) { this(controllers, controllerAdvice, printRequestResponse, 1); } public MockMvcTarget(List<Object> controllers, List<Object> controllerAdvice, boolean printRequestResponse, int runTimes) { Optional<List<Object>> c = Optional.ofNullable(controllers); this.controllers = c.orElseThrow(() -> new IllegalArgumentException("controllers cannot be null")); this.controllerAdvice = Optional.ofNullable(controllerAdvice).orElse(Collections.emptyList()); this.printRequestResponse = printRequestResponse; this.runTimes = runTimes; } public void setRunTimes(int runTimes) { this.runTimes = runTimes; } public void setPrintRequestResponse(boolean printRequestResponse) { this.printRequestResponse = printRequestResponse; } public void setControllers(Object... controllers) { Optional<Object[]> c = Optional.ofNullable(controllers); this.controllers = Arrays.asList(c.orElseThrow(() -> new IllegalArgumentException("controllers cannot be null"))); } public void setControllerAdvice(Object... controllerAdvice) { this.controllerAdvice = Arrays.asList(Optional.ofNullable(controllerAdvice).orElse(new Object[0])); } /** * {@inheritDoc} */ @Override public void testInteraction(final String consumerName, final Interaction interaction) { ProviderInfo provider = getProviderInfo(); ConsumerInfo consumer = new ConsumerInfo(consumerName); provider.setVerificationType(PactVerification.ANNOTATED_METHOD); MockMvc mockMvc = standaloneSetup(controllers.toArray()) .setControllerAdvice(controllerAdvice.toArray()) .build(); MvcProviderVerifier verifier = (MvcProviderVerifier)setupVerifier(interaction, provider, consumer); Map<String, Object> failures = new HashMap<>(); for(int i = 0; i < runTimes; i++) { verifier.verifyResponseFromProvider(provider, interaction, interaction.getDescription(), failures, mockMvc); } try { if (!failures.isEmpty()) { verifier.displayFailures(failures); throw getAssertionError(failures); } } finally { verifier.finialiseReports(); } } private URL[] getClassPathUrls() { return ((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs(); } @Override protected ProviderVerifier setupVerifier(Interaction interaction, ProviderInfo provider, ConsumerInfo consumer) { MvcProviderVerifier verifier = new MvcProviderVerifier(); verifier.setDebugRequestResponse(printRequestResponse); setupReporters(verifier, provider.getName(), interaction.getDescription()); verifier.setProjectClasspath(new MethodClosure(this, "getClassPathUrls")); verifier.initialiseReporters(provider); verifier.reportVerificationForConsumer(consumer, provider); if (interaction.getProviderState() != null) { verifier.reportStateForInteraction(interaction.getProviderState(), provider, consumer, true); } verifier.reportInteractionDescription(interaction); return verifier; } @Override protected ProviderInfo getProviderInfo() { Provider provider = testClass.getAnnotation(Provider.class); final ProviderInfo providerInfo = new ProviderInfo(provider.value()); if (testClass != null) { final List<FrameworkMethod> methods = testClass.getAnnotatedMethods(TargetRequestFilter.class); if (!methods.isEmpty()) { providerInfo.setRequestFilter((Consumer<HttpRequest>) httpRequest -> methods.forEach(method -> { try { method.invokeExplosively(testTarget, httpRequest); } catch (Throwable t) { throw new AssertionError("Request filter method " + method.getName() + " failed with an exception", t); } })); } } return providerInfo; } }