Last active
August 29, 2015 14:10
-
-
Save warmuuh/439db36ef02f9496b2f0 to your computer and use it in GitHub Desktop.
Junit Rule implementation of pacts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.junit.Assert.assertEquals; | |
import java.lang.reflect.Method; | |
import java.util.HashMap; | |
import java.util.Map; | |
import lombok.extern.slf4j.Slf4j; | |
import org.junit.rules.ExternalResource; | |
import org.junit.runner.Description; | |
import org.junit.runners.model.Statement; | |
import au.com.dius.pact.consumer.ConsumerPactBuilder; | |
import au.com.dius.pact.consumer.ConsumerPactBuilder.PactDslWithProvider.PactDslWithState; | |
import au.com.dius.pact.consumer.PactError; | |
import au.com.dius.pact.consumer.PactVerified$; | |
import au.com.dius.pact.consumer.TestRun; | |
import au.com.dius.pact.consumer.VerificationResult; | |
import au.com.dius.pact.model.MockProviderConfig; | |
import au.com.dius.pact.model.PactFragment; | |
/** | |
* a junit rule that wraps every test annotated with {@link PactVerification}. | |
* Before each test, a mock server will be setup at given port/host that will provide mocked responses. | |
* after each test, it will be teared down. | |
* | |
* | |
* @author pmucha | |
* | |
*/ | |
@Slf4j | |
public class PactRule extends ExternalResource { | |
public static VerificationResult PACT_VERIFIED = PactVerified$.MODULE$; | |
private Map < String, PactFragment > fragments; | |
private Object target; | |
final MockProviderConfig config; | |
public PactRule(int port, String host, Object target) { | |
config = new MockProviderConfig(port, host); | |
this.target = target; | |
} | |
@Override | |
public Statement apply(final Statement base, final Description description) { | |
return new Statement() { | |
@Override | |
public void evaluate() throws Throwable { | |
PactVerification pactDef = description.getAnnotation(PactVerification.class); | |
//no pactVerification? execute the test normally | |
if (pactDef == null) { | |
base.evaluate(); | |
} | |
VerificationResult result = getPacts().get(pactDef.value()).runConsumer(config, new TestRun() { | |
@Override | |
public void run(MockProviderConfig config) { | |
try { | |
base.evaluate(); | |
} catch (Throwable e) { | |
throw new PactRuleFailed(e); | |
} | |
} | |
}); | |
//unpack and rethrow assert-exceptions | |
if (result instanceof PactError) { | |
PactError pactError = (PactError) result; | |
if (pactError.error() instanceof PactRuleFailed) throw pactError.error().getCause(); | |
throw pactError.error(); | |
} | |
//writes all pacts to json files | |
assertEquals(PACT_VERIFIED, result); | |
} | |
}; | |
} | |
/** | |
* scann all methods for @Pact annotation and execute them, if not already initialized | |
* @return | |
*/ | |
protected Map < String, PactFragment > getPacts() { | |
if (fragments == null) { | |
fragments = new HashMap < > (); | |
for (Method m: target.getClass().getMethods()) { | |
if (conformsToSigniture(m)) { | |
Pact pact = m.getAnnotation(Pact.class); | |
PactDslWithState dslBuilder = ConsumerPactBuilder.consumer(pact.consumer()) | |
.hasPactWith(pact.provider()) | |
.given(pact.state()); | |
try { | |
fragments.put(pact.state(), (PactFragment) m.invoke(target, dslBuilder)); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
return fragments; | |
} | |
/** | |
* validates method signature as described at {@link Pact} | |
* | |
*/ | |
private boolean conformsToSigniture(Method m) { | |
Pact pact = m.getAnnotation(Pact.class); | |
boolean conforms = | |
pact != null | |
&& PactFragment.class.isAssignableFrom(m.getReturnType()) | |
&& m.getParameterCount() == 1 | |
&& m.getParameterTypes()[0].isAssignableFrom(PactDslWithState.class); | |
if (!conforms && pact != null) { | |
log.error("Method {} does not conform required method signature " + "'public PactFragment xxx(PactDslWithState builder)': ", | |
m.getName()); | |
} | |
return conforms; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment