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 = new HBaseRESTTestingUtility();
078  private static Client client;
079  private static JAXBContext context;
080
081  @BeforeClass
082  public static void setUpBeforeClass() throws Exception {
083    TEST_UTIL.startMiniCluster(3);
084    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
085    client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()));
086    context = JAXBContext.newInstance(TableModel.class, TableInfoModel.class, TableListModel.class,
087      TableRegionModel.class);
088    TEST_UTIL.createMultiRegionTable(TABLE, Bytes.toBytes(COLUMN_FAMILY), NUM_REGIONS);
089    byte[] k = new byte[3];
090    byte[][] famAndQf = CellUtil.parseColumn(Bytes.toBytes(COLUMN));
091    List<Put> puts = new ArrayList<>();
092    for (byte b1 = 'a'; b1 < 'z'; b1++) {
093      for (byte b2 = 'a'; b2 < 'z'; b2++) {
094        for (byte b3 = 'a'; b3 < 'z'; b3++) {
095          k[0] = b1;
096          k[1] = b2;
097          k[2] = b3;
098          Put put = new Put(k);
099          put.setDurability(Durability.SKIP_WAL);
100          put.addColumn(famAndQf[0], famAndQf[1], k);
101          puts.add(put);
102        }
103      }
104    }
105
106    Connection connection = TEST_UTIL.getConnection();
107
108    Table table = connection.getTable(TABLE);
109    table.put(puts);
110    table.close();
111
112    RegionLocator regionLocator = connection.getRegionLocator(TABLE);
113    List<HRegionLocation> m = regionLocator.getAllRegionLocations();
114
115    // should have four regions now
116    assertEquals(NUM_REGIONS, m.size());
117    regionMap = m;
118    LOG.error("regions: " + regionMap);
119    regionLocator.close();
120  }
121
122  @AfterClass
123  public static void tearDownAfterClass() throws Exception {
124    REST_TEST_UTIL.shutdownServletContainer();
125    TEST_UTIL.shutdownMiniCluster();
126  }
127
128  private static void checkTableList(TableListModel model) {
129    boolean found = false;
130    Iterator<TableModel> tables = model.getTables().iterator();
131    assertTrue(tables.hasNext());
132    while (tables.hasNext()) {
133      TableModel table = tables.next();
134      if (table.getName().equals(TABLE.getNameAsString())) {
135        found = true;
136        break;
137      }
138    }
139    assertTrue(found);
140  }
141
142  void checkTableInfo(TableInfoModel model) {
143    assertEquals(model.getName(), TABLE.getNameAsString());
144    Iterator<TableRegionModel> regions = model.getRegions().iterator();
145    assertTrue(regions.hasNext());
146    while (regions.hasNext()) {
147      TableRegionModel region = regions.next();
148      boolean found = false;
149      LOG.debug("looking for region " + region.getName());
150      for (HRegionLocation e : regionMap) {
151        HRegionInfo hri = e.getRegionInfo();
152        // getRegionNameAsString uses Bytes.toStringBinary which escapes some non-printable
153        // characters
154        String hriRegionName = Bytes.toString(hri.getRegionName());
155        String regionName = region.getName();
156        LOG.debug("comparing to region " + hriRegionName);
157        if (hriRegionName.equals(regionName)) {
158          found = true;
159          byte[] startKey = hri.getStartKey();
160          byte[] endKey = hri.getEndKey();
161          ServerName serverName = e.getServerName();
162          InetSocketAddress sa =
163            new InetSocketAddress(serverName.getHostname(), serverName.getPort());
164          String location = sa.getHostName() + ":" + Integer.valueOf(sa.getPort());
165          assertEquals(hri.getRegionId(), region.getId());
166          assertTrue(Bytes.equals(startKey, region.getStartKey()));
167          assertTrue(Bytes.equals(endKey, region.getEndKey()));
168          assertEquals(location, region.getLocation());
169          break;
170        }
171      }
172      assertTrue("Couldn't find region " + region.getName(), found);
173    }
174  }
175
176  @Test
177  public void testTableListText() throws IOException {
178    Response response = client.get("/", Constants.MIMETYPE_TEXT);
179    assertEquals(200, response.getCode());
180    assertEquals(Constants.MIMETYPE_TEXT, response.getHeader("content-type"));
181  }
182
183  @Test
184  public void testTableListXML() throws IOException, JAXBException {
185    Response response = client.get("/", Constants.MIMETYPE_XML);
186    assertEquals(200, response.getCode());
187    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
188    TableListModel model = (TableListModel) context.createUnmarshaller()
189      .unmarshal(new ByteArrayInputStream(response.getBody()));
190    checkTableList(model);
191  }
192
193  @Test
194  public void testTableListJSON() throws IOException {
195    Response response = client.get("/", Constants.MIMETYPE_JSON);
196    assertEquals(200, response.getCode());
197    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
198  }
199
200  @Test
201  public void testTableListPB() throws IOException, JAXBException {
202    Response response = client.get("/", Constants.MIMETYPE_PROTOBUF);
203    assertEquals(200, response.getCode());
204    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
205    TableListModel model = new TableListModel();
206    model.getObjectFromMessage(response.getBody());
207    checkTableList(model);
208    response = client.get("/", Constants.MIMETYPE_PROTOBUF_IETF);
209    assertEquals(200, response.getCode());
210    assertEquals(Constants.MIMETYPE_PROTOBUF_IETF, response.getHeader("content-type"));
211    model = new TableListModel();
212    model.getObjectFromMessage(response.getBody());
213    checkTableList(model);
214  }
215
216  @Test
217  public void testTableInfoText() throws IOException {
218    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_TEXT);
219    assertEquals(200, response.getCode());
220    assertEquals(Constants.MIMETYPE_TEXT, response.getHeader("content-type"));
221  }
222
223  @Test
224  public void testTableInfoXML() throws IOException, JAXBException {
225    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_XML);
226    assertEquals(200, response.getCode());
227    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
228    TableInfoModel model = (TableInfoModel) context.createUnmarshaller()
229      .unmarshal(new ByteArrayInputStream(response.getBody()));
230    checkTableInfo(model);
231  }
232
233  @Test
234  public void testTableInfoJSON() throws IOException {
235    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_JSON);
236    assertEquals(200, response.getCode());
237    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
238  }
239
240  @Test
241  public void testTableInfoPB() throws IOException, JAXBException {
242    Response response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_PROTOBUF);
243    assertEquals(200, response.getCode());
244    assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
245    TableInfoModel model = new TableInfoModel();
246    model.getObjectFromMessage(response.getBody());
247    checkTableInfo(model);
248    response = client.get("/" + TABLE + "/regions", Constants.MIMETYPE_PROTOBUF_IETF);
249    assertEquals(200, response.getCode());
250    assertEquals(Constants.MIMETYPE_PROTOBUF_IETF, response.getHeader("content-type"));
251    model = new TableInfoModel();
252    model.getObjectFromMessage(response.getBody());
253    checkTableInfo(model);
254  }
255
256  @Test
257  public void testTableNotFound() throws IOException {
258    String notExistTable = "notexist";
259    Response response1 = client.get("/" + notExistTable + "/schema", Constants.MIMETYPE_JSON);
260    assertEquals(404, response1.getCode());
261    Response response2 = client.get("/" + notExistTable + "/regions", Constants.MIMETYPE_XML);
262    assertEquals(404, response2.getCode());
263  }
264
265}