001package org.slf4j.testHarness;
002
003import static org.junit.Assert.assertTrue;
004import static org.junit.Assert.fail;
005
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009import java.util.concurrent.BrokenBarrierException;
010import java.util.concurrent.CyclicBarrier;
011import java.util.concurrent.atomic.AtomicLong;
012
013import org.junit.Test;
014import org.slf4j.Logger;
015import org.slf4j.LoggerAccessingThread;
016import org.slf4j.LoggerFactory;
017import org.slf4j.event.EventRecodingLogger;
018import org.slf4j.helpers.SubstituteLogger;
019
020abstract public class MultithreadedInitializationTest {
021    final protected static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
022
023    private final List<Logger> createdLoggers = Collections.synchronizedList(new ArrayList<>());
024
025    final protected AtomicLong eventCount = new AtomicLong(0);
026    final private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
027
028    @Test
029    public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException {
030        @SuppressWarnings("unused")
031        LoggerAccessingThread[] accessors = harness();
032
033        Logger logger = LoggerFactory.getLogger(getClass().getName());
034        logger.info("hello");
035        eventCount.getAndIncrement();
036
037        assertAllSubstLoggersAreFixed();
038        long recordedEventCount = getRecordedEventCount();
039        int LENIENCY_COUNT = 21;
040
041        long expectedEventCount = eventCount.get() + extraLogEvents();
042
043        assertTrue(expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount);
044        assertTrue(expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < recordedEventCount + LENIENCY_COUNT);
045    }
046
047    abstract protected long getRecordedEventCount();
048
049    protected int extraLogEvents() {
050        return 0;
051    }
052
053    private void assertAllSubstLoggersAreFixed() {
054        for (Logger logger : createdLoggers) {
055            if (logger instanceof SubstituteLogger) {
056                SubstituteLogger substLogger = (SubstituteLogger) logger;
057                if (substLogger.delegate() instanceof EventRecodingLogger)
058                    fail("substLogger " + substLogger.getName() + " has a delegate of type EventRecodingLogger");
059            }
060        }
061    }
062
063    private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
064        LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
065        for (int i = 0; i < THREAD_COUNT; i++) {
066            threads[i] = new LoggerAccessingThread(barrier, createdLoggers, i, eventCount);
067            threads[i].start();
068        }
069
070        // trigger barrier
071        barrier.await();
072
073        for (int i = 0; i < THREAD_COUNT; i++) {
074            threads[i].join();
075        }
076
077        return threads;
078    }
079}