package org.hbase.async;
import static org.junit.Assert.assertArrayEquals;
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.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.stumbleupon.async.Deferred;
@RunWith(PowerMockRunner.class)
//"Classloader hell"... It's real. Tell PowerMock to ignore these classes
//because they fiddle with the class loader. We don't test them anyway.
@PowerMockIgnore({"javax.management.*", "javax.xml.*",
"ch.qos.*", "org.slf4j.*",
"com.sum.*", "org.xml.*"})
@PrepareForTest({ HBaseClient.class, RegionClient.class, RegionInfo.class,
HBaseRpc.class })
public class TestHBaseClient extends BaseTestHBaseClient {
@Before
public void before2() {
Whitebox.setInternalState(client, "has_root", false);
}
@Test
public void getRegionNotCached() throws Exception {
this.regions_cache.clear();
assertNull(Whitebox.invokeMethod(client, "getRegion", TABLE, KEY));
}
@Test
public void getRegionDiffKey() throws Exception {
final Object obj = Whitebox.invokeMethod(client, "getRegion", TABLE, KEY2);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(TABLE, info.table());
assertEquals(0, info.stopKey().length);
assertArrayEquals("table,,1234567890".getBytes(CHARSET), info.name());
}
@Test
public void getRegionRootAlreadyLookedUp() throws Exception {
Whitebox.setInternalState(client, "has_root", true);
final Object obj = Whitebox.invokeMethod(client, "getRegion",
HBaseClient.ROOT, HBaseClient.EMPTY_ARRAY);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(HBaseClient.ROOT, info.table());
assertArrayEquals(HBaseClient.EMPTY_ARRAY, info.stopKey());
assertArrayEquals(HBaseClient.ROOT_REGION, info.name());
}
@Test
public void getRegionRootHasRoot() throws Exception {
Whitebox.setInternalState(client, "has_root", true);
final Object obj = Whitebox.invokeMethod(client, "getRegion",
HBaseClient.ROOT, null);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(HBaseClient.ROOT, info.table());
assertArrayEquals(HBaseClient.EMPTY_ARRAY, info.stopKey());
assertArrayEquals(HBaseClient.ROOT_REGION, info.name());
}
@Test
public void getRegion96Meta() throws Exception {
final Object obj = Whitebox.invokeMethod(client, "getRegion",
HBaseClient.HBASE96_META, null);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(HBaseClient.HBASE96_META, info.table());
assertArrayEquals(HBaseClient.EMPTY_ARRAY, info.stopKey());
assertArrayEquals(HBaseClient.META_REGION_NAME, info.name());
}
@Test
public void getRegionCached() throws Exception {
final Object obj = Whitebox.invokeMethod(client, "getRegion", TABLE, KEY);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(TABLE, info.table());
assertEquals(0, info.stopKey().length);
assertArrayEquals("table,,1234567890".getBytes(CHARSET), info.name());
}
// TODO - come back to this one
// @Test
// public void getRegionCachedIncorrectly() throws Exception {
//// PowerMockito.doReturn(false)
//// .when(HBaseClient.class, "isCacheKeyForTable", byte[].class, byte[].class);
// //PowerMockito.when(HBaseClient.class, "isCacheKeyForTable", any(), any()).thenReturn(false);
// final Object obj = Whitebox.invokeMethod(client, "getRegion", TABLE, KEY);
// assertNotNull(obj);
// final RegionInfo info = (RegionInfo)obj;
// assertArrayEquals(TABLE, info.table());
// assertEquals(0, info.stopKey().length);
// assertArrayEquals("table,,1234567890".getBytes(CHARSET), info.name());
// }
@Test
public void getRegionCachedBeyondStopKey() throws Exception {
final RegionInfo keyed_region = new RegionInfo(TABLE, region.name(),
"aaa".getBytes(CHARSET));
regions_cache.put(region.name(), keyed_region);
assertNull(Whitebox.invokeMethod(client, "getRegion", TABLE, KEY));
}
@Test
public void getRegionCachedAfterStopKey() throws Exception {
final RegionInfo keyed_region = new RegionInfo(TABLE, region.name(),
"lll".getBytes(CHARSET));
regions_cache.put(region.name(), keyed_region);
final Object obj = Whitebox.invokeMethod(client, "getRegion", TABLE, KEY);
assertNotNull(obj);
final RegionInfo info = (RegionInfo)obj;
assertArrayEquals(TABLE, info.table());
assertArrayEquals("lll".getBytes(CHARSET), info.stopKey());
assertArrayEquals("table,,1234567890".getBytes(CHARSET), info.name());
}
@Test
public void getRegionCachedSameStopKey() throws Exception {
final RegionInfo keyed_region = new RegionInfo(TABLE, region.name(), KEY);
regions_cache.put(region.name(), keyed_region);
assertNull(Whitebox.invokeMethod(client, "getRegion", TABLE, KEY));
}
@Test
public void createRegionSearchKey() throws Exception {
final Object obj = Whitebox.invokeMethod(HBaseClient.class,
"createRegionSearchKey", TABLE, KEY);
assertNotNull(obj);
final byte[] key = (byte[])obj;
assertArrayEquals("table,key,:".getBytes(CHARSET), key);
}
@Test (expected = NullPointerException.class)
public void createRegionSearchKeyNullTable() throws Exception {
Whitebox.invokeMethod(HBaseClient.class, "createRegionSearchKey",
(byte[])null, KEY);
}
@Test (expected = NullPointerException.class)
public void createRegionSearchKeyNullKey() throws Exception {
Whitebox.invokeMethod(HBaseClient.class, "createRegionSearchKey",
TABLE, (byte[])null);
}
@Test
public void createRegionSearchKeyEmptyTable() throws Exception {
final Object obj = Whitebox.invokeMethod(HBaseClient.class,
"createRegionSearchKey", HBaseClient.EMPTY_ARRAY, KEY);
assertNotNull(obj);
final byte[] key = (byte[])obj;
assertArrayEquals(",key,:".getBytes(CHARSET), key);
}
@Test
public void createRegionSearchKeyEmptyKey() throws Exception {
final Object obj = Whitebox.invokeMethod(HBaseClient.class,
"createRegionSearchKey", TABLE, HBaseClient.EMPTY_ARRAY);
assertNotNull(obj);
final byte[] key = (byte[])obj;
assertArrayEquals("table,,:".getBytes(CHARSET), key);
}
@Test
public void isCacheKeyForTable() throws Exception {
final boolean is_key = (Boolean)Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", TABLE, region.name());
assertTrue(is_key);
}
@Test
public void isCacheKeyForTableDiffTable() throws Exception {
final boolean is_key = (Boolean)Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", KEY, region.name());
assertFalse(is_key);
}
@Test
public void isCacheKeyForTablePrefix() throws Exception {
final byte[] diff_region = "table2,,1234567890".getBytes(CHARSET);
final boolean is_key = (Boolean)Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", TABLE, diff_region);
assertFalse(is_key);
}
@Test
public void isCacheKeyForTableBadCache() throws Exception {
final byte[] diff_region = "table,".getBytes(CHARSET);
final boolean is_key = (Boolean)Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", TABLE, diff_region);
assertTrue(is_key);
}
@Test (expected = ArrayIndexOutOfBoundsException.class)
public void isCacheKeyForTableBadCache2() throws Exception {
final byte[] diff_region = "table".getBytes(CHARSET);
Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", TABLE, diff_region);
}
@Test (expected = NullPointerException.class)
public void isCacheKeyForTableNullTable() throws Exception {
Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", (byte[])null, region.name());
}
@Test (expected = NullPointerException.class)
public void isCacheKeyForTableNullKey() throws Exception {
Whitebox.invokeMethod(HBaseClient.class,
"isCacheKeyForTable", TABLE, (byte[])null);
}
@Test
public void tooManyAttempts() throws Exception {
final HBaseRpc rpc = getMockHBaseRpc(null);
rpc.attempt = (byte) (10 + 1);
final Deferred<Object> error = HBaseClient.tooManyAttempts(rpc,
new NoSuchColumnFamilyException("Fail!", rpc));
assertNotNull(error);
NonRecoverableException ex = null;
try {
error.joinUninterruptibly();
} catch (NonRecoverableException e) {
ex = e;
}
assertNotNull(ex);
assertTrue(ex instanceof NonRecoverableException);
assertNotNull(ex.getCause());
assertTrue(ex.getCause() instanceof NoSuchColumnFamilyException);
verify(rpc).callback(any());
}
@Test
public void tooManyAttemptsNullException() throws Exception {
final HBaseRpc rpc = getMockHBaseRpc(null);
rpc.attempt = (byte) (10 + 1);
final Deferred<Object> error = HBaseClient.tooManyAttempts(rpc, null);
assertNotNull(error);
NonRecoverableException ex = null;
try {
error.joinUninterruptibly();
} catch (NonRecoverableException e) {
ex = e;
}
assertNotNull(ex);
assertTrue(ex instanceof NonRecoverableException);
assertNull(ex.getCause());
}
@Test
public void knownToBeNSREdFalse() throws Exception {
assertFalse((Boolean)Whitebox.invokeMethod(HBaseClient.class,
"knownToBeNSREd", region));
}
@Test
public void knownToBeNSREdTrue() throws Exception {
final RegionInfo nsre = new RegionInfo(HBaseClient.EMPTY_ARRAY, region.name(),
HBaseClient.EMPTY_ARRAY);
assertTrue((Boolean)Whitebox.invokeMethod(HBaseClient.class,
"knownToBeNSREd", nsre));
}
@Test (expected = NullPointerException.class)
public void knownToBeNSREdNullRegionInfo() throws Exception {
Whitebox.invokeMethod(HBaseClient.class, "knownToBeNSREd", (RegionInfo)null);
}
// discoverRegion
@Test
public void discoverRegionNewRegionInfo() throws Exception {
clearCaches();
final Object obj = Whitebox.invokeMethod(client, "discoverRegion",
metaRow());
assertNotNull(obj);
final RegionClient region_client = (RegionClient)obj;
assertEquals(1, regions_cache.size());
assertEquals(1, region2client.size());
assertEquals(1, client2regions.size());
assertEquals("127.0.0.1:54321", region_client.getRemoteAddress());
assertTrue(region_client == region2client.values().iterator().next());
PowerMockito.verifyPrivate(client, never()).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test
public void discoverRegionReplaceRegionInfo() throws Exception {
final Object obj = Whitebox.invokeMethod(client, "discoverRegion",
metaRow());
assertNotNull(obj);
final RegionClient region_client = (RegionClient)obj;
assertEquals(2, regions_cache.size());
assertEquals(2, region2client.size());
assertEquals(3, client2regions.size());
assertEquals("127.0.0.1:54321", region_client.getRemoteAddress());
final Iterator<RegionClient> iterator = region2client.values().iterator();
assertTrue(region_client != iterator.next());
assertTrue(region_client == iterator.next());
PowerMockito.verifyPrivate(client, never()).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test
public void discoverRegionNewRegionInfoColumnsOutOfOrder() throws Exception {
// really should never happen, but *shrug*
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, false, TABLE));
final Object obj = Whitebox.invokeMethod(client, "discoverRegion", row);
assertNotNull(obj);
final RegionClient region_client = (RegionClient)obj;
assertEquals(1, regions_cache.size());
assertEquals(1, region2client.size());
assertEquals(1, client2regions.size());
assertTrue(region_client == region2client.values().iterator().next());
assertEquals("127.0.0.1:54321", region_client.getRemoteAddress());
PowerMockito.verifyPrivate(client, never()).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test
public void discoverRegionNewRegionInfoMultiHost() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, false, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "remotehost:12345".getBytes()));
// ignores all but the last
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
final Object obj = Whitebox.invokeMethod(client, "discoverRegion", row);
assertNotNull(obj);
final RegionClient region_client = (RegionClient)obj;
assertEquals(1, regions_cache.size());
assertEquals(1, region2client.size());
assertEquals(1, client2regions.size());
assertTrue(region_client == region2client.values().iterator().next());
assertEquals("127.0.0.1:54321", region_client.getRemoteAddress());
PowerMockito.verifyPrivate(client, never()).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test
public void discoverRegionNewRegionInfoMissingServerColumn() throws Exception {
// really should never happen, but *shrug*
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, false, TABLE));
assertNull(Whitebox.invokeMethod(client, "discoverRegion", row));
assertEquals(1, regions_cache.size());
assertEquals(0, region2client.size());
assertEquals(0, client2regions.size());
PowerMockito.verifyPrivate(client).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test (expected = BrokenMetaException.class)
public void discoverRegionNewRegionInfoMissingRegionrColumn() throws Exception {
// really should never happen, but *shrug*
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
Whitebox.invokeMethod(client, "discoverRegion", row);
}
@Test (expected = RegionOfflineException.class)
public void discoverRegionNewRegionInfoOffline() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, true, false, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
Whitebox.invokeMethod(client, "discoverRegion", row);
}
@Test
public void discoverRegionNewRegionInfoSplitting() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
// Don't know if this is valid to be online and splitting. Prolly is
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, true, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
assertNull(Whitebox.invokeMethod(client, "discoverRegion", row));
assertEquals(1, regions_cache.size());
assertEquals(0, region2client.size());
assertEquals(0, client2regions.size());
PowerMockito.verifyPrivate(client).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test
public void discoverRegionNewRegionInfoOfflineAndSplitting() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, true, true, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:54321".getBytes()));
assertNull(Whitebox.invokeMethod(client, "discoverRegion", row));
assertEquals(1, regions_cache.size());
assertEquals(0, region2client.size());
assertEquals(0, client2regions.size());
PowerMockito.verifyPrivate(client).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test (expected = BrokenMetaException.class)
public void discoverRegionNewRegionInfoMissingPort() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, false, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost".getBytes()));
Whitebox.invokeMethod(client, "discoverRegion", row);
}
@Test (expected = BrokenMetaException.class)
public void discoverRegionNewRegionInfoNotAPort() throws Exception {
clearCaches();
final ArrayList<KeyValue> row = new ArrayList<KeyValue>(2);
row.add(metaRegionInfo(EMPTY_ARRAY, EMPTY_ARRAY, false, false, TABLE));
row.add(new KeyValue(region.name(), INFO, SERVER, "localhost:myport".getBytes()));
Whitebox.invokeMethod(client, "discoverRegion", row);
}
@Test (expected = BrokenMetaException.class)
public void discoverRegionNewRegionNullStartKey() throws Exception {
PowerMockito.mockStatic(RegionInfo.class);
PowerMockito.when(RegionInfo.fromKeyValue((KeyValue)any(), (byte[][])any()))
.thenAnswer(new Answer<RegionInfo>() {
@Override
public RegionInfo answer(final InvocationOnMock invocation) throws Throwable {
final byte[][] tmp = (byte[][])invocation.getArguments()[1];
tmp[0] = null;
return region;
}
});
clearCaches();
Whitebox.invokeMethod(client, "discoverRegion", metaRow());
}
@Test
public void discoverRegionNewRegionInfoNullHost() throws Exception {
mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getByName("54321"))
.thenThrow(new UnknownHostException("No such host 54321"));
clearCaches();
assertNull(Whitebox.invokeMethod(client, "discoverRegion", metaRow()));
assertEquals(1, regions_cache.size());
assertEquals(0, region2client.size());
assertEquals(0, client2regions.size());
PowerMockito.verifyPrivate(client).invoke("invalidateRegionCache",
(byte[])any(), anyBoolean(), anyString());
}
@Test (expected = TableNotFoundException.class)
public void discoverRegionEmpty() throws Exception {
Whitebox.invokeMethod(client, "discoverRegion", new ArrayList<KeyValue>());
}
@Test (expected = NullPointerException.class)
public void discoverRegionNull() throws Exception {
Whitebox.invokeMethod(client, "discoverRegion", (ArrayList<KeyValue>)null);
}
}