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    Get get = new Get(ROW_1);
168    Result result = remoteTable.get(get);
169    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
170    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
171    assertNotNull(value1);
172    assertTrue(Bytes.equals(VALUE_1, value1));
173    assertNull(value2);
174
175    get = new Get(ROW_1);
176    get.addFamily(COLUMN_3);
177    result = remoteTable.get(get);
178    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
179    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
180    assertNull(value1);
181    assertNull(value2);
182
183    get = new Get(ROW_1);
184    get.addColumn(COLUMN_1, QUALIFIER_1);
185    get.addColumn(COLUMN_2, QUALIFIER_2);
186    result = remoteTable.get(get);
187    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
188    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
189    assertNotNull(value1);
190    assertTrue(Bytes.equals(VALUE_1, value1));
191    assertNull(value2);
192
193    get = new Get(ROW_2);
194    result = remoteTable.get(get);
195    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
196    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
197    assertNotNull(value1);
198    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
199    assertNotNull(value2);
200    assertTrue(Bytes.equals(VALUE_2, value2));
201
202    get = new Get(ROW_2);
203    get.addFamily(COLUMN_1);
204    result = remoteTable.get(get);
205    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
206    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
207    assertNotNull(value1);
208    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
209    assertNull(value2);
210
211    get = new Get(ROW_2);
212    get.addColumn(COLUMN_1, QUALIFIER_1);
213    get.addColumn(COLUMN_2, QUALIFIER_2);
214    result = remoteTable.get(get);
215    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
216    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
217    assertNotNull(value1);
218    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
219    assertNotNull(value2);
220    assertTrue(Bytes.equals(VALUE_2, value2));
221
222    // test timestamp
223    get = new Get(ROW_2);
224    get.addFamily(COLUMN_1);
225    get.addFamily(COLUMN_2);
226    get.setTimestamp(TS_1);
227    result = remoteTable.get(get);
228    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
229    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
230    assertNotNull(value1);
231    assertTrue(Bytes.equals(VALUE_1, value1)); // @TS_1
232    assertNull(value2);
233
234    // test timerange
235    get = new Get(ROW_2);
236    get.addFamily(COLUMN_1);
237    get.addFamily(COLUMN_2);
238    get.setTimeRange(0, TS_1 + 1);
239    result = remoteTable.get(get);
240    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
241    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
242    assertNotNull(value1);
243    assertTrue(Bytes.equals(VALUE_1, value1)); // @TS_1
244    assertNull(value2);
245
246    // test maxVersions
247    get = new Get(ROW_2);
248    get.addFamily(COLUMN_1);
249    get.readVersions(2);
250    result = remoteTable.get(get);
251    int count = 0;
252    for (Cell kv : result.listCells()) {
253      if (CellUtil.matchingFamily(kv, COLUMN_1) && TS_1 == kv.getTimestamp()) {
254        assertTrue(CellUtil.matchingValue(kv, VALUE_1)); // @TS_1
255        count++;
256      }
257      if (CellUtil.matchingFamily(kv, COLUMN_1) && TS_2 == kv.getTimestamp()) {
258        assertTrue(CellUtil.matchingValue(kv, VALUE_2)); // @TS_2
259        count++;
260      }
261    }
262    assertEquals(2, count);
263  }
264
265  @Test
266  public void testMultiGet() throws Exception {
267    ArrayList<Get> gets = new ArrayList<>(2);
268    gets.add(new Get(ROW_1));
269    gets.add(new Get(ROW_2));
270    Result[] results = remoteTable.get(gets);
271    assertNotNull(results);
272    assertEquals(2, results.length);
273    assertEquals(1, results[0].size());
274    assertEquals(2, results[1].size());
275
276    // Test Versions
277    gets = new ArrayList<>(2);
278    Get g = new Get(ROW_1);
279    g.readVersions(3);
280    gets.add(g);
281    gets.add(new Get(ROW_2));
282    results = remoteTable.get(gets);
283    assertNotNull(results);
284    assertEquals(2, results.length);
285    assertEquals(1, results[0].size());
286    assertEquals(3, results[1].size());
287
288    // 404
289    gets = new ArrayList<>(1);
290    gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE")));
291    results = remoteTable.get(gets);
292    assertNotNull(results);
293    assertEquals(0, results.length);
294
295    gets = new ArrayList<>(3);
296    gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE")));
297    gets.add(new Get(ROW_1));
298    gets.add(new Get(ROW_2));
299    results = remoteTable.get(gets);
300    assertNotNull(results);
301    assertEquals(2, results.length);
302  }
303
304  @Test
305  public void testPut() throws IOException {
306    Put put = new Put(ROW_3);
307    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
308    remoteTable.put(put);
309
310    Get get = new Get(ROW_3);
311    get.addFamily(COLUMN_1);
312    Result result = remoteTable.get(get);
313    byte[] value = result.getValue(COLUMN_1, QUALIFIER_1);
314    assertNotNull(value);
315    assertTrue(Bytes.equals(VALUE_1, value));
316
317    // multiput
318    List<Put> puts = new ArrayList<>(3);
319    put = new Put(ROW_3);
320    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
321    puts.add(put);
322    put = new Put(ROW_4);
323    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
324    puts.add(put);
325    put = new Put(ROW_4);
326    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
327    puts.add(put);
328    remoteTable.put(puts);
329
330    get = new Get(ROW_3);
331    get.addFamily(COLUMN_2);
332    result = remoteTable.get(get);
333    value = result.getValue(COLUMN_2, QUALIFIER_2);
334    assertNotNull(value);
335    assertTrue(Bytes.equals(VALUE_2, value));
336    get = new Get(ROW_4);
337    result = remoteTable.get(get);
338    value = result.getValue(COLUMN_1, QUALIFIER_1);
339    assertNotNull(value);
340    assertTrue(Bytes.equals(VALUE_1, value));
341    value = result.getValue(COLUMN_2, QUALIFIER_2);
342    assertNotNull(value);
343    assertTrue(Bytes.equals(VALUE_2, value));
344
345    assertTrue(Bytes.equals(Bytes.toBytes("TestRemoteTable" + VALID_TABLE_NAME_CHARS),
346      remoteTable.getTableName()));
347  }
348
349  @Test
350  public void testDelete() throws IOException {
351    Put put = new Put(ROW_3);
352    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
353    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
354    put.addColumn(COLUMN_3, QUALIFIER_1, VALUE_1);
355    put.addColumn(COLUMN_3, QUALIFIER_2, VALUE_2);
356    remoteTable.put(put);
357
358    Get get = new Get(ROW_3);
359    get.addFamily(COLUMN_1);
360    get.addFamily(COLUMN_2);
361    get.addFamily(COLUMN_3);
362    Result result = remoteTable.get(get);
363    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
364    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
365    byte[] value3 = result.getValue(COLUMN_3, QUALIFIER_1);
366    byte[] value4 = result.getValue(COLUMN_3, QUALIFIER_2);
367    assertNotNull(value1);
368    assertTrue(Bytes.equals(VALUE_1, value1));
369    assertNotNull(value2);
370    assertTrue(Bytes.equals(VALUE_2, value2));
371    assertNotNull(value3);
372    assertTrue(Bytes.equals(VALUE_1, value3));
373    assertNotNull(value4);
374    assertTrue(Bytes.equals(VALUE_2, value4));
375
376    Delete delete = new Delete(ROW_3);
377    delete.addColumn(COLUMN_2, QUALIFIER_2);
378    remoteTable.delete(delete);
379
380    get = new Get(ROW_3);
381    get.addFamily(COLUMN_1);
382    get.addFamily(COLUMN_2);
383    result = remoteTable.get(get);
384    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
385    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
386    assertNotNull(value1);
387    assertTrue(Bytes.equals(VALUE_1, value1));
388    assertNull(value2);
389
390    delete = new Delete(ROW_3);
391    delete.setTimestamp(1L);
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    // Delete column family from row
405    delete = new Delete(ROW_3);
406    delete.addFamily(COLUMN_3);
407    remoteTable.delete(delete);
408
409    get = new Get(ROW_3);
410    get.addFamily(COLUMN_3);
411    result = remoteTable.get(get);
412    value3 = result.getValue(COLUMN_3, QUALIFIER_1);
413    value4 = result.getValue(COLUMN_3, QUALIFIER_2);
414    assertNull(value3);
415    assertNull(value4);
416
417    delete = new Delete(ROW_3);
418    remoteTable.delete(delete);
419
420    get = new Get(ROW_3);
421    get.addFamily(COLUMN_1);
422    get.addFamily(COLUMN_2);
423    result = remoteTable.get(get);
424    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
425    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
426    assertNull(value1);
427    assertNull(value2);
428  }
429
430  /**
431   * Test RemoteHTable.Scanner
432   */
433  @Test
434  public void testScanner() throws IOException {
435    List<Put> puts = new ArrayList<>(4);
436    Put put = new Put(ROW_1);
437    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
438    puts.add(put);
439    put = new Put(ROW_2);
440    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
441    puts.add(put);
442    put = new Put(ROW_3);
443    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
444    puts.add(put);
445    put = new Put(ROW_4);
446    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
447    puts.add(put);
448    remoteTable.put(puts);
449
450    ResultScanner scanner = remoteTable.getScanner(new Scan());
451
452    Result[] results = scanner.next(1);
453    assertNotNull(results);
454    assertEquals(1, results.length);
455    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
456
457    Result result = scanner.next();
458    assertNotNull(result);
459    assertTrue(Bytes.equals(ROW_2, result.getRow()));
460
461    results = scanner.next(2);
462    assertNotNull(results);
463    assertEquals(2, results.length);
464    assertTrue(Bytes.equals(ROW_3, results[0].getRow()));
465    assertTrue(Bytes.equals(ROW_4, results[1].getRow()));
466
467    results = scanner.next(1);
468    assertNull(results);
469    scanner.close();
470
471    scanner = remoteTable.getScanner(COLUMN_1);
472    results = scanner.next(4);
473    assertNotNull(results);
474    assertEquals(4, results.length);
475    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
476    assertTrue(Bytes.equals(ROW_2, results[1].getRow()));
477    assertTrue(Bytes.equals(ROW_3, results[2].getRow()));
478    assertTrue(Bytes.equals(ROW_4, results[3].getRow()));
479
480    scanner.close();
481
482    scanner = remoteTable.getScanner(COLUMN_1, QUALIFIER_1);
483    results = scanner.next(4);
484    assertNotNull(results);
485    assertEquals(4, results.length);
486    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
487    assertTrue(Bytes.equals(ROW_2, results[1].getRow()));
488    assertTrue(Bytes.equals(ROW_3, results[2].getRow()));
489    assertTrue(Bytes.equals(ROW_4, results[3].getRow()));
490    scanner.close();
491    assertTrue(remoteTable.isAutoFlush());
492  }
493
494  @Test
495  public void testCheckAndDelete() throws IOException {
496    Get get = new Get(ROW_1);
497    Result result = remoteTable.get(get);
498    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
499    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
500    assertNotNull(value1);
501    assertTrue(Bytes.equals(VALUE_1, value1));
502    assertNull(value2);
503    assertTrue(remoteTable.exists(get));
504    assertEquals(1, remoteTable.exists(Collections.singletonList(get)).length);
505    Delete delete = new Delete(ROW_1);
506
507    remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_1)
508      .thenDelete(delete);
509    assertFalse(remoteTable.exists(get));
510
511    Put put = new Put(ROW_1);
512    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
513    remoteTable.put(put);
514
515    assertTrue(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_1)
516      .thenPut(put));
517    assertFalse(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1).ifEquals(VALUE_2)
518      .thenPut(put));
519  }
520
521  /**
522   * Test RemoteHable.Scanner.iterator method
523   */
524  @Test
525  public void testIteratorScaner() throws IOException {
526    List<Put> puts = new ArrayList<>(4);
527    Put put = new Put(ROW_1);
528    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
529    puts.add(put);
530    put = new Put(ROW_2);
531    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
532    puts.add(put);
533    put = new Put(ROW_3);
534    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
535    puts.add(put);
536    put = new Put(ROW_4);
537    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
538    puts.add(put);
539    remoteTable.put(puts);
540
541    ResultScanner scanner = remoteTable.getScanner(new Scan());
542    Iterator<Result> iterator = scanner.iterator();
543    assertTrue(iterator.hasNext());
544    int counter = 0;
545    while (iterator.hasNext()) {
546      iterator.next();
547      counter++;
548    }
549    assertEquals(4, counter);
550  }
551
552  /**
553   * Test a some methods of class Response.
554   */
555  @Test
556  public void testResponse() {
557    Response response = new Response(200);
558    assertEquals(200, response.getCode());
559    Header[] headers = new Header[2];
560    headers[0] = new BasicHeader("header1", "value1");
561    headers[1] = new BasicHeader("header2", "value2");
562    response = new Response(200, headers);
563    assertEquals("value1", response.getHeader("header1"));
564    assertFalse(response.hasBody());
565    response.setCode(404);
566    assertEquals(404, response.getCode());
567    headers = new Header[2];
568    headers[0] = new BasicHeader("header1", "value1.1");
569    headers[1] = new BasicHeader("header2", "value2");
570    response.setHeaders(headers);
571    assertEquals("value1.1", response.getHeader("header1"));
572    response.setBody(Bytes.toBytes("body"));
573    assertTrue(response.hasBody());
574  }
575
576  /**
577   * Tests scanner with limitation limit the number of rows each scanner scan fetch at life time The
578   * number of rows returned should be equal to the limit
579   */
580  @Test
581  public void testLimitedScan() throws Exception {
582    int numTrials = 100;
583    int limit = 60;
584
585    // Truncate the test table for inserting test scenarios rows keys
586    TEST_UTIL.getAdmin().disableTable(TABLE);
587    TEST_UTIL.getAdmin().truncateTable(TABLE, false);
588    String row = "testrow";
589
590    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
591      List<Put> puts = new ArrayList<>();
592      Put put = null;
593      for (int i = 1; i <= numTrials; i++) {
594        put = new Put(Bytes.toBytes(row + i));
595        put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i));
596        puts.add(put);
597      }
598      table.put(puts);
599    }
600
601    remoteTable =
602      new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())),
603        TEST_UTIL.getConfiguration(), TABLE.toBytes());
604
605    Scan scan = new Scan();
606    scan.setLimit(limit);
607    ResultScanner scanner = remoteTable.getScanner(scan);
608    Iterator<Result> resultIterator = scanner.iterator();
609    int counter = 0;
610    while (resultIterator.hasNext()) {
611      resultIterator.next();
612      counter++;
613    }
614    assertEquals(limit, counter);
615  }
616
617  /**
618   * Tests keeping a HBase scanner alive for long periods of time. Each call to next() should reset
619   * the ConnectionCache timeout for the scanner's connection.
620   * @throws Exception if starting the servlet container or disabling or truncating the table fails
621   */
622  @Test
623  public void testLongLivedScan() throws Exception {
624    int numTrials = 6;
625    int trialPause = 1000;
626    int cleanUpInterval = 100;
627
628    // Shutdown the Rest Servlet container
629    REST_TEST_UTIL.shutdownServletContainer();
630
631    // Set the ConnectionCache timeout to trigger halfway through the trials
632    TEST_UTIL.getConfiguration().setLong(RESTServlet.MAX_IDLETIME, (numTrials / 2) * trialPause);
633    TEST_UTIL.getConfiguration().setLong(RESTServlet.CLEANUP_INTERVAL, cleanUpInterval);
634
635    // Start the Rest Servlet container
636    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
637
638    // Truncate the test table for inserting test scenarios rows keys
639    TEST_UTIL.getAdmin().disableTable(TABLE);
640    TEST_UTIL.getAdmin().truncateTable(TABLE, false);
641
642    remoteTable =
643      new RemoteHTable(new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())),
644        TEST_UTIL.getConfiguration(), TABLE.toBytes());
645
646    String row = "testrow";
647
648    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
649      List<Put> puts = new ArrayList<Put>();
650      Put put = null;
651      for (int i = 1; i <= numTrials; i++) {
652        put = new Put(Bytes.toBytes(row + i));
653        put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i));
654        puts.add(put);
655      }
656      table.put(puts);
657    }
658
659    Scan scan = new Scan();
660    scan.setCaching(1);
661    scan.setBatch(1);
662
663    ResultScanner scanner = remoteTable.getScanner(scan);
664    Result result = null;
665    // get scanner and rows
666    for (int i = 1; i <= numTrials; i++) {
667      // Make sure that the Scanner doesn't throw an exception after the ConnectionCache timeout
668      result = scanner.next();
669      assertEquals(row + i, Bytes.toString(result.getRow()));
670      Thread.sleep(trialPause);
671    }
672  }
673}