package de.is24.util.monitoring;
import de.is24.util.monitoring.jmx.SimpleJmxAppmon4jNamingStrategy;
import de.is24.util.monitoring.keyhandler.DefaultKeyEscaper;
import de.is24.util.monitoring.keyhandler.KeyHandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.NumberFormat;
import java.util.Random;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class ConcurrencyTest {
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance();
private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrencyTest.class);
static {
NUMBER_FORMAT.setGroupingUsed(true);
NUMBER_FORMAT.setMinimumFractionDigits(3);
NUMBER_FORMAT.setMaximumFractionDigits(3);
}
private static final int THREADS = 10, RUNS = 10, LOOPS = 10;
private ThreadPoolExecutor executor;
private Job observerJob, timerJob, initJob;
private Random rnd;
private AtomicLong exceptions;
private AtomicLong successfullInits;
private AtomicLong failedInits;
@Before
public void setUp() throws Exception {
this.observerJob = new ObserverJob();
this.timerJob = new TimerJob();
this.initJob = new InitJob();
this.rnd = new Random();
this.exceptions = new AtomicLong();
this.successfullInits = new AtomicLong();
this.failedInits = new AtomicLong();
}
@After
public void tearDown() {
TestingInApplicationMonitor.resetInstanceForTesting();
}
@Test
public void testConcurrency() throws InterruptedException {
for (int i = 0; i < LOOPS; i++) {
LOGGER.info("######################### run " + i + " ###########################");
LOGGER.info("######################### run " + i + " ###########################");
LOGGER.info("######################### run " + i + " ###########################");
LOGGER.info("######################### run " + i + " ###########################");
TestingInApplicationMonitor.resetInstanceForTesting();
assertFalse(JMXTestHelper.checkInApplicationMonitorJMXBeanRegistered());
createExecutor(THREADS);
executeJobs(timerJob, observerJob, initJob);
assertTrue(JMXTestHelper.checkInApplicationMonitorJMXBeanRegistered());
}
assertThat(exceptions.get(), is(0L));
assertThat(successfullInits.get(), is((long) LOOPS));
}
private void createExecutor(int threads) {
this.executor = new ScheduledThreadPoolExecutor(threads);
this.executor.setMaximumPoolSize(threads);
}
private void executeJobs(Runnable... jobs) throws InterruptedException {
for (int i = 0; i < RUNS; i++) {
for (Runnable job : jobs) {
executor.execute(job);
}
}
executor.shutdown();
executor.awaitTermination(100, TimeUnit.SECONDS);
}
private abstract class Job implements Runnable {
public void run() {
try {
doJob();
} catch (Exception e) {
LOGGER.info("oops", e);
exceptions.incrementAndGet();
}
}
protected abstract void doJob();
}
private class ObserverJob extends Job {
@Override
protected void doJob() {
InApplicationMonitor.getInstance().getCorePlugin().addReportableObserver(new ReportableObserver() {
@Override
public void addNewReportable(Reportable reportable) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
});
}
}
private class TimerJob extends Job {
@Override
protected void doJob() {
String key = "t" + rnd.nextInt(100000);
InApplicationMonitor.getInstance().addTimerMeasurement(key, 1);
}
}
private class InitJob extends Job {
@Override
protected void doJob() {
KeyHandler keyEscaper = new DefaultKeyEscaper();
try {
CorePlugin corePlugin = new CorePlugin(new SimpleJmxAppmon4jNamingStrategy("is24"), keyEscaper);
InApplicationMonitor.initInstance(corePlugin, keyEscaper);
successfullInits.incrementAndGet();
} catch (IllegalStateException e) {
failedInits.incrementAndGet();
}
}
}
}