// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.util.thread.strategy; import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.ExecutionStrategy; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ExecutionStrategy.Producer; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class ExecutionStrategyTest { @Parameterized.Parameters(name = "{0}") public static Iterable<Object[]> data() { return Arrays.asList(new Object[][]{ {ProduceExecuteConsume.class}, {ExecuteProduceConsume.class}, {EatWhatYouKill.class} }); } QueuedThreadPool _threads = new QueuedThreadPool(20); Class<? extends ExecutionStrategy> _strategyClass; ExecutionStrategy _strategy; public ExecutionStrategyTest(Class<? extends ExecutionStrategy> strategy) { _strategyClass = strategy; } void newExecutionStrategy(Producer producer, Executor executor) throws Exception { _strategy = _strategyClass.getConstructor(Producer.class,Executor.class).newInstance(producer,executor); LifeCycle.start(_strategy); } @Before public void before() throws Exception { _threads.start(); } @After public void after() throws Exception { LifeCycle.stop(_strategy); _threads.stop(); } public static abstract class TestProducer implements Producer { @Override public String toString() { return "TestProducer"; } } @Test public void idleTest() throws Exception { AtomicInteger count = new AtomicInteger(0); Producer producer = new TestProducer() { @Override public Runnable produce() { count.incrementAndGet(); return null; } }; newExecutionStrategy(producer,_threads); _strategy.produce(); assertThat(count.get(),greaterThan(0)); } @Test public void simpleTest() throws Exception { final int TASKS = 3*_threads.getMaxThreads(); final CountDownLatch latch = new CountDownLatch(TASKS); Producer producer = new TestProducer() { int tasks = TASKS; @Override public Runnable produce() { if (tasks-->0) { return new Runnable() { @Override public void run() { latch.countDown(); } }; } return null; } }; newExecutionStrategy(producer,_threads); for (int p=0; latch.getCount()>0 && p<TASKS; p++) _strategy.produce(); assertTrue(latch.await(10,TimeUnit.SECONDS)); } @Test public void blockingProducerTest() throws Exception { final int TASKS = 3*_threads.getMaxThreads(); final BlockingQueue<CountDownLatch> q = new ArrayBlockingQueue<>(500); Producer producer = new TestProducer() { int tasks=TASKS; @Override public Runnable produce() { if (tasks-->0) { try { final CountDownLatch latch = q.poll(10,TimeUnit.SECONDS); if (latch!=null) { return new Runnable() { @Override public void run() { latch.countDown(); } }; } } catch(InterruptedException e) { e.printStackTrace(); } } return null; } }; newExecutionStrategy(producer,_threads); _threads.execute(()->_strategy.produce()); final CountDownLatch latch = new CountDownLatch(TASKS); _threads.execute(new Runnable() { @Override public void run() { try { for (int t=TASKS;t-->0;) { Thread.sleep(20); q.offer(latch); _strategy.produce(); } } catch(Exception e) { e.printStackTrace(); } } }); assertTrue(latch.await(10,TimeUnit.SECONDS)); } }