/** * 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 org.apache.aurora.scheduler.async; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ScheduledExecutorService; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Time; import org.apache.aurora.common.testing.easymock.EasyMockTest; import org.easymock.EasyMock; import org.easymock.IExpectationSetters; import org.junit.Before; import org.junit.Test; import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; public class GatingDelayExecutorTest extends EasyMockTest { private static final Amount<Long, Time> ONE_SECOND = Amount.of(1L, Time.SECONDS); private ScheduledExecutorService gatedExecutor; private Runnable runnable; private GatingDelayExecutor gatingExecutor; @Before public void setUp() { gatedExecutor = createMock(ScheduledExecutorService.class); runnable = createMock(Runnable.class); gatingExecutor = new GatingDelayExecutor(gatedExecutor); } @Test public void testGateOpen() { gatedExecutor.execute(runnable); control.replay(); // The gate was not closed, so the work is executed immediately. gatingExecutor.execute(runnable); } private IExpectationSetters<?> invokeWorkWhenSubmitted() { return expectLastCall().andAnswer(() -> { ((Runnable) EasyMock.getCurrentArguments()[0]).run(); return null; }); } @Test public void testGateIsThreadSpecific() throws InterruptedException { gatedExecutor.execute(runnable); control.replay(); CountDownLatch gateClosed = new CountDownLatch(1); CountDownLatch unblock = new CountDownLatch(1); Runnable closer = () -> gatingExecutor.closeDuring(() -> { gateClosed.countDown(); try { unblock.await(); } catch (InterruptedException e) { throw Throwables.propagate(e); } return "hi"; }); new ThreadFactoryBuilder() .setDaemon(true) .setNameFormat("GateTest") .build() .newThread(closer) .start(); gateClosed.await(); gatingExecutor.execute(runnable); assertQueueSize(0); unblock.countDown(); } private void assertQueueSize(int size) { assertEquals(size, gatingExecutor.getQueueSize()); } @Test public void testReentrantClose() { gatedExecutor.execute(runnable); expectLastCall().times(3); control.replay(); gatingExecutor.execute(runnable); assertQueueSize(0); String result = gatingExecutor.closeDuring(() -> { gatingExecutor.execute(runnable); assertQueueSize(1); String result1 = gatingExecutor.closeDuring(() -> { gatingExecutor.execute(runnable); assertQueueSize(2); return "hello"; }); assertEquals("hello", result1); return "hi"; }); assertEquals("hi", result); assertQueueSize(0); } @Test public void testExecute() { gatedExecutor.execute(runnable); invokeWorkWhenSubmitted(); runnable.run(); expectLastCall(); control.replay(); gatingExecutor.execute(runnable); } @Test public void testExecuteAfterDelay() { gatedExecutor.schedule( runnable, ONE_SECOND.getValue().longValue(), ONE_SECOND.getUnit().getTimeUnit()); invokeWorkWhenSubmitted(); runnable.run(); control.replay(); gatingExecutor.execute(runnable, ONE_SECOND); } }