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;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.ByteArrayInputStream;
024import java.io.IOException;
025import java.net.InetSocketAddress;
026import java.util.ArrayList;
027import java.util.Iterator;
028import java.util.List;
029import javax.xml.bind.JAXBContext;
030import javax.xml.bind.JAXBException;
031import org.apache.hadoop.hbase.CellUtil;
032import org.apache.hadoop.hbase.HBaseClassTestRule;
033import org.apache.hadoop.hbase.HBaseTestingUtility;
034import org.apache.hadoop.hbase.HRegionInfo;
035import org.apache.hadoop.hbase.HRegionLocation;
036import org.apache.hadoop.hbase.ServerName;
037import org.apache.hadoop.hbase.TableName;
038import org.apache.hadoop.hbase.client.Connection;
039import org.apache.hadoop.hbase.client.Durability;
040import org.apache.hadoop.hbase.client.Put;
041import org.apache.hadoop.hbase.client.RegionLocator;
042import org.apache.hadoop.hbase.client.Table;
043import org.apache.hadoop.hbase.rest.client.Client;
044import org.apache.hadoop.hbase.rest.client.Cluster;
045import org.apache.hadoop.hbase.rest.client.Response;
046import org.apache.hadoop.hbase.rest.model.TableInfoModel;
047import org.apache.hadoop.hbase.rest.model.TableListModel;
048import org.apache.hadoop.hbase.rest.model.TableModel;
049import org.apache.hadoop.hbase.rest.model.TableRegionModel;
050import org.apache.hadoop.hbase.testclassification.MediumTests;
051import org.apache.hadoop.hbase.testclassification.RestTests;
052import org.apache.hadoop.hbase.util.Bytes;
053import org.junit.AfterClass;
054import org.junit.BeforeClass;
055import org.junit.ClassRule;
056import org.junit.Test;
057import org.junit.experimental.categories.Category;
058import org.slf4j.Logger;
059import org.slf4j.LoggerFactory;
060
061@Category({RestTests.class, MediumTests.class})
062public class TestTableResource {
063
064  @ClassRule
065  public static final HBaseClassTestRule CLASS_RULE =
066      HBaseClassTestRule.forClass(TestTableResource.class);
067
068  private static final Logger LOG = LoggerFactory.getLogger(TestTableResource.class);
069
070  private static final TableName TABLE = TableName.valueOf("TestTableResource");
071  private static final String COLUMN_FAMILY = "test";
072  private static final String COLUMN = COLUMN_FAMILY + ":qualifier";
073  private static final int NUM_REGIONS = 4;
074  private static List<HRegionLocation> regionMap;
075
076  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
077  private static final HBaseRESTTestingUtility REST_TEST_UTIL =
078    new HBaseRESTTestingUtility();
079  private static Client client;
080  private static JAXBContext context;
081
082  @BeforeClass
083  public static void setUpBeforeClass() throws Exception {
084    TEST_UTIL.startMiniCluster(3);
085    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
086    client = new Client(new Cluster().add("localhost",
087      REST_TEST_UTIL.getServletPort()));
088    context = JAXBContext.newInstance(
089        TableModel.class,
090        TableInfoModel.class,
091        TableListModel.class,
092        TableRegionModel.class);
093    TEST_UTIL.createMultiRegionTable(TABLE, Bytes.toBytes(COLUMN_FAMILY), NUM_REGIONS);
094    byte[] k = new byte[3];
095    byte [][] famAndQf = CellUtil.parseColumn(Bytes.toBytes(COLUMN));
096    List<Put> puts = new ArrayList<>();
097    for (byte b1 = 'a'; b1 < 'z'; b1++) {
098      for (byte b2 = 'a'; b2 < 'z'; b2++) {
099        for (byte b3 = 'a'; b3 < 'z'; b3++) {
100          k[0] = b1;
101          k[1] = b2;
102          k[2] = b3;
103          Put put = new Put(k);
104          put.setDurability(Durability.SKIP_WAL);
105          put.addColumn(famAndQf[0], famAndQf[1], k);
106          puts.add(put);
107        }
108      }
109    }
110
111    Connection connection = TEST_UTIL.getConnection();
112
113    Table table =  connection.getTable(TABLE);
114    table.put(puts);
115    table.close();
116
117    RegionLocator regionLocator = connection.getRegionLocator(TABLE);
118    List<HRegionLocation> m = regionLocator.getAllRegionLocations();
119
120    // should have four regions now
121    assertEquals(NUM_REGIONS, m.size());
122    regionMap = m;
123    LOG.error("regions: " + regionMap);
124    regionLocator.close();
125  }
126
127  @AfterClass
128  public static void tearDownAfterClass() throws Exception {
129    REST_TEST_UTIL.shutdownServletContainer();
130    TEST_UTIL.shutdownMiniCluster();
131  }
132
133  private static void checkTableList(TableListModel model) {
134    boolean found = false;
135    Iterator<TableModel> tables = model.getTables().iterator();
136    assertTrue(tables.hasNext());
137    while (tables.hasNext()) {
138      TableModel table = tables.next();
139      if (table.getName().equals(TABLE.getNameAsString())) {
140        found = true;
141        break;
142      }
143    }
144    assertTrue(found);
145  }
146
147  void checkTableInfo(TableInfoModel model) {
148    assertEquals(model.getName(), TABLE.getNameAsString());
149    Iterator<TableRegionModel> regions = model.getRegions().iterator();
150    assertTrue(regions.hasNext());
151    while (regions.hasNext()) {
152      TableRegionModel region = regions.next();
153      boolean found = false;
154      LOG.debug("looking for region " + region.getName());
155      for (HRegionLocation e: regionMap) {
156        HRegionInfo hri = e.getRegionInfo();
157        // getRegionNameAsString uses Bytes.toStringBinary which escapes some non-printable
158        // characters
159        String hriRegionName = Bytes.toString(hri.getRegionName());
160        String regionName = region.getName();
161        LOG.debug("comparing to region " + hriRegionName);
162        if (hriRegionName.equals(regionName)) {
163          found = true;
164          byte[] startKey = hri.getStartKey();
165          byte[] endKey = hri.getEndKey();
166          ServerName serverName = e.getServerName();
167          InetSocketAddress sa =
168              new InetSocketAddress(serverName.getHostname(), serverName.getPort());
169          String location = sa.getHostName() + ":" +
170            Integer.valueOf(sa.getPort());
171          assertEquals(hri.getRegionId(), region.getId());
172          assertTrue(Bytes.equals(startKey, region.getStartKey()));
173          assertTrue(Bytes.equals(endKey, region.getEndKey()));
174          assertEquals(location, region.getLocation());
175          break;
176        }
177      }
178      assertTrue("Couldn't find region " + region.getName(), found);
179    }
180  }
181
182  @Test
183  public void testTableListText() throws IOException {
184    Response response = client.get("/", Constants.MIMETYPE_TEXT);
185    assertEquals(200, response.getCode());
186    assertEquals(Constants.MIMETYPE_TEXT, response.getHeader("content-type"));
187  }
188
189  @Test
190  public void testTableListXML() throws IOException, JAXBException {
191    Response response = client.get("/", Constants.MIMETYPE_XML);
192    assertEquals(200, response.getCode());
193    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
194    TableListModel model = (TableListModel)
195      context.createUnmarshaller()
196        .unmarshal(new ByteArrayInputStream(response.getBody()));
197    checkTableList(model);
198  }
199
200  @Test
201  public void testTableListJSON() throws IOException {
202    Response response = client.get("/", Constants.MIMETYPE_JSON);
203    assertEquals(200, response.getCode());
204    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
205  }
206
207  @Test
208  public void testTableListPB() throws IOException, JAXBException {
209    Response response = client.get("/", Constants.MIMETYPE_PROTOBUF);
210    assertEquals(200, response.getCode());
211    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
212    TableListModel model = new TableListModel();
213    model.getObjectFromMessage(response.getBody());
214    checkTableList(model);
215    response = client.get("/", Constants.MIMETYPE_PROTOBUF_IETF);
216    assertEquals(200, response.getCode());
217    assertEquals(Constants.MIMETYPE_PROTOBUF_IETF, response.getHeader("content-type"));
218    model = new TableListModel();
219    model.getObjectFromMessage(response.getBody());
220    checkTableList(model);
221  }
222
223  @Test
224  public void testTableInfoText() throws IOException {
225    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_TEXT);
226    assertEquals(200, response.getCode());
227    assertEquals(Constants.MIMETYPE_TEXT, response.getHeader("content-type"));
228  }
229
230  @Test
231  public void testTableInfoXML() throws IOException, JAXBException {
232    Response response = client.get("/" + TABLE + "/regions",  Constants.MIMETYPE_XML);
233    assertEquals(200, response.getCode());
234    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
235    TableInfoModel model = (TableInfoModel)
236      context.createUnmarshaller()
237        .unmarshal(new ByteArrayInputStream(response.getBody()));
238    checkTableInfo(model);
239  }
240
241  @Test
242  public void testTableInfoJSON() throws IOException {
243    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_JSON);
244    assertEquals(200, response.getCode());
245    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
246  }
247
248  @Test
249  public void testTableInfoPB() throws IOException, JAXBException {
250    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_PROTOBUF);
251    assertEquals(200, response.getCode());
252    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
253    TableInfoModel model = new TableInfoModel();
254    model.getObjectFromMessage(response.getBody());
255    checkTableInfo(model);
256    response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_PROTOBUF_IETF);
257    assertEquals(200, response.getCode());
258    assertEquals(Constants.MIMETYPE_PROTOBUF_IETF, response.getHeader("content-type"));
259    model = new TableInfoModel();
260    model.getObjectFromMessage(response.getBody());
261    checkTableInfo(model);
262  }
263
264}
265