aboutsummaryrefslogtreecommitdiff
path: root/slf4j-api/src/test/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'slf4j-api/src/test/java/org')
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java62
-rw-r--r--slf4j-api/src/test/java/org/slf4j/LoggerFactoryTest.java91
-rw-r--r--slf4j-api/src/test/java/org/slf4j/basicTests/BasicMarkerTest.java (renamed from slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java)22
-rw-r--r--slf4j-api/src/test/java/org/slf4j/basicTests/Differentiator.java (renamed from slf4j-api/src/test/java/org/slf4j/Differentiator.java)2
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/basicTests/DoubleCheckedInt.java141
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/basicTests/FluentAPIUsage.java27
-rw-r--r--slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingMultithreadedInitializationTest.java (renamed from slf4j-api/src/test/java/org/slf4j/helpers/MyRandom.java)43
-rw-r--r--slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingTest.java (renamed from slf4j-api/src/test/java/org/slf4j/NoBindingTest.java)18
-rw-r--r--slf4j-api/src/test/java/org/slf4j/eventTest/EventRecordingLoggerTest.java531
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java17
-rw-r--r--slf4j-api/src/test/java/org/slf4j/helpers/BogoPerf.java150
-rw-r--r--slf4j-api/src/test/java/org/slf4j/helpers/BubbleSortTest.java100
-rw-r--r--slf4j-api/src/test/java/org/slf4j/helpers/MDCAdapterTestBase.java147
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java111
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java37
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/helpers/StringPrintStream.java74
-rw-r--r--slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java81
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java21
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/rule/BlaTest.java38
-rwxr-xr-x[-rw-r--r--]slf4j-api/src/test/java/org/slf4j/rule/RunInNewThread.java (renamed from slf4j-api/src/test/java/org/slf4j/helpers/BubbleSort.java)36
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadRule.java54
-rwxr-xr-xslf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadStatement.java68
-rw-r--r--slf4j-api/src/test/java/org/slf4j/testHarness/MultithreadedInitializationTest.java79
23 files changed, 1483 insertions, 467 deletions
diff --git a/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java b/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java
new file mode 100755
index 00000000..30ab5705
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/LoggerAccessingThread.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2004-2016 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j;
+
+import java.util.List;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class LoggerAccessingThread extends Thread {
+ private static final int LOOP_LEN = 32;
+
+ final CyclicBarrier barrier;
+ final int count;
+ final AtomicLong eventCount;
+ List<Logger> loggerList;
+
+ public LoggerAccessingThread(final CyclicBarrier barrier, List<Logger> loggerList, final int count, final AtomicLong eventCount) {
+ this.barrier = barrier;
+ this.loggerList = loggerList;
+ this.count = count;
+ this.eventCount = eventCount;
+ }
+
+ public void run() {
+ try {
+ barrier.await();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ String loggerNamePrefix = this.getClass().getName();
+ for (int i = 0; i < LOOP_LEN; i++) {
+ Logger logger = LoggerFactory.getLogger(loggerNamePrefix + "-" + count + "-" + i);
+ loggerList.add(logger);
+ Thread.yield();
+ logger.info("in run method");
+ eventCount.getAndIncrement();
+ }
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/LoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/LoggerFactoryTest.java
new file mode 100644
index 00000000..ed618171
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/LoggerFactoryTest.java
@@ -0,0 +1,91 @@
+package org.slf4j;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.spi.MDCAdapter;
+import org.slf4j.spi.SLF4JServiceProvider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+public class LoggerFactoryTest {
+ private PrintStream rawSyserr;
+ private ByteArrayOutputStream mockedSyserr;
+
+ final ClassLoader classLoaderOfLoggerFactory = LoggerFactory.class.getClassLoader();
+
+ @Before
+ public void setUp() {
+ rawSyserr = System.err;
+ mockedSyserr = new ByteArrayOutputStream();
+ System.setErr(new PrintStream(mockedSyserr));
+ }
+
+ @After
+ public void cleanUp() {
+ System.clearProperty(LoggerFactory.PROVIDER_PROPERTY_KEY);
+ System.setErr(rawSyserr);
+ }
+
+ @Test
+ public void testExplicitlySpecified() {
+ System.setProperty(LoggerFactory.PROVIDER_PROPERTY_KEY, "org.slf4j.LoggerFactoryTest$TestingProvider");
+ SLF4JServiceProvider provider = LoggerFactory.loadExplicitlySpecified(classLoaderOfLoggerFactory);
+ assertTrue("provider should be instance of TestingProvider class", provider instanceof TestingProvider);
+ assertTrue(mockedSyserr.toString().contains(" Attempting to load provider \"org.slf4j.LoggerFactoryTest$TestingProvider\" specified via \"slf4j.provider\" system property"));
+ System.out.println(mockedSyserr.toString());
+
+
+ }
+
+ @Test
+ public void testExplicitlySpecifiedNull() {
+ assertNull(LoggerFactory.loadExplicitlySpecified(classLoaderOfLoggerFactory));
+ }
+
+ @Test
+ public void testExplicitlySpecifyMissingServiceProvider() {
+ System.setProperty(LoggerFactory.PROVIDER_PROPERTY_KEY, "com.example.ServiceProvider");
+ SLF4JServiceProvider provider = LoggerFactory.loadExplicitlySpecified(classLoaderOfLoggerFactory);
+ assertNull(provider);
+ assertTrue(mockedSyserr.toString().contains("Failed to instantiate the specified SLF4JServiceProvider (com.example.ServiceProvider)"));
+ }
+
+ @Test
+ public void testExplicitlySpecifyNonServiceProvider() {
+ System.setProperty(LoggerFactory.PROVIDER_PROPERTY_KEY, "java.lang.String");
+ assertNull(LoggerFactory.loadExplicitlySpecified(classLoaderOfLoggerFactory));
+ assertTrue(mockedSyserr.toString().contains("Specified SLF4JServiceProvider (java.lang.String) does not implement SLF4JServiceProvider interface"));
+ }
+
+ public static class TestingProvider implements SLF4JServiceProvider {
+ @Override
+ public ILoggerFactory getLoggerFactory() {
+ return null;
+ }
+
+ @Override
+ public IMarkerFactory getMarkerFactory() {
+ return null;
+ }
+
+ @Override
+ public MDCAdapter getMDCAdapter() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedApiVersion() {
+ return null;
+ }
+
+ @Override
+ public void initialize() {
+
+ }
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java b/slf4j-api/src/test/java/org/slf4j/basicTests/BasicMarkerTest.java
index 50471b59..5ce33471 100644
--- a/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/BasicMarkerTest.java
@@ -22,12 +22,15 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
-package org.slf4j;
+package org.slf4j.basicTests;
-import java.util.Iterator;
+import static org.junit.Assert.*;
-import junit.framework.TestCase;
+import java.util.Iterator;
+import org.junit.Test;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.Marker;
import org.slf4j.helpers.BasicMarkerFactory;
/**
@@ -36,7 +39,7 @@ import org.slf4j.helpers.BasicMarkerFactory;
* @author Ceki G&uuml;lc&uuml;
* @author Joern Huxhorn
*/
-public class BasicMarkerTest extends TestCase {
+public class BasicMarkerTest {
static final String BLUE_STR = "BLUE";
static final String RED_STR = "RED";
static final String GREEN_STR = "GREEN";
@@ -69,6 +72,7 @@ public class BasicMarkerTest extends TestCase {
multiComp.add(comp);
}
+ @Test
public void testPrimitive() {
assertEquals(BLUE_STR, blue.getName());
assertTrue(blue.contains(blue));
@@ -80,20 +84,24 @@ public class BasicMarkerTest extends TestCase {
assertTrue(blue2.contains(blue));
}
+ @Test
public void testPrimitiveByName() {
assertTrue(blue.contains(BLUE_STR));
}
+ @Test
public void testComposite() {
assertTrue(comp.contains(comp));
assertTrue(comp.contains(blue));
}
+ @Test
public void testCompositeByName() {
assertTrue(comp.contains(COMP_STR));
assertTrue(comp.contains(BLUE_STR));
}
+ @Test
public void testMultiComposite() {
assertTrue(multiComp.contains(comp));
assertTrue(multiComp.contains(blue));
@@ -101,6 +109,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(multiComp.contains(red));
}
+ @Test
public void testMultiCompositeByName() {
assertTrue(multiComp.contains(COMP_STR));
assertTrue(multiComp.contains(BLUE_STR));
@@ -108,6 +117,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(multiComp.contains(RED_STR));
}
+ @Test
public void testMultiAdd() {
Marker parent = factory.getMarker(PARENT_MARKER_STR);
Marker child = factory.getMarker(CHILD_MARKER_STR);
@@ -122,6 +132,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(iterator.hasNext());
}
+ @Test
public void testAddRemove() {
final String NEW_PREFIX = "NEW_";
Marker parent = factory.getMarker(NEW_PREFIX + PARENT_MARKER_STR);
@@ -142,6 +153,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(parent.remove(child));
}
+ @Test
public void testSelfRecursion() {
final String diffPrefix = "NEW_" + diff;
final String PARENT_NAME = diffPrefix + PARENT_MARKER_STR;
@@ -155,6 +167,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(parent.contains(NOT_CONTAINED_MARKER_STR));
}
+ @Test
public void testIndirectRecursion() {
final String diffPrefix = "NEW_" + diff;
final String PARENT_NAME = diffPrefix + PARENT_MARKER_STR;
@@ -175,6 +188,7 @@ public class BasicMarkerTest extends TestCase {
assertFalse(parent.contains(NOT_CONTAINED_MARKER_STR));
}
+ @Test
public void testHomonyms() {
final String diffPrefix = "homonym" + diff;
final String PARENT_NAME = diffPrefix + PARENT_MARKER_STR;
diff --git a/slf4j-api/src/test/java/org/slf4j/Differentiator.java b/slf4j-api/src/test/java/org/slf4j/basicTests/Differentiator.java
index 09b9a35a..fe2a72ee 100644
--- a/slf4j-api/src/test/java/org/slf4j/Differentiator.java
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/Differentiator.java
@@ -23,7 +23,7 @@
*
*/
-package org.slf4j;
+package org.slf4j.basicTests;
import java.util.Random;
diff --git a/slf4j-api/src/test/java/org/slf4j/basicTests/DoubleCheckedInt.java b/slf4j-api/src/test/java/org/slf4j/basicTests/DoubleCheckedInt.java
new file mode 100755
index 00000000..42a39e64
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/DoubleCheckedInt.java
@@ -0,0 +1,141 @@
+package org.slf4j.basicTests;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+/**
+ * This class demonstrates that threads accessing the STATE variable always see a consistent value.
+ *
+ * During ongoing initialization the observed value is either ONGOING_INITIALIZATION
+ * or one of {SUCCESS, FAILURE}.
+ *
+ * Post initialization the observed value is always one of {SUCCESS, FAILURE}.
+ *
+ * See also http://jira.qos.ch/browse/SLF4J-167
+ *
+ * @author ceki
+ *
+ */
+public class DoubleCheckedInt {
+
+ final static int THREAD_COUNT = 10 + Runtime.getRuntime().availableProcessors() * 2;
+ final static int UNINITIALIZED_STATE = 0;
+ final static int ONGOING_INITIALIZATION = 1;
+ final static int SUCCESS = 2;
+ final static int FAILURE = 3;
+ final static int NUMBER_OF_STATES = FAILURE + 1;
+
+ private static int STATE = UNINITIALIZED_STATE;
+
+ public static int getState() {
+ if (STATE == 0) {
+ synchronized (DoubleCheckedInt.class) {
+ if (STATE == UNINITIALIZED_STATE) {
+ STATE = ONGOING_INITIALIZATION;
+ long r = System.nanoTime();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ if (r % 2 == 0) {
+ STATE = SUCCESS;
+ } else {
+ STATE = FAILURE;
+ }
+ }
+ }
+ }
+ return STATE;
+ }
+
+ static public void main(String[] args) throws InterruptedException, BrokenBarrierException {
+ StateAccessingThread[] preInitializationThreads = harness();
+ check(preInitializationThreads, false);
+
+ System.out.println("============");
+ StateAccessingThread[] postInitializationThreads = harness();
+ check(postInitializationThreads, true);
+ }
+
+ private static StateAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
+ StateAccessingThread[] threads = new StateAccessingThread[THREAD_COUNT];
+ final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ threads[i] = new StateAccessingThread(barrier);
+ threads[i].start();
+ }
+
+ barrier.await();
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ threads[i].join();
+ }
+ return threads;
+ }
+
+ private static void check(StateAccessingThread[] threads, boolean postInit) {
+
+ int[] stateCount = getStateCount(threads);
+ printStateCount(stateCount);
+
+ if (stateCount[UNINITIALIZED_STATE] != 0) {
+ throw new IllegalStateException("getState() should never return a zero value");
+ }
+
+ if (stateCount[SUCCESS] != 0 && stateCount[FAILURE] != 0) {
+ throw new IllegalStateException("getState() should return consistent values");
+ }
+
+ if (postInit) {
+ if (stateCount[SUCCESS] != THREAD_COUNT && stateCount[FAILURE] != THREAD_COUNT) {
+ throw new IllegalStateException("getState() should return consistent values");
+ }
+ }
+
+ }
+
+ private static void printStateCount(int[] stateCount) {
+ for (int i = 0; i < NUMBER_OF_STATES; i++) {
+ switch (i) {
+ case UNINITIALIZED_STATE:
+ System.out.println("UNINITIALIZED_STATE count: " + stateCount[i]);
+ break;
+ case ONGOING_INITIALIZATION:
+ System.out.println("ONGOING_INITIALIZATION count: " + stateCount[i]);
+ break;
+ case SUCCESS:
+ System.out.println("SUCCESS count: " + stateCount[i]);
+ break;
+ case FAILURE:
+ System.out.println("FAILURE count: " + stateCount[i]);
+ break;
+ }
+ }
+ }
+
+ private static int[] getStateCount(StateAccessingThread[] threads) {
+ int[] valCount = new int[NUMBER_OF_STATES];
+ for (StateAccessingThread thread : threads) {
+ int val = thread.state;
+ valCount[val] = valCount[val] + 1;
+ }
+ return valCount;
+ }
+
+ static class StateAccessingThread extends Thread {
+ public int state = -1;
+ final CyclicBarrier barrier;
+
+ StateAccessingThread(CyclicBarrier barrier) {
+ this.barrier = barrier;
+ }
+
+ public void run() {
+ try {
+ barrier.await();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ state = DoubleCheckedInt.getState();
+ }
+ };
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/basicTests/FluentAPIUsage.java b/slf4j-api/src/test/java/org/slf4j/basicTests/FluentAPIUsage.java
new file mode 100755
index 00000000..cc8434a9
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/FluentAPIUsage.java
@@ -0,0 +1,27 @@
+package org.slf4j.basicTests;
+
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.Level;
+
+public class FluentAPIUsage {
+
+ @Test
+ public void smoke() {
+ String name = "smoke";
+ Logger logger = LoggerFactory.getLogger(name);
+ logger.atTrace().addKeyValue("a", "n").setCause(new Throwable()).log("hello");
+ }
+
+
+ @Test
+ public void smokxce() {
+ String name = "smoke";
+ Logger logger = LoggerFactory.getLogger(name);
+ assertFalse(logger.isEnabledForLevel(Level.DEBUG));
+ }
+
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MyRandom.java b/slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingMultithreadedInitializationTest.java
index c817d673..024a7f82 100644
--- a/slf4j-api/src/test/java/org/slf4j/helpers/MyRandom.java
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingMultithreadedInitializationTest.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2004-2011 QOS.ch
+ * Copyright (c) 2004-2016 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -22,30 +22,35 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
-package org.slf4j.helpers;
+package org.slf4j.basicTests;
-class MyRandom {
+import org.junit.After;
+import org.junit.Before;
+import org.slf4j.LoggerFactoryFriend;
+import org.slf4j.testHarness.MultithreadedInitializationTest;
- private final static long m = 200000000041L; // a prime number
- private final static long a = 2000000011L; // a prime number
-
- long y;
- long unused;
- int bits = 32;
+/**
+ * Checks that when no binding is present, proper clean up is performed by LoggerFactory.
+ *
+ * See SLF4J-469
+ *
+ * @author David Harsha
+ */
+public class NoBindingMultithreadedInitializationTest extends MultithreadedInitializationTest {
+ final String loggerName = this.getClass().getName();
- public MyRandom() {
- this(System.nanoTime());
+ @Before
+ public void setup() {
+ LoggerFactoryFriend.reset();
}
- public MyRandom(long seed) {
- this.y = seed;
+ @After
+ public void tearDown() throws Exception {
+ LoggerFactoryFriend.reset();
}
- int nextInt() {
- // we don't really care about the randomness of this
- // generator
- y = (a * y + 1) % m;
- unused = y >>> (48 - bits); // just exercise the >>> operator
- return (int) (y);
+ @Override
+ protected long getRecordedEventCount() {
+ return eventCount.get();
}
}
diff --git a/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java b/slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingTest.java
index 7a5ec2d8..8e1dd16c 100644
--- a/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/basicTests/NoBindingTest.java
@@ -22,30 +22,40 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
-package org.slf4j;
+package org.slf4j.basicTests;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.util.Random;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
import org.slf4j.helpers.BasicMarker;
import org.slf4j.helpers.NOPLogger;
-import junit.framework.TestCase;
-
-public class NoBindingTest extends TestCase {
+public class NoBindingTest {
int diff = new Random().nextInt(10000);
+ @Test
public void testLogger() {
Logger logger = LoggerFactory.getLogger(NoBindingTest.class);
logger.debug("hello" + diff);
assertTrue(logger instanceof NOPLogger);
}
+ @Test
public void testMDC() {
MDC.put("k" + diff, "v");
assertNull(MDC.get("k"));
}
+ @Test
public void testMarker() {
Marker m = MarkerFactory.getMarker("a" + diff);
assertTrue(m instanceof BasicMarker);
diff --git a/slf4j-api/src/test/java/org/slf4j/eventTest/EventRecordingLoggerTest.java b/slf4j-api/src/test/java/org/slf4j/eventTest/EventRecordingLoggerTest.java
new file mode 100644
index 00000000..e2ec1c05
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/eventTest/EventRecordingLoggerTest.java
@@ -0,0 +1,531 @@
+package org.slf4j.eventTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Marker;
+import org.slf4j.event.EventRecordingLogger;
+import org.slf4j.event.Level;
+import org.slf4j.event.SubstituteLoggingEvent;
+import org.slf4j.helpers.BasicMarkerFactory;
+import org.slf4j.helpers.SubstituteLogger;
+
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import static org.junit.Assert.*;
+
+public class EventRecordingLoggerTest {
+ private Queue<SubstituteLoggingEvent> queue;
+ private EventRecordingLogger logger;
+ private String message;
+ private Object param1;
+ private Object param2;
+ private Object param3;
+ private Object[] oneParam;
+ private Object[] twoParams;
+ private Object[] threeParams;
+ private Throwable exception;
+ private Marker marker;
+
+ @Before
+ public void setUp() {
+ queue = new LinkedBlockingQueue<>();
+ logger = new EventRecordingLogger(new SubstituteLogger("testLogger", queue, true), queue);
+ message = "Test message with 3 parameters {} {} {} {}";
+ param1 = 1;
+ param2 = 2;
+ param3 = 3;
+ oneParam = new Object[] { param1 };
+ twoParams = new Object[] { param1, param2 };
+ threeParams = new Object[] { param1, param2, param3 };
+ exception = new IllegalStateException("We just need an exception");
+ marker = new BasicMarkerFactory().getMarker("testMarker");
+ }
+
+ @After
+ public void tearDown() {
+ assertTrue(queue.isEmpty());
+ }
+
+ @Test
+ public void singleMessage() {
+ for (Level level : Level.values()) {
+ singleMessageCheck(level);
+ }
+ }
+
+ private void singleMessageCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message);
+ break;
+ case DEBUG:
+ logger.debug(message);
+ break;
+ case INFO:
+ logger.info(message);
+ break;
+ case WARN:
+ logger.warn(message);
+ break;
+ case ERROR:
+ logger.error(message);
+ break;
+ }
+ verifyMessageWithoutMarker(level, null, null);
+ }
+
+ @Test
+ public void oneParameter() {
+ for (Level level : Level.values()) {
+ oneParameterCheck(level);
+ }
+ }
+
+ private void oneParameterCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1);
+ break;
+ case DEBUG:
+ logger.debug(message, param1);
+ break;
+ case INFO:
+ logger.info(message, param1);
+ break;
+ case WARN:
+ logger.warn(message, param1);
+ break;
+ case ERROR:
+ logger.error(message, param1);
+ break;
+ }
+ verifyMessageWithoutMarker(level, oneParam, null);
+ }
+
+ @Test
+ public void messageTwoParameters() {
+ for (Level level : Level.values()) {
+ messageTwoParametersCheck(level);
+ }
+ }
+
+ private void messageTwoParametersCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1, param2);
+ break;
+ case DEBUG:
+ logger.debug(message, param1, param2);
+ break;
+ case INFO:
+ logger.info(message, param1, param2);
+ break;
+ case WARN:
+ logger.warn(message, param1, param2);
+ break;
+ case ERROR:
+ logger.error(message, param1, param2);
+ break;
+ }
+ verifyMessageWithoutMarker(level, twoParams, null);
+ }
+
+ @Test
+ public void traceMessageThreeParameters() {
+ for (Level level : Level.values()) {
+ threeParameterCheck(level);
+ }
+ }
+
+ private void threeParameterCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1, param2, param3);
+ break;
+ case DEBUG:
+ logger.debug(message, param1, param2, param3);
+ break;
+ case INFO:
+ logger.info(message, param1, param2, param3);
+ break;
+ case WARN:
+ logger.warn(message, param1, param2, param3);
+ break;
+ case ERROR:
+ logger.error(message, param1, param2, param3);
+ break;
+ }
+ verifyMessageWithoutMarker(level, threeParams, null);
+ }
+
+ @Test
+ public void testMessageThrowable() {
+ for (Level level : Level.values()) {
+ throwableCheck(level);
+ }
+ }
+
+ private void throwableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, exception);
+ break;
+ case DEBUG:
+ logger.debug(message, exception);
+ break;
+ case INFO:
+ logger.info(message, exception);
+ break;
+ case WARN:
+ logger.warn(message, exception);
+ break;
+ case ERROR:
+ logger.error(message, exception);
+ break;
+ }
+ verifyMessageWithoutMarker(level, null, exception);
+ }
+
+ @Test
+ public void traceMessageOneParameterThrowable() {
+ for (Level level : Level.values()) {
+ oneParamThrowableCheck(level);
+ }
+ }
+
+ private void oneParamThrowableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1, exception);
+ break;
+ case DEBUG:
+ logger.debug(message, param1, exception);
+ break;
+ case INFO:
+ logger.info(message, param1, exception);
+ break;
+ case WARN:
+ logger.warn(message, param1, exception);
+ break;
+ case ERROR:
+ logger.error(message, param1, exception);
+ break;
+ }
+ verifyMessageWithoutMarker(level, oneParam, exception);
+ }
+
+ @Test
+ public void traceMessageTwoParametersThrowable() {
+ for (Level level : Level.values()) {
+ twoParamThrowableCheck(level);
+ }
+ }
+
+ private void twoParamThrowableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1, param2, exception);
+ break;
+ case DEBUG:
+ logger.debug(message, param1, param2, exception);
+ break;
+ case INFO:
+ logger.info(message, param1, param2, exception);
+ break;
+ case WARN:
+ logger.warn(message, param1, param2, exception);
+ break;
+ case ERROR:
+ logger.error(message, param1, param2, exception);
+ break;
+ }
+ verifyMessageWithoutMarker(level, twoParams, exception);
+ }
+
+ @Test
+ public void testMessageThreeParametersThrowable() {
+ for (Level level : Level.values()) {
+ messageWith3ArgsPlusException(level);
+ }
+ }
+
+ private void messageWith3ArgsPlusException(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(message, param1, param2, param3, exception);
+ break;
+ case DEBUG:
+ logger.debug(message, param1, param2, param3, exception);
+ break;
+ case INFO:
+ logger.info(message, param1, param2, param3, exception);
+ break;
+ case WARN:
+ logger.warn(message, param1, param2, param3, exception);
+ break;
+ case ERROR:
+ logger.error(message, param1, param2, param3, exception);
+ break;
+ }
+ verifyMessageWithoutMarker(level, threeParams, exception);
+ }
+
+ @Test
+ public void markerMessage() {
+ for (Level level : Level.values()) {
+ markerMessageCheck(level);
+ }
+ }
+
+ private void markerMessageCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message);
+ break;
+ case DEBUG:
+ logger.debug(marker, message);
+ break;
+ case INFO:
+ logger.info(marker, message);
+ break;
+ case WARN:
+ logger.warn(marker, message);
+ break;
+ case ERROR:
+ logger.error(marker, message);
+ break;
+ }
+ verifyMessage(level, marker, null, null);
+ }
+
+ @Test
+ public void markerMessageOneParameter() {
+ for (Level level : Level.values()) {
+ markerMessageOneParameter(level);
+ }
+ }
+
+ private void markerMessageOneParameter(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1);
+ break;
+ case INFO:
+ logger.info(marker, message, param1);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1);
+ break;
+ }
+ verifyMessage(level, marker, oneParam, null);
+ }
+
+ @Test
+ public void traceMarkerMessageTwoParameters() {
+ for (Level level : Level.values()) {
+ markerMessageTwoParameters(level);
+ }
+ }
+
+ private void markerMessageTwoParameters(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1, param2);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1, param2);
+ break;
+ case INFO:
+ logger.info(marker, message, param1, param2);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1, param2);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1, param2);
+ break;
+ }
+ verifyMessage(level, marker, twoParams, null);
+ }
+
+ @Test
+ public void traceMarkerMessageThreeParameters() {
+ for (Level level : Level.values()) {
+ markerMessageThreeParameters(level);
+ }
+ }
+
+ private void markerMessageThreeParameters(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1, param2, param3);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1, param2, param3);
+ break;
+ case INFO:
+ logger.info(marker, message, param1, param2, param3);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1, param2, param3);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1, param2, param3);
+ break;
+ }
+ verifyMessage(level, marker, threeParams, null);
+ }
+
+ @Test
+ public void markerMessageThrowable() {
+ for (Level level : Level.values()) {
+ markerMessageThrowable(level);
+ }
+ }
+
+ private void markerMessageThrowable(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, exception);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, exception);
+ break;
+ case INFO:
+ logger.info(marker, message, exception);
+ break;
+ case WARN:
+ logger.warn(marker, message, exception);
+ break;
+ case ERROR:
+ logger.error(marker, message, exception);
+ break;
+ }
+ verifyMessage(level, marker, null, exception);
+ }
+
+ @Test
+ public void markerMessageOneParameterThrowable() {
+ for (Level level : Level.values()) {
+ markerMessageOneParameterThrowableCheck(level);
+ }
+ }
+
+ private void markerMessageOneParameterThrowableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1, exception);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1, exception);
+ break;
+ case INFO:
+ logger.info(marker, message, param1, exception);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1, exception);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1, exception);
+ break;
+ }
+ verifyMessage(level, marker, oneParam, exception);
+ }
+
+ @Test
+ public void traceMarkerMessageTwoParametersThrowable() {
+ for (Level level : Level.values()) {
+ markerMessageTwoParametersThrowableCheck(level);
+ }
+ }
+
+ private void markerMessageTwoParametersThrowableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1, param2, exception);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1, param2, exception);
+ break;
+ case INFO:
+ logger.info(marker, message, param1, param2, exception);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1, param2, exception);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1, param2, exception);
+ break;
+ }
+ verifyMessage(level, marker, twoParams, exception);
+ }
+
+ @Test
+ public void traceMarkerMessageThreeParametersThrowable() {
+ for (Level level : Level.values()) {
+ markerMessageThreeParametersThrowableCheck(level);
+ }
+ }
+
+ private void markerMessageThreeParametersThrowableCheck(Level level) {
+ switch (level) {
+ case TRACE:
+ logger.trace(marker, message, param1, param2, param3, exception);
+ break;
+ case DEBUG:
+ logger.debug(marker, message, param1, param2, param3, exception);
+ break;
+ case INFO:
+ logger.info(marker, message, param1, param2, param3, exception);
+ break;
+ case WARN:
+ logger.warn(marker, message, param1, param2, param3, exception);
+ break;
+ case ERROR:
+ logger.error(marker, message, param1, param2, param3, exception);
+ break;
+ }
+ verifyMessage(level, marker, threeParams, exception);
+ }
+
+ private void verifyMessageWithoutMarker(Level level, Object[] arguments, Throwable exception) {
+ verifyMessage(level, null, arguments, exception);
+ }
+
+ private void verifyMessage(Level level, Marker marker, Object[] arguments, Throwable exception) {
+
+ assertEquals("missing event: ", 1, queue.size());
+ SubstituteLoggingEvent event = queue.poll();
+ assertNotNull(event);
+
+ if (marker == null) {
+ assertNull(event.getMarkers());
+ } else {
+ assertEquals(marker, event.getMarkers().get(0));
+ }
+
+ assertEquals(message, event.getMessage());
+
+ if (arguments == null) {
+ assertNull(event.getArgumentArray());
+ } else {
+ assertArrayEquals(arguments, event.getArgumentArray());
+ }
+
+ assertEquals("wrong level: ", level, event.getLevel());
+
+ if (exception == null) {
+ assertNull(event.getThrowable());
+ } else {
+ assertEquals(exception, event.getThrowable());
+ }
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java
new file mode 100755
index 00000000..f73a6e06
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java
@@ -0,0 +1,17 @@
+package org.slf4j.helpers;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class BasicMDCAdapterTest extends MDCAdapterTestBase {
+
+ @Test
+ public void testClearingMDC() {
+ mdc.put("testKey", "testValue");
+ assertFalse(mdc.getCopyOfContextMap().isEmpty());
+ mdc.clear();
+ assertNull(mdc.getCopyOfContextMap());
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/BogoPerf.java b/slf4j-api/src/test/java/org/slf4j/helpers/BogoPerf.java
deleted file mode 100644
index 86f7d67d..00000000
--- a/slf4j-api/src/test/java/org/slf4j/helpers/BogoPerf.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * Copyright (c) 2004-2011 QOS.ch
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-package org.slf4j.helpers;
-
-import junit.framework.AssertionFailedError;
-
-/**
- * BogoPerf is used to check that the time required to perform a certain
- * operation does not deteriorate over time. BogoPerf adjusts to the CPU speed
- * and capabilities of the host.
- *
- * @author Ceki G&uuml;lc&uuml;
- *
- */
-public class BogoPerf {
-
- private static long NANOS_IN_ONE_SECOND = 1000 * 1000 * 1000;
- private static int INITIAL_N = 1000;
- private static int LAST_N = 100;
- private static int SLACK_FACTOR = 3;
-
- static {
- // let the JIT warm up
- computeBogoIPS(INITIAL_N);
- double bogo_ips = computeBogoIPS(INITIAL_N);
- System.out.println("Host runs at " + bogo_ips + " BIPS");
- }
-
- /**
- * Compute bogoInstructions per second
- * <p>
- * on a 3.2 Ghz Pentium D CPU (around 2007), we obtain about 9'000 bogoIPS.
- *
- * @param N
- * number of bogoInstructions to average over in order to
- * compute the result
- * @return bogo Instructions Per Second
- */
- private static double computeBogoIPS(int N) {
- long begin = System.nanoTime();
-
- for (int i = 0; i < N; i++) {
- bogoInstruction();
- }
- long end = System.nanoTime();
-
- // duration
- double D = end - begin;
- // average duration per instruction
- double avgDPIS = D / N;
- // System.out.println(D + " nanos for " + N + " instructions");
- // System.out.println(avgD + " nanos per instruction");
-
- double bogoIPS = NANOS_IN_ONE_SECOND / avgDPIS;
- // System.out.println(bogoIPS + " bogoIPS");
-
- return bogoIPS;
- }
-
- private static void bogoInstruction() {
- // use our own random number generator, independent of the host JDK
- MyRandom myRandom = new MyRandom(100);
- int len = 150;
- int[] intArray = new int[len];
- for (int i = 0; i < len; i++) {
- intArray[i] = myRandom.nextInt();
- }
- // use our own sort algorithm, independent of the host JDK
- BubbleSort.sort(intArray);
- }
-
- /**
- * Computed the BogoIPS for this host CPU.
- *
- * @return
- */
- public static double currentBIPS() {
- return computeBogoIPS(LAST_N);
- }
-
- static double min(double a, double b) {
- return (a <= b) ? a : b;
- }
-
- /**
- * Assertion used for values that <b>decrease</b> with faster CPUs, typically
- * the time (duration) needed to perform a task.
- *
- * @param currentDuration
- * @param referenceDuration
- * @param referenceBIPS
- * @throws AssertionFailedError
- */
- public static void assertDuration(double currentDuration, long referenceDuration, double referenceBIPS) throws AssertionFailedError {
- double ajustedDuration = adjustExpectedDuration(referenceDuration, referenceBIPS);
- if (currentDuration > ajustedDuration * SLACK_FACTOR) {
- throw new AssertionFailedError("current duration " + currentDuration + " exceeded expected " + ajustedDuration + " (adjusted reference), "
- + referenceDuration + " (raw reference)");
- }
- }
-
- /**
- * Assertion used for values that <b>increase<b> with faster CPUs, typically
- * the number of operations accomplished per unit of time.
- *
- * @param currentPerformance
- * @param referencePerformance
- * @param referenceBIPS
- * @throws AssertionFailedError
- */
- public static void assertPerformance(double currentPerformance, long referencePerformance, double referenceBIPS) throws AssertionFailedError {
- double ajustedPerf = adjustExpectedPerformance(referencePerformance, referenceBIPS);
- if (currentPerformance * SLACK_FACTOR < ajustedPerf) {
- throw new AssertionFailedError(currentPerformance + " below expected " + ajustedPerf + " (adjusted), " + referencePerformance + " (raw)");
- }
- }
-
- private static double adjustExpectedPerformance(long referenceDuration, double referenceBIPS) {
- double currentBIPS = currentBIPS();
- return referenceDuration * (currentBIPS / referenceBIPS);
- }
-
- private static double adjustExpectedDuration(long referenceDuration, double referenceBIPS) {
- double currentBIPS = currentBIPS();
- System.out.println("currentBIPS=" + currentBIPS + " BIPS");
- return referenceDuration * (referenceBIPS / currentBIPS);
- }
-}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/BubbleSortTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/BubbleSortTest.java
deleted file mode 100644
index 3592eb02..00000000
--- a/slf4j-api/src/test/java/org/slf4j/helpers/BubbleSortTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Copyright (c) 2004-2011 QOS.ch
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-package org.slf4j.helpers;
-
-import java.util.Arrays;
-import java.util.Random;
-
-import junit.framework.TestCase;
-
-/**
- * Test that our BubbleSort algorithm is correctly implemented.
- *
- * @author Ceki
- *
- */
-public class BubbleSortTest extends TestCase {
-
- public void testSmoke() {
- int[] a = new int[] { 5, 3, 2, 7 };
- BubbleSort.sort(a);
- int i = 0;
- assertEquals(2, a[i++]);
- assertEquals(3, a[i++]);
- assertEquals(5, a[i++]);
- assertEquals(7, a[i++]);
- }
-
- public void testEmpty() {
- int[] a = new int[] {};
- BubbleSort.sort(a);
- }
-
- public void testSorted() {
- int[] a = new int[] { 3, 30, 300, 3000 };
- BubbleSort.sort(a);
- int i = 0;
- assertEquals(3, a[i++]);
- assertEquals(30, a[i++]);
- assertEquals(300, a[i++]);
- assertEquals(3000, a[i++]);
- }
-
- public void testInverted() {
- int[] a = new int[] { 3000, 300, 30, 3 };
- BubbleSort.sort(a);
- int i = 0;
- assertEquals(3, a[i++]);
- assertEquals(30, a[i++]);
- assertEquals(300, a[i++]);
- assertEquals(3000, a[i++]);
- }
-
- public void testWithSameEntry() {
- int[] a = new int[] { 10, 20, 10, 20 };
- BubbleSort.sort(a);
- int i = 0;
- assertEquals(10, a[i++]);
- assertEquals(10, a[i++]);
- assertEquals(20, a[i++]);
- assertEquals(20, a[i++]);
- }
-
- public void testRandom() {
- int len = 100;
- Random random = new Random(156);
- int[] a = new int[len];
- int[] witness = new int[len];
- for (int i = 0; i < len; i++) {
- int r = random.nextInt();
- a[i] = r;
- witness[i] = r;
- }
- BubbleSort.sort(a);
- Arrays.sort(witness);
- assertTrue(Arrays.equals(witness, a));
- }
-
-}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MDCAdapterTestBase.java b/slf4j-api/src/test/java/org/slf4j/helpers/MDCAdapterTestBase.java
new file mode 100644
index 00000000..cd97b1c3
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/MDCAdapterTestBase.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2004-2013 QOS.ch, Copyright (C) 2015 Google Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.slf4j.helpers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Test;
+import org.slf4j.spi.MDCAdapter;
+
+/**
+ * Tests for {@link BasicMDCAdapter}
+ *
+ * @author Lukasz Cwik
+ */
+public class MDCAdapterTestBase {
+
+ protected MDCAdapter mdc = instantiateMDC();
+
+
+
+ protected MDCAdapter instantiateMDC() {
+ return new BasicMDCAdapter();
+ }
+
+ // leave MDC clean
+ @After
+ public void tearDown() throws Exception {
+ mdc.clear();
+ }
+
+ @Test
+ public void testSettingAndGettingWithMDC() {
+ assertNull(mdc.get("testKey"));
+ mdc.put("testKey", "testValue");
+ assertEquals(mdc.get("testKey"), "testValue");
+ }
+
+ @Test
+ public void testOverwritingAKeyInMDC() {
+ assertNull(mdc.get("testKey"));
+ mdc.put("testKey", "testValue");
+ mdc.put("testKey", "differentTestValue");
+ assertEquals(mdc.get("testKey"), "differentTestValue");
+ }
+
+ @Test
+ public void testGetCopyOfContextMapFromMDC() {
+ mdc.put("testKey", "testValue");
+ Map<String, String> copy = mdc.getCopyOfContextMap();
+ mdc.put("anotherTestKey", "anotherTestValue");
+ assertFalse(copy.size() == mdc.getCopyOfContextMap().size());
+ }
+
+ @Test
+ public void testMDCInheritsValuesFromParentThread() throws Exception {
+ mdc.put("parentKey", "parentValue");
+ runAndWait(() -> {
+ mdc.put("childKey", "childValue");
+ assertEquals("parentValue", mdc.get("parentKey"));
+ });
+ }
+
+ @Test
+ public void testMDCDoesntGetValuesFromChildThread() throws Exception {
+ mdc.put("parentKey", "parentValue");
+ runAndWait(() -> mdc.put("childKey", "childValue"));
+ assertEquals("parentValue", mdc.get("parentKey"));
+ assertNull(mdc.get("childKey"));
+ }
+
+
+ @Test
+ public void testInvokingSetContextMap_WithANullMap_SLF4J_414() {
+ mdc.setContextMap(null);
+ }
+
+ @Test
+ public void testMDCChildThreadCanOverwriteParentThread() throws Exception {
+ mdc.put("sharedKey", "parentValue");
+ runAndWait(() -> {
+ assertEquals("parentValue", mdc.get("sharedKey"));
+ mdc.put("sharedKey", "childValue");
+ assertEquals("childValue", mdc.get("sharedKey"));
+ });
+ assertEquals("parentValue", mdc.get("sharedKey"));
+ }
+
+ private void runAndWait(Runnable runnable) {
+ RecordingExceptionHandler handler = new RecordingExceptionHandler();
+ Thread thread = new Thread(runnable);
+ thread.setUncaughtExceptionHandler(handler);
+ thread.start();
+ try {
+ thread.join();
+ } catch (Throwable t) {
+ fail("Unexpected failure in child thread:" + t.getMessage());
+ }
+ assertFalse(handler.getMessage(), handler.hadException());
+ }
+
+ /** A {@link UncaughtExceptionHandler} that records whether the thread threw an exception. */
+ private static class RecordingExceptionHandler implements UncaughtExceptionHandler {
+ private Throwable exception;
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ exception = e;
+ }
+
+ boolean hadException() {
+ return exception != null;
+ }
+
+ String getMessage() {
+ return exception != null ? exception.getMessage() : "";
+ }
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java
deleted file mode 100755
index 7b9640bb..00000000
--- a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Copyright (c) 2004-2011 QOS.ch
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-package org.slf4j.helpers;
-
-import java.text.MessageFormat;
-
-import junit.framework.TestCase;
-import org.junit.Ignore;
-
-@Ignore
-public class MessageFormatterPerfTest extends TestCase {
-
- Integer i1 = new Integer(1);
- Integer i2 = new Integer(2);
- static long RUN_LENGTH = 100 * 1000;
- //
- static long REFERENCE_BIPS = 48416;
-
- public MessageFormatterPerfTest(String name) {
- super(name);
- }
-
- protected void setUp() throws Exception {
- }
-
- protected void tearDown() throws Exception {
- }
-
- public void XtestJDKFormatterPerf() {
- jdkMessageFormatter(RUN_LENGTH);
- double duration = jdkMessageFormatter(RUN_LENGTH);
- System.out.println("jdk duration = " + duration + " nanos");
- }
-
- public void testSLF4JPerf_OneArg() {
- slf4jMessageFormatter_OneArg(RUN_LENGTH);
- double duration = slf4jMessageFormatter_OneArg(RUN_LENGTH);
- System.out.println("duration=" + duration);
- long referencePerf = 36;
- BogoPerf.assertDuration(duration, referencePerf, REFERENCE_BIPS);
- }
-
- public void testSLF4JPerf_TwoArg() {
- slf4jMessageFormatter_TwoArg(RUN_LENGTH);
- double duration = slf4jMessageFormatter_TwoArg(RUN_LENGTH);
- long referencePerf = 60;
- BogoPerf.assertDuration(duration, referencePerf, REFERENCE_BIPS);
- }
-
- public double slf4jMessageFormatter_OneArg(long len) {
- long start = System.nanoTime();
- for (int i = 0; i < len; i++) {
- final FormattingTuple tp = MessageFormatter.format("This is some rather short message {} ", i1);
- tp.getMessage();
- tp.getArgArray();
- tp.getThrowable();
-
- MessageFormatter.format("This is some rather short message {} ", i1);
- }
- long end = System.nanoTime();
- return (end - start) / (1000 * 1000.0);
- }
-
- public double slf4jMessageFormatter_TwoArg(long len) {
- long start = System.nanoTime();
- for (int i = 0; i < len; i++) {
- final FormattingTuple tp = MessageFormatter.format("This is some {} short message {} ", i1, i2);
- tp.getMessage();
- tp.getArgArray();
- tp.getThrowable();
- }
- long end = System.nanoTime();
- return (end - start) / (1000 * 1000.0);
- }
-
- public double jdkMessageFormatter(long len) {
- @SuppressWarnings("unused")
- String s = "";
- s += ""; // keep compiler happy
- long start = System.currentTimeMillis();
- Object[] oa = new Object[] { i1 };
- for (int i = 0; i < len; i++) {
- s = MessageFormat.format("This is some rather short message {0}", oa);
- }
- long end = System.currentTimeMillis();
- return (1.0 * end - start);
- }
-
-}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
index 98ebaa78..4edd59f5 100755
--- a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
@@ -35,11 +35,11 @@ import static org.junit.Assert.*;
*/
public class MessageFormatterTest {
- Integer i1 = new Integer(1);
- Integer i2 = new Integer(2);
- Integer i3 = new Integer(3);
+ Integer i1 = Integer.valueOf(1);
+ Integer i2 = Integer.valueOf(2);
+ Integer i3 = Integer.valueOf(3);
Integer[] ia0 = new Integer[] { i1, i2, i3 };
- Integer[] ia1 = new Integer[] { new Integer(10), new Integer(20), new Integer(30) };
+ Integer[] ia1 = new Integer[] { Integer.valueOf(10), Integer.valueOf(20), Integer.valueOf(30) };
String result;
@@ -50,6 +50,15 @@ public class MessageFormatterTest {
}
@Test
+ public void testParamaterContainingAnAnchor() {
+ result = MessageFormatter.format("Value is {}.", "[{}]").getMessage();
+ assertEquals("Value is [{}].", result);
+
+ result = MessageFormatter.format("Values are {} and {}.", i1, "[{}]").getMessage();
+ assertEquals("Values are 1 and [{}].", result);
+ }
+
+ @Test
public void nullParametersShouldBeHandledWithoutBarfing() {
result = MessageFormatter.format("Value is {}.", null).getMessage();
assertEquals("Value is null.", result);
@@ -311,14 +320,20 @@ public class MessageFormatterTest {
assertTrue(Arrays.equals(iaWitness, ft.getArgArray()));
assertEquals(t, ft.getThrowable());
- ft = MessageFormatter.arrayFormat("Value {} is smaller than {} and {} -- {} .", ia);
- assertEquals("Value 1 is smaller than 2 and 3 -- " + t.toString() + " .", ft.getMessage());
- assertTrue(Arrays.equals(ia, ft.getArgArray()));
- assertNull(ft.getThrowable());
+ ft = MessageFormatter.arrayFormat("Value {} is smaller than {} and {}.", ia);
+ assertEquals("Value 1 is smaller than 2 and 3.", ft.getMessage());
+ assertTrue(Arrays.equals(iaWitness, ft.getArgArray()));
+ assertEquals(t, ft.getThrowable());
ft = MessageFormatter.arrayFormat("{}{}{}{}", ia);
- assertEquals("123" + t.toString(), ft.getMessage());
- assertTrue(Arrays.equals(ia, ft.getArgArray()));
- assertNull(ft.getThrowable());
+ assertEquals("123{}", ft.getMessage());
+ assertTrue(Arrays.equals(iaWitness, ft.getArgArray()));
+ assertEquals(t, ft.getThrowable());
+
+ ft = MessageFormatter.arrayFormat("1={}", new Object[] { i1 }, t);
+ assertEquals("1=1", ft.getMessage());
+ assertTrue(Arrays.equals(new Object[] { i1 }, ft.getArgArray()));
+ assertEquals(t, ft.getThrowable());
+
}
}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/StringPrintStream.java b/slf4j-api/src/test/java/org/slf4j/helpers/StringPrintStream.java
new file mode 100755
index 00000000..68a76257
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/StringPrintStream.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2004-2021 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j.helpers;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Copied from org.slfj.helpers.
+ *
+ * Currently it is not possible to use test-jar from tests running on the module-path.
+ *
+ * @author ceki
+ */
+public class StringPrintStream extends PrintStream {
+
+ public static final String LINE_SEP = System.getProperty("line.separator");
+ PrintStream other;
+ boolean duplicate = false;
+
+ public List<String> stringList = Collections.synchronizedList(new ArrayList<>());
+
+ public StringPrintStream(PrintStream ps, boolean duplicate) {
+ super(ps);
+ other = ps;
+ this.duplicate = duplicate;
+ }
+
+ public StringPrintStream(PrintStream ps) {
+ this(ps, false);
+ }
+
+ public void print(String s) {
+ if (duplicate)
+ other.print(s);
+ stringList.add(s);
+ }
+
+ public void println(String s) {
+ if (duplicate)
+ other.println(s);
+ stringList.add(s);
+ }
+
+ public void println(Object o) {
+ if (duplicate)
+ other.println(o);
+ stringList.add(o.toString());
+ }
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java
index 210252f3..f82c4f5d 100644
--- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java
@@ -24,56 +24,84 @@
*/
package org.slf4j.helpers;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-import junit.framework.TestCase;
+import org.junit.Test;
import org.slf4j.Logger;
+import org.slf4j.event.EventRecordingLogger;
/**
* @author Chetan Mehrotra
+ * @author Ceki Gülcü
*/
-public class SubstitutableLoggerTest extends TestCase {
- private static final Set<String> EXCLUDED_METHODS = new HashSet<String>(Arrays.asList("getName"));
+public class SubstitutableLoggerTest {
+
+ // NOTE: previous implementations of this class performed a handcrafted conversion of
+ // a method to a string. In this implementation we just invoke method.toString().
+
+ // WARNING: if you need to add an excluded method to have tests pass, ask yourself whether you
+ // forgot to implement the said method with delegation in SubstituteLogger. You probably did.
+ private static final Set<String> EXCLUDED_METHODS = new HashSet<>(
+ Arrays.asList("getName"));
- public void testDelegate() throws Exception {
- SubstituteLogger log = new SubstituteLogger("foo");
- assertTrue(log.delegate() instanceof NOPLogger);
+
+ /**
+ * Test that all SubstituteLogger methods invoke the delegate, except for explicitly excluded methods.
+ */
+ @Test
+ public void delegateIsInvokedTest() throws Exception {
+ SubstituteLogger substituteLogger = new SubstituteLogger("foo", null, false);
+ assertTrue(substituteLogger.delegate() instanceof EventRecordingLogger);
Set<String> expectedMethodSignatures = determineMethodSignatures(Logger.class);
- LoggerInvocationHandler ih = new LoggerInvocationHandler();
- Logger proxyLogger = (Logger) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Logger.class }, ih);
- log.setDelegate(proxyLogger);
+ LoggerInvocationHandler loggerInvocationHandler = new LoggerInvocationHandler();
+ Logger proxyLogger = (Logger) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Logger.class }, loggerInvocationHandler);
+ substituteLogger.setDelegate(proxyLogger);
- invokeMethods(log);
+ invokeAllMethodsOf(substituteLogger);
// Assert that all methods are delegated
- expectedMethodSignatures.removeAll(ih.getInvokedMethodSignatures());
+ expectedMethodSignatures.removeAll(loggerInvocationHandler.getInvokedMethodSignatures());
if (!expectedMethodSignatures.isEmpty()) {
fail("Following methods are not delegated " + expectedMethodSignatures.toString());
}
}
- private void invokeMethods(Logger proxyLogger) throws InvocationTargetException, IllegalAccessException {
+ private void invokeAllMethodsOf(Logger logger) throws InvocationTargetException, IllegalAccessException {
for (Method m : Logger.class.getDeclaredMethods()) {
if (!EXCLUDED_METHODS.contains(m.getName())) {
- m.invoke(proxyLogger, new Object[m.getParameterTypes().length]);
+ m.invoke(logger, new Object[m.getParameterTypes().length]);
}
}
}
+ private static Set<String> determineMethodSignatures(Class<Logger> loggerClass) {
+ Set<String> methodSignatures = new HashSet<>();
+ // Note: Class.getDeclaredMethods() does not include inherited methods
+ for (Method m : loggerClass.getDeclaredMethods()) {
+ if (!EXCLUDED_METHODS.contains(m.getName())) {
+ methodSignatures.add(m.toString());
+ }
+ }
+ return methodSignatures;
+ }
+
+
+ // implements InvocationHandler
private class LoggerInvocationHandler implements InvocationHandler {
- private final Set<String> invokedMethodSignatures = new HashSet<String>();
+ private final Set<String> invokedMethodSignatures = new HashSet<>();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- invokedMethodSignatures.add(getMethodSignature(method));
+ invokedMethodSignatures.add(method.toString());
if (method.getName().startsWith("is")) {
return true;
}
@@ -84,23 +112,4 @@ public class SubstitutableLoggerTest extends TestCase {
return invokedMethodSignatures;
}
}
-
- private static Set<String> determineMethodSignatures(Class<Logger> loggerClass) {
- Set<String> methodSignatures = new HashSet<String>();
- for (Method m : loggerClass.getDeclaredMethods()) {
- if (!EXCLUDED_METHODS.contains(m.getName())) {
- methodSignatures.add(getMethodSignature(m));
- }
- }
- return methodSignatures;
- }
-
- private static String getMethodSignature(Method m) {
- List<String> result = new ArrayList<String>();
- result.add(m.getName());
- for (Class<?> clazz : m.getParameterTypes()) {
- result.add(clazz.getSimpleName());
- }
- return result.toString();
- }
}
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java
index 370fc14b..a836f86b 100755
--- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java
@@ -24,16 +24,21 @@
*/
package org.slf4j.helpers;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
import org.slf4j.Logger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
-public class SubstituteLoggerFactoryTest extends TestCase {
- private SubstituteLoggerFactory factory = new SubstituteLoggerFactory();
+public class SubstituteLoggerFactoryTest {
+ private final SubstituteLoggerFactory factory = new SubstituteLoggerFactory();
+ @Test
public void testFactory() {
Logger log = factory.getLogger("foo");
assertNotNull(log);
@@ -42,23 +47,25 @@ public class SubstituteLoggerFactoryTest extends TestCase {
assertTrue("Loggers with same name must be same", log == log2);
}
+ @Test
public void testLoggerNameList() {
factory.getLogger("foo1");
factory.getLogger("foo2");
- Set<String> expectedNames = new HashSet<String>(Arrays.asList("foo1", "foo2"));
- Set<String> actualNames = new HashSet<String>(factory.getLoggerNames());
+ Set<String> expectedNames = new HashSet<>(Arrays.asList("foo1", "foo2"));
+ Set<String> actualNames = new HashSet<>(factory.getLoggerNames());
assertEquals(expectedNames, actualNames);
}
+ @Test
public void testLoggers() {
factory.getLogger("foo1");
factory.getLogger("foo2");
- Set<String> expectedNames = new HashSet<String>(Arrays.asList("foo1", "foo2"));
+ Set<String> expectedNames = new HashSet<>(Arrays.asList("foo1", "foo2"));
- Set<String> actualNames = new HashSet<String>();
+ Set<String> actualNames = new HashSet<>();
for (SubstituteLogger slog : factory.getLoggers()) {
actualNames.add(slog.getName());
}
diff --git a/slf4j-api/src/test/java/org/slf4j/rule/BlaTest.java b/slf4j-api/src/test/java/org/slf4j/rule/BlaTest.java
new file mode 100755
index 00000000..259d063a
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/rule/BlaTest.java
@@ -0,0 +1,38 @@
+package org.slf4j.rule;
+
+import static org.junit.Assert.fail;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+@Ignore // this test has intentional fails
+public class BlaTest {
+
+ @Rule
+ public RunInNewThreadRule runInThread = new RunInNewThreadRule();
+
+ @Test
+ public void aTest() {
+ System.out.println("running aTest in "+ Thread.currentThread().getName());
+ }
+
+ @RunInNewThread
+ @Test
+ public void bTest() {
+ System.out.println("running bTest in "+ Thread.currentThread().getName());
+ }
+
+ @RunInNewThread(timeout = 2000L)
+ @Test
+ public void cTest() {
+ System.out.println("running cTest in "+ Thread.currentThread().getName());
+ }
+ @RunInNewThread()
+ @Test
+ public void dTest() {
+ System.out.println("running dTest in "+ Thread.currentThread().getName());
+ fail();
+ }
+}
+
diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/BubbleSort.java b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThread.java
index e8f7bcfc..1bf5944f 100644..100755
--- a/slf4j-api/src/test/java/org/slf4j/helpers/BubbleSort.java
+++ b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThread.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2004-2011 QOS.ch
+ * Copyright (c) 2021 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -22,30 +22,18 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
-package org.slf4j.helpers;
-/**
- * This class is used internally by BogoPerf, hence the package private
- * (default) access.
- *
- * @author Ceki
- */
-class BubbleSort {
+package org.slf4j.rule;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
- static void sort(int[] a) {
- int len = a.length;
- for (int i = 0; i < len - 1; i++) {
- for (int j = 0; j < len - 1 - i; j++) {
- if (a[j] > a[j + 1]) {
- swap(a, j, j + 1);
- }
- }
- }
- }
- static void swap(int[] a, int i, int j) {
- int t = a[i];
- a[i] = a[j];
- a[j] = t;
- }
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface RunInNewThread {
+ static final long DEFAULT_TIMEOUT = 1000L;
+ public long timeout() default DEFAULT_TIMEOUT;
}
diff --git a/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadRule.java b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadRule.java
new file mode 100755
index 00000000..3945144f
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadRule.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2021 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+package org.slf4j.rule;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+// This class has been inspired by the article "A JUnit Rule to Run a Test in Its Own Thread"
+// published by Frank Appel, author of the book "Testing with JUnit" published by Packt publishing.
+//
+// See also
+// https://www.codeaffine.com/2014/07/21/a-junit-rule-to-run-a-test-in-its-own-thread/
+
+public class RunInNewThreadRule implements TestRule {
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ RunInNewThread desiredAnnotaton = description.getAnnotation(RunInNewThread.class);
+
+ if (desiredAnnotaton == null) {
+ System.out.println("test "+ description.getMethodName() +" not annotated");
+ return base;
+ } else {
+ long timeout = desiredAnnotaton.timeout();
+ System.out.println("running "+ description.getMethodName() +" in separate tjread");
+ return new RunInNewThreadStatement(base, timeout);
+ }
+ }
+
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadStatement.java b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadStatement.java
new file mode 100755
index 00000000..2b8869e5
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/rule/RunInNewThreadStatement.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2021 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j.rule;
+
+import org.junit.runners.model.Statement;
+
+//This class has been inspired by the article "A JUnit Rule to Run a Test in Its Own Thread"
+//published by Frank Appel, author of the book "Testing with JUnit" published by Packt publishing.
+//
+//See also
+//https://www.codeaffine.com/2014/07/21/a-junit-rule-to-run-a-test-in-its-own-thread/
+
+public class RunInNewThreadStatement extends Statement implements Runnable {
+
+ final Statement base;
+ final long timeout;
+ Throwable throwable;
+
+ RunInNewThreadStatement(Statement base, long timeout) {
+ this.base = base;
+ this.timeout = timeout;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ Thread thread = new Thread(this);
+ thread.start();
+ System.out.println("Timeout is "+timeout);
+ thread.join(timeout);
+
+ if (throwable != null) {
+ throw throwable;
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ base.evaluate();
+ } catch (Throwable e) {
+ this.throwable = e;
+ }
+ }
+
+
+}
diff --git a/slf4j-api/src/test/java/org/slf4j/testHarness/MultithreadedInitializationTest.java b/slf4j-api/src/test/java/org/slf4j/testHarness/MultithreadedInitializationTest.java
new file mode 100644
index 00000000..c534bad1
--- /dev/null
+++ b/slf4j-api/src/test/java/org/slf4j/testHarness/MultithreadedInitializationTest.java
@@ -0,0 +1,79 @@
+package org.slf4j.testHarness;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerAccessingThread;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.EventRecordingLogger;
+import org.slf4j.helpers.SubstituteLogger;
+
+abstract public class MultithreadedInitializationTest {
+ final protected static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
+
+ private final List<Logger> createdLoggers = Collections.synchronizedList(new ArrayList<>());
+
+ final protected AtomicLong eventCount = new AtomicLong(0);
+ final private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
+
+ @Test
+ public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException {
+ @SuppressWarnings("unused")
+ LoggerAccessingThread[] accessors = harness();
+
+ Logger logger = LoggerFactory.getLogger(getClass().getName());
+ logger.info("hello");
+ eventCount.getAndIncrement();
+
+ assertAllSubstLoggersAreFixed();
+ long recordedEventCount = getRecordedEventCount();
+ int LENIENCY_COUNT = 30;
+
+ long expectedEventCount = eventCount.get() + extraLogEvents();
+
+ assertTrue(expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount);
+ assertTrue(expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < recordedEventCount + LENIENCY_COUNT);
+ }
+
+ abstract protected long getRecordedEventCount();
+
+ protected int extraLogEvents() {
+ return 0;
+ }
+
+ private void assertAllSubstLoggersAreFixed() {
+ for (Logger logger : createdLoggers) {
+ if (logger instanceof SubstituteLogger) {
+ SubstituteLogger substLogger = (SubstituteLogger) logger;
+ if (substLogger.delegate() instanceof EventRecordingLogger)
+ fail("substLogger " + substLogger.getName() + " has a delegate of type EventRecodingLogger");
+ }
+ }
+ }
+
+ private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
+ LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ threads[i] = new LoggerAccessingThread(barrier, createdLoggers, i, eventCount);
+ threads[i].start();
+ }
+
+ // trigger barrier
+ barrier.await();
+
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ threads[i].join();
+ }
+
+ return threads;
+ }
+}