001/**
002 * Copyright (c) 2004-2016 QOS.ch
003 * All rights reserved.
004 *
005 * Permission is hereby granted, free  of charge, to any person obtaining
006 * a  copy  of this  software  and  associated  documentation files  (the
007 * "Software"), to  deal in  the Software without  restriction, including
008 * without limitation  the rights to  use, copy, modify,  merge, publish,
009 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
010 * permit persons to whom the Software  is furnished to do so, subject to
011 * the following conditions:
012 *
013 * The  above  copyright  notice  and  this permission  notice  shall  be
014 * included in all copies or substantial portions of the Software.
015 *
016 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
017 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
018 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
021 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023 *
024 */
025package org.slf4j.nop;
026
027import static org.junit.Assert.assertEquals;
028
029import java.io.PrintStream;
030import java.util.ArrayList;
031import java.util.List;
032import java.util.Random;
033import java.util.concurrent.BrokenBarrierException;
034import java.util.concurrent.CyclicBarrier;
035import java.util.concurrent.atomic.AtomicLong;
036
037import org.junit.After;
038import org.junit.Before;
039import org.junit.Test;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042import org.slf4j.LoggerFactoryFriend;
043
044public class MultithreadedInitializationTest {
045
046    final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2;
047
048    private static final AtomicLong EVENT_COUNT = new AtomicLong(0);
049
050    final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
051
052    int diff = new Random().nextInt(10000);
053    String loggerName = "org.slf4j.impl.MultithreadedInitializationTest";
054    private final PrintStream oldErr = System.err;
055    StringPrintStream sps = new StringPrintStream(oldErr);
056
057    @Before
058    public void setup() {
059        LoggerFactoryFriend.reset();
060        System.setErr(sps);
061    }
062
063    @After
064    public void tearDown() throws Exception {
065        LoggerFactoryFriend.reset();
066        System.setErr(oldErr);
067    }
068
069    @Test
070    public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException {
071        System.out.println("THREAD_COUNT=" + THREAD_COUNT);
072        LoggerAccessingThread[] accessors = harness();
073
074        for (LoggerAccessingThread accessor : accessors) {
075            EVENT_COUNT.getAndIncrement();
076            accessor.logger.info("post harness");
077        }
078
079        Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff);
080        logger.info("hello");
081        EVENT_COUNT.getAndIncrement();
082
083        assertEquals(0, sps.stringList.size());
084    }
085
086    private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException {
087        LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT];
088        final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1);
089        for (int i = 0; i < THREAD_COUNT; i++) {
090            threads[i] = new LoggerAccessingThread(barrier, i);
091            threads[i].start();
092        }
093
094        barrier.await();
095        for (int i = 0; i < THREAD_COUNT; i++) {
096            threads[i].join();
097        }
098        return threads;
099    }
100
101    static class LoggerAccessingThread extends Thread {
102        final CyclicBarrier barrier;
103        Logger logger;
104        int count;
105
106        LoggerAccessingThread(CyclicBarrier barrier, int count) {
107            this.barrier = barrier;
108            this.count = count;
109        }
110
111        public void run() {
112            try {
113                barrier.await();
114            } catch (Exception e) {
115                e.printStackTrace();
116            }
117            logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count);
118            logger.info("in run method");
119            EVENT_COUNT.getAndIncrement();
120        }
121    };
122
123    public static class StringPrintStream extends PrintStream {
124
125        public static final String LINE_SEP = System.getProperty("line.separator");
126        PrintStream other;
127        List<String> stringList = new ArrayList<>();
128
129        public StringPrintStream(PrintStream ps) {
130            super(ps);
131            other = ps;
132        }
133
134        public void print(String s) {
135            other.print(s);
136            stringList.add(s);
137        }
138
139        public void println(String s) {
140            other.println(s);
141            stringList.add(s);
142        }
143
144        public void println(Object o) {
145            other.println(o);
146            stringList.add(o.toString());
147        }
148    };
149
150}