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