001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.rest.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertNull; 024import static org.junit.Assert.assertTrue; 025 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.List; 031import org.apache.hadoop.hbase.Cell; 032import org.apache.hadoop.hbase.CellUtil; 033import org.apache.hadoop.hbase.HBaseClassTestRule; 034import org.apache.hadoop.hbase.HBaseTestingUtil; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.hadoop.hbase.client.Admin; 037import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 038import org.apache.hadoop.hbase.client.Delete; 039import org.apache.hadoop.hbase.client.Get; 040import org.apache.hadoop.hbase.client.Put; 041import org.apache.hadoop.hbase.client.Result; 042import org.apache.hadoop.hbase.client.ResultScanner; 043import org.apache.hadoop.hbase.client.Scan; 044import org.apache.hadoop.hbase.client.Table; 045import org.apache.hadoop.hbase.client.TableDescriptor; 046import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 047import org.apache.hadoop.hbase.rest.HBaseRESTTestingUtility; 048import org.apache.hadoop.hbase.rest.RESTServlet; 049import org.apache.hadoop.hbase.testclassification.MediumTests; 050import org.apache.hadoop.hbase.testclassification.RestTests; 051import org.apache.hadoop.hbase.util.Bytes; 052import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 053import org.apache.http.Header; 054import org.apache.http.message.BasicHeader; 055import org.junit.After; 056import org.junit.AfterClass; 057import org.junit.Before; 058import org.junit.BeforeClass; 059import org.junit.ClassRule; 060import org.junit.Test; 061import org.junit.experimental.categories.Category; 062 063@Category({ RestTests.class, MediumTests.class }) 064public class TestRemoteTable { 065 @ClassRule 066 public static final HBaseClassTestRule CLASS_RULE = 067 HBaseClassTestRule.forClass(TestRemoteTable.class); 068 069 // Verify that invalid URL characters and arbitrary bytes are escaped when 070 // constructing REST URLs per HBASE-7621. RemoteHTable should support row keys 071 // and qualifiers containing any byte for all table operations. 072 private static final String INVALID_URL_CHARS_1 = 073 "|\"\\^{}\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000B\u000C"; 074 075 // HColumnDescriptor prevents certain characters in column names. The following 076 // are examples of characters are allowed in column names but are not valid in 077 // URLs. 078 private static final String INVALID_URL_CHARS_2 = "|^{}\u0242"; 079 080 // Besides alphanumeric these characters can also be present in table names. 081 private static final String VALID_TABLE_NAME_CHARS = "_-."; 082 083 private static final TableName TABLE = 084 TableName.valueOf("TestRemoteTable" + VALID_TABLE_NAME_CHARS); 085 086 private static final byte[] ROW_1 = Bytes.toBytes("testrow1" + INVALID_URL_CHARS_1); 087 private static final byte[] ROW_2 = Bytes.toBytes("testrow2" + INVALID_URL_CHARS_1); 088 private static final byte[] ROW_3 = Bytes.toBytes("testrow3" + INVALID_URL_CHARS_1); 089 private static final byte[] ROW_4 = Bytes.toBytes("testrow4" + INVALID_URL_CHARS_1); 090 091 private static final byte[] COLUMN_1 = Bytes.toBytes("a" + INVALID_URL_CHARS_2); 092 private static final byte[] COLUMN_2 = Bytes.toBytes("b" + INVALID_URL_CHARS_2); 093 private static final byte[] COLUMN_3 = Bytes.toBytes("c" + INVALID_URL_CHARS_2); 094 095 private static final byte[] QUALIFIER_1 = Bytes.toBytes("1" + INVALID_URL_CHARS_1); 096 private static final byte[] QUALIFIER_2 = Bytes.toBytes("2" + INVALID_URL_CHARS_1); 097 private static final byte[] VALUE_1 = Bytes.toBytes("testvalue1"); 098 private static final byte[] VALUE_2 = Bytes.toBytes("testvalue2"); 099 100 private static final long ONE_HOUR = 60 * 60 * 1000; 101 private static final long TS_2 = EnvironmentEdgeManager.currentTime(); 102 private static final long TS_1 = TS_2 - ONE_HOUR; 103 104 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 105 private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility(); 106 private RemoteHTable remoteTable; 107 108 @BeforeClass 109 public static void setUpBeforeClass() throws Exception { 110 TEST_UTIL.startMiniCluster(); 111 REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration()); 112 } 113 114 @Before 115 public void before() throws Exception { 116 Admin admin = TEST_UTIL.getAdmin(); 117 if (admin.tableExists(TABLE)) { 118 if (admin.isTableEnabled(TABLE)) { 119 admin.disableTable(TABLE); 120 } 121 122 admin.deleteTable(TABLE); 123 } 124 125 TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(TABLE) 126 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_1).setMaxVersions(3).build()) 127 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_2).setMaxVersions(3).build()) 128 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_3).setMaxVersions(3).build()) 129 .build(); 130 admin.createTable(tableDescriptor); 131 try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) { 132 Put put = new Put(ROW_1); 133 put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_1); 134 table.put(put); 135 put = new Put(ROW_2); 136 put.addColumn(COLUMN_1, QUALIFIER_1, TS_1, VALUE_1); 137 put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_2); 138 put.addColumn(COLUMN_2, QUALIFIER_2, TS_2, VALUE_2); 139 table.put(put); 140 } 141 remoteTable = 142 new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())), 143 TEST_UTIL.getConfiguration(), TABLE.toBytes()); 144 } 145 146 @After 147 public void after() throws Exception { 148 remoteTable.close(); 149 } 150 151 @AfterClass 152 public static void tearDownAfterClass() throws Exception { 153 REST_TEST_UTIL.shutdownServletContainer(); 154 TEST_UTIL.shutdownMiniCluster(); 155 } 156 157 @Test 158 public void testGetTableDescriptor() throws IOException { 159 try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) { 160 TableDescriptor local = table.getDescriptor(); 161 assertEquals(remoteTable.getDescriptor(), local); 162 } 163 } 164 165 @Test 166 public void testGet() throws IOException { 167 // Requires UriCompliance.Violation.SUSPICIOUS_PATH_CHARACTERS 168 // Otherwise fails with "400: Suspicious Path Character" 169 // In this test, the request path resolves to 170 // "/TestRemoteTable_-./testrow1%7C%22%5C%5E%7B%7D%01%02%03%04%05%06%07%08%09%0B%0C/" 171 // and is considered suspicious by the Jetty 12. 172 // Basically ROW_1 contains invalid URL characters here. 173 Get get = new Get(ROW_1); 174 Result result = remoteTable.get(get); 175 byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1); 176 byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2); 177 assertNotNull(value1); 178 assertTrue(Bytes.equals(VALUE_1, value1)); 179 assertNull(value2); 180 181 get = new Get(ROW_1); 182 get.addFamily(COLUMN_3); 183 result = remoteTable.get(get); 184 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 185 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 186 assertNull(value1); 187 assertNull(value2); 188 189 get = new Get(ROW_1); 190 get.addColumn(COLUMN_1, QUALIFIER_1); 191 get.addColumn(COLUMN_2, QUALIFIER_2); 192 result = remoteTable.get(get); 193 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 194 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 195 assertNotNull(value1); 196 assertTrue(Bytes.equals(VALUE_1, value1)); 197 assertNull(value2); 198 199 get = new Get(ROW_2); 200 result = remoteTable.get(get); 201 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 202 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 203 assertNotNull(value1); 204 assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2 205 assertNotNull(value2); 206 assertTrue(Bytes.equals(VALUE_2, value2)); 207 208 get = new Get(ROW_2); 209 get.addFamily(COLUMN_1); 210 result = remoteTable.get(get); 211 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 212 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 213 assertNotNull(value1); 214 assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2 215 assertNull(value2); 216 217 get = new Get(ROW_2); 218 get.addColumn(COLUMN_1, QUALIFIER_1); 219 get.addColumn(COLUMN_2, QUALIFIER_2); 220 result = remoteTable.get(get); 221 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 222 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 223 assertNotNull(value1); 224 assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2 225 assertNotNull(value2); 226 assertTrue(Bytes.equals(VALUE_2, value2)); 227 228 // test timestamp 229 get = new Get(ROW_2); 230 get.addFamily(COLUMN_1); 231 get.addFamily(COLUMN_2); 232 get.setTimestamp(TS_1); 233 result = remoteTable.get(get); 234 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 235 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 236 assertNotNull(value1); 237 assertTrue(Bytes.equals(VALUE_1, value1)); // @TS_1 238 assertNull(value2); 239 240 // test timerange 241 get = new Get(ROW_2); 242 get.addFamily(COLUMN_1); 243 get.addFamily(COLUMN_2); 244 get.setTimeRange(0, TS_1 + 1); 245 result = remoteTable.get(get); 246 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 247 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 248 assertNotNull(value1); 249 assertTrue(Bytes.equals(VALUE_1, value1)); // @TS_1 250 assertNull(value2); 251 252 // test maxVersions 253 get = new Get(ROW_2); 254 get.addFamily(COLUMN_1); 255 get.readVersions(2); 256 result = remoteTable.get(get); 257 int count = 0; 258 for (Cell kv : result.listCells()) { 259 if (CellUtil.matchingFamily(kv, COLUMN_1) && TS_1 == kv.getTimestamp()) { 260 assertTrue(CellUtil.matchingValue(kv, VALUE_1)); // @TS_1 261 count++; 262 } 263 if (CellUtil.matchingFamily(kv, COLUMN_1) && TS_2 == kv.getTimestamp()) { 264 assertTrue(CellUtil.matchingValue(kv, VALUE_2)); // @TS_2 265 count++; 266 } 267 } 268 assertEquals(2, count); 269 } 270 271 @Test 272 public void testMultiGet() throws Exception { 273 // In case of multi gets, the request path resolves to 274 // "/TestRemoteTable_-./multiget/?row=testrow1%7C%22%5C%5E&row=testrow2%7C%22%5C%5E%&v=3" 275 // and hence is not considered suspicious by the Jetty 12. 276 ArrayList<Get> gets = new ArrayList<>(2); 277 gets.add(new Get(ROW_1)); 278 gets.add(new Get(ROW_2)); 279 Result[] results = remoteTable.get(gets); 280 assertNotNull(results); 281 assertEquals(2, results.length); 282 assertEquals(1, results[0].size()); 283 assertEquals(2, results[1].size()); 284 285 // Test Versions 286 gets = new ArrayList<>(2); 287 Get g = new Get(ROW_1); 288 g.readVersions(3); 289 gets.add(g); 290 gets.add(new Get(ROW_2)); 291 results = remoteTable.get(gets); 292 assertNotNull(results); 293 assertEquals(2, results.length); 294 assertEquals(1, results[0].size()); 295 assertEquals(3, results[1].size()); 296 297 // 404 298 gets = new ArrayList<>(1); 299 gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE"))); 300 results = remoteTable.get(gets); 301 assertNotNull(results); 302 assertEquals(0, results.length); 303 304 gets = new ArrayList<>(3); 305 gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE"))); 306 gets.add(new Get(ROW_1)); 307 gets.add(new Get(ROW_2)); 308 results = remoteTable.get(gets); 309 assertNotNull(results); 310 assertEquals(2, results.length); 311 } 312 313 @Test 314 public void testPut() throws IOException { 315 // Requires UriCompliance.Violation.SUSPICIOUS_PATH_CHARACTERS 316 // Otherwise fails with "400: Suspicious Path Character" 317 Put put = new Put(ROW_3); 318 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 319 remoteTable.put(put); 320 321 Get get = new Get(ROW_3); 322 get.addFamily(COLUMN_1); 323 Result result = remoteTable.get(get); 324 byte[] value = result.getValue(COLUMN_1, QUALIFIER_1); 325 assertNotNull(value); 326 assertTrue(Bytes.equals(VALUE_1, value)); 327 328 // multiput 329 List<Put> puts = new ArrayList<>(3); 330 put = new Put(ROW_3); 331 put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2); 332 puts.add(put); 333 put = new Put(ROW_4); 334 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 335 puts.add(put); 336 put = new Put(ROW_4); 337 put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2); 338 puts.add(put); 339 remoteTable.put(puts); 340 341 get = new Get(ROW_3); 342 get.addFamily(COLUMN_2); 343 result = remoteTable.get(get); 344 value = result.getValue(COLUMN_2, QUALIFIER_2); 345 assertNotNull(value); 346 assertTrue(Bytes.equals(VALUE_2, value)); 347 get = new Get(ROW_4); 348 result = remoteTable.get(get); 349 value = result.getValue(COLUMN_1, QUALIFIER_1); 350 assertNotNull(value); 351 assertTrue(Bytes.equals(VALUE_1, value)); 352 value = result.getValue(COLUMN_2, QUALIFIER_2); 353 assertNotNull(value); 354 assertTrue(Bytes.equals(VALUE_2, value)); 355 356 assertTrue(Bytes.equals(Bytes.toBytes("TestRemoteTable" + VALID_TABLE_NAME_CHARS), 357 remoteTable.getTableName())); 358 } 359 360 @Test 361 public void testDelete() throws IOException { 362 // Requires UriCompliance.Violation.SUSPICIOUS_PATH_CHARACTERS for put, 363 // otherwise fails with "400: Suspicious Path Character" 364 // This example is considered suspicious by the Jetty 12 due to reasons same as shown in 365 // testGet() 366 367 // Also, requires UriCompliance.Violation.AMBIGUOUS_EMPTY_SEGMENT 368 // Otherwise fails with "400: Ambiguous URI empty segment" 369 Put put = new Put(ROW_3); 370 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 371 put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2); 372 put.addColumn(COLUMN_3, QUALIFIER_1, VALUE_1); 373 put.addColumn(COLUMN_3, QUALIFIER_2, VALUE_2); 374 remoteTable.put(put); 375 376 Get get = new Get(ROW_3); 377 get.addFamily(COLUMN_1); 378 get.addFamily(COLUMN_2); 379 get.addFamily(COLUMN_3); 380 Result result = remoteTable.get(get); 381 byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1); 382 byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2); 383 byte[] value3 = result.getValue(COLUMN_3, QUALIFIER_1); 384 byte[] value4 = result.getValue(COLUMN_3, QUALIFIER_2); 385 assertNotNull(value1); 386 assertTrue(Bytes.equals(VALUE_1, value1)); 387 assertNotNull(value2); 388 assertTrue(Bytes.equals(VALUE_2, value2)); 389 assertNotNull(value3); 390 assertTrue(Bytes.equals(VALUE_1, value3)); 391 assertNotNull(value4); 392 assertTrue(Bytes.equals(VALUE_2, value4)); 393 394 Delete delete = new Delete(ROW_3); 395 delete.addColumn(COLUMN_2, QUALIFIER_2); 396 remoteTable.delete(delete); 397 398 get = new Get(ROW_3); 399 get.addFamily(COLUMN_1); 400 get.addFamily(COLUMN_2); 401 result = remoteTable.get(get); 402 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 403 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 404 assertNotNull(value1); 405 assertTrue(Bytes.equals(VALUE_1, value1)); 406 assertNull(value2); 407 408 // This leads to path which resolves to 409 // "/TestRemoteTable_-./testrow3%7C%22%5C%5E%7B%7D%01%02%03%04%05%06%07%08%09%0B%0C//1" 410 // causing "400: Ambiguous URI empty segment" error with Jetty 12. 411 delete = new Delete(ROW_3); 412 delete.setTimestamp(1L); 413 remoteTable.delete(delete); 414 415 get = new Get(ROW_3); 416 get.addFamily(COLUMN_1); 417 get.addFamily(COLUMN_2); 418 result = remoteTable.get(get); 419 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 420 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 421 assertNotNull(value1); 422 assertTrue(Bytes.equals(VALUE_1, value1)); 423 assertNull(value2); 424 425 // Delete column family from row 426 delete = new Delete(ROW_3); 427 delete.addFamily(COLUMN_3); 428 remoteTable.delete(delete); 429 430 get = new Get(ROW_3); 431 get.addFamily(COLUMN_3); 432 result = remoteTable.get(get); 433 value3 = result.getValue(COLUMN_3, QUALIFIER_1); 434 value4 = result.getValue(COLUMN_3, QUALIFIER_2); 435 assertNull(value3); 436 assertNull(value4); 437 438 delete = new Delete(ROW_3); 439 remoteTable.delete(delete); 440 441 get = new Get(ROW_3); 442 get.addFamily(COLUMN_1); 443 get.addFamily(COLUMN_2); 444 result = remoteTable.get(get); 445 value1 = result.getValue(COLUMN_1, QUALIFIER_1); 446 value2 = result.getValue(COLUMN_2, QUALIFIER_2); 447 assertNull(value1); 448 assertNull(value2); 449 } 450 451 /** 452 * Test RemoteHTable.Scanner 453 */ 454 @Test 455 public void testScanner() throws IOException { 456 List<Put> puts = new ArrayList<>(4); 457 Put put = new Put(ROW_1); 458 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 459 puts.add(put); 460 put = new Put(ROW_2); 461 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 462 puts.add(put); 463 put = new Put(ROW_3); 464 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 465 puts.add(put); 466 put = new Put(ROW_4); 467 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 468 puts.add(put); 469 remoteTable.put(puts); 470 471 ResultScanner scanner = remoteTable.getScanner(new Scan()); 472 473 Result[] results = scanner.next(1); 474 assertNotNull(results); 475 assertEquals(1, results.length); 476 assertTrue(Bytes.equals(ROW_1, results[0].getRow())); 477 478 Result result = scanner.next(); 479 assertNotNull(result); 480 assertTrue(Bytes.equals(ROW_2, result.getRow())); 481 482 results = scanner.next(2); 483 assertNotNull(results); 484 assertEquals(2, results.length); 485 assertTrue(Bytes.equals(ROW_3, results[0].getRow())); 486 assertTrue(Bytes.equals(ROW_4, results[1].getRow())); 487 488 results = scanner.next(1); 489 assertNull(results); 490 scanner.close(); 491 492 scanner = remoteTable.getScanner(COLUMN_1); 493 results = scanner.next(4); 494 assertNotNull(results); 495 assertEquals(4, results.length); 496 assertTrue(Bytes.equals(ROW_1, results[0].getRow())); 497 assertTrue(Bytes.equals(ROW_2, results[1].getRow())); 498 assertTrue(Bytes.equals(ROW_3, results[2].getRow())); 499 assertTrue(Bytes.equals(ROW_4, results[3].getRow())); 500 501 scanner.close(); 502 503 scanner = remoteTable.getScanner(COLUMN_1, QUALIFIER_1); 504 results = scanner.next(4); 505 assertNotNull(results); 506 assertEquals(4, results.length); 507 assertTrue(Bytes.equals(ROW_1, results[0].getRow())); 508 assertTrue(Bytes.equals(ROW_2, results[1].getRow())); 509 assertTrue(Bytes.equals(ROW_3, results[2].getRow())); 510 assertTrue(Bytes.equals(ROW_4, results[3].getRow())); 511 scanner.close(); 512 assertTrue(remoteTable.isAutoFlush()); 513 } 514 515 @Test 516 public void testCheckAndDelete() throws IOException { 517 // Requires UriCompliance.Violation.SUSPICIOUS_PATH_CHARACTERS 518 // Otherwise fails with "400: Suspicious Path Character" 519 // This example is considered suspicious by the Jetty 12 due to reasons same as shown in 520 // testGet() 521 Get get = new Get(ROW_1); 522 Result result = remoteTable.get(get); 523 byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1); 524 byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2); 525 assertNotNull(value1); 526 assertTrue(Bytes.equals(VALUE_1, value1)); 527 assertNull(value2); 528 assertTrue(remoteTable.exists(get)); 529 assertEquals(1, remoteTable.exists(Collections.singletonList(get)).length); 530 Delete delete = new Delete(ROW_1); 531 532 remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_1) 533 .thenDelete(delete); 534 assertFalse(remoteTable.exists(get)); 535 536 Put put = new Put(ROW_1); 537 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 538 remoteTable.put(put); 539 540 assertTrue(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_1) 541 .thenPut(put)); 542 assertFalse(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_2) 543 .thenPut(put)); 544 } 545 546 /** 547 * Test RemoteHable.Scanner.iterator method 548 */ 549 @Test 550 public void testIteratorScaner() throws IOException { 551 List<Put> puts = new ArrayList<>(4); 552 Put put = new Put(ROW_1); 553 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 554 puts.add(put); 555 put = new Put(ROW_2); 556 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 557 puts.add(put); 558 put = new Put(ROW_3); 559 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 560 puts.add(put); 561 put = new Put(ROW_4); 562 put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1); 563 puts.add(put); 564 remoteTable.put(puts); 565 566 ResultScanner scanner = remoteTable.getScanner(new Scan()); 567 Iterator<Result> iterator = scanner.iterator(); 568 assertTrue(iterator.hasNext()); 569 int counter = 0; 570 while (iterator.hasNext()) { 571 iterator.next(); 572 counter++; 573 } 574 assertEquals(4, counter); 575 } 576 577 /** 578 * Test a some methods of class Response. 579 */ 580 @Test 581 public void testResponse() { 582 Response response = new Response(200); 583 assertEquals(200, response.getCode()); 584 Header[] headers = new Header[2]; 585 headers[0] = new BasicHeader("header1", "value1"); 586 headers[1] = new BasicHeader("header2", "value2"); 587 response = new Response(200, headers); 588 assertEquals("value1", response.getHeader("header1")); 589 assertFalse(response.hasBody()); 590 response.setCode(404); 591 assertEquals(404, response.getCode()); 592 headers = new Header[2]; 593 headers[0] = new BasicHeader("header1", "value1.1"); 594 headers[1] = new BasicHeader("header2", "value2"); 595 response.setHeaders(headers); 596 assertEquals("value1.1", response.getHeader("header1")); 597 response.setBody(Bytes.toBytes("body")); 598 assertTrue(response.hasBody()); 599 } 600 601 /** 602 * Tests scanner with limitation limit the number of rows each scanner scan fetch at life time The 603 * number of rows returned should be equal to the limit 604 */ 605 @Test 606 public void testLimitedScan() throws Exception { 607 int numTrials = 100; 608 int limit = 60; 609 610 // Truncate the test table for inserting test scenarios rows keys 611 TEST_UTIL.getAdmin().disableTable(TABLE); 612 TEST_UTIL.getAdmin().truncateTable(TABLE, false); 613 String row = "testrow"; 614 615 try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) { 616 List<Put> puts = new ArrayList<>(); 617 Put put = null; 618 for (int i = 1; i <= numTrials; i++) { 619 put = new Put(Bytes.toBytes(row + i)); 620 put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i)); 621 puts.add(put); 622 } 623 table.put(puts); 624 } 625 626 remoteTable = 627 new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())), 628 TEST_UTIL.getConfiguration(), TABLE.toBytes()); 629 630 Scan scan = new Scan(); 631 scan.setLimit(limit); 632 ResultScanner scanner = remoteTable.getScanner(scan); 633 Iterator<Result> resultIterator = scanner.iterator(); 634 int counter = 0; 635 while (resultIterator.hasNext()) { 636 resultIterator.next(); 637 counter++; 638 } 639 assertEquals(limit, counter); 640 } 641 642 /** 643 * Tests keeping a HBase scanner alive for long periods of time. Each call to next() should reset 644 * the ConnectionCache timeout for the scanner's connection. 645 * @throws Exception if starting the servlet container or disabling or truncating the table fails 646 */ 647 @Test 648 public void testLongLivedScan() throws Exception { 649 int numTrials = 6; 650 int trialPause = 1000; 651 int cleanUpInterval = 100; 652 653 // Shutdown the Rest Servlet container 654 REST_TEST_UTIL.shutdownServletContainer(); 655 656 // Set the ConnectionCache timeout to trigger halfway through the trials 657 TEST_UTIL.getConfiguration().setLong(RESTServlet.MAX_IDLETIME, (numTrials / 2) * trialPause); 658 TEST_UTIL.getConfiguration().setLong(RESTServlet.CLEANUP_INTERVAL, cleanUpInterval); 659 660 // Start the Rest Servlet container 661 REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration()); 662 663 // Truncate the test table for inserting test scenarios rows keys 664 TEST_UTIL.getAdmin().disableTable(TABLE); 665 TEST_UTIL.getAdmin().truncateTable(TABLE, false); 666 667 remoteTable = 668 new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())), 669 TEST_UTIL.getConfiguration(), TABLE.toBytes()); 670 671 String row = "testrow"; 672 673 try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) { 674 List<Put> puts = new ArrayList<Put>(); 675 Put put = null; 676 for (int i = 1; i <= numTrials; i++) { 677 put = new Put(Bytes.toBytes(row + i)); 678 put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i)); 679 puts.add(put); 680 } 681 table.put(puts); 682 } 683 684 Scan scan = new Scan(); 685 scan.setCaching(1); 686 scan.setBatch(1); 687 688 ResultScanner scanner = remoteTable.getScanner(scan); 689 Result result = null; 690 // get scanner and rows 691 for (int i = 1; i <= numTrials; i++) { 692 // Make sure that the Scanner doesn't throw an exception after the ConnectionCache timeout 693 result = scanner.next(); 694 assertEquals(row + i, Bytes.toString(result.getRow())); 695 Thread.sleep(trialPause); 696 } 697 } 698 699 @Test 700 public void testScanWithInlcudeStartStopRow() throws Exception { 701 int numTrials = 6; 702 703 // Truncate the test table for inserting test scenarios rows keys 704 TEST_UTIL.getAdmin().disableTable(TABLE); 705 TEST_UTIL.getAdmin().truncateTable(TABLE, false); 706 String row = "testrow"; 707 708 try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) { 709 List<Put> puts = new ArrayList<>(); 710 Put put = null; 711 for (int i = 1; i <= numTrials; i++) { 712 put = new Put(Bytes.toBytes(row + i)); 713 put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i)); 714 puts.add(put); 715 } 716 table.put(puts); 717 } 718 719 remoteTable = 720 new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())), 721 TEST_UTIL.getConfiguration(), TABLE.toBytes()); 722 723 Scan scan = 724 new Scan().withStartRow(Bytes.toBytes(row + "1")).withStopRow(Bytes.toBytes(row + "5")); 725 726 ResultScanner scanner = remoteTable.getScanner(scan); 727 Iterator<Result> resultIterator = scanner.iterator(); 728 int counter = 0; 729 while (resultIterator.hasNext()) { 730 byte[] row1 = resultIterator.next().getRow(); 731 System.out.println(Bytes.toString(row1)); 732 counter++; 733 } 734 assertEquals(4, counter); 735 736 // test with include start row false 737 scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), false) 738 .withStopRow(Bytes.toBytes(row + "5")); 739 scanner = remoteTable.getScanner(scan); 740 resultIterator = scanner.iterator(); 741 counter = 0; 742 while (resultIterator.hasNext()) { 743 byte[] row1 = resultIterator.next().getRow(); 744 System.out.println(Bytes.toString(row1)); 745 counter++; 746 } 747 assertEquals(3, counter); 748 749 // test with include start row false and stop row true 750 scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), false) 751 .withStopRow(Bytes.toBytes(row + "5"), true); 752 scanner = remoteTable.getScanner(scan); 753 resultIterator = scanner.iterator(); 754 counter = 0; 755 while (resultIterator.hasNext()) { 756 byte[] row1 = resultIterator.next().getRow(); 757 System.out.println(Bytes.toString(row1)); 758 counter++; 759 } 760 assertEquals(4, counter); 761 762 // test with include start row true and stop row true 763 scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), true) 764 .withStopRow(Bytes.toBytes(row + "5"), true); 765 scanner = remoteTable.getScanner(scan); 766 resultIterator = scanner.iterator(); 767 counter = 0; 768 while (resultIterator.hasNext()) { 769 byte[] row1 = resultIterator.next().getRow(); 770 System.out.println(Bytes.toString(row1)); 771 counter++; 772 } 773 assertEquals(5, counter); 774 } 775 776}