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.HBaseTestingUtility;
035import org.apache.hadoop.hbase.HColumnDescriptor;
036import org.apache.hadoop.hbase.HTableDescriptor;
037import org.apache.hadoop.hbase.TableName;
038import org.apache.hadoop.hbase.client.Admin;
039import org.apache.hadoop.hbase.client.Delete;
040import org.apache.hadoop.hbase.client.Get;
041import org.apache.hadoop.hbase.client.Put;
042import org.apache.hadoop.hbase.client.Result;
043import org.apache.hadoop.hbase.client.ResultScanner;
044import org.apache.hadoop.hbase.client.Scan;
045import org.apache.hadoop.hbase.client.Table;
046import org.apache.hadoop.hbase.rest.HBaseRESTTestingUtility;
047import org.apache.hadoop.hbase.rest.RESTServlet;
048import org.apache.hadoop.hbase.testclassification.MediumTests;
049import org.apache.hadoop.hbase.testclassification.RestTests;
050import org.apache.hadoop.hbase.util.Bytes;
051import org.apache.http.Header;
052import org.apache.http.message.BasicHeader;
053import org.junit.After;
054import org.junit.AfterClass;
055import org.junit.Before;
056import org.junit.BeforeClass;
057import org.junit.ClassRule;
058import org.junit.Test;
059import org.junit.experimental.categories.Category;
060
061@Category({RestTests.class, MediumTests.class})
062public class TestRemoteTable {
063  @ClassRule
064  public static final HBaseClassTestRule CLASS_RULE =
065      HBaseClassTestRule.forClass(TestRemoteTable.class);
066
067  // Verify that invalid URL characters and arbitrary bytes are escaped when
068  // constructing REST URLs per HBASE-7621. RemoteHTable should support row keys
069  // and qualifiers containing any byte for all table operations.
070  private static final String INVALID_URL_CHARS_1 =
071      "|\"\\^{}\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000B\u000C";
072
073  // HColumnDescriptor prevents certain characters in column names.  The following
074  // are examples of characters are allowed in column names but are not valid in
075  // URLs.
076  private static final String INVALID_URL_CHARS_2 = "|^{}\u0242";
077
078  // Besides alphanumeric these characters can also be present in table names.
079  private static final String VALID_TABLE_NAME_CHARS = "_-.";
080
081  private static final TableName TABLE =
082      TableName.valueOf("TestRemoteTable" + VALID_TABLE_NAME_CHARS);
083
084  private static final byte[] ROW_1 = Bytes.toBytes("testrow1" + INVALID_URL_CHARS_1);
085  private static final byte[] ROW_2 = Bytes.toBytes("testrow2" + INVALID_URL_CHARS_1);
086  private static final byte[] ROW_3 = Bytes.toBytes("testrow3" + INVALID_URL_CHARS_1);
087  private static final byte[] ROW_4 = Bytes.toBytes("testrow4"+ INVALID_URL_CHARS_1);
088
089  private static final byte[] COLUMN_1 = Bytes.toBytes("a" + INVALID_URL_CHARS_2);
090  private static final byte[] COLUMN_2 = Bytes.toBytes("b" + INVALID_URL_CHARS_2);
091  private static final byte[] COLUMN_3 = Bytes.toBytes("c" + INVALID_URL_CHARS_2);
092
093  private static final byte[] QUALIFIER_1 = Bytes.toBytes("1" + INVALID_URL_CHARS_1);
094  private static final byte[] QUALIFIER_2 = Bytes.toBytes("2" + INVALID_URL_CHARS_1);
095  private static final byte[] VALUE_1 = Bytes.toBytes("testvalue1");
096  private static final byte[] VALUE_2 = Bytes.toBytes("testvalue2");
097
098  private static final long ONE_HOUR = 60 * 60 * 1000;
099  private static final long TS_2 = System.currentTimeMillis();
100  private static final long TS_1 = TS_2 - ONE_HOUR;
101
102  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
103  private static final HBaseRESTTestingUtility REST_TEST_UTIL =
104    new HBaseRESTTestingUtility();
105  private RemoteHTable remoteTable;
106
107  @BeforeClass
108  public static void setUpBeforeClass() throws Exception {
109    TEST_UTIL.startMiniCluster();
110    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
111  }
112
113  @Before
114  public void before() throws Exception  {
115    Admin admin = TEST_UTIL.getAdmin();
116    if (admin.tableExists(TABLE)) {
117      if (admin.isTableEnabled(TABLE)) {
118        admin.disableTable(TABLE);
119      }
120
121      admin.deleteTable(TABLE);
122    }
123    HTableDescriptor htd = new HTableDescriptor(TABLE);
124    htd.addFamily(new HColumnDescriptor(COLUMN_1).setMaxVersions(3));
125    htd.addFamily(new HColumnDescriptor(COLUMN_2).setMaxVersions(3));
126    htd.addFamily(new HColumnDescriptor(COLUMN_3).setMaxVersions(3));
127    admin.createTable(htd);
128    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
129      Put put = new Put(ROW_1);
130      put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_1);
131      table.put(put);
132      put = new Put(ROW_2);
133      put.addColumn(COLUMN_1, QUALIFIER_1, TS_1, VALUE_1);
134      put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_2);
135      put.addColumn(COLUMN_2, QUALIFIER_2, TS_2, VALUE_2);
136      table.put(put);
137    }
138    remoteTable = new RemoteHTable(
139      new Client(new Cluster().add("localhost",
140          REST_TEST_UTIL.getServletPort())),
141        TEST_UTIL.getConfiguration(), TABLE.toBytes());
142  }
143
144  @After
145  public void after() throws Exception {
146    remoteTable.close();
147  }
148
149  @AfterClass
150  public static void tearDownAfterClass() throws Exception {
151    REST_TEST_UTIL.shutdownServletContainer();
152    TEST_UTIL.shutdownMiniCluster();
153  }
154
155  @Test
156  public void testGetTableDescriptor() throws IOException {
157    Table table = null;
158    try {
159      table = TEST_UTIL.getConnection().getTable(TABLE);
160      HTableDescriptor local = table.getTableDescriptor();
161      assertEquals(remoteTable.getTableDescriptor(), local);
162    } finally {
163      if (null != table) table.close();
164    }
165  }
166
167  @Test
168  public void testGet() throws IOException {
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.setMaxVersions(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    ArrayList<Get> gets = new ArrayList<>(2);
270    gets.add(new Get(ROW_1));
271    gets.add(new Get(ROW_2));
272    Result[] results = remoteTable.get(gets);
273    assertNotNull(results);
274    assertEquals(2, results.length);
275    assertEquals(1, results[0].size());
276    assertEquals(2, results[1].size());
277
278    //Test Versions
279    gets = new ArrayList<>(2);
280    Get g = new Get(ROW_1);
281    g.setMaxVersions(3);
282    gets.add(g);
283    gets.add(new Get(ROW_2));
284    results = remoteTable.get(gets);
285    assertNotNull(results);
286    assertEquals(2, results.length);
287    assertEquals(1, results[0].size());
288    assertEquals(3, results[1].size());
289
290    //404
291    gets = new ArrayList<>(1);
292    gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE")));
293    results = remoteTable.get(gets);
294    assertNotNull(results);
295    assertEquals(0, results.length);
296
297    gets = new ArrayList<>(3);
298    gets.add(new Get(Bytes.toBytes("RESALLYREALLYNOTTHERE")));
299    gets.add(new Get(ROW_1));
300    gets.add(new Get(ROW_2));
301    results = remoteTable.get(gets);
302    assertNotNull(results);
303    assertEquals(2, results.length);
304  }
305
306  @Test
307  public void testPut() throws IOException {
308    Put put = new Put(ROW_3);
309    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
310    remoteTable.put(put);
311
312    Get get = new Get(ROW_3);
313    get.addFamily(COLUMN_1);
314    Result result = remoteTable.get(get);
315    byte[] value = result.getValue(COLUMN_1, QUALIFIER_1);
316    assertNotNull(value);
317    assertTrue(Bytes.equals(VALUE_1, value));
318
319    // multiput
320    List<Put> puts = new ArrayList<>(3);
321    put = new Put(ROW_3);
322    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
323    puts.add(put);
324    put = new Put(ROW_4);
325    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
326    puts.add(put);
327    put = new Put(ROW_4);
328    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
329    puts.add(put);
330    remoteTable.put(puts);
331
332    get = new Get(ROW_3);
333    get.addFamily(COLUMN_2);
334    result = remoteTable.get(get);
335    value = result.getValue(COLUMN_2, QUALIFIER_2);
336    assertNotNull(value);
337    assertTrue(Bytes.equals(VALUE_2, value));
338    get = new Get(ROW_4);
339    result = remoteTable.get(get);
340    value = result.getValue(COLUMN_1, QUALIFIER_1);
341    assertNotNull(value);
342    assertTrue(Bytes.equals(VALUE_1, value));
343    value = result.getValue(COLUMN_2, QUALIFIER_2);
344    assertNotNull(value);
345    assertTrue(Bytes.equals(VALUE_2, value));
346
347    assertTrue(Bytes.equals(Bytes.toBytes("TestRemoteTable" + VALID_TABLE_NAME_CHARS),
348        remoteTable.getTableName()));
349  }
350
351  @Test
352  public void testDelete() throws IOException {
353    Put put = new Put(ROW_3);
354    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
355    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
356    put.addColumn(COLUMN_3, QUALIFIER_1, VALUE_1);
357    put.addColumn(COLUMN_3, QUALIFIER_2, VALUE_2);
358    remoteTable.put(put);
359
360    Get get = new Get(ROW_3);
361    get.addFamily(COLUMN_1);
362    get.addFamily(COLUMN_2);
363    get.addFamily(COLUMN_3);
364    Result result = remoteTable.get(get);
365    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
366    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
367    byte[] value3 = result.getValue(COLUMN_3, QUALIFIER_1);
368    byte[] value4 = result.getValue(COLUMN_3, QUALIFIER_2);
369    assertNotNull(value1);
370    assertTrue(Bytes.equals(VALUE_1, value1));
371    assertNotNull(value2);
372    assertTrue(Bytes.equals(VALUE_2, value2));
373    assertNotNull(value3);
374    assertTrue(Bytes.equals(VALUE_1, value3));
375    assertNotNull(value4);
376    assertTrue(Bytes.equals(VALUE_2, value4));
377
378    Delete delete = new Delete(ROW_3);
379    delete.addColumn(COLUMN_2, QUALIFIER_2);
380    remoteTable.delete(delete);
381
382    get = new Get(ROW_3);
383    get.addFamily(COLUMN_1);
384    get.addFamily(COLUMN_2);
385    result = remoteTable.get(get);
386    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
387    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
388    assertNotNull(value1);
389    assertTrue(Bytes.equals(VALUE_1, value1));
390    assertNull(value2);
391
392    delete = new Delete(ROW_3);
393    delete.setTimestamp(1L);
394    remoteTable.delete(delete);
395
396    get = new Get(ROW_3);
397    get.addFamily(COLUMN_1);
398    get.addFamily(COLUMN_2);
399    result = remoteTable.get(get);
400    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
401    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
402    assertNotNull(value1);
403    assertTrue(Bytes.equals(VALUE_1, value1));
404    assertNull(value2);
405
406    // Delete column family from row
407    delete = new Delete(ROW_3);
408    delete.addFamily(COLUMN_3);
409    remoteTable.delete(delete);
410
411    get = new Get(ROW_3);
412    get.addFamily(COLUMN_3);
413    result = remoteTable.get(get);
414    value3 = result.getValue(COLUMN_3, QUALIFIER_1);
415    value4 = result.getValue(COLUMN_3, QUALIFIER_2);
416    assertNull(value3);
417    assertNull(value4);
418
419    delete = new Delete(ROW_3);
420    remoteTable.delete(delete);
421
422    get = new Get(ROW_3);
423    get.addFamily(COLUMN_1);
424    get.addFamily(COLUMN_2);
425    result = remoteTable.get(get);
426    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
427    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
428    assertNull(value1);
429    assertNull(value2);
430  }
431
432  /**
433   * Test RemoteHTable.Scanner
434   */
435  @Test
436  public void testScanner() throws IOException {
437    List<Put> puts = new ArrayList<>(4);
438    Put put = new Put(ROW_1);
439    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
440    puts.add(put);
441    put = new Put(ROW_2);
442    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
443    puts.add(put);
444    put = new Put(ROW_3);
445    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
446    puts.add(put);
447    put = new Put(ROW_4);
448    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
449    puts.add(put);
450    remoteTable.put(puts);
451
452    ResultScanner scanner = remoteTable.getScanner(new Scan());
453
454    Result[] results = scanner.next(1);
455    assertNotNull(results);
456    assertEquals(1, results.length);
457    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
458
459    Result result = scanner.next();
460    assertNotNull(result);
461    assertTrue(Bytes.equals(ROW_2, result.getRow()));
462
463    results = scanner.next(2);
464    assertNotNull(results);
465    assertEquals(2, results.length);
466    assertTrue(Bytes.equals(ROW_3, results[0].getRow()));
467    assertTrue(Bytes.equals(ROW_4, results[1].getRow()));
468
469    results = scanner.next(1);
470    assertNull(results);
471    scanner.close();
472
473    scanner = remoteTable.getScanner(COLUMN_1);
474    results = scanner.next(4);
475    assertNotNull(results);
476    assertEquals(4, results.length);
477    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
478    assertTrue(Bytes.equals(ROW_2, results[1].getRow()));
479    assertTrue(Bytes.equals(ROW_3, results[2].getRow()));
480    assertTrue(Bytes.equals(ROW_4, results[3].getRow()));
481
482    scanner.close();
483
484    scanner = remoteTable.getScanner(COLUMN_1,QUALIFIER_1);
485    results = scanner.next(4);
486    assertNotNull(results);
487    assertEquals(4, results.length);
488    assertTrue(Bytes.equals(ROW_1, results[0].getRow()));
489    assertTrue(Bytes.equals(ROW_2, results[1].getRow()));
490    assertTrue(Bytes.equals(ROW_3, results[2].getRow()));
491    assertTrue(Bytes.equals(ROW_4, results[3].getRow()));
492    scanner.close();
493    assertTrue(remoteTable.isAutoFlush());
494  }
495
496  @Test
497  public void testCheckAndDelete() throws IOException {
498    Get get = new Get(ROW_1);
499    Result result = remoteTable.get(get);
500    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
501    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
502    assertNotNull(value1);
503    assertTrue(Bytes.equals(VALUE_1, value1));
504    assertNull(value2);
505    assertTrue(remoteTable.exists(get));
506    assertEquals(1, remoteTable.existsAll(Collections.singletonList(get)).length);
507    Delete delete = new Delete(ROW_1);
508
509    remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
510        .ifEquals(VALUE_1).thenDelete(delete);
511    assertFalse(remoteTable.exists(get));
512
513    Put put = new Put(ROW_1);
514    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
515    remoteTable.put(put);
516
517    assertTrue(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
518        .ifEquals(VALUE_1).thenPut(put));
519    assertFalse(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
520        .ifEquals(VALUE_2).thenPut(put));
521  }
522
523  /**
524   * Test RemoteHable.Scanner.iterator method
525   */
526  @Test
527  public void testIteratorScaner() throws IOException {
528    List<Put> puts = new ArrayList<>(4);
529    Put put = new Put(ROW_1);
530    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
531    puts.add(put);
532    put = new Put(ROW_2);
533    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
534    puts.add(put);
535    put = new Put(ROW_3);
536    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
537    puts.add(put);
538    put = new Put(ROW_4);
539    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
540    puts.add(put);
541    remoteTable.put(puts);
542
543    ResultScanner scanner = remoteTable.getScanner(new Scan());
544    Iterator<Result> iterator = scanner.iterator();
545    assertTrue(iterator.hasNext());
546    int counter = 0;
547    while (iterator.hasNext()) {
548      iterator.next();
549      counter++;
550    }
551    assertEquals(4, counter);
552  }
553
554  /**
555   * Test a some methods of class Response.
556   */
557  @Test
558  public void testResponse(){
559    Response response = new Response(200);
560    assertEquals(200, response.getCode());
561    Header[] headers = new Header[2];
562    headers[0] = new BasicHeader("header1", "value1");
563    headers[1] = new BasicHeader("header2", "value2");
564    response = new Response(200, headers);
565    assertEquals("value1", response.getHeader("header1"));
566    assertFalse(response.hasBody());
567    response.setCode(404);
568    assertEquals(404, response.getCode());
569    headers = new Header[2];
570    headers[0] = new BasicHeader("header1", "value1.1");
571    headers[1] = new BasicHeader("header2", "value2");
572    response.setHeaders(headers);
573    assertEquals("value1.1", response.getHeader("header1"));
574    response.setBody(Bytes.toBytes("body"));
575    assertTrue(response.hasBody());
576  }
577
578  /**
579   * Tests keeping a HBase scanner alive for long periods of time. Each call to next() should reset
580   * the ConnectionCache timeout for the scanner's connection.
581   *
582   * @throws Exception if starting the servlet container or disabling or truncating the table fails
583   */
584  @Test
585  public void testLongLivedScan() throws Exception {
586    int numTrials = 6;
587    int trialPause = 1000;
588    int cleanUpInterval = 100;
589
590    // Shutdown the Rest Servlet container
591    REST_TEST_UTIL.shutdownServletContainer();
592
593    // Set the ConnectionCache timeout to trigger halfway through the trials
594    TEST_UTIL.getConfiguration().setLong(RESTServlet.MAX_IDLETIME, (numTrials / 2) * trialPause);
595    TEST_UTIL.getConfiguration().setLong(RESTServlet.CLEANUP_INTERVAL, cleanUpInterval);
596
597    // Start the Rest Servlet container
598    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
599
600    // Truncate the test table for inserting test scenarios rows keys
601    TEST_UTIL.getHBaseAdmin().disableTable(TABLE);
602    TEST_UTIL.getHBaseAdmin().truncateTable(TABLE, false);
603
604    remoteTable = new RemoteHTable(
605        new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())),
606        TEST_UTIL.getConfiguration(), TABLE.toBytes());
607
608    String row = "testrow";
609
610    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
611      List<Put> puts = new ArrayList<Put>();
612      Put put = null;
613      for (int i = 1; i <= numTrials; i++) {
614        put = new Put(Bytes.toBytes(row + i));
615        put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + i));
616        puts.add(put);
617      }
618      table.put(puts);
619    }
620
621    Scan scan = new Scan();
622    scan.setCaching(1);
623    scan.setBatch(1);
624
625    ResultScanner scanner = remoteTable.getScanner(scan);
626    Result result = null;
627    // get scanner and rows
628    for (int i = 1; i <= numTrials; i++) {
629      // Make sure that the Scanner doesn't throw an exception after the ConnectionCache timeout
630      result = scanner.next();
631      assertEquals(row + i, Bytes.toString(result.getRow()));
632      Thread.sleep(trialPause);
633    }
634  }
635}