All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mats3.test.junit.Rule_MatsEndpoint Maven / Gradle / Ivy

There is a newer version: 0.19.22-2024-11-09
Show newest version
package io.mats3.test.junit;

import javax.inject.Inject;

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.mats3.MatsEndpoint.ProcessSingleLambda;
import io.mats3.MatsFactory;
import io.mats3.test.abstractunit.AbstractMatsTestEndpoint;

/**
 * Rule to create a single staged endpoint whose reply/processor can be changed throughout its life, i.e. per test (e.g.
 * answer "Sorry, no can do." for the first test, and then "Yes, we can!" for the next test). Useful for mocking
 * endpoints in tests where you need predictable replies, and may also be used to verify that an endpoint was
 * not invoked.
 * 

* The endpoint processor can be changed on demand using {@link #setProcessLambda(ProcessSingleLambda)} *

* Must be annotated with {@link Rule @Rule}. Do not use with {@link ClassRule @ClassRule} *

* Retrieve the endpoint's received(incoming) message/messages by calling on of the following methods: *

    *
  • {@link Rule_MatsEndpoint#waitForRequest()} - Wait for a message(singular) using the default timeout
  • *
  • {@link Rule_MatsEndpoint#waitForRequest(long)} - Wait for a message(singular) with user specified timeout
  • *
  • {@link Rule_MatsEndpoint#waitForRequests(int)} - Wait for X messages using the default timeout
  • *
  • {@link Rule_MatsEndpoint#waitForRequests(int, long)} - Wait for X messages with user specified timeout
  • *
* Given a case where one does not expect the endpoint to be invoked (no messages received) one can utilize * {@link Rule_MatsEndpoint#verifyNotInvoked()} to ensure that the endpoint was not in fact invoked during the test. *

* If no process lambda is specified for the endpoint it will act as a terminator, thus it does not generate a reply. *

* *

 * @Rule
 * public Rule_MatsEndpoint<String, String> _world = Rule_MatsEndpoint.single(endpointFactory, "World",
 *         String.class, String.class, (context, in) -> in + "World");
 * 
* * Should one want to utilize this test endpoint approach in a test which brings up a Spring context which contains a * {@link MatsFactory} one can utilize the @SpringInjectRulesAndExtensions (in 'mats-spring-test') which * will inject/autowire this class automatically by providing the {@link MatsFactory} located in said Spring context. * * @param * The reply class of the message generated by this endpoint. (Reply Class) * @param * The incoming message class for this endpoint. (Request Class) * @author Kevin Mc Tiernan, 2020-10-22, [email protected] * @author Geir Gullestad Pettersen, 2017 - [email protected] * @author Johan Herman Hausberg, 2017.04 - [email protected] * @author Asbjørn Aarrestad, 2017 - [email protected] * @author Endre Stølsvik, 2017 - http://stolsvik.com/, [email protected] */ public class Rule_MatsEndpoint extends AbstractMatsTestEndpoint implements TestRule { private static final Logger log = LoggerFactory.getLogger(Rule_MatsEndpoint.class); /** * Private constructor, utilize {@link #create(String, Class, Class)} to create an instance of this object. */ private Rule_MatsEndpoint(String endpointId, Class replyMsgClass, Class incomingMsgClass) { super(endpointId, replyMsgClass, incomingMsgClass); } /** * Sets the internal {@link MatsFactory} to be utilized for the creation of this endpoint. *

* If not utilized explicitly can also be injected/autowired through the use of the test execution listener * @SpringInjectRulesAndExtensions should this Rule be utilized in a test where a Spring context is in * play. * * @param matsFactory * to set. * @return this instance of the object. */ @Inject @Override public Rule_MatsEndpoint setMatsFactory(MatsFactory matsFactory) { log.debug("+++ JUnit +++ setMatsFactory(" + matsFactory + ") invoked."); _matsFactory = matsFactory; return this; } @Override public Rule_MatsEndpoint setProcessLambda(ProcessSingleLambda processLambda) { log.debug("+++ JUnit +++ setProcessLambda(" + processLambda + ") invoked."); _processLambda = processLambda; return this; } /** * Creates a JUnit Rule for a single-staged endpoint whose processor is not defined at start. Sets it up on * JUnit lifecycle 'before' and tears it down on 'after'. Notice that a {@link MatsFactory} must be set before it * is usable! In a Spring environment, you should probably employ the * @SpringInjectRulesAndExtensions to make this happen automagically. In a "pure Java" environment, * consider the convenience overload {@link #create(Rule_Mats, String, Class, Class) create(Mats_Rule, endpointId, * replyClass, incomingClass)} to easily supply the corresponding {@literal @ClassRule} * {@link Rule_Mats} for fetching the MatsFactory. *

* Do notice that you need to invoke {@link #setProcessLambda(ProcessSingleLambda)} - typically inside the * {@literal @Test} method - before sending messages to it, as there is no default. * * @param endpointId * of the endpoint. * @param replyMsgClass * the class of the reply message generated by this endpoint. * @param incomingMsgClass * the incoming message class for this endpoint. * @return {@link Rule_MatsEndpoint} */ public static Rule_MatsEndpoint create(String endpointId, Class replyMsgClass, Class incomingMsgClass) { return new Rule_MatsEndpoint<>(endpointId, replyMsgClass, incomingMsgClass); } /** * Convenience variant of {@link #create(String, Class, Class) create(endpointId, replyClass, incomingClass)} taking * a {@link Rule_Mats} as first argument for fetching the {@link MatsFactory}, for use in "pure Java" environments * (read as: non-Spring). */ public static Rule_MatsEndpoint create(Rule_Mats matsRule, String endpointId, Class replyMsgClass, Class incomingMsgClass) { Rule_MatsEndpoint rule_matsEndpoint = new Rule_MatsEndpoint<>(endpointId, replyMsgClass, incomingMsgClass); // Set MatsFactory from the supplied Rule_Mats rule_matsEndpoint.setMatsFactory(matsRule.getMatsFactory()); return rule_matsEndpoint; } // ================== Junit LifeCycle ============================================================================= /** * Note: Shamelessly inspired from: How to combine @Rule * and @ClassRule in JUnit 4.12 */ @Override public Statement apply(Statement base, Description description) { if (description.isSuite()) { throw new IllegalStateException("The Rule_MatsEndpoint should be applied as a @Rule, NOT as a @ClassRule"); } return new Statement() { public void evaluate() throws Throwable { before(); try { base.evaluate(); } finally { after(); } } }; } }