diff options
Diffstat (limited to 'slf4j-api/src/test/java/org')
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ülcü * @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ülcü - * - */ -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; + } +} |