summaryrefslogtreecommitdiffstats
path: root/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java')
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java b/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
new file mode 100644
index 00000000000..95ce73b4414
--- /dev/null
+++ b/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
@@ -0,0 +1,134 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.handler;
+
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import com.yahoo.container.protect.ProcessTerminator;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.yahoo.concurrent.Receiver;
+import com.yahoo.concurrent.Receiver.MessageState;
+import com.yahoo.collections.Tuple2;
+import com.yahoo.jdisc.Metric;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Check threadpool provider accepts tasks and shuts down properly.
+ *
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+public class ThreadPoolProviderTestCase {
+
+ @Test
+ public final void testThreadPoolProvider() throws InterruptedException {
+ ThreadpoolConfig config = new ThreadpoolConfig(new ThreadpoolConfig.Builder().maxthreads(1));
+ ThreadPoolProvider provider = new ThreadPoolProvider(config, Mockito.mock(Metric.class));
+ Executor exec = provider.get();
+ Tuple2<MessageState, Boolean> reply;
+ FlipIt command = new FlipIt();
+ for (boolean done = false; !done;) {
+ try {
+ exec.execute(command);
+ done = true;
+ } catch (RejectedExecutionException e) {
+ // just try again
+ }
+ }
+ reply = command.didItRun.get(5 * 60 * 1000);
+ if (reply.first != MessageState.VALID) {
+ fail("Executor task probably timed out, five minutes should be enough to flip a boolean.");
+ }
+ if (reply.second != Boolean.TRUE) {
+ fail("Executor task seemed to run, but did not get correct value.");
+ }
+ provider.deconstruct();
+ command = new FlipIt();
+ try {
+ exec.execute(command);
+ } catch (final RejectedExecutionException e) {
+ // this is what should happen
+ return;
+ }
+ fail("Pool did not reject tasks after shutdown.");
+ }
+
+ private class FlipIt implements Runnable {
+ public final Receiver<Boolean> didItRun = new Receiver<>();
+
+ @Override
+ public void run() {
+ didItRun.put(Boolean.TRUE);
+ }
+ }
+
+ @Test
+ @Ignore
+ public final void testThreadPoolProviderTerminationOnBreakdown() throws InterruptedException {
+ ThreadpoolConfig config = new ThreadpoolConfig(new ThreadpoolConfig.Builder().maxthreads(2)
+ .maxThreadExecutionTimeSeconds(1));
+ MockProcessTerminator terminator = new MockProcessTerminator();
+ ThreadPoolProvider provider = new ThreadPoolProvider(config, Mockito.mock(Metric.class), terminator);
+
+ // No dying when threads hang shorter than max thread execution time
+ provider.get().execute(new Hang(500));
+ provider.get().execute(new Hang(500));
+ assertEquals(0, terminator.dieRequests);
+ assertRejected(provider, new Hang(500)); // no more threads
+ assertEquals(0, terminator.dieRequests); // ... but not for long enough yet
+ try { Thread.sleep(1500); } catch (InterruptedException e) {}
+ provider.get().execute(new Hang(1));
+ assertEquals(0, terminator.dieRequests);
+ try { Thread.sleep(50); } catch (InterruptedException e) {} // Make sure both threads are available
+
+ // Dying when hanging both thread pool threads for longer than max thread execution time
+ provider.get().execute(new Hang(2000));
+ provider.get().execute(new Hang(2000));
+ assertEquals(0, terminator.dieRequests);
+ assertRejected(provider, new Hang(2000)); // no more threads
+ assertEquals(0, terminator.dieRequests); // ... but not for long enough yet
+ try { Thread.sleep(1500); } catch (InterruptedException e) {}
+ assertRejected(provider, new Hang(2000)); // no more threads
+ assertEquals(1, terminator.dieRequests); // ... for longer than maxThreadExecutionTime
+ }
+
+ private void assertRejected(ThreadPoolProvider provider, Runnable task) {
+ try {
+ provider.get().execute(task);
+ fail("Expected execution rejected");
+ } catch (final RejectedExecutionException expected) {
+ }
+ }
+
+ private class Hang implements Runnable {
+
+ private final long hangMillis;
+
+ public Hang(int hangMillis) {
+ this.hangMillis = hangMillis;
+ }
+
+ @Override
+ public void run() {
+ try { Thread.sleep(hangMillis); } catch (InterruptedException e) {}
+ }
+
+ }
+
+ private static class MockProcessTerminator extends ProcessTerminator {
+
+ public volatile int dieRequests = 0;
+
+ @Override
+ public void logAndDie(String message, boolean dumpThreads) {
+ dieRequests++;
+ }
+
+ }
+
+}