From 286ae5557e3b49519bea9e9f65fbe1c15810f388 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s=20Alcarraz?=
+ * Usage example:
+ *
+ * {@code @ExtendWith(LogSupplierExtension.class)}
+ * {@code
+ * @ExtendWith(LogSupplierExtension.class)
+ * class XxxxTest ...{
+ * ...
+ * @LogSource
+ * Log log;
+ * ....
+ *
+ * @AfterEach
+ * tearDown() {
+ * log.debug(...);
+ * }
+ * }
+ * }
+ *
The {@link Method} or {@link Constructor} + * in which the parameter is declared can be retrieved via + * {@link ParameterContext#getDeclaringExecutable()}. + * + * @param parameterContext the context for the parameter for which an argument should + * be resolved; never {@code null} + * @param extensionContext the extension context for the {@code Executable} + * about to be invoked; never {@code null} + * @return {@code true} if this resolver can resolve an argument for the parameter + * @see #resolveParameter + * @see ParameterContext + */ + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return parameterContext.isAnnotated(LogSource.class) && parameterContext.getTarget().map(Object::getClass).filter(c -> c.isAssignableFrom(LogSource.class)).isPresent(); + } + + /** + * Resolve an argument for the parameter in the supplied {@link ParameterContext} + * for the supplied {@link ExtensionContext}. + * + *
This method is only called by the framework if {@link #supportsParameter} + * previously returned {@code true} for the same {@link ParameterContext} + * and {@link ExtensionContext}. + * + *
The {@link Method} or {@link Constructor} + * in which the parameter is declared can be retrieved via + * {@link ParameterContext#getDeclaringExecutable()}. + * + * @param parameterContext the context for the parameter for which an argument should + * be resolved; never {@code null} + * @param extensionContext the extension context for the {@code Executable} + * about to be invoked; never {@code null} + * @return the resolved argument for the parameter; may only be {@code null} if the + * parameter type is not a primitive + * @see #supportsParameter + * @see ParameterContext + */ + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return getLog(parameterContext.getParameter().getAnnotation(LogSource.class), extensionContext.getRequiredTestClass()); + } + + + /** + * Callback that is invoked once before all tests in the current + * container. + * + * @param context the current extension context; never {@code null} + */ + @Override + public void beforeAll(ExtensionContext context) throws Exception { + setUp(context, true); + } +} diff --git a/modules/test/src/main/java/org/jpos/ee/test/MUXMock.java b/modules/test/src/main/java/org/jpos/ee/test/MUXMock.java new file mode 100644 index 0000000000..9bad46d3fc --- /dev/null +++ b/modules/test/src/main/java/org/jpos/ee/test/MUXMock.java @@ -0,0 +1,54 @@ +package org.jpos.ee.test; + +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *
Injects a muck mux in the declared member or parameter. It needs to be used alongside
+ * {@code @ExtendWith(MUXSupplierExtension.class)}.
+ * Usage example: + *
+ *{@code + * @ExtendWith(MUXSupplierExtension.class) + * class XxxxTest ...{ + * ... + * @MUXMock //register the mux mock in name registrar, if not already registered, and injects it + * MUX mux + * .... + * + * testXxx() { + * //define return for some condition, this example uses mockito + * when(mux.request(same(request), anyLong())).thenReturn(response); + * } + * } + * }+ */ +@Target({ ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(MUXSupplierExtension.class) +public @interface MUXMock { + String MUX_NAME = ""; + + /** + *
Name by which the mux is going tobe registered in Name Registrar
+ * + *Don't use the same name for instance and static, unless you don't care the static is unregistered from + * {@link org.jpos.util.NameRegistrar}
+ * + * Defaults to {@code ""}, in which case one with a random name will be generated + * + * @return the name under which the mux mock will be registered. + */ + String name() default MUX_NAME; + + /** + * Tells if the mocked mux should return true when its {@code isConnected()} method is called. + * @return the value the mocked mux {@code isConnected()} method should return. + */ + boolean connected() default true; +} diff --git a/modules/test/src/main/java/org/jpos/ee/test/MUXSupplierExtension.java b/modules/test/src/main/java/org/jpos/ee/test/MUXSupplierExtension.java new file mode 100644 index 0000000000..4a1f92b319 --- /dev/null +++ b/modules/test/src/main/java/org/jpos/ee/test/MUXSupplierExtension.java @@ -0,0 +1,152 @@ +package org.jpos.ee.test; + +import org.jpos.iso.MUX; +import org.jpos.util.NameRegistrar; +import org.junit.jupiter.api.extension.*; + +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.Random; +import java.util.function.BiConsumer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MUXSupplierExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver, BeforeAllCallback, AfterAllCallback { + + protected static void runOnFields(ExtensionContext context, boolean staticFields, BiConsumerThe {@link Method} or {@link Constructor} + * in which the parameter is declared can be retrieved via + * {@link ParameterContext#getDeclaringExecutable()}. + * + * @param parameterContext the context for the parameter for which an argument should + * be resolved; never {@code null} + * @param extensionContext the extension context for the {@code Executable} + * about to be invoked; never {@code null} + * @return {@code true} if this resolver can resolve an argument for the parameter + * @see #resolveParameter + * @see ParameterContext + */ + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return parameterContext.isAnnotated(MUXMock.class); + } + + /** + * Resolve an argument for the parameter in the supplied {@link ParameterContext} + * for the supplied {@link ExtensionContext}. + * + *
This method is only called by the framework if {@link #supportsParameter} + * previously returned {@code true} for the same {@link ParameterContext} + * and {@link ExtensionContext}. + * + *
The {@link Method} or {@link Constructor}
+ * in which the parameter is declared can be retrieved via
+ * {@link ParameterContext#getDeclaringExecutable()}.
+ *
+ * @param parameterContext the context for the parameter for which an argument should
+ * be resolved; never {@code null}
+ * @param extensionContext the extension context for the {@code Executable}
+ * about to be invoked; never {@code null}
+ * @return the resolved argument for the parameter; may only be {@code null} if the
+ * parameter type is not a primitive
+ * @see #supportsParameter
+ * @see ParameterContext
+ */
+ @Override
+ public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+ return getMUXMock(parameterContext.getParameter().getAnnotation(MUXMock.class));
+ }
+
+ /**
+ * Callback that is invoked once after all tests in the current
+ * container.
+ *
+ * @param context the current extension context; never {@code null}
+ */
+ @Override
+ public void afterAll(ExtensionContext context) throws Exception {
+ tearDown(context, true);
+ }
+
+ /**
+ * Callback that is invoked once before all tests in the current
+ * container.
+ *
+ * @param context the current extension context; never {@code null}
+ */
+ @Override
+ public void beforeAll(ExtensionContext context) throws Exception {
+ setUp(context, true);
+ }
+}
diff --git a/modules/test/src/main/java/org/jpos/ee/test/TestUtil.java b/modules/test/src/main/java/org/jpos/ee/test/TestUtil.java
new file mode 100644
index 0000000000..f121c19677
--- /dev/null
+++ b/modules/test/src/main/java/org/jpos/ee/test/TestUtil.java
@@ -0,0 +1,18 @@
+package org.jpos.ee.test;
+
+import org.jpos.util.LogListener;
+import org.jpos.util.Logger;
+import org.jpos.util.SimpleLogListener;
+
+public class TestUtil {
+ private final static Logger logger = new Logger();
+
+ static {
+ LogListener stdout = new SimpleLogListener();
+ logger.addListener(stdout);
+ }
+
+ public static Logger getLogger() {
+ return logger;
+ }
+}
diff --git a/modules/test/src/test/java/org/jpos/ee/test/LogSupplierExtensionTest.java b/modules/test/src/test/java/org/jpos/ee/test/LogSupplierExtensionTest.java
new file mode 100644
index 0000000000..b0a8b29454
--- /dev/null
+++ b/modules/test/src/test/java/org/jpos/ee/test/LogSupplierExtensionTest.java
@@ -0,0 +1,51 @@
+package org.jpos.ee.test;
+
+import org.jpos.util.Log;
+import org.jpos.util.Logger;
+import org.jpos.util.SimpleLogListener;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@ExtendWith(LogSupplierExtension.class)
+class LogSupplierExtensionTest {
+ static final String LOGGER_NAME = "test-logger";
+ @LogSource (logger=LOGGER_NAME, realm="log-test")
+ Log log;
+
+ Logger logger;
+
+ SimpleLogListener logListener = new SimpleLogListener();
+
+ @BeforeEach
+ void setUp() {
+ logger = Logger.getLogger(LOGGER_NAME);
+ logListener = spy(new SimpleLogListener());
+ logger.addListener(logListener);
+ }
+
+ @AfterEach
+ void tearDown() {
+ logger.removeListener(logListener);
+ }
+
+ @Test
+ public void testDebug(){
+ log.debug("debug called");
+ verify(logListener, times(1)).log(argThat(event -> {
+ assertSame(log, event.getSource());
+ assertEquals(Log.DEBUG, event.getTag());
+ assertEquals(1, event.getPayLoad().size());
+ assertEquals("debug called", event.getPayLoad().get(0));
+ return true;
+ }));
+ }
+
+}
\ No newline at end of file
diff --git a/modules/test/src/test/java/org/jpos/ee/test/MUXSupplierExtensionTest.java b/modules/test/src/test/java/org/jpos/ee/test/MUXSupplierExtensionTest.java
new file mode 100644
index 0000000000..41ca3ecc0b
--- /dev/null
+++ b/modules/test/src/test/java/org/jpos/ee/test/MUXSupplierExtensionTest.java
@@ -0,0 +1,46 @@
+package org.jpos.ee.test;
+
+import org.jpos.iso.ISOException;
+import org.jpos.iso.ISOMsg;
+import org.jpos.iso.MUX;
+import org.jpos.q2.iso.QMUX;
+import org.jpos.util.NameRegistrar;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MUXSupplierExtension.class)
+class MUXSupplierExtensionTest {
+
+ private static final String MUX_NAME = "connected-mux";
+ @MUXMock(connected = true, name = MUX_NAME)
+ MUX connectedMux;
+
+ @MUXMock(connected = false)
+ MUX disconnectedMux;
+ @Test
+ void testConnectedMux() throws NameRegistrar.NotFoundException {
+ assertSame(connectedMux, QMUX.getMUX(MUX_NAME));
+ assertTrue(connectedMux.isConnected());
+ }
+
+ @Test
+ void testDisconnectedMux() {
+ assertFalse(disconnectedMux.isConnected());
+ }
+
+ @Test
+ void testMockRequest() throws NameRegistrar.NotFoundException, ISOException {
+ ISOMsg request = new ISOMsg("2100");
+ ISOMsg response = new ISOMsg("2110");
+ when(connectedMux.request(same(request), anyLong())).thenReturn(response);
+ MUX mux = QMUX.getMUX(MUX_NAME);
+ assertSame(connectedMux, mux);
+ assertTrue(mux.isConnected());
+ assertSame(response, mux.request(request, 1000L));
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index cfa0ad84a1..89e7e49855 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -47,6 +47,7 @@ include ':modules:core',
':modules:db-flyway',
':modules:elasticsearch',
':modules:bom'
+ ':modules:test'
rootProject.name = 'jposee'
From 034fab1b1d8ccdce5ab636eb2b689b6b3c1d0f6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s=20Alcarraz?=