    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}