001/** 002 * Copyright (c) 2004-2021 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.simple.multiThreadedExecution; 026 027import java.io.PrintStream; 028 029import org.junit.After; 030import org.junit.Before; 031import org.junit.Test; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035/** 036 * Tests that output in multi-threaded environments is not mingled. 037 * 038 * See also https://jira.qos.ch/browse/SLF4J-515 039 */ 040public class MultithereadedExecutionTest { 041 042 private static final int THREAD_COUNT = 2; 043 private final Thread[] threads = new Thread[THREAD_COUNT]; 044 045 private static final long TEST_DURATION_IN_MILLIS = 100; 046 047 private final PrintStream oldOut = System.out; 048 StateCheckingPrintStream scps = new StateCheckingPrintStream(oldOut); 049 050 volatile boolean signal = false; 051 052 @Before 053 public void setup() { 054 System.setErr(scps); 055 // System.setProperty(SimpleLogger.LOG_FILE_KEY, "System.err"); 056 // LoggerFactoryFriend.reset(); 057 } 058 059 @After 060 public void tearDown() throws Exception { 061 // LoggerFactoryFriend.reset(); 062 // System.clearProperty(SimpleLogger.LOG_FILE_KEY); 063 System.setErr(oldOut); 064 } 065 066 @Test 067 public void test() throws Throwable { 068 WithException withException = new WithException(); 069 Other other = new Other(); 070 threads[0] = new Thread(withException); 071 threads[1] = new Thread(other); 072 threads[0].start(); 073 threads[1].start(); 074 Thread.sleep(TEST_DURATION_IN_MILLIS); 075 signal = true; 076 threads[0].join(); 077 threads[1].join(); 078 079 if (withException.throwable != null) { 080 throw withException.throwable; 081 } 082 083 if (other.throwable != null) { 084 throw other.throwable; 085 } 086 087 } 088 089 class WithException implements Runnable { 090 091 volatile Throwable throwable; 092 Logger logger = LoggerFactory.getLogger(WithException.class); 093 094 @Override 095 public void run() { // TODO Auto-generated method stub 096 int i = 0; 097 098 while (!signal) { 099 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}