001package org.slf4j.helpers;
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.Random;
010import java.util.concurrent.BrokenBarrierException;
011import java.util.concurrent.CyclicBarrier;
012import java.util.concurrent.atomic.AtomicLong;
013
014import org.junit.Test;
015import org.slf4j.Logger;
016import org.slf4j.LoggerAccessingThread;
017import org.slf4j.LoggerFactory;
018import org.slf4j.event.EventRecodingLogger;
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<Logger>());
024
025    final private AtomicLong eventCount = new AtomicLong(0);
026    final private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
027
028    int diff = new Random().nextInt(10000);
029
030    @Test
031    public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException {
032        @SuppressWarnings("unused")
033        LoggerAccessingThread[] accessors = harness();
034
035        Logger logger = LoggerFactory.getLogger(getClass().getName());
036        logger.info("hello");
037        eventCount.getAndIncrement();
038
039        assertAllSubstLoggersAreFixed();
040        long recordedEventCount = getRecordedEventCount();
041        int LENIENCY_COUNT = 16;
042
043        long expectedEventCount = eventCount.get() + extraLogEvents();
044
045        assertTrue(expectedEventCount + " >= " + recordedEventCount, expectedEventCount >= recordedEventCount);
046        assertTrue(expectedEventCount + " < " + recordedEventCount + "+" + LENIENCY_COUNT, expectedEventCount < recordedEventCount + LENIENCY_COUNT);
047    }
048
049    abstract protected long getRecordedEventCount();
050
051    protected int extraLogEvents() {
052        return 0;
053    }
054
055    private void assertAllSubstLoggersAreFixed() {
056        for (Logger logger : createdLoggers) {
057            if (logger instanceof SubstituteLogger) {
058                SubstituteLogger substLogger = (SubstituteLogger) logger;
059                if (substLogger.delegate() instanceof EventRecodingLogger)
060                    fail("substLogger " + substLogger.getName() + " has a delegate of type EventRecodingLogger");
061            }
062        }
063    }
064
065    private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
066        LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
067        for (int i = 0; i < THREAD_COUNT; i++) {
068            threads[i] = new LoggerAccessingThread(barrier, createdLoggers, i, eventCount);
069            threads[i].start();
070        }
071
072        // trigger barrier
073        barrier.await();
074
075        for (int i = 0; i < THREAD_COUNT; i++) {
076            threads[i].join();
077        }
078
079        return threads;
080    }
081}