/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.MDC; import org.testng.annotations.Test; import com.opengamma.util.test.TestGroup; /** * Tests that MdcAwareThreadPoolExecutorTest correctly segregates MDC * information from different threads. Prints output to standard out * as it's otherwise difficult to check that everything is created by * the expected thread. */ @Test(groups = TestGroup.UNIT) public class MdcAwareThreadPoolExecutorTest { private ExecutorService createMdcAwareService(int threads) { return new MdcAwareThreadPoolExecutor(threads, threads, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new NamedThreadPoolFactory("mdcAware")); } private ExecutorService createStandardService(int threads) { return new ThreadPoolExecutor(threads, threads, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new NamedThreadPoolFactory("standard")); } @Test(enabled = false) public void testMdcIdLostWhenUsingStandardPool() throws InterruptedException { // This is the case we want our new code to cope with. i.e. a thread pool losing // the MDC information. Unfortunately, the test below fails as the MDC data // *is* being magically passed across the threads final ExecutorService service = createStandardService(3); final AtomicInteger checkCount = new AtomicInteger(0); createStarterThreads(3, service, checkCount, false); // Wait for the threads to complete Thread.sleep(200); assertThat(checkCount.get(), is(3)); } @Test public void testMdcIdLoggedForSingleThread() throws InterruptedException { final ExecutorService service = createMdcAwareService(1); final AtomicInteger checkCount = new AtomicInteger(0); createStarterThreads(1, service, checkCount, true); Thread.sleep(200); assertThat(checkCount.get(), is(1)); } @Test public void testCorrectIdLoggedForMultipleThreads() throws InterruptedException { final ExecutorService service = createMdcAwareService(3); final AtomicInteger checkCount = new AtomicInteger(0); createStarterThreads(3, service, checkCount, true); Thread.sleep(200); assertThat(checkCount.get(), is(3)); } @Test public void testCorrectIdLoggedForMultipleThreadsWithPoolReuse() throws InterruptedException { final ExecutorService service = createMdcAwareService(3); final AtomicInteger checkCount = new AtomicInteger(0); createStarterThreads(3, service, checkCount, true); Thread.sleep(200); createStarterThreads(3, service, checkCount, true); Thread.sleep(200); createStarterThreads(3, service, checkCount, true); Thread.sleep(200); createStarterThreads(3, service, checkCount, true); Thread.sleep(200); assertThat(checkCount.get(), is(12)); } private void createStarterThreads(int qty, final ExecutorService service, final AtomicInteger checkCount, final boolean mdcPropagationExpected) { Set<Thread> threads = new HashSet<>(); for (int i = 0; i < qty; i++) { final int value = i; threads.add(new Thread(new Runnable() { @Override public void run() { Map<String, String> contextMap = new HashMap<>(); contextMap.put("some_key" + value, "somevalue"); contextMap.put("name", Thread.currentThread().getName()); System.out.println("Putting MDC values: " + contextMap); MDC.setContextMap(contextMap); Map<String, String> expectedContext = mdcPropagationExpected ? contextMap : null; service.execute(createCheckJob(expectedContext, checkCount)); } }, "starter" + i)); } System.out.println("Threads created - MDC contains: " + MDC.getCopyOfContextMap()); for (Thread thread : threads) { thread.start(); } System.out.println("Threads started - MDC contains: " + MDC.getCopyOfContextMap()); } private Runnable createCheckJob(final Map<String, String> expectedContext, final AtomicInteger checkCount) { System.out.println("Creating check job on thread - " + Thread.currentThread().getName() + " MDC: " + MDC.getCopyOfContextMap()); return new Runnable() { @Override public void run() { @SuppressWarnings("unchecked") Map<String, String> mdc = MDC.getCopyOfContextMap(); System.out.println("Running on thread-" + Thread.currentThread().getName() + " => " + mdc) ; try { assertThat(mdc, is(expectedContext)); checkCount.incrementAndGet(); } catch (Throwable e) { System.out.println(e); } } }; } }