1 /**
2 * Copyright (c) 2004-2021 QOS.ch
3 * All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25 package org.slf4j.simple.multiThreadedExecution;
26
27 import java.io.PrintStream;
28
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36 * Tests that output in multi-threaded environments is not mingled.
37 *
38 * See also https://jira.qos.ch/browse/SLF4J-515
39 */
40 public class MultithereadedExecutionTest {
41
42 private static final int THREAD_COUNT = 2;
43 private final Thread[] threads = new Thread[THREAD_COUNT];
44
45 private static final long TEST_DURATION_IN_MILLIS = 100;
46
47 private final PrintStream oldOut = System.out;
48 StateCheckingPrintStream scps = new StateCheckingPrintStream(oldOut);
49
50 volatile boolean signal = false;
51
52 @Before
53 public void setup() {
54 System.setErr(scps);
55 // System.setProperty(SimpleLogger.LOG_FILE_KEY, "System.err");
56 // LoggerFactoryFriend.reset();
57 }
58
59 @After
60 public void tearDown() throws Exception {
61 // LoggerFactoryFriend.reset();
62 // System.clearProperty(SimpleLogger.LOG_FILE_KEY);
63 System.setErr(oldOut);
64 }
65
66 @Test
67 public void test() throws Throwable {
68 WithException withException = new WithException();
69 Other other = new Other();
70 threads[0] = new Thread(withException);
71 threads[1] = new Thread(other);
72 threads[0].start();
73 threads[1].start();
74 Thread.sleep(TEST_DURATION_IN_MILLIS);
75 signal = true;
76 threads[0].join();
77 threads[1].join();
78
79 if (withException.throwable != null) {
80 throw withException.throwable;
81 }
82
83 if (other.throwable != null) {
84 throw other.throwable;
85 }
86
87 }
88
89 class WithException implements Runnable {
90
91 volatile Throwable throwable;
92 Logger logger = LoggerFactory.getLogger(WithException.class);
93
94 @Override
95 public void run() { // TODO Auto-generated method stub
96 int i = 0;
97
98 while (!signal) {
99 try {
100 logger.info("Hello {}", i, new Throwable("i=" + i));
101 i++;
102 } catch (Throwable t) {
103 throwable = t;
104 MultithereadedExecutionTest.this.signal = true;
105 return;
106 }
107 }
108
109 }
110 }
111
112 class Other implements Runnable {
113 volatile Throwable throwable;
114 Logger logger = LoggerFactory.getLogger(Other.class);
115
116 @Override
117 public void run() {
118 int i = 0;
119 while (!signal) {
120 try {
121 logger.info("Other {}", i++);
122 } catch (Throwable t) {
123 throwable = t;
124 MultithereadedExecutionTest.this.signal = true;
125 return;
126 }
127 }
128 }
129 }
130
131 }