/*
* Copyright 2012 Jason Miller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jj.logging;
import static java.util.concurrent.TimeUnit.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.text.DecimalFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import jj.execution.MockTaskRunner;
import jj.util.RandomHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.slf4j.MDC;
/**
* @author jason
*
*/
@RunWith(MockitoJUnitRunner.class)
public class SystemLoggerTest {
MockTaskRunner taskRunner;
@Mock Loggers loggers;
SystemLogger sl;
Thread publishLoop;
@Before
public void before() throws Exception {
taskRunner = new MockTaskRunner();
sl = new SystemLogger(taskRunner, loggers);
sl.on(null); // it ignores the event
publishLoop = taskRunner.runFirstTaskInDaemon();
}
@After
public void after() {
publishLoop.interrupt();
}
CountDownLatch latch;
String threadName;
class HelperEvent1 extends LoggedEvent {
@Override
public void describeTo(Logger logger) {
SystemLoggerTest.this.threadName = MDC.get(SystemLogger.THREAD_NAME);
latch.countDown();
}
}
@Test
public void test() throws Exception {
latch = new CountDownLatch(1);
String name = "name 1";
Thread.currentThread().setName(name);
sl.on(new HelperEvent1());
assertTrue(latch.await(400, MILLISECONDS));
assertThat(threadName, is(name));
}
class HelperEvent2 extends LoggedEvent {
@Override
public void describeTo(Logger logger) {
count.getAndIncrement();
}
}
//@Test
// this doesn't run well as part of the build, i suspect it
// gets shut down too early
public void testUnderLoad() throws Exception {
// warm up runs
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
// System.gc();
// Thread.sleep(150);
// for (int i = 0; i < 5; ++i) {
// loadTest(4, 10000, 10001, 3, 15);
// loadTest(4, 10000, 10001, 3, 15);
// loadTest(4, 10000, 10001, 3, 15);
// loadTest(4, 10000, 10001, 3, 15);
// loadTest(4, 10000, 10001, 3, 15);
// System.gc();
// Thread.sleep(150);
// }
// loadTest(18, 250000, 250001, 30, 100);
}
/*
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
loadTest(4, 7000, 7001, 3, 15);
loadTest(18, 250000, 250001, 30, 100);
run 1
++++++++++++++++++++++++++++++++++++
28000, 572, 637
118342936 in use
run 2
+++++++++++
28000, 175, 177
182894056 in use
run 3
++++++
28000, 96, 99
258203504 in use
run 4
+++++++
28000, 112, 114
322754616 in use
run 5
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4500000, 19565, 19909
2439246920 in use
*/
int run = 0;
final AtomicInteger count = new AtomicInteger();
final AtomicInteger expected = new AtomicInteger();
private void loadTest(final int threadTotal, final int lowerBound, final int upperBound, final int timeout, final int waitTime) throws Exception {
System.out.println("run " + ++run);
ExecutorService executor = Executors.newFixedThreadPool(threadTotal);
final HelperEvent2 helperEvent = new HelperEvent2();
long start = System.nanoTime();
long latchTime = 0;
try {
count.set(0);
expected.set(0);
latch = new CountDownLatch(threadTotal);
for (int i = 0; i < threadTotal; ++i) {
executor.submit(() -> {
int runs = RandomHelper.nextInt(lowerBound, upperBound);
expected.getAndAdd(runs);
for (int i1 = 0; i1 < runs; ++i1) {
sl.on(helperEvent);
}
latch.countDown();
});
}
assertTrue("timed out", latch.await(timeout, SECONDS));
latchTime = System.nanoTime();
int lastCount;
while ((lastCount = count.get()) != expected.get()) {
Thread.sleep(waitTime);
if(count.get() > lastCount) {
System.out.print("+");
} else {
throw new AssertionError("count froze at " + count + ", waiting for " + expected);
}
}
} finally {
long now = System.nanoTime();
System.out.println();
System.out.println(
"count = " +
count + ", time to populate = " +
MILLISECONDS.convert(latchTime - start, NANOSECONDS) + ", time to finish processing = " +
MILLISECONDS.convert(now - latchTime, NANOSECONDS)
);
String memory = DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
System.out.println(memory + " in use");
System.out.println();
executor.shutdownNow();
}
}
}