/* Copyright (c) 2016 LinkedIn Corp. 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 test.r2.transport.http.client; import com.linkedin.common.callback.Callback; import com.linkedin.common.util.None; import com.linkedin.r2.transport.http.client.AsyncPool; import com.linkedin.r2.transport.http.client.PoolStats; import com.linkedin.r2.transport.http.client.TimeoutAsyncPoolHandle; import com.linkedin.r2.util.Cancellable; import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.Test; public class TestTimeoutAsyncPoolHandle { private static final int IMMEDIATE_TIMEOUT = 0; private static final int LONG_TIMEOUT = 30; private static final int OPERATION_TIMEOUT = 30; private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS; private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor(); @AfterSuite public void doAfterSuites() { _scheduler.shutdown(); } @Test public void testTimeout() throws Exception { FakePool<Object> pool = new FakePool<>(); TimeoutAsyncPoolHandle<Object> handle = new TimeoutAsyncPoolHandle<>(pool, _scheduler, IMMEDIATE_TIMEOUT, TIME_UNIT, new Object()); CountDownLatch latch = new CountDownLatch(1); handle.addTimeoutTask(() -> latch.countDown()); latch.await(OPERATION_TIMEOUT, TIME_UNIT); Assert.assertEquals(pool.getPutCount(), 0); Assert.assertEquals(pool.getDisposeCount(), 1); } @Test public void testBadReleaseAfterTimeout() throws Exception { FakePool<Object> pool = new FakePool<>(); TimeoutAsyncPoolHandle<Object> handle = new TimeoutAsyncPoolHandle<>( pool, _scheduler, IMMEDIATE_TIMEOUT, TIME_UNIT, new Object()); CountDownLatch latch = new CountDownLatch(1); handle.addTimeoutTask(() -> latch.countDown()); latch.await(OPERATION_TIMEOUT, TIME_UNIT); handle.error().release(); Assert.assertEquals(pool.getPutCount(), 0); Assert.assertEquals(pool.getDisposeCount(), 1); } @Test public void testGoodReleaseAfterTimeout() throws Exception { FakePool<Object> pool = new FakePool<>(); TimeoutAsyncPoolHandle<Object> handle = new TimeoutAsyncPoolHandle<>( pool, _scheduler, IMMEDIATE_TIMEOUT, TIME_UNIT, new Object()); CountDownLatch latch = new CountDownLatch(1); handle.addTimeoutTask(() -> latch.countDown()); latch.await(OPERATION_TIMEOUT, TIME_UNIT); handle.release(); Assert.assertEquals(pool.getPutCount(), 0); Assert.assertEquals(pool.getDisposeCount(), 1); } @Test public void testBadReleaseBeforeTimeout() throws Exception { FakePool<Object> pool = new FakePool<>(); TimeoutAsyncPoolHandle<Object> handle = new TimeoutAsyncPoolHandle<>( pool, _scheduler, LONG_TIMEOUT, TIME_UNIT, new Object()); handle.error().release(); Assert.assertEquals(pool.getPutCount(), 0); Assert.assertEquals(pool.getDisposeCount(), 1); } @Test public void testGoodReleaseBeforeTimeout() throws Exception { FakePool<Object> pool = new FakePool<>(); TimeoutAsyncPoolHandle<Object> handle = new TimeoutAsyncPoolHandle<>( pool, _scheduler, LONG_TIMEOUT, TIME_UNIT, new Object()); handle.release(); Assert.assertEquals(pool.getPutCount(), 1); Assert.assertEquals(pool.getDisposeCount(), 0); } private class FakePool<T> implements AsyncPool<T> { private volatile int _putCount = 0; private volatile int _disposeCount = 0; public int getPutCount() { return _putCount; } public int getDisposeCount() { return _disposeCount; } @Override public String getName() { return null; } @Override public void start() { } @Override public void shutdown(Callback<None> callback) { } @Override public Collection<Callback<T>> cancelWaiters() { return null; } @Override public Cancellable get(Callback<T> callback) { return null; } @Override public void put(T obj) { _putCount += 1; } @Override public void dispose(T obj) { _disposeCount += 1; } @Override public PoolStats getStats() { return null; } } }