/*
* Copyright (C) 2015 The Async HBase Authors. All rights reserved.
* This file is part of Async HBase.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the StumbleUpon nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.hbase.async;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.socket.nio.NioClientBossPool;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioWorkerPool;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.stumbleupon.async.Deferred;
import com.stumbleupon.async.TimeoutException;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ HBaseClient.class, RegionClient.class, HBaseRpc.class,
GetRequest.class, RegionInfo.class, NioClientSocketChannelFactory.class,
Executors.class, HashedWheelTimer.class, NioClientBossPool.class,
NioWorkerPool.class })
public class TestHBaseRpc extends BaseTestHBaseClient {
private int default_timeout;
@Before
public void beforeLocal() throws Exception {
timer.stop();
when(regionclient.getHBaseClient()).thenReturn(client);
Whitebox.setInternalState(client, "rpc_timeout", 60000);
default_timeout = 60000;
}
@Test
public void enqueueTimeout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
final Deferred<Object> deferred = rpc.getDeferred();
assertNull(rpc.timeout_handle);
assertEquals(0, timer.tasks.size());
assertFalse(rpc.hasTimedOut());
rpc.enqueueTimeout(regionclient);
assertEquals(1, timer.tasks.size());
assertNotNull(rpc.timeout_handle);
assertEquals(default_timeout, rpc.getTimeout());
assertEquals(default_timeout, (long)timer.tasks.get(0).getValue());
assertFalse(rpc.hasTimedOut());
verify(regionclient, never()).removeRpc(any(HBaseRpc.class), anyBoolean());
try {
deferred.join(1);
fail("Expected a TimeoutException");
} catch (TimeoutException e) { }
}
@Test
public void enqueueTimeoutCustomTimeout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.setTimeout(42000);
final Deferred<Object> deferred = rpc.getDeferred();
assertNull(rpc.timeout_handle);
assertEquals(0, timer.tasks.size());
assertFalse(rpc.hasTimedOut());
rpc.enqueueTimeout(regionclient);
assertEquals(1, timer.tasks.size());
assertNotNull(rpc.timeout_handle);
assertEquals(42000, rpc.getTimeout());
assertEquals(42000, (long)timer.tasks.get(0).getValue());
assertFalse(rpc.hasTimedOut());
verify(regionclient, never()).removeRpc(any(HBaseRpc.class), anyBoolean());
try {
deferred.join(1);
fail("Expected a TimeoutException");
} catch (TimeoutException e) { }
}
@Test (expected = IllegalStateException.class)
public void enqueueTimeoutAlreadyTimedout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
Whitebox.setInternalState(rpc, "has_timedout", true);
rpc.enqueueTimeout(regionclient);
}
@Test (expected = NullPointerException.class)
public void enqueueTimeoutNullRegionClient() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.enqueueTimeout(null);
}
@Test
public void enqueueTimeoutZeroTimeout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.setTimeout(0);
final Deferred<Object> deferred = rpc.getDeferred();
assertNull(rpc.timeout_handle);
assertEquals(0, timer.tasks.size());
assertFalse(rpc.hasTimedOut());
rpc.enqueueTimeout(regionclient);
assertNull(rpc.timeout_handle);
assertEquals(0, rpc.getTimeout());
assertEquals(0, timer.tasks.size());
assertFalse(rpc.hasTimedOut());
verify(regionclient, never()).removeRpc(any(HBaseRpc.class), anyBoolean());
try {
deferred.join(1);
fail("Expected a TimeoutException");
} catch (TimeoutException e) { }
}
@Test
public void enqueueTimeoutTimerShuttingDown() throws Exception {
timer = mock(FakeTimer.class);
when(timer.newTimeout(any(TimerTask.class), anyLong(), any(TimeUnit.class)))
.thenThrow(new IllegalStateException("Shutdown!"));
Whitebox.setInternalState(client, "rpc_timeout_timer", timer);
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
final Deferred<Object> deferred = rpc.getDeferred();
assertNull(rpc.timeout_handle);
assertFalse(rpc.hasTimedOut());
rpc.enqueueTimeout(regionclient);
assertNull(rpc.timeout_handle);
assertEquals(default_timeout, rpc.getTimeout());
assertFalse(rpc.hasTimedOut());
verify(regionclient, never()).removeRpc(any(HBaseRpc.class), anyBoolean());
verify(timer).newTimeout(any(TimerTask.class), anyLong(), any(TimeUnit.class));
try {
deferred.join(1);
fail("Expected a TimeoutException");
} catch (TimeoutException e) { }
}
@Test
public void callback() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Deferred<Object> deferred = rpc.getDeferred();
final Object response = new Object();
assertEquals(4, rpc.attempt);
assertNull(rpc.timeout_handle);
assertTrue(rpc.hasDeferred());
rpc.callback(response);
assertSame(response, deferred.join());
assertEquals(0, rpc.attempt);
assertFalse(rpc.hasDeferred());
}
@Test
public void callbackNullResult() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Deferred<Object> deferred = rpc.getDeferred();
assertEquals(4, rpc.attempt);
assertNull(rpc.timeout_handle);
assertTrue(rpc.hasDeferred());
rpc.callback(null);
assertNull(deferred.join());
assertEquals(0, rpc.attempt);
assertFalse(rpc.hasDeferred());
}
@Test
public void callbackException() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Deferred<Object> deferred = rpc.getDeferred();
assertEquals(4, rpc.attempt);
assertNull(rpc.timeout_handle);
assertTrue(rpc.hasDeferred());
rpc.callback(new NonRecoverableException("Boo!"));
try {
deferred.join();
} catch (NonRecoverableException e) { }
assertEquals(0, rpc.attempt);
assertFalse(rpc.hasDeferred());
}
@Test
public void callbackWithTimeout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Timeout timeout_handle = mock(Timeout.class);
final Deferred<Object> deferred = rpc.getDeferred();
final Object response = new Object();
rpc.timeout_handle = timeout_handle;
assertTrue(rpc.hasDeferred());
rpc.callback(response);
assertSame(response, deferred.join());
assertEquals(0, rpc.attempt);
assertFalse(rpc.hasDeferred());
verify(timeout_handle).cancel();
}
@Test
public void callbackWithoutDeferred() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Object response = new Object();
assertEquals(4, rpc.attempt);
assertNull(rpc.timeout_handle);
assertFalse(rpc.hasDeferred());
rpc.callback(response);
assertEquals(4, rpc.attempt);
assertFalse(rpc.hasDeferred());
}
@Test
public void callbackWithTimeoutWithoutDeferred() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.attempt = 4;
final Timeout timeout_handle = mock(Timeout.class);
final Object response = new Object();
rpc.timeout_handle = timeout_handle;
assertFalse(rpc.hasDeferred());
rpc.callback(response);
assertEquals(4, rpc.attempt);
assertFalse(rpc.hasDeferred());
verify(timeout_handle).cancel();
}
@Test
public void timeout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
final Deferred<Object> deferred = rpc.getDeferred();
rpc.enqueueTimeout(regionclient);
timer.tasks.get(0).getKey().run(rpc.timeout_handle);
assertNull(rpc.timeout_handle);
verify(regionclient).removeRpc(rpc, true);
try {
deferred.join(1);
fail("Expected a RpcTimedOutException");
} catch (RpcTimedOutException ex) { }
}
@Test (expected = IllegalStateException.class)
public void timeoutAlreadyTimedout() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
rpc.enqueueTimeout(regionclient);
timer.tasks.get(0).getKey().run(rpc.timeout_handle);
// better not happen
timer.tasks.get(0).getKey().run(rpc.timeout_handle);
}
@Test
public void timeoutDifferentHandle() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
final Deferred<Object> deferred = rpc.getDeferred();
rpc.enqueueTimeout(regionclient);
timer.tasks.get(0).getKey().run(mock(Timeout.class));
assertNull(rpc.timeout_handle);
verify(regionclient).removeRpc(rpc, true);
try {
deferred.join(1);
fail("Expected a RpcTimedOutException");
} catch (RpcTimedOutException ex) { }
}
@Test
public void timeoutNulledRegionClient() throws Exception {
final GetRequest rpc = new GetRequest(TABLE, KEY, FAMILY);
final Deferred<Object> deferred = rpc.getDeferred();
rpc.enqueueTimeout(regionclient);
Whitebox.setInternalState(rpc, "region_client", (RegionClient)null);
timer.tasks.get(0).getKey().run(rpc.timeout_handle);
assertNull(rpc.timeout_handle);
verify(regionclient, never()).removeRpc(rpc, true);
try {
deferred.join(1);
fail("Expected a RpcTimedOutException");
} catch (RpcTimedOutException ex) { }
}
}