001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.net.server; 015 016import static org.junit.Assert.assertFalse; 017import static org.junit.Assert.assertNotNull; 018import static org.junit.Assert.assertSame; 019import static org.junit.Assert.assertTrue; 020 021import java.util.concurrent.Executor; 022import java.util.concurrent.ExecutorService; 023import java.util.concurrent.Executors; 024import java.util.concurrent.TimeUnit; 025import java.util.concurrent.locks.Condition; 026import java.util.concurrent.locks.Lock; 027import java.util.concurrent.locks.ReentrantLock; 028 029import org.junit.After; 030import org.junit.Before; 031import org.junit.Test; 032 033import ch.qos.logback.core.net.mock.MockContext; 034import ch.qos.logback.core.net.server.test.MockServerListener; 035 036public class ConcurrentServerRunnerTest { 037 038 private static final int DELAY = 10000; 039 private static final int SHORT_DELAY = 10; 040 041 private MockContext context = new MockContext(); 042 private MockServerListener<MockClient> listener = new MockServerListener<MockClient>(); 043 044 private ExecutorService executor = Executors.newCachedThreadPool(); 045 private InstrumentedConcurrentServerRunner runner = new InstrumentedConcurrentServerRunner(listener, executor); 046 047 @Before 048 public void setUp() throws Exception { 049 runner.setContext(context); 050 } 051 052 @After 053 public void tearDown() throws Exception { 054 executor.shutdownNow(); 055 assertTrue(executor.awaitTermination(DELAY, TimeUnit.MILLISECONDS)); 056 } 057 058 @Test 059 public void testStartStop() throws Exception { 060 assertFalse(runner.isRunning()); 061 executor.execute(runner); 062 assertTrue(runner.awaitRunState(true, DELAY)); 063 int retries = DELAY / SHORT_DELAY; 064 synchronized (listener) { 065 while (retries-- > 0 && listener.getWaiter() == null) { 066 listener.wait(SHORT_DELAY); 067 } 068 } 069 assertNotNull(listener.getWaiter()); 070 runner.stop(); 071 assertTrue(listener.isClosed()); 072 assertFalse(runner.awaitRunState(false, DELAY)); 073 } 074 075 @Test 076 public void testRunOneClient() throws Exception { 077 executor.execute(runner); 078 MockClient client = new MockClient(); 079 listener.addClient(client); 080 int retries = DELAY / SHORT_DELAY; 081 synchronized (client) { 082 while (retries-- > 0 && !client.isRunning()) { 083 client.wait(SHORT_DELAY); 084 } 085 } 086 assertTrue(runner.awaitRunState(true, DELAY)); 087 client.close(); 088 runner.stop(); 089 } 090 091 @Test 092 public void testRunManyClients() throws Exception { 093 executor.execute(runner); 094 int count = 10; 095 while (count-- > 0) { 096 MockClient client = new MockClient(); 097 listener.addClient(client); 098 int retries = DELAY / SHORT_DELAY; 099 synchronized (client) { 100 while (retries-- > 0 && !client.isRunning()) { 101 client.wait(SHORT_DELAY); 102 } 103 } 104 assertTrue(runner.awaitRunState(true, DELAY)); 105 } 106 runner.stop(); 107 } 108 109 @Test 110 public void testRunClientAndVisit() throws Exception { 111 executor.execute(runner); 112 MockClient client = new MockClient(); 113 listener.addClient(client); 114 int retries = DELAY / SHORT_DELAY; 115 synchronized (client) { 116 while (retries-- > 0 && !client.isRunning()) { 117 client.wait(SHORT_DELAY); 118 } 119 } 120 assertTrue(runner.awaitRunState(true, DELAY)); 121 MockClientVisitor visitor = new MockClientVisitor(); 122 runner.accept(visitor); 123 assertSame(client, visitor.getLastVisited()); 124 runner.stop(); 125 } 126 127 static class InstrumentedConcurrentServerRunner extends ConcurrentServerRunner<MockClient> { 128 129 private final Lock lock = new ReentrantLock(); 130 private final Condition runningCondition = lock.newCondition(); 131 132 public InstrumentedConcurrentServerRunner(ServerListener<MockClient> listener, Executor executor) { 133 super(listener, executor); 134 } 135 136 @Override 137 protected boolean configureClient(MockClient client) { 138 return true; 139 } 140 141 @Override 142 protected void setRunning(boolean running) { 143 lock.lock(); 144 try { 145 super.setRunning(running); 146 runningCondition.signalAll(); 147 } finally { 148 lock.unlock(); 149 } 150 } 151 152 public boolean awaitRunState(boolean state, long delay) throws InterruptedException { 153 lock.lock(); 154 try { 155 while (isRunning() != state) { 156 runningCondition.await(delay, TimeUnit.MILLISECONDS); 157 } 158 return isRunning(); 159 } finally { 160 lock.unlock(); 161 } 162 } 163 } 164 165}