package au.com.dius.pact.provider.junit.target;
import au.com.dius.pact.model.Interaction;
import au.com.dius.pact.provider.ConsumerInfo;
import au.com.dius.pact.provider.ProviderInfo;
import au.com.dius.pact.provider.ProviderVerifier;
import au.com.dius.pact.provider.junit.VerificationReports;
import au.com.dius.pact.provider.junit.sysprops.SystemPropertyResolver;
import au.com.dius.pact.provider.junit.sysprops.ValueResolver;
import au.com.dius.pact.provider.reporters.ReporterManager;
import au.com.dius.pact.provider.reporters.VerifierReporter;
import org.apache.commons.lang3.StringUtils;
import org.jooq.lambda.Seq;
import org.jooq.lambda.tuple.Tuple2;
import org.junit.runners.model.TestClass;
import java.io.File;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Out-of-the-box implementation of {@link Target},
* that run {@link Interaction} against message pact and verify response
*/
public abstract class BaseTarget implements TestClassAwareTarget {
protected TestClass testClass;
protected Object testTarget;
protected ValueResolver valueResolver = new SystemPropertyResolver();
/**
* {@inheritDoc}
*/
@Override
public abstract void testInteraction(final String consumerName, final Interaction interaction);
protected abstract ProviderInfo getProviderInfo();
protected abstract ProviderVerifier setupVerifier(Interaction interaction, ProviderInfo provider,
ConsumerInfo consumer);
protected void setupReporters(ProviderVerifier verifier, String name, String description) {
String reportDirectory = "target/pact/reports";
String[] reports = new String[]{};
boolean reportingEnabled = false;
VerificationReports verificationReports = testClass.getAnnotation(VerificationReports.class);
if (verificationReports != null) {
reportingEnabled = true;
reportDirectory = verificationReports.reportDir();
reports = verificationReports.value();
} else if (valueResolver.propertyDefined("pact.verification.reports")) {
reportingEnabled = true;
reportDirectory = valueResolver.resolveValue("pact.verification.reportDir:" + reportDirectory);
reports = valueResolver.resolveValue("pact.verification.reports:").split(",");
}
if (reportingEnabled) {
File reportDir = new File(reportDirectory);
reportDir.mkdirs();
verifier.setReporters(Seq.of(reports)
.filter(r -> !r.isEmpty())
.map(r -> {
VerifierReporter reporter = ReporterManager.createReporter(r.trim());
reporter.setReportDir(reportDir);
reporter.setReportFile(new File(reportDir, name + " - " + description + reporter.getExt()));
return reporter;
}).toList());
}
}
protected AssertionError getAssertionError(final Map<String, Object> mismatches) {
String error = System.lineSeparator() + Seq.seq(mismatches.values()).zipWithIndex()
.map(i -> {
String errPrefix = String.valueOf(i.v2) + " - ";
if (i.v1 instanceof Throwable) {
return errPrefix + exceptionMessage((Throwable) i.v1, errPrefix.length());
} else if (i.v1 instanceof Map) {
return errPrefix + convertMapToErrorString((Map) i.v1);
} else {
return errPrefix + i.v1.toString();
}
}).toString(System.lineSeparator());
return new AssertionError(error);
}
private String exceptionMessage(Throwable err, int prefixLength) {
String message = err.getMessage();
if (message.contains("\n")) {
String padString = StringUtils.leftPad("", prefixLength);
Tuple2<Optional<String>, Seq<String>> lines = Seq.of(message.split("\n")).splitAtHead();
return lines.v1.orElse("") + System.lineSeparator() + lines.v2.map(line -> padString + line)
.toString(System.lineSeparator());
} else {
return message;
}
}
private String convertMapToErrorString(Map mismatches) {
if (mismatches.containsKey("comparison")) {
Object comparison = mismatches.get("comparison");
if (mismatches.containsKey("diff")) {
return mapToString((Map) comparison);
} else {
if (comparison instanceof Map) {
return mapToString((Map) comparison);
} else {
return String.valueOf(comparison);
}
}
} else {
return mapToString(mismatches);
}
}
private String mapToString(Map comparison) {
return comparison.entrySet().stream()
.map(e -> String.valueOf(((Map.Entry)e).getKey()) + " -> " + ((Map.Entry)e).getValue())
.collect(Collectors.joining(System.lineSeparator())).toString();
}
@Override
public void setTestClass(final TestClass testClass, final Object testTarget) {
this.testClass = testClass;
this.testTarget = testTarget;
}
public ValueResolver getValueResolver() {
return valueResolver;
}
public void setValueResolver(ValueResolver valueResolver) {
this.valueResolver = valueResolver;
}
}