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.testclassification.MediumTests;
048import org.apache.hadoop.hbase.testclassification.RestTests;
049import org.apache.hadoop.hbase.util.Bytes;
050import org.apache.http.Header;
051import org.apache.http.message.BasicHeader;
052import org.junit.After;
053import org.junit.AfterClass;
054import org.junit.Before;
055import org.junit.BeforeClass;
056import org.junit.ClassRule;
057import org.junit.Test;
058import org.junit.experimental.categories.Category;
059
060@Category({RestTests.class, MediumTests.class})
061public class TestRemoteTable {
062
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)) admin.disableTable(TABLE);
118      admin.deleteTable(TABLE);
119    }
120    HTableDescriptor htd = new HTableDescriptor(TABLE);
121    htd.addFamily(new HColumnDescriptor(COLUMN_1).setMaxVersions(3));
122    htd.addFamily(new HColumnDescriptor(COLUMN_2).setMaxVersions(3));
123    htd.addFamily(new HColumnDescriptor(COLUMN_3).setMaxVersions(3));
124    admin.createTable(htd);
125    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
126      Put put = new Put(ROW_1);
127      put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_1);
128      table.put(put);
129      put = new Put(ROW_2);
130      put.addColumn(COLUMN_1, QUALIFIER_1, TS_1, VALUE_1);
131      put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, VALUE_2);
132      put.addColumn(COLUMN_2, QUALIFIER_2, TS_2, VALUE_2);
133      table.put(put);
134    }
135    remoteTable = new RemoteHTable(
136      new Client(new Cluster().add("localhost",
137          REST_TEST_UTIL.getServletPort())),
138        TEST_UTIL.getConfiguration(), TABLE.toBytes());
139  }
140
141  @After
142  public void after() throws Exception {
143    remoteTable.close();
144  }
145
146  @AfterClass
147  public static void tearDownAfterClass() throws Exception {
148    REST_TEST_UTIL.shutdownServletContainer();
149    TEST_UTIL.shutdownMiniCluster();
150  }
151
152  @Test
153  public void testGetTableDescriptor() throws IOException {
154    Table table = null;
155    try {
156      table = TEST_UTIL.getConnection().getTable(TABLE);
157      HTableDescriptor local = table.getTableDescriptor();
158      assertEquals(remoteTable.getTableDescriptor(), local);
159    } finally {
160      if (null != table) table.close();
161    }
162  }
163
164  @Test
165  public void testGet() throws IOException {
166    Get get = new Get(ROW_1);
167    Result result = remoteTable.get(get);
168    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
169    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
170    assertNotNull(value1);
171    assertTrue(Bytes.equals(VALUE_1, value1));
172    assertNull(value2);
173
174    get = new Get(ROW_1);
175    get.addFamily(COLUMN_3);
176    result = remoteTable.get(get);
177    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
178    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
179    assertNull(value1);
180    assertNull(value2);
181
182    get = new Get(ROW_1);
183    get.addColumn(COLUMN_1, QUALIFIER_1);
184    get.addColumn(COLUMN_2, QUALIFIER_2);
185    result = remoteTable.get(get);
186    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
187    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
188    assertNotNull(value1);
189    assertTrue(Bytes.equals(VALUE_1, value1));
190    assertNull(value2);
191
192    get = new Get(ROW_2);
193    result = remoteTable.get(get);
194    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
195    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
196    assertNotNull(value1);
197    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
198    assertNotNull(value2);
199    assertTrue(Bytes.equals(VALUE_2, value2));
200
201    get = new Get(ROW_2);
202    get.addFamily(COLUMN_1);
203    result = remoteTable.get(get);
204    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
205    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
206    assertNotNull(value1);
207    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
208    assertNull(value2);
209
210    get = new Get(ROW_2);
211    get.addColumn(COLUMN_1, QUALIFIER_1);
212    get.addColumn(COLUMN_2, QUALIFIER_2);
213    result = remoteTable.get(get);
214    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
215    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
216    assertNotNull(value1);
217    assertTrue(Bytes.equals(VALUE_2, value1)); // @TS_2
218    assertNotNull(value2);
219    assertTrue(Bytes.equals(VALUE_2, value2));
220
221    // test timestamp
222
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
236    get = new Get(ROW_2);
237    get.addFamily(COLUMN_1);
238    get.addFamily(COLUMN_2);
239    get.setTimeRange(0, TS_1 + 1);
240    result = remoteTable.get(get);
241    value1 = result.getValue(COLUMN_1, QUALIFIER_1);
242    value2 = result.getValue(COLUMN_2, QUALIFIER_2);
243    assertNotNull(value1);
244    assertTrue(Bytes.equals(VALUE_1, value1)); // @TS_1
245    assertNull(value2);
246
247    // test maxVersions
248
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
321    List<Put> puts = new ArrayList<>(3);
322    put = new Put(ROW_3);
323    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
324    puts.add(put);
325    put = new Put(ROW_4);
326    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
327    puts.add(put);
328    put = new Put(ROW_4);
329    put.addColumn(COLUMN_2, QUALIFIER_2, VALUE_2);
330    puts.add(put);
331    remoteTable.put(puts);
332
333    get = new Get(ROW_3);
334    get.addFamily(COLUMN_2);
335    result = remoteTable.get(get);
336    value = result.getValue(COLUMN_2, QUALIFIER_2);
337    assertNotNull(value);
338    assertTrue(Bytes.equals(VALUE_2, value));
339    get = new Get(ROW_4);
340    result = remoteTable.get(get);
341    value = result.getValue(COLUMN_1, QUALIFIER_1);
342    assertNotNull(value);
343    assertTrue(Bytes.equals(VALUE_1, value));
344    value = result.getValue(COLUMN_2, QUALIFIER_2);
345    assertNotNull(value);
346    assertTrue(Bytes.equals(VALUE_2, value));
347
348    assertTrue(Bytes.equals(Bytes.toBytes("TestRemoteTable" + VALID_TABLE_NAME_CHARS), 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
497  @Test
498  public void testCheckAndDelete() throws IOException {
499    Get get = new Get(ROW_1);
500    Result result = remoteTable.get(get);
501    byte[] value1 = result.getValue(COLUMN_1, QUALIFIER_1);
502    byte[] value2 = result.getValue(COLUMN_2, QUALIFIER_2);
503    assertNotNull(value1);
504    assertTrue(Bytes.equals(VALUE_1, value1));
505    assertNull(value2);
506    assertTrue(remoteTable.exists(get));
507    assertEquals(1, remoteTable.existsAll(Collections.singletonList(get)).length);
508    Delete delete = new Delete(ROW_1);
509
510    remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
511        .ifEquals(VALUE_1).thenDelete(delete);
512    assertFalse(remoteTable.exists(get));
513
514    Put put = new Put(ROW_1);
515    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
516    remoteTable.put(put);
517
518    assertTrue(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
519        .ifEquals(VALUE_1).thenPut(put));
520    assertFalse(remoteTable.checkAndMutate(ROW_1, COLUMN_1).qualifier(QUALIFIER_1)
521        .ifEquals(VALUE_2).thenPut(put));
522  }
523
524  /**
525   * Test RemoteHable.Scanner.iterator method
526   */
527  @Test
528  public void testIteratorScaner() throws IOException {
529    List<Put> puts = new ArrayList<>(4);
530    Put put = new Put(ROW_1);
531    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
532    puts.add(put);
533    put = new Put(ROW_2);
534    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
535    puts.add(put);
536    put = new Put(ROW_3);
537    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
538    puts.add(put);
539    put = new Put(ROW_4);
540    put.addColumn(COLUMN_1, QUALIFIER_1, VALUE_1);
541    puts.add(put);
542    remoteTable.put(puts);
543
544    ResultScanner scanner = remoteTable.getScanner(new Scan());
545    Iterator<Result> iterator = scanner.iterator();
546    assertTrue(iterator.hasNext());
547    int counter = 0;
548    while (iterator.hasNext()) {
549      iterator.next();
550      counter++;
551    }
552    assertEquals(4, counter);
553  }
554
555  /**
556   * Test a some methods of class Response.
557   */
558  @Test
559  public void testResponse(){
560    Response response = new Response(200);
561    assertEquals(200, response.getCode());
562    Header[] headers = new Header[2];
563    headers[0] = new BasicHeader("header1", "value1");
564    headers[1] = new BasicHeader("header2", "value2");
565    response = new Response(200, headers);
566    assertEquals("value1", response.getHeader("header1"));
567    assertFalse(response.hasBody());
568    response.setCode(404);
569    assertEquals(404, response.getCode());
570    headers = new Header[2];
571    headers[0] = new BasicHeader("header1", "value1.1");
572    headers[1] = new BasicHeader("header2", "value2");
573    response.setHeaders(headers);
574    assertEquals("value1.1", response.getHeader("header1"));
575    response.setBody(Bytes.toBytes("body"));
576    assertTrue(response.hasBody());
577  }
578
579}
580