1 // This file is part of OpenTSDB. 2 // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 // 4 // This program is free software: you can redistribute it and/or modify it 5 // under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 2.1 of the License, or (at your 7 // option) any later version. This program is distributed in the hope that it 8 // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License for more details. You should have received a copy 11 // of the GNU Lesser General Public License along with this program. If not, 12 // see <http://www.gnu.org/licenses/>. 13 package net.opentsdb.uid; 14 15 import java.util.ArrayList; 16 import java.util.Arrays; 17 import java.util.List; 18 import java.util.Map; 19 20 import com.stumbleupon.async.Callback; 21 import com.stumbleupon.async.Deferred; 22 23 import net.opentsdb.core.Const; 24 import net.opentsdb.core.TSDB; 25 import net.opentsdb.core.BaseTsdbTest.UnitTestException; 26 import net.opentsdb.storage.MockBase; 27 import net.opentsdb.uid.UniqueId.UniqueIdType; 28 import net.opentsdb.utils.Config; 29 30 import org.hbase.async.AtomicIncrementRequest; 31 import org.hbase.async.Bytes; 32 import org.hbase.async.DeleteRequest; 33 import org.hbase.async.GetRequest; 34 import org.hbase.async.HBaseClient; 35 import org.hbase.async.HBaseException; 36 import org.hbase.async.KeyValue; 37 import org.hbase.async.PutRequest; 38 import org.hbase.async.Scanner; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import org.mockito.ArgumentMatcher; 43 import org.mockito.InOrder; 44 import org.mockito.invocation.InvocationOnMock; 45 import org.mockito.stubbing.Answer; 46 47 import static org.junit.Assert.*; 48 import static org.mockito.Matchers.any; 49 import static org.mockito.Matchers.anyMapOf; 50 import static org.mockito.Matchers.anyString; 51 import static org.mockito.Mockito.anyInt; 52 import static org.mockito.Mockito.argThat; 53 import static org.mockito.Mockito.eq; 54 import static org.mockito.Mockito.inOrder; 55 import static org.mockito.Mockito.never; 56 import static org.mockito.Mockito.times; 57 import static org.mockito.Mockito.verify; 58 import static org.mockito.Mockito.when; 59 60 import org.powermock.api.mockito.PowerMockito; 61 import org.powermock.core.classloader.annotations.PowerMockIgnore; 62 import org.powermock.core.classloader.annotations.PrepareForTest; 63 import org.powermock.modules.junit4.PowerMockRunner; 64 65 import static org.powermock.api.mockito.PowerMockito.mock; 66 67 @RunWith(PowerMockRunner.class) 68 // "Classloader hell"... It's real. Tell PowerMock to ignore these classes 69 // because they fiddle with the class loader. We don't test them anyway. 70 @PowerMockIgnore({"javax.management.*", "javax.xml.*", 71 "ch.qos.*", "org.slf4j.*", 72 "com.sum.*", "org.xml.*"}) 73 @PrepareForTest({ HBaseClient.class, TSDB.class, Config.class, Scanner.class, 74 RandomUniqueId.class, Const.class, Deferred.class }) 75 public final class TestUniqueId { 76 private static final byte[] table = { 't', 's', 'd', 'b', '-', 'u', 'i', 'd' }; 77 private static final byte[] ID = { 'i', 'd' }; 78 private static final byte[] NAME = { 'n', 'a', 'm', 'e' }; 79 private static final String METRIC = "metric"; 80 private static final byte[] METRIC_ARRAY = { 'm', 'e', 't', 'r', 'i', 'c' }; 81 private static final String TAGK = "tagk"; 82 private static final byte[] TAGK_ARRAY = { 't', 'a', 'g', 'k' }; 83 private static final String TAGV = "tagv"; 84 private static final byte[] TAGV_ARRAY = { 't', 'a', 'g', 'v' }; 85 private static final byte[] UID = new byte[] { 0, 0, 1 }; 86 private TSDB tsdb = mock(TSDB.class); 87 private HBaseClient client = mock(HBaseClient.class); 88 private UniqueId uid; 89 private MockBase storage; 90 91 @Test(expected=IllegalArgumentException.class) testCtorZeroWidth()92 public void testCtorZeroWidth() { 93 uid = new UniqueId(client, table, METRIC, 0); 94 } 95 96 @Test(expected=IllegalArgumentException.class) testCtorNegativeWidth()97 public void testCtorNegativeWidth() { 98 uid = new UniqueId(client, table, METRIC, -1); 99 } 100 101 @Test(expected=IllegalArgumentException.class) testCtorEmptyKind()102 public void testCtorEmptyKind() { 103 uid = new UniqueId(client, table, "", 3); 104 } 105 106 @Test(expected=IllegalArgumentException.class) testCtorLargeWidth()107 public void testCtorLargeWidth() { 108 uid = new UniqueId(client, table, METRIC, 9); 109 } 110 111 @Test kindEqual()112 public void kindEqual() { 113 uid = new UniqueId(client, table, METRIC, 3); 114 assertEquals(METRIC, uid.kind()); 115 } 116 117 @Test widthEqual()118 public void widthEqual() { 119 uid = new UniqueId(client, table, METRIC, 3); 120 assertEquals(3, uid.width()); 121 } 122 123 @Test getNameSuccessfulHBaseLookup()124 public void getNameSuccessfulHBaseLookup() { 125 uid = new UniqueId(client, table, METRIC, 3); 126 final byte[] id = { 0, 'a', 0x42 }; 127 final byte[] byte_name = { 'f', 'o', 'o' }; 128 129 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 130 kvs.add(new KeyValue(id, ID, METRIC_ARRAY, byte_name)); 131 when(client.get(anyGet())) 132 .thenReturn(Deferred.fromResult(kvs)); 133 134 assertEquals("foo", uid.getName(id)); 135 // Should be a cache hit ... 136 assertEquals("foo", uid.getName(id)); 137 138 assertEquals(1, uid.cacheHits()); 139 assertEquals(1, uid.cacheMisses()); 140 assertEquals(2, uid.cacheSize()); 141 142 // ... so verify there was only one HBase Get. 143 verify(client).get(anyGet()); 144 } 145 146 @Test getNameWithErrorDuringHBaseLookup()147 public void getNameWithErrorDuringHBaseLookup() { 148 uid = new UniqueId(client, table, METRIC, 3); 149 final byte[] id = { 0, 'a', 0x42 }; 150 final byte[] byte_name = { 'f', 'o', 'o' }; 151 152 HBaseException hbe = mock(HBaseException.class); 153 154 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 155 kvs.add(new KeyValue(id, ID, METRIC_ARRAY, byte_name)); 156 when(client.get(anyGet())) 157 .thenThrow(hbe) 158 .thenReturn(Deferred.fromResult(kvs)); 159 160 // 1st calls fails. 161 try { 162 uid.getName(id); 163 fail("HBaseException should have been thrown."); 164 } catch (HBaseException e) { 165 assertSame(hbe, e); // OK. 166 } 167 168 // 2nd call succeeds. 169 assertEquals("foo", uid.getName(id)); 170 171 assertEquals(0, uid.cacheHits()); 172 assertEquals(2, uid.cacheMisses()); // 1st (failed) attempt + 2nd. 173 assertEquals(2, uid.cacheSize()); 174 175 verify(client, times(2)).get(anyGet()); 176 } 177 178 @Test(expected=NoSuchUniqueId.class) getNameForNonexistentId()179 public void getNameForNonexistentId() { 180 uid = new UniqueId(client, table, METRIC, 3); 181 182 when(client.get(anyGet())) 183 .thenReturn(Deferred.fromResult(new ArrayList<KeyValue>(0))); 184 185 uid.getName(new byte[] { 1, 2, 3 }); 186 } 187 188 @Test(expected=IllegalArgumentException.class) getNameWithInvalidId()189 public void getNameWithInvalidId() { 190 uid = new UniqueId(client, table, METRIC, 3); 191 192 uid.getName(new byte[] { 1 }); 193 } 194 195 @Test getIdSuccessfulHBaseLookup()196 public void getIdSuccessfulHBaseLookup() { 197 uid = new UniqueId(client, table, METRIC, 3); 198 final byte[] id = { 0, 'a', 0x42 }; 199 final byte[] byte_name = { 'f', 'o', 'o' }; 200 201 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 202 kvs.add(new KeyValue(byte_name, ID, METRIC_ARRAY, id)); 203 when(client.get(anyGet())) 204 .thenReturn(Deferred.fromResult(kvs)); 205 206 assertArrayEquals(id, uid.getId("foo")); 207 // Should be a cache hit ... 208 assertArrayEquals(id, uid.getId("foo")); 209 // Should be a cache hit too ... 210 assertArrayEquals(id, uid.getId("foo")); 211 212 assertEquals(2, uid.cacheHits()); 213 assertEquals(1, uid.cacheMisses()); 214 assertEquals(2, uid.cacheSize()); 215 216 // ... so verify there was only one HBase Get. 217 verify(client).get(anyGet()); 218 } 219 220 // The table contains IDs encoded on 2 bytes but the instance wants 3. 221 @Test(expected=IllegalStateException.class) getIdMisconfiguredWidth()222 public void getIdMisconfiguredWidth() { 223 uid = new UniqueId(client, table, METRIC, 3); 224 final byte[] id = { 'a', 0x42 }; 225 final byte[] byte_name = { 'f', 'o', 'o' }; 226 227 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 228 kvs.add(new KeyValue(byte_name, ID, METRIC_ARRAY, id)); 229 when(client.get(anyGet())) 230 .thenReturn(Deferred.fromResult(kvs)); 231 232 uid.getId("foo"); 233 } 234 235 @Test(expected=NoSuchUniqueName.class) getIdForNonexistentName()236 public void getIdForNonexistentName() { 237 uid = new UniqueId(client, table, METRIC, 3); 238 239 when(client.get(anyGet())) // null => ID doesn't exist. 240 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 241 // Watch this! ______,^ I'm writing C++ in Java! 242 243 uid.getId("foo"); 244 } 245 246 @Test getOrCreateIdWithExistingId()247 public void getOrCreateIdWithExistingId() { 248 uid = new UniqueId(client, table, METRIC, 3); 249 final byte[] id = { 0, 'a', 0x42 }; 250 final byte[] byte_name = { 'f', 'o', 'o' }; 251 252 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 253 kvs.add(new KeyValue(byte_name, ID, METRIC_ARRAY, id)); 254 when(client.get(anyGet())) 255 .thenReturn(Deferred.fromResult(kvs)); 256 257 assertArrayEquals(id, uid.getOrCreateId("foo")); 258 // Should be a cache hit ... 259 assertArrayEquals(id, uid.getOrCreateId("foo")); 260 assertEquals(1, uid.cacheHits()); 261 assertEquals(1, uid.cacheMisses()); 262 assertEquals(2, uid.cacheSize()); 263 264 // ... so verify there was only one HBase Get. 265 verify(client).get(anyGet()); 266 } 267 268 @Test // Test the creation of an ID with no problem. getOrCreateIdAssignFilterOK()269 public void getOrCreateIdAssignFilterOK() { 270 uid = new UniqueId(client, table, METRIC, 3); 271 final byte[] id = { 0, 0, 5 }; 272 final Config config = mock(Config.class); 273 when(config.enable_realtime_uid()).thenReturn(false); 274 final TSDB tsdb = mock(TSDB.class); 275 when(tsdb.getConfig()).thenReturn(config); 276 uid.setTSDB(tsdb); 277 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 278 when(filter.fillterUIDAssignments()).thenReturn(true); 279 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 280 anyString(), anyMapOf(String.class, String.class))) 281 .thenReturn(Deferred.fromResult(true)); 282 when(tsdb.getUidFilter()).thenReturn(filter); 283 284 when(client.get(anyGet())) // null => ID doesn't exist. 285 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 286 // Watch this! ______,^ I'm writing C++ in Java! 287 288 when(client.atomicIncrement(incrementForRow(MAXID))) 289 .thenReturn(Deferred.fromResult(5L)); 290 291 when(client.compareAndSet(anyPut(), emptyArray())) 292 .thenReturn(Deferred.fromResult(true)) 293 .thenReturn(Deferred.fromResult(true)); 294 295 assertArrayEquals(id, uid.getOrCreateId("foo")); 296 // Should be a cache hit since we created that entry. 297 assertArrayEquals(id, uid.getOrCreateId("foo")); 298 // Should be a cache hit too for the same reason. 299 assertEquals("foo", uid.getName(id)); 300 301 verify(client).get(anyGet()); // Initial Get. 302 verify(client).atomicIncrement(incrementForRow(MAXID)); 303 // Reverse + forward mappings. 304 verify(client, times(2)).compareAndSet(anyPut(), emptyArray()); 305 verify(filter, times(1)).allowUIDAssignment(any(UniqueIdType.class), anyString(), 306 anyString(), anyMapOf(String.class, String.class)); 307 } 308 309 @Test (expected = FailedToAssignUniqueIdException.class) getOrCreateIdAssignFilterBlocked()310 public void getOrCreateIdAssignFilterBlocked() { 311 uid = new UniqueId(client, table, METRIC, 3); 312 final Config config = mock(Config.class); 313 when(config.enable_realtime_uid()).thenReturn(false); 314 final TSDB tsdb = mock(TSDB.class); 315 when(tsdb.getConfig()).thenReturn(config); 316 uid.setTSDB(tsdb); 317 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 318 when(filter.fillterUIDAssignments()).thenReturn(true); 319 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 320 anyString(), anyMapOf(String.class, String.class))) 321 .thenReturn(Deferred.fromResult(false)); 322 when(tsdb.getUidFilter()).thenReturn(filter); 323 324 when(client.get(anyGet())) // null => ID doesn't exist. 325 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 326 // Watch this! ______,^ I'm writing C++ in Java! 327 328 when(client.atomicIncrement(incrementForRow(MAXID))) 329 .thenReturn(Deferred.fromResult(5L)); 330 331 when(client.compareAndSet(anyPut(), emptyArray())) 332 .thenReturn(Deferred.fromResult(true)) 333 .thenReturn(Deferred.fromResult(true)); 334 335 uid.getOrCreateId("foo"); 336 } 337 338 @Test(expected = RuntimeException.class) getOrCreateIdAssignFilterReturnException()339 public void getOrCreateIdAssignFilterReturnException() { 340 uid = new UniqueId(client, table, METRIC, 3); 341 final Config config = mock(Config.class); 342 when(config.enable_realtime_uid()).thenReturn(false); 343 final TSDB tsdb = mock(TSDB.class); 344 when(tsdb.getConfig()).thenReturn(config); 345 uid.setTSDB(tsdb); 346 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 347 when(filter.fillterUIDAssignments()).thenReturn(true); 348 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 349 anyString(), anyMapOf(String.class, String.class))) 350 .thenReturn(Deferred.<Boolean>fromError(new UnitTestException())); 351 when(tsdb.getUidFilter()).thenReturn(filter); 352 353 when(client.get(anyGet())) // null => ID doesn't exist. 354 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 355 // Watch this! ______,^ I'm writing C++ in Java! 356 357 when(client.atomicIncrement(incrementForRow(MAXID))) 358 .thenReturn(Deferred.fromResult(5L)); 359 360 when(client.compareAndSet(anyPut(), emptyArray())) 361 .thenReturn(Deferred.fromResult(true)) 362 .thenReturn(Deferred.fromResult(true)); 363 364 uid.getOrCreateId("foo"); 365 } 366 367 @Test(expected = RuntimeException.class) getOrCreateIdAssignFilterThrowsException()368 public void getOrCreateIdAssignFilterThrowsException() { 369 uid = new UniqueId(client, table, METRIC, 3); 370 final Config config = mock(Config.class); 371 when(config.enable_realtime_uid()).thenReturn(false); 372 final TSDB tsdb = mock(TSDB.class); 373 when(tsdb.getConfig()).thenReturn(config); 374 uid.setTSDB(tsdb); 375 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 376 when(filter.fillterUIDAssignments()).thenReturn(true); 377 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 378 anyString(), anyMapOf(String.class, String.class))) 379 .thenThrow(new UnitTestException()); 380 when(tsdb.getUidFilter()).thenReturn(filter); 381 382 when(client.get(anyGet())) // null => ID doesn't exist. 383 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 384 // Watch this! ______,^ I'm writing C++ in Java! 385 386 when(client.atomicIncrement(incrementForRow(MAXID))) 387 .thenReturn(Deferred.fromResult(5L)); 388 389 when(client.compareAndSet(anyPut(), emptyArray())) 390 .thenReturn(Deferred.fromResult(true)) 391 .thenReturn(Deferred.fromResult(true)); 392 393 uid.getOrCreateId("foo"); 394 } 395 396 @Test getOrCreateIdAsyncAssignFilterOK()397 public void getOrCreateIdAsyncAssignFilterOK() throws Exception { 398 uid = new UniqueId(client, table, METRIC, 3); 399 final byte[] id = { 0, 0, 5 }; 400 final Config config = mock(Config.class); 401 when(config.enable_realtime_uid()).thenReturn(false); 402 final TSDB tsdb = mock(TSDB.class); 403 when(tsdb.getConfig()).thenReturn(config); 404 uid.setTSDB(tsdb); 405 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 406 when(filter.fillterUIDAssignments()).thenReturn(true); 407 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 408 anyString(), anyMapOf(String.class, String.class))) 409 .thenReturn(Deferred.fromResult(true)); 410 when(tsdb.getUidFilter()).thenReturn(filter); 411 when(client.get(anyGet())) // null => ID doesn't exist. 412 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 413 // Watch this! ______,^ I'm writing C++ in Java! 414 415 when(client.atomicIncrement(incrementForRow(MAXID))) 416 .thenReturn(Deferred.fromResult(5L)); 417 418 when(client.compareAndSet(anyPut(), emptyArray())) 419 .thenReturn(Deferred.fromResult(true)) 420 .thenReturn(Deferred.fromResult(true)); 421 422 assertArrayEquals(id, uid.getOrCreateIdAsync("foo").join()); 423 // Should be a cache hit since we created that entry. 424 assertArrayEquals(id, uid.getOrCreateIdAsync("foo").join()); 425 // Should be a cache hit too for the same reason. 426 assertEquals("foo", uid.getName(id)); 427 428 verify(client).get(anyGet()); // Initial Get. 429 verify(client).atomicIncrement(incrementForRow(MAXID)); 430 // Reverse + forward mappings. 431 verify(client, times(2)).compareAndSet(anyPut(), emptyArray()); 432 verify(filter, times(1)).allowUIDAssignment(any(UniqueIdType.class), anyString(), 433 anyString(), anyMapOf(String.class, String.class)); 434 } 435 436 @Test (expected = FailedToAssignUniqueIdException.class) getOrCreateIdAsyncAssignFilterBlocked()437 public void getOrCreateIdAsyncAssignFilterBlocked() throws Exception { 438 uid = new UniqueId(client, table, METRIC, 3); 439 final Config config = mock(Config.class); 440 when(config.enable_realtime_uid()).thenReturn(false); 441 final TSDB tsdb = mock(TSDB.class); 442 when(tsdb.getConfig()).thenReturn(config); 443 uid.setTSDB(tsdb); 444 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 445 when(filter.fillterUIDAssignments()).thenReturn(true); 446 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 447 anyString(), anyMapOf(String.class, String.class))) 448 .thenReturn(Deferred.fromResult(false)); 449 when(tsdb.getUidFilter()).thenReturn(filter); 450 when(client.get(anyGet())) // null => ID doesn't exist. 451 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 452 453 when(client.atomicIncrement(incrementForRow(MAXID))) 454 .thenReturn(Deferred.fromResult(5L)); 455 456 when(client.compareAndSet(anyPut(), emptyArray())) 457 .thenReturn(Deferred.fromResult(true)) 458 .thenReturn(Deferred.fromResult(true)); 459 460 uid.getOrCreateIdAsync("foo").join(); 461 } 462 463 @Test (expected = UnitTestException.class) getOrCreateIdAsyncAssignFilterReturnException()464 public void getOrCreateIdAsyncAssignFilterReturnException() throws Exception { 465 uid = new UniqueId(client, table, METRIC, 3); 466 final Config config = mock(Config.class); 467 when(config.enable_realtime_uid()).thenReturn(false); 468 final TSDB tsdb = mock(TSDB.class); 469 when(tsdb.getConfig()).thenReturn(config); 470 uid.setTSDB(tsdb); 471 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 472 when(filter.fillterUIDAssignments()).thenReturn(true); 473 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 474 anyString(), anyMapOf(String.class, String.class))) 475 .thenReturn(Deferred.<Boolean>fromError(new UnitTestException())); 476 when(tsdb.getUidFilter()).thenReturn(filter); 477 when(client.get(anyGet())) // null => ID doesn't exist. 478 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 479 480 when(client.atomicIncrement(incrementForRow(MAXID))) 481 .thenReturn(Deferred.fromResult(5L)); 482 483 when(client.compareAndSet(anyPut(), emptyArray())) 484 .thenReturn(Deferred.fromResult(true)) 485 .thenReturn(Deferred.fromResult(true)); 486 487 uid.getOrCreateIdAsync("foo").join(); 488 } 489 490 @Test (expected = UnitTestException.class) getOrCreateIdAsyncAssignFilterThrowsException()491 public void getOrCreateIdAsyncAssignFilterThrowsException() throws Exception { 492 uid = new UniqueId(client, table, METRIC, 3); 493 final Config config = mock(Config.class); 494 when(config.enable_realtime_uid()).thenReturn(false); 495 final TSDB tsdb = mock(TSDB.class); 496 when(tsdb.getConfig()).thenReturn(config); 497 uid.setTSDB(tsdb); 498 final UniqueIdFilterPlugin filter = mock(UniqueIdFilterPlugin.class); 499 when(filter.fillterUIDAssignments()).thenReturn(true); 500 when(filter.allowUIDAssignment(any(UniqueIdType.class), anyString(), 501 anyString(),anyMapOf(String.class, String.class))) 502 .thenThrow(new UnitTestException()); 503 when(tsdb.getUidFilter()).thenReturn(filter); 504 when(client.get(anyGet())) // null => ID doesn't exist. 505 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 506 507 when(client.atomicIncrement(incrementForRow(MAXID))) 508 .thenReturn(Deferred.fromResult(5L)); 509 510 when(client.compareAndSet(anyPut(), emptyArray())) 511 .thenReturn(Deferred.fromResult(true)) 512 .thenReturn(Deferred.fromResult(true)); 513 514 uid.getOrCreateIdAsync("foo").join(); 515 } 516 517 @Test // Test the creation of an ID when unable to increment MAXID getOrCreateIdUnableToIncrementMaxId()518 public void getOrCreateIdUnableToIncrementMaxId() throws Exception { 519 PowerMockito.mockStatic(Thread.class); 520 521 uid = new UniqueId(client, table, METRIC, 3); 522 523 when(client.get(anyGet())) // null => ID doesn't exist. 524 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 525 // Watch this! ______,^ I'm writing C++ in Java! 526 527 HBaseException hbe = fakeHBaseException(); 528 when(client.atomicIncrement(incrementForRow(MAXID))) 529 .thenThrow(hbe); 530 PowerMockito.doNothing().when(Thread.class); Thread.sleep(anyInt()); 531 532 try { 533 uid.getOrCreateId("foo"); 534 fail("HBaseException should have been thrown!"); 535 } catch (HBaseException e) { 536 assertSame(hbe, e); 537 } 538 } 539 540 @Test // Test the creation of an ID with a race condition. getOrCreateIdAssignIdWithRaceCondition()541 public void getOrCreateIdAssignIdWithRaceCondition() { 542 // Simulate a race between client A and client B. 543 // A does a Get and sees that there's no ID for this name. 544 // B does a Get and sees that there's no ID too, and B actually goes 545 // through the entire process to create the ID. 546 // Then A attempts to go through the process and should discover that the 547 // ID has already been assigned. 548 549 uid = new UniqueId(client, table, METRIC, 3); // Used by client A. 550 HBaseClient client_b = mock(HBaseClient.class); // For client B. 551 final UniqueId uid_b = new UniqueId(client_b, table, METRIC, 3); 552 553 final byte[] id = { 0, 0, 5 }; 554 final byte[] byte_name = { 'f', 'o', 'o' }; 555 final ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 556 kvs.add(new KeyValue(byte_name, ID, METRIC_ARRAY, id)); 557 558 final Deferred<ArrayList<KeyValue>> d = 559 PowerMockito.spy(new Deferred<ArrayList<KeyValue>>()); 560 when(client.get(anyGet())) 561 .thenReturn(d) 562 .thenReturn(Deferred.fromResult(kvs)); 563 564 final Answer<byte[]> the_race = new Answer<byte[]>() { 565 public byte[] answer(final InvocationOnMock unused_invocation) throws Exception { 566 // While answering A's first Get, B doest a full getOrCreateId. 567 assertArrayEquals(id, uid_b.getOrCreateId("foo")); 568 d.callback(null); 569 return (byte[]) ((Deferred) d).join(); 570 } 571 }; 572 573 // Start the race when answering A's first Get. 574 try { 575 PowerMockito.doAnswer(the_race).when(d).joinUninterruptibly(); 576 } catch (Exception e) { 577 fail("Should never happen: " + e); 578 } 579 580 when(client_b.get(anyGet())) // null => ID doesn't exist. 581 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 582 // Watch this! ______,^ I'm writing C++ in Java! 583 584 when(client_b.atomicIncrement(incrementForRow(MAXID))) 585 .thenReturn(Deferred.fromResult(5L)); 586 587 when(client_b.compareAndSet(anyPut(), emptyArray())) 588 .thenReturn(Deferred.fromResult(true)) 589 .thenReturn(Deferred.fromResult(true)); 590 591 // Now that B is finished, A proceeds and allocates a UID that will be 592 // wasted, and creates the reverse mapping, but fails at creating the 593 // forward mapping. 594 when(client.atomicIncrement(incrementForRow(MAXID))) 595 .thenReturn(Deferred.fromResult(6L)); 596 597 when(client.compareAndSet(anyPut(), emptyArray())) 598 .thenReturn(Deferred.fromResult(true)) // Orphan reverse mapping. 599 .thenReturn(Deferred.fromResult(false)); // Already CAS'ed by A. 600 601 // Start the execution. 602 assertArrayEquals(id, uid.getOrCreateId("foo")); 603 604 // Verify the order of execution too. 605 final InOrder order = inOrder(client, client_b); 606 order.verify(client).get(anyGet()); // 1st Get for A. 607 order.verify(client_b).get(anyGet()); // 1st Get for B. 608 order.verify(client_b).atomicIncrement(incrementForRow(MAXID)); 609 order.verify(client_b, times(2)).compareAndSet(anyPut(), // both mappings. 610 emptyArray()); 611 order.verify(client).atomicIncrement(incrementForRow(MAXID)); 612 order.verify(client, times(2)).compareAndSet(anyPut(), // both mappings. 613 emptyArray()); 614 order.verify(client).get(anyGet()); // A retries and gets it. 615 } 616 617 @Test 618 // Test the creation of an ID when all possible IDs are already in use getOrCreateIdWithOverflow()619 public void getOrCreateIdWithOverflow() { 620 uid = new UniqueId(client, table, METRIC, 1); // IDs are only on 1 byte. 621 622 when(client.get(anyGet())) // null => ID doesn't exist. 623 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 624 // Watch this! ______,^ I'm writing C++ in Java! 625 626 // Update once HBASE-2292 is fixed: 627 when(client.atomicIncrement(incrementForRow(MAXID))) 628 .thenReturn(Deferred.fromResult(256L)); 629 630 try { 631 final byte[] id = uid.getOrCreateId("foo"); 632 fail("IllegalArgumentException should have been thrown but instead " 633 + " this was returned id=" + Arrays.toString(id)); 634 } catch (IllegalStateException e) { 635 // OK. 636 } 637 638 verify(client, times(1)).get(anyGet()); // Initial Get. 639 verify(client).atomicIncrement(incrementForRow(MAXID)); 640 } 641 642 @Test // ICV throws an exception, we can't get an ID. getOrCreateIdWithICVFailure()643 public void getOrCreateIdWithICVFailure() { 644 uid = new UniqueId(client, table, METRIC, 3); 645 final Config config = mock(Config.class); 646 when(config.enable_realtime_uid()).thenReturn(false); 647 final TSDB tsdb = mock(TSDB.class); 648 when(tsdb.getConfig()).thenReturn(config); 649 uid.setTSDB(tsdb); 650 651 when(client.get(anyGet())) // null => ID doesn't exist. 652 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 653 // Watch this! ______,^ I'm writing C++ in Java! 654 655 // Update once HBASE-2292 is fixed: 656 HBaseException hbe = fakeHBaseException(); 657 when(client.atomicIncrement(incrementForRow(MAXID))) 658 .thenReturn(Deferred.<Long>fromError(hbe)) 659 .thenReturn(Deferred.fromResult(5L)); 660 661 when(client.compareAndSet(anyPut(), emptyArray())) 662 .thenReturn(Deferred.fromResult(true)) 663 .thenReturn(Deferred.fromResult(true)); 664 665 final byte[] id = { 0, 0, 5 }; 666 assertArrayEquals(id, uid.getOrCreateId("foo")); 667 verify(client, times(1)).get(anyGet()); // Initial Get. 668 // First increment (failed) + retry. 669 verify(client, times(2)).atomicIncrement(incrementForRow(MAXID)); 670 // Reverse + forward mappings. 671 verify(client, times(2)).compareAndSet(anyPut(), emptyArray()); 672 } 673 674 @Test // Test that the reverse mapping is created before the forward one. getOrCreateIdPutsReverseMappingFirst()675 public void getOrCreateIdPutsReverseMappingFirst() { 676 uid = new UniqueId(client, table, METRIC, 3); 677 final Config config = mock(Config.class); 678 when(config.enable_realtime_uid()).thenReturn(false); 679 final TSDB tsdb = mock(TSDB.class); 680 when(tsdb.getConfig()).thenReturn(config); 681 uid.setTSDB(tsdb); 682 683 when(client.get(anyGet())) // null => ID doesn't exist. 684 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 685 // Watch this! ______,^ I'm writing C++ in Java! 686 687 when(client.atomicIncrement(incrementForRow(MAXID))) 688 .thenReturn(Deferred.fromResult(6L)); 689 690 when(client.compareAndSet(anyPut(), emptyArray())) 691 .thenReturn(Deferred.fromResult(true)) 692 .thenReturn(Deferred.fromResult(true)); 693 694 final byte[] id = { 0, 0, 6 }; 695 final byte[] row = { 'f', 'o', 'o' }; 696 assertArrayEquals(id, uid.getOrCreateId("foo")); 697 698 final InOrder order = inOrder(client); 699 order.verify(client).get(anyGet()); // Initial Get. 700 order.verify(client).atomicIncrement(incrementForRow(MAXID)); 701 order.verify(client).compareAndSet(putForRow(id), emptyArray()); 702 order.verify(client).compareAndSet(putForRow(row), emptyArray()); 703 } 704 705 @Test getOrCreateIdRandom()706 public void getOrCreateIdRandom() { 707 PowerMockito.mockStatic(RandomUniqueId.class); 708 uid = new UniqueId(client, table, METRIC, 3, true); 709 final long id = 42L; 710 final byte[] id_array = { 0, 0, 0x2A }; 711 712 when(RandomUniqueId.getRandomUID()).thenReturn(id); 713 when(client.get(any(GetRequest.class))) 714 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 715 716 when(client.compareAndSet(any(PutRequest.class), any(byte[].class))) 717 .thenReturn(Deferred.fromResult(true)) 718 .thenReturn(Deferred.fromResult(true)); 719 720 assertArrayEquals(id_array, uid.getOrCreateId("foo")); 721 // Should be a cache hit ... 722 assertArrayEquals(id_array, uid.getOrCreateId("foo")); 723 assertEquals(1, uid.cacheHits()); 724 assertEquals(1, uid.cacheMisses()); 725 assertEquals(2, uid.cacheSize()); 726 assertEquals(0, uid.randomIdCollisions()); 727 // ... so verify there was only one HBase Get. 728 verify(client).get(any(GetRequest.class)); 729 } 730 731 @Test getOrCreateIdRandomCollision()732 public void getOrCreateIdRandomCollision() { 733 PowerMockito.mockStatic(RandomUniqueId.class); 734 uid = new UniqueId(client, table, METRIC, 3, true); 735 final long id = 42L; 736 final byte[] id_array = { 0, 0, 0x2A }; 737 738 when(RandomUniqueId.getRandomUID()).thenReturn(24L).thenReturn(id); 739 740 when(client.get(any(GetRequest.class))) 741 .thenReturn(Deferred.fromResult((ArrayList<KeyValue>)null)); 742 743 when(client.compareAndSet(anyPut(), any(byte[].class))) 744 .thenReturn(Deferred.fromResult(false)) 745 .thenReturn(Deferred.fromResult(true)) 746 .thenReturn(Deferred.fromResult(true)); 747 748 assertArrayEquals(id_array, uid.getOrCreateId("foo")); 749 // Should be a cache hit ... 750 assertArrayEquals(id_array, uid.getOrCreateId("foo")); 751 assertEquals(1, uid.cacheHits()); 752 assertEquals(1, uid.cacheMisses()); 753 assertEquals(2, uid.cacheSize()); 754 assertEquals(1, uid.randomIdCollisions()); 755 756 // ... so verify there was only one HBase Get. 757 verify(client).get(anyGet()); 758 } 759 760 @Test getOrCreateIdRandomCollisionTooManyAttempts()761 public void getOrCreateIdRandomCollisionTooManyAttempts() { 762 PowerMockito.mockStatic(RandomUniqueId.class); 763 uid = new UniqueId(client, table, METRIC, 3, true); 764 final long id = 42L; 765 766 when(RandomUniqueId.getRandomUID()).thenReturn(24L).thenReturn(id); 767 768 when(client.get(any(GetRequest.class))) 769 .thenReturn(Deferred.fromResult((ArrayList<KeyValue>)null)); 770 771 when(client.compareAndSet(any(PutRequest.class), any(byte[].class))) 772 .thenReturn(Deferred.fromResult(false)) 773 .thenReturn(Deferred.fromResult(false)) 774 .thenReturn(Deferred.fromResult(false)) 775 .thenReturn(Deferred.fromResult(false)) 776 .thenReturn(Deferred.fromResult(false)) 777 .thenReturn(Deferred.fromResult(false)) 778 .thenReturn(Deferred.fromResult(false)) 779 .thenReturn(Deferred.fromResult(false)) 780 .thenReturn(Deferred.fromResult(false)) 781 .thenReturn(Deferred.fromResult(false)); 782 783 try { 784 final byte[] assigned_id = uid.getOrCreateId("foo"); 785 fail("FailedToAssignUniqueIdException should have been thrown but instead " 786 + " this was returned id=" + Arrays.toString(assigned_id)); 787 } catch (FailedToAssignUniqueIdException e) { 788 // OK 789 } 790 assertEquals(0, uid.cacheHits()); 791 assertEquals(1, uid.cacheMisses()); 792 assertEquals(0, uid.cacheSize()); 793 assertEquals(9, uid.randomIdCollisions()); 794 795 // ... so verify there was only one HBase Get. 796 verify(client).get(any(GetRequest.class)); 797 } 798 799 @Test getOrCreateIdRandomWithRaceCondition()800 public void getOrCreateIdRandomWithRaceCondition() { 801 PowerMockito.mockStatic(RandomUniqueId.class); 802 uid = new UniqueId(client, table, METRIC, 3, true); 803 final long id = 24L; 804 final byte[] id_array = { 0, 0, 0x2A }; 805 final byte[] byte_name = { 'f', 'o', 'o' }; 806 807 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 808 kvs.add(new KeyValue(byte_name, ID, METRIC_ARRAY, id_array)); 809 810 when(RandomUniqueId.getRandomUID()).thenReturn(id); 811 812 when(client.get(any(GetRequest.class))) 813 .thenReturn(Deferred.fromResult((ArrayList<KeyValue>)null)) 814 .thenReturn(Deferred.fromResult(kvs)); 815 816 when(client.compareAndSet(any(PutRequest.class), any(byte[].class))) 817 .thenReturn(Deferred.fromResult(true)) 818 .thenReturn(Deferred.fromResult(false)); 819 820 assertArrayEquals(id_array, uid.getOrCreateId("foo")); 821 assertEquals(0, uid.cacheHits()); 822 assertEquals(2, uid.cacheMisses()); 823 assertEquals(2, uid.cacheSize()); 824 assertEquals(1, uid.randomIdCollisions()); 825 826 // ... so verify there was only one HBase Get. 827 verify(client, times(2)).get(any(GetRequest.class)); 828 } 829 830 @Test suggestWithNoMatch()831 public void suggestWithNoMatch() { 832 uid = new UniqueId(client, table, METRIC, 3); 833 834 final Scanner fake_scanner = mock(Scanner.class); 835 when(client.newScanner(table)) 836 .thenReturn(fake_scanner); 837 838 when(fake_scanner.nextRows()) 839 .thenReturn(Deferred.<ArrayList<ArrayList<KeyValue>>>fromResult(null)); 840 // Watch this! ______,^ I'm writing C++ in Java! 841 842 final List<String> suggestions = uid.suggest("nomatch"); 843 assertEquals(0, suggestions.size()); // No results. 844 845 verify(fake_scanner).setStartKey("nomatch".getBytes()); 846 verify(fake_scanner).setStopKey("nomatci".getBytes()); 847 verify(fake_scanner).setFamily(ID); 848 verify(fake_scanner).setQualifier(METRIC_ARRAY); 849 } 850 851 @Test suggestWithMatches()852 public void suggestWithMatches() { 853 uid = new UniqueId(client, table, METRIC, 3); 854 855 final Scanner fake_scanner = mock(Scanner.class); 856 when(client.newScanner(table)) 857 .thenReturn(fake_scanner); 858 859 final ArrayList<ArrayList<KeyValue>> rows = new ArrayList<ArrayList<KeyValue>>(2); 860 final byte[] foo_bar_id = { 0, 0, 1 }; 861 { 862 ArrayList<KeyValue> row = new ArrayList<KeyValue>(1); 863 row.add(new KeyValue("foo.bar".getBytes(), ID, METRIC_ARRAY, foo_bar_id)); 864 rows.add(row); 865 row = new ArrayList<KeyValue>(1); 866 row.add(new KeyValue("foo.baz".getBytes(), ID, METRIC_ARRAY, 867 new byte[] { 0, 0, 2 })); 868 rows.add(row); 869 } 870 when(fake_scanner.nextRows()) 871 .thenReturn(Deferred.<ArrayList<ArrayList<KeyValue>>>fromResult(rows)) 872 .thenReturn(Deferred.<ArrayList<ArrayList<KeyValue>>>fromResult(null)); 873 // Watch this! ______,^ I'm writing C++ in Java! 874 875 final List<String> suggestions = uid.suggest("foo"); 876 final ArrayList<String> expected = new ArrayList<String>(2); 877 expected.add("foo.bar"); 878 expected.add("foo.baz"); 879 assertEquals(expected, suggestions); 880 // Verify that we cached the forward + backwards mapping for both results 881 // we "discovered" as a result of the scan. 882 assertEquals(4, uid.cacheSize()); 883 assertEquals(0, uid.cacheHits()); 884 885 // Verify that the cached results are usable. 886 // Should be a cache hit ... 887 assertArrayEquals(foo_bar_id, uid.getOrCreateId("foo.bar")); 888 assertEquals(1, uid.cacheHits()); 889 // ... so verify there was no HBase Get. 890 verify(client, never()).get(anyGet()); 891 } 892 893 @Test uidToString()894 public void uidToString() { 895 assertEquals("01", UniqueId.uidToString(new byte[] { 1 })); 896 } 897 898 @Test uidToString2()899 public void uidToString2() { 900 assertEquals("0A0B", UniqueId.uidToString(new byte[] { 10, 11 })); 901 } 902 903 @Test uidToString3()904 public void uidToString3() { 905 assertEquals("1A1B", UniqueId.uidToString(new byte[] { 26, 27 })); 906 } 907 908 @Test uidToStringZeros()909 public void uidToStringZeros() { 910 assertEquals("00", UniqueId.uidToString(new byte[] { 0 })); 911 } 912 913 @Test uidToString255()914 public void uidToString255() { 915 assertEquals("FF", UniqueId.uidToString(new byte[] { (byte) 255 })); 916 } 917 918 @Test (expected = NullPointerException.class) uidToStringNull()919 public void uidToStringNull() { 920 UniqueId.uidToString(null); 921 } 922 923 @Test stringToUid()924 public void stringToUid() { 925 assertArrayEquals(new byte[] { 0x0a, 0x0b }, UniqueId.stringToUid("0A0B")); 926 } 927 928 @Test stringToUidNormalize()929 public void stringToUidNormalize() { 930 assertArrayEquals(new byte[] { (byte) 171 }, UniqueId.stringToUid("AB")); 931 } 932 933 @Test stringToUidCase()934 public void stringToUidCase() { 935 assertArrayEquals(new byte[] { (byte) 11 }, UniqueId.stringToUid("B")); 936 } 937 938 @Test stringToUidWidth()939 public void stringToUidWidth() { 940 assertArrayEquals(new byte[] { (byte) 0, (byte) 42, (byte) 12 }, 941 UniqueId.stringToUid("2A0C", (short)3)); 942 } 943 944 @Test stringToUidWidth2()945 public void stringToUidWidth2() { 946 assertArrayEquals(new byte[] { (byte) 0, (byte) 0, (byte) 0 }, 947 UniqueId.stringToUid("0", (short)3)); 948 } 949 950 @Test (expected = IllegalArgumentException.class) stringToUidNull()951 public void stringToUidNull() { 952 UniqueId.stringToUid(null); 953 } 954 955 @Test (expected = IllegalArgumentException.class) stringToUidEmpty()956 public void stringToUidEmpty() { 957 UniqueId.stringToUid(""); 958 } 959 960 @Test (expected = IllegalArgumentException.class) stringToUidNotHex()961 public void stringToUidNotHex() { 962 UniqueId.stringToUid("HelloWorld"); 963 } 964 965 @Test (expected = IllegalArgumentException.class) stringToUidNotHex2()966 public void stringToUidNotHex2() { 967 UniqueId.stringToUid(" "); 968 } 969 970 @Test getTSUIDFromKey()971 public void getTSUIDFromKey() { 972 final byte[] tsuid = UniqueId.getTSUIDFromKey(new byte[] 973 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 974 assertArrayEquals(new byte[] { 0, 0, 1, 0, 0, 2, 0, 0, 3 }, 975 tsuid); 976 } 977 978 @Test getTSUIDFromKeySalted()979 public void getTSUIDFromKeySalted() { 980 PowerMockito.mockStatic(Const.class); 981 PowerMockito.when(Const.SALT_WIDTH()).thenReturn(1); 982 983 final byte[] expected = { 0, 0, 1, 0, 0, 2, 0, 0, 3 }; 984 byte[] tsuid = UniqueId.getTSUIDFromKey(new byte[] 985 { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 986 assertArrayEquals(expected, tsuid); 987 988 tsuid = UniqueId.getTSUIDFromKey(new byte[] 989 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 990 assertArrayEquals(expected, tsuid); 991 992 PowerMockito.when(Const.SALT_WIDTH()).thenReturn(4); 993 tsuid = UniqueId.getTSUIDFromKey(new byte[] 994 { 1, 2, 3, 4, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 995 assertArrayEquals(expected, tsuid); 996 997 tsuid = UniqueId.getTSUIDFromKey(new byte[] 998 { 4, 3, 2, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 999 assertArrayEquals(expected, tsuid); 1000 } 1001 1002 @Test (expected = IllegalArgumentException.class) getTSUIDFromKeyMissingTags()1003 public void getTSUIDFromKeyMissingTags() { 1004 UniqueId.getTSUIDFromKey(new byte[] 1005 { 0, 0, 1, 1, 1, 1, 1 }, (short)3, (short)4); 1006 } 1007 1008 @Test (expected = IllegalArgumentException.class) getTSUIDFromKeyMissingTagsSalted()1009 public void getTSUIDFromKeyMissingTagsSalted() { 1010 PowerMockito.mockStatic(Const.class); 1011 PowerMockito.when(Const.SALT_WIDTH()).thenReturn(1); 1012 1013 UniqueId.getTSUIDFromKey(new byte[] 1014 { 0, 0, 0, 1, 1, 1, 1, 1 }, (short)3, (short)4); 1015 } 1016 1017 @Test (expected = IllegalArgumentException.class) getTSUIDFromKeyMissingSalt()1018 public void getTSUIDFromKeyMissingSalt() { 1019 PowerMockito.mockStatic(Const.class); 1020 PowerMockito.when(Const.SALT_WIDTH()).thenReturn(1); 1021 1022 UniqueId.getTSUIDFromKey(new byte[] 1023 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 1024 } 1025 1026 @Test (expected = IllegalArgumentException.class) getTSUIDFromKeySaltButShouldntBe()1027 public void getTSUIDFromKeySaltButShouldntBe() { 1028 UniqueId.getTSUIDFromKey(new byte[] 1029 { 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 0, 3 }, (short)3, (short)4); 1030 } 1031 1032 @Test getTagPairsFromTSUIDString()1033 public void getTagPairsFromTSUIDString() { 1034 List<byte[]> tags = UniqueId.getTagPairsFromTSUID( 1035 "000000000001000002000003000004"); 1036 assertNotNull(tags); 1037 assertEquals(2, tags.size()); 1038 assertArrayEquals(new byte[] { 0, 0, 1, 0, 0, 2 }, tags.get(0)); 1039 assertArrayEquals(new byte[] { 0, 0, 3, 0, 0, 4 }, tags.get(1)); 1040 } 1041 1042 @Test getTagPairsFromTSUIDStringNonStandardWidth()1043 public void getTagPairsFromTSUIDStringNonStandardWidth() { 1044 PowerMockito.mockStatic(TSDB.class); 1045 when(TSDB.metrics_width()).thenReturn((short)3); 1046 when(TSDB.tagk_width()).thenReturn((short)4); 1047 when(TSDB.tagv_width()).thenReturn((short)3); 1048 1049 List<byte[]> tags = UniqueId.getTagPairsFromTSUID( 1050 "0000000000000100000200000003000004"); 1051 assertNotNull(tags); 1052 assertEquals(2, tags.size()); 1053 assertArrayEquals(new byte[] { 0, 0, 0, 1, 0, 0, 2 }, tags.get(0)); 1054 assertArrayEquals(new byte[] { 0, 0, 0, 3, 0, 0, 4 }, tags.get(1)); 1055 } 1056 1057 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringMissingTags()1058 public void getTagPairsFromTSUIDStringMissingTags() { 1059 UniqueId.getTagPairsFromTSUID("123456"); 1060 } 1061 1062 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringMissingMetric()1063 public void getTagPairsFromTSUIDStringMissingMetric() { 1064 UniqueId.getTagPairsFromTSUID("000001000002"); 1065 } 1066 1067 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringOddNumberOfCharacters()1068 public void getTagPairsFromTSUIDStringOddNumberOfCharacters() { 1069 UniqueId.getTagPairsFromTSUID("0000080000010000020"); 1070 } 1071 1072 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringMissingTagv()1073 public void getTagPairsFromTSUIDStringMissingTagv() { 1074 UniqueId.getTagPairsFromTSUID("000008000001"); 1075 } 1076 1077 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringNull()1078 public void getTagPairsFromTSUIDStringNull() { 1079 UniqueId.getTagPairsFromTSUID((String)null); 1080 } 1081 1082 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDStringEmpty()1083 public void getTagPairsFromTSUIDStringEmpty() { 1084 UniqueId.getTagPairsFromTSUID(""); 1085 } 1086 1087 @Test getTagPairsFromTSUIDBytes()1088 public void getTagPairsFromTSUIDBytes() { 1089 List<byte[]> tags = UniqueId.getTagPairsFromTSUID( 1090 new byte[] { 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4 }); 1091 assertNotNull(tags); 1092 assertEquals(2, tags.size()); 1093 assertArrayEquals(new byte[] { 0, 0, 1, 0, 0, 2 }, tags.get(0)); 1094 assertArrayEquals(new byte[] { 0, 0, 3, 0, 0, 4 }, tags.get(1)); 1095 } 1096 1097 @Test getTagPairsFromTSUIDBytesNonStandardWidth()1098 public void getTagPairsFromTSUIDBytesNonStandardWidth() { 1099 PowerMockito.mockStatic(TSDB.class); 1100 when(TSDB.metrics_width()).thenReturn((short)3); 1101 when(TSDB.tagk_width()).thenReturn((short)4); 1102 when(TSDB.tagv_width()).thenReturn((short)3); 1103 1104 List<byte[]> tags = UniqueId.getTagPairsFromTSUID( 1105 new byte[] { 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 3, 0, 0, 4 }); 1106 assertNotNull(tags); 1107 assertEquals(2, tags.size()); 1108 assertArrayEquals(new byte[] { 0, 0, 0, 1, 0, 0, 2 }, tags.get(0)); 1109 assertArrayEquals(new byte[] { 0, 0, 0, 3, 0, 0, 4 }, tags.get(1)); 1110 } 1111 1112 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDBytesMissingTags()1113 public void getTagPairsFromTSUIDBytesMissingTags() { 1114 UniqueId.getTagPairsFromTSUID(new byte[] { 0, 0, 1 }); 1115 } 1116 1117 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDBytesMissingMetric()1118 public void getTagPairsFromTSUIDBytesMissingMetric() { 1119 UniqueId.getTagPairsFromTSUID(new byte[] { 0, 0, 1, 0, 0, 2 }); 1120 } 1121 1122 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDBytesMissingTagv()1123 public void getTagPairsFromTSUIDBytesMissingTagv() { 1124 UniqueId.getTagPairsFromTSUID(new byte[] { 0, 0, 8, 0, 0, 2 }); 1125 } 1126 1127 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDBytesNull()1128 public void getTagPairsFromTSUIDBytesNull() { 1129 UniqueId.getTagPairsFromTSUID((byte[])null); 1130 } 1131 1132 @Test (expected = IllegalArgumentException.class) getTagPairsFromTSUIDBytesEmpty()1133 public void getTagPairsFromTSUIDBytesEmpty() { 1134 UniqueId.getTagPairsFromTSUID(new byte[0]); 1135 } 1136 1137 @Test getTagFromTSUID()1138 public void getTagFromTSUID() { 1139 List<byte[]> tags = UniqueId.getTagsFromTSUID( 1140 "000000000001000002000003000004"); 1141 assertNotNull(tags); 1142 assertEquals(4, tags.size()); 1143 assertArrayEquals(new byte[] { 0, 0, 1 }, tags.get(0)); 1144 assertArrayEquals(new byte[] { 0, 0, 2 }, tags.get(1)); 1145 assertArrayEquals(new byte[] { 0, 0, 3 }, tags.get(2)); 1146 assertArrayEquals(new byte[] { 0, 0, 4 }, tags.get(3)); 1147 } 1148 1149 @Test getTagFromTSUIDNonStandardWidth()1150 public void getTagFromTSUIDNonStandardWidth() { 1151 PowerMockito.mockStatic(TSDB.class); 1152 when(TSDB.metrics_width()).thenReturn((short)3); 1153 when(TSDB.tagk_width()).thenReturn((short)4); 1154 when(TSDB.tagv_width()).thenReturn((short)3); 1155 1156 List<byte[]> tags = UniqueId.getTagsFromTSUID( 1157 "0000000000000100000200000003000004"); 1158 assertNotNull(tags); 1159 assertEquals(4, tags.size()); 1160 assertArrayEquals(new byte[] { 0, 0, 0, 1 }, tags.get(0)); 1161 assertArrayEquals(new byte[] { 0, 0, 2 }, tags.get(1)); 1162 assertArrayEquals(new byte[] { 0, 0, 0, 3 }, tags.get(2)); 1163 assertArrayEquals(new byte[] { 0, 0, 4 }, tags.get(3)); 1164 } 1165 1166 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDMissingTags()1167 public void getTagFromTSUIDMissingTags() { 1168 UniqueId.getTagsFromTSUID("123456"); 1169 } 1170 1171 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDMissingMetric()1172 public void getTagFromTSUIDMissingMetric() { 1173 UniqueId.getTagsFromTSUID("000001000002"); 1174 } 1175 1176 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDOddNumberOfCharacters()1177 public void getTagFromTSUIDOddNumberOfCharacters() { 1178 UniqueId.getTagsFromTSUID("0000080000010000020"); 1179 } 1180 1181 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDMissingTagv()1182 public void getTagFromTSUIDMissingTagv() { 1183 UniqueId.getTagsFromTSUID("000008000001"); 1184 } 1185 1186 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDNull()1187 public void getTagFromTSUIDNull() { 1188 UniqueId.getTagsFromTSUID(null); 1189 } 1190 1191 @Test (expected = IllegalArgumentException.class) getTagFromTSUIDEmpty()1192 public void getTagFromTSUIDEmpty() { 1193 UniqueId.getTagsFromTSUID(""); 1194 } 1195 1196 @Test getUsedUIDs()1197 public void getUsedUIDs() throws Exception { 1198 final ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(3); 1199 final byte[] metrics = { 'm', 'e', 't', 'r', 'i', 'c', 's' }; 1200 final byte[] tagk = { 't', 'a', 'g', 'k' }; 1201 final byte[] tagv = { 't', 'a', 'g', 'v' }; 1202 kvs.add(new KeyValue(MAXID, ID, metrics, Bytes.fromLong(64L))); 1203 kvs.add(new KeyValue(MAXID, ID, tagk, Bytes.fromLong(42L))); 1204 kvs.add(new KeyValue(MAXID, ID, tagv, Bytes.fromLong(1024L))); 1205 final TSDB tsdb = mock(TSDB.class); 1206 when(tsdb.getClient()).thenReturn(client); 1207 when(tsdb.uidTable()).thenReturn(new byte[] { 'u', 'i', 'd' }); 1208 when(client.get(anyGet())) 1209 .thenReturn(Deferred.fromResult(kvs)); 1210 1211 final byte[][] kinds = { metrics, tagk, tagv }; 1212 final Map<String, Long> uids = UniqueId.getUsedUIDs(tsdb, kinds) 1213 .joinUninterruptibly(); 1214 assertNotNull(uids); 1215 assertEquals(3, uids.size()); 1216 assertEquals(64L, uids.get("metrics").longValue()); 1217 assertEquals(42L, uids.get("tagk").longValue()); 1218 assertEquals(1024L, uids.get("tagv").longValue()); 1219 } 1220 1221 @Test getUsedUIDsEmptyRow()1222 public void getUsedUIDsEmptyRow() throws Exception { 1223 final ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(0); 1224 final byte[] metrics = { 'm', 'e', 't', 'r', 'i', 'c', 's' }; 1225 final byte[] tagk = { 't', 'a', 'g', 'k' }; 1226 final byte[] tagv = { 't', 'a', 'g', 'v' }; 1227 final TSDB tsdb = mock(TSDB.class); 1228 when(tsdb.getClient()).thenReturn(client); 1229 when(tsdb.uidTable()).thenReturn(new byte[] { 'u', 'i', 'd' }); 1230 when(client.get(anyGet())) 1231 .thenReturn(Deferred.fromResult(kvs)); 1232 1233 final byte[][] kinds = { metrics, tagk, tagv }; 1234 final Map<String, Long> uids = UniqueId.getUsedUIDs(tsdb, kinds) 1235 .joinUninterruptibly(); 1236 assertNotNull(uids); 1237 assertEquals(3, uids.size()); 1238 assertEquals(0L, uids.get("metrics").longValue()); 1239 assertEquals(0L, uids.get("tagk").longValue()); 1240 assertEquals(0L, uids.get("tagv").longValue()); 1241 } 1242 1243 @Test uidToLong()1244 public void uidToLong() throws Exception { 1245 assertEquals(42, UniqueId.uidToLong(new byte[] { 0, 0, 0x2A }, (short)3)); 1246 } 1247 1248 @Test uidToLongFromString()1249 public void uidToLongFromString() throws Exception { 1250 assertEquals(42L, UniqueId.uidToLong("00002A", (short) 3)); 1251 } 1252 1253 @Test (expected = IllegalArgumentException.class) uidToLongTooLong()1254 public void uidToLongTooLong() throws Exception { 1255 UniqueId.uidToLong(new byte[] { 0, 0, 0, 0x2A }, (short)3); 1256 } 1257 1258 @Test (expected = IllegalArgumentException.class) uidToLongTooShort()1259 public void uidToLongTooShort() throws Exception { 1260 UniqueId.uidToLong(new byte[] { 0, 0x2A }, (short)3); 1261 } 1262 1263 @Test (expected = NullPointerException.class) uidToLongNull()1264 public void uidToLongNull() throws Exception { 1265 UniqueId.uidToLong((byte[])null, (short)3); 1266 } 1267 1268 @Test longToUID()1269 public void longToUID() throws Exception { 1270 assertArrayEquals(new byte[] { 0, 0, 0x2A }, 1271 UniqueId.longToUID(42L, (short)3)); 1272 } 1273 1274 @Test (expected = IllegalStateException.class) longToUIDTooBig()1275 public void longToUIDTooBig() throws Exception { 1276 UniqueId.longToUID(257, (short)1); 1277 } 1278 1279 @Test rename()1280 public void rename() throws Exception { 1281 uid = new UniqueId(client, table, METRIC, 3); 1282 final byte[] foo_id = { 0, 'a', 0x42 }; 1283 final byte[] foo_name = { 'f', 'o', 'o' }; 1284 1285 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 1286 kvs.add(new KeyValue(foo_name, ID, METRIC_ARRAY, foo_id)); 1287 when(client.get(anyGet())) 1288 .thenReturn(Deferred.fromResult(kvs)) 1289 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 1290 when(client.put(anyPut())).thenAnswer(answerTrue()); 1291 when(client.delete(anyDelete())).thenAnswer(answerTrue()); 1292 1293 uid.rename("foo", "bar"); 1294 } 1295 1296 @Test (expected = IllegalArgumentException.class) renameNewNameExists()1297 public void renameNewNameExists() throws Exception { 1298 uid = new UniqueId(client, table, METRIC, 3); 1299 final byte[] foo_id = { 0, 'a', 0x42 }; 1300 final byte[] foo_name = { 'f', 'o', 'o' }; 1301 final byte[] bar_id = { 1, 'b', 0x43 }; 1302 final byte[] bar_name = { 'b', 'a', 'r' }; 1303 1304 ArrayList<KeyValue> foo_kvs = new ArrayList<KeyValue>(1); 1305 ArrayList<KeyValue> bar_kvs = new ArrayList<KeyValue>(1); 1306 foo_kvs.add(new KeyValue(foo_name, ID, METRIC_ARRAY, foo_id)); 1307 bar_kvs.add(new KeyValue(bar_name, ID, METRIC_ARRAY, bar_id)); 1308 when(client.get(anyGet())) 1309 .thenReturn(Deferred.fromResult(foo_kvs)) 1310 .thenReturn(Deferred.fromResult(bar_kvs)); 1311 when(client.put(anyPut())).thenAnswer(answerTrue()); 1312 when(client.delete(anyDelete())).thenAnswer(answerTrue()); 1313 1314 uid.rename("foo", "bar"); 1315 } 1316 1317 @Test (expected = IllegalStateException.class) renameRaceCondition()1318 public void renameRaceCondition() throws Exception { 1319 // Simulate a race between client A(default) and client B. 1320 // A and B rename same UID to different name. 1321 // B waits till A start to invoke PutRequest to start. 1322 1323 uid = new UniqueId(client, table, METRIC, 3); 1324 HBaseClient client_b = mock(HBaseClient.class); 1325 final UniqueId uid_b = new UniqueId(client_b, table, METRIC, 3); 1326 1327 final byte[] foo_id = { 0, 'a', 0x42 }; 1328 final byte[] foo_name = { 'f', 'o', 'o' }; 1329 1330 ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(1); 1331 kvs.add(new KeyValue(foo_name, ID, METRIC_ARRAY, foo_id)); 1332 1333 when(client_b.get(anyGet())) 1334 .thenReturn(Deferred.fromResult(kvs)) 1335 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 1336 when(client_b.put(anyPut())).thenAnswer(answerTrue()); 1337 when(client_b.delete(anyDelete())).thenAnswer(answerTrue()); 1338 1339 final Answer<Deferred<Boolean>> the_race = new Answer<Deferred<Boolean>>() { 1340 public Deferred<Boolean> answer(final InvocationOnMock inv) throws Exception { 1341 uid_b.rename("foo", "xyz"); 1342 return Deferred.fromResult(true); 1343 } 1344 }; 1345 1346 when(client.get(anyGet())) 1347 .thenReturn(Deferred.fromResult(kvs)) 1348 .thenReturn(Deferred.<ArrayList<KeyValue>>fromResult(null)); 1349 when(client.put(anyPut())).thenAnswer(the_race); 1350 when(client.delete(anyDelete())).thenAnswer(answerTrue()); 1351 1352 uid.rename("foo", "bar"); 1353 } 1354 1355 @Test deleteCached()1356 public void deleteCached() throws Exception { 1357 setupStorage(); 1358 uid = new UniqueId(client, table, METRIC, 3); 1359 uid.setTSDB(tsdb); 1360 assertArrayEquals(UID, uid.getId("sys.cpu.user")); 1361 assertEquals("sys.cpu.user", uid.getName(UID)); 1362 1363 uid.deleteAsync("sys.cpu.user").join(); 1364 try { 1365 uid.getId("sys.cpu.user"); 1366 fail("Expected a NoSuchUniqueName"); 1367 } catch (NoSuchUniqueName nsun) { } 1368 1369 try { 1370 uid.getName(UID); 1371 fail("Expected a NoSuchUniqueId"); 1372 } catch (NoSuchUniqueId nsui) { } 1373 1374 uid = new UniqueId(client, table, TAGK, 3); 1375 uid.setTSDB(tsdb); 1376 assertArrayEquals(UID, uid.getId("host")); 1377 assertEquals("host", uid.getName(UID)); 1378 1379 uid = new UniqueId(client, table, TAGV, 3); 1380 uid.setTSDB(tsdb); 1381 assertArrayEquals(UID, uid.getId("web01")); 1382 assertEquals("web01", uid.getName(UID)); 1383 } 1384 1385 @Test deleteNotCached()1386 public void deleteNotCached() throws Exception { 1387 setupStorage(); 1388 uid = new UniqueId(client, table, METRIC, 3); 1389 uid.setTSDB(tsdb); 1390 uid.deleteAsync("sys.cpu.user").join(); 1391 try { 1392 uid.getId("sys.cpu.user"); 1393 fail("Expected a NoSuchUniqueName"); 1394 } catch (NoSuchUniqueName nsun) { } 1395 1396 try { 1397 uid.getName(UID); 1398 fail("Expected a NoSuchUniqueId"); 1399 } catch (NoSuchUniqueId nsui) { } 1400 1401 uid = new UniqueId(client, table, TAGK, 3); 1402 uid.setTSDB(tsdb); 1403 assertArrayEquals(UID, uid.getId("host")); 1404 assertEquals("host", uid.getName(UID)); 1405 1406 uid = new UniqueId(client, table, TAGV, 3); 1407 uid.setTSDB(tsdb); 1408 assertArrayEquals(UID, uid.getId("web01")); 1409 assertEquals("web01", uid.getName(UID)); 1410 } 1411 1412 @Test deleteFailForwardDelete()1413 public void deleteFailForwardDelete() throws Exception { 1414 setupStorage(); 1415 uid = new UniqueId(client, table, METRIC, 3); 1416 uid.setTSDB(tsdb); 1417 assertArrayEquals(UID, uid.getId("sys.cpu.user")); 1418 assertEquals("sys.cpu.user", uid.getName(UID)); 1419 1420 storage.throwException("sys.cpu.user".getBytes(), fakeHBaseException()); 1421 try { 1422 uid.deleteAsync("sys.cpu.user").join(); 1423 fail("Expected HBaseException"); 1424 } catch (HBaseException e) { } 1425 catch (Exception e) { } 1426 storage.clearExceptions(); 1427 try { 1428 uid.getName(UID); 1429 fail("Expected a NoSuchUniqueId"); 1430 } catch (NoSuchUniqueId nsui) { } 1431 assertArrayEquals(UID, uid.getId("sys.cpu.user")); 1432 // now it pollutes the cache 1433 assertEquals("sys.cpu.user", uid.getName(UID)); 1434 } 1435 1436 @Test deleteFailReverseDelete()1437 public void deleteFailReverseDelete() throws Exception { 1438 setupStorage(); 1439 storage.throwException(UID, fakeHBaseException()); 1440 uid = new UniqueId(client, table, METRIC, 3); 1441 uid.setTSDB(tsdb); 1442 try { 1443 uid.deleteAsync("sys.cpu.user").join(); 1444 fail("Expected HBaseException"); 1445 } catch (HBaseException e) { } 1446 catch (Exception e) { } 1447 storage.clearExceptions(); 1448 try { 1449 uid.getId("sys.cpu.user"); 1450 fail("Expected a NoSuchUniqueName"); 1451 } catch (NoSuchUniqueName nsun) { } 1452 assertEquals("sys.cpu.user", uid.getName(UID)); 1453 } 1454 1455 @Test deleteNoSuchUniqueName()1456 public void deleteNoSuchUniqueName() throws Exception { 1457 setupStorage(); 1458 uid = new UniqueId(client, table, METRIC, 3); 1459 uid.setTSDB(tsdb); 1460 storage.flushRow(table, "sys.cpu.user".getBytes()); 1461 try { 1462 uid.deleteAsync("sys.cpu.user").join(); 1463 fail("Expected NoSuchUniqueName"); 1464 } catch (NoSuchUniqueName e) { } 1465 assertEquals("sys.cpu.user", uid.getName(UID)); 1466 } 1467 1468 // ----------------- // 1469 // Helper functions. // 1470 // ----------------- // 1471 setupStorage()1472 private void setupStorage() throws Exception { 1473 final Config config = mock(Config.class); 1474 when(tsdb.getConfig()).thenReturn(config); 1475 when(tsdb.getClient()).thenReturn(client); 1476 storage = new MockBase(tsdb, client, true, true, true, true); 1477 1478 final List<byte[]> families = new ArrayList<byte[]>(); 1479 families.add(ID); 1480 families.add(NAME); 1481 storage.addTable(table, families); 1482 1483 storage.addColumn(table, "sys.cpu.user".getBytes(), ID, METRIC_ARRAY, UID); 1484 storage.addColumn(table, UID, NAME, METRIC_ARRAY, "sys.cpu.user".getBytes()); 1485 storage.addColumn(table, "host".getBytes(), ID, TAGK_ARRAY, UID); 1486 storage.addColumn(table, UID, NAME, TAGK_ARRAY, "host".getBytes()); 1487 storage.addColumn(table, "web01".getBytes(), ID, TAGV_ARRAY, UID); 1488 storage.addColumn(table, UID, NAME,TAGV_ARRAY, "web01".getBytes()); 1489 } 1490 emptyArray()1491 private static byte[] emptyArray() { 1492 return eq(HBaseClient.EMPTY_ARRAY); 1493 } 1494 anyGet()1495 private static GetRequest anyGet() { 1496 return any(GetRequest.class); 1497 } 1498 incrementForRow(final byte[] row)1499 private static AtomicIncrementRequest incrementForRow(final byte[] row) { 1500 return argThat(new ArgumentMatcher<AtomicIncrementRequest>() { 1501 public boolean matches(Object incr) { 1502 return Arrays.equals(((AtomicIncrementRequest) incr).key(), row); 1503 } 1504 public void describeTo(org.hamcrest.Description description) { 1505 description.appendText("AtomicIncrementRequest for row " 1506 + Arrays.toString(row)); 1507 } 1508 }); 1509 } 1510 1511 private static PutRequest anyPut() { 1512 return any(PutRequest.class); 1513 } 1514 1515 private static DeleteRequest anyDelete() { 1516 return any(DeleteRequest.class); 1517 } 1518 1519 private static Answer<Deferred<Boolean>> answerTrue() { 1520 return new Answer<Deferred<Boolean>>() { 1521 public Deferred<Boolean> answer(final InvocationOnMock inv) { 1522 return Deferred.fromResult(true); 1523 } 1524 }; 1525 } 1526 1527 @SuppressWarnings("unchecked") 1528 private static Callback<byte[], ArrayList<KeyValue>> anyByteCB() { 1529 return any(Callback.class); 1530 } 1531 1532 private static PutRequest putForRow(final byte[] row) { 1533 return argThat(new ArgumentMatcher<PutRequest>() { 1534 public boolean matches(Object put) { 1535 return Arrays.equals(((PutRequest) put).key(), row); 1536 } 1537 public void describeTo(org.hamcrest.Description description) { 1538 description.appendText("PutRequest for row " + Arrays.toString(row)); 1539 } 1540 }); 1541 } 1542 1543 private static HBaseException fakeHBaseException() { 1544 final HBaseException hbe = mock(HBaseException.class); 1545 when(hbe.getStackTrace()) 1546 // Truncate the stack trace because otherwise it's gigantic. 1547 .thenReturn(Arrays.copyOf(new RuntimeException().getStackTrace(), 3)); 1548 when(hbe.getMessage()) 1549 .thenReturn("fake exception"); 1550 return hbe; 1551 } 1552 1553 private static final byte[] MAXID = { 0 }; 1554 1555 } 1556