1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.rest;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.IOException;
25  import java.net.InetSocketAddress;
26  import java.util.Iterator;
27  import java.util.Map;
28  
29  import javax.xml.bind.JAXBContext;
30  import javax.xml.bind.JAXBException;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HColumnDescriptor;
36  import org.apache.hadoop.hbase.HRegionInfo;
37  import org.apache.hadoop.hbase.HServerAddress;
38  import org.apache.hadoop.hbase.HTableDescriptor;
39  import org.apache.hadoop.hbase.KeyValue;
40  import org.apache.hadoop.hbase.client.HBaseAdmin;
41  import org.apache.hadoop.hbase.client.HTable;
42  import org.apache.hadoop.hbase.client.Put;
43  import org.apache.hadoop.hbase.rest.client.Client;
44  import org.apache.hadoop.hbase.rest.client.Cluster;
45  import org.apache.hadoop.hbase.rest.client.Response;
46  import org.apache.hadoop.hbase.rest.model.TableModel;
47  import org.apache.hadoop.hbase.rest.model.TableInfoModel;
48  import org.apache.hadoop.hbase.rest.model.TableListModel;
49  import org.apache.hadoop.hbase.rest.model.TableRegionModel;
50  import org.apache.hadoop.hbase.util.Bytes;
51  import org.apache.hadoop.util.StringUtils;
52  
53  import static org.junit.Assert.*;
54  import org.junit.AfterClass;
55  import org.junit.BeforeClass;
56  import org.junit.Test;
57  
58  public class TestTableResource {
59    private static final Log LOG = LogFactory.getLog(TestTableResource.class);
60  
61    private static String TABLE = "TestTableResource";
62    private static String COLUMN_FAMILY = "test";
63    private static String COLUMN = COLUMN_FAMILY + ":qualifier";
64    private static Map<HRegionInfo,HServerAddress> regionMap;
65  
66    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
67    private static final HBaseRESTTestingUtility REST_TEST_UTIL = 
68      new HBaseRESTTestingUtility();
69    private static Client client;
70    private static JAXBContext context;
71  
72    @BeforeClass
73    public static void setUpBeforeClass() throws Exception {
74      TEST_UTIL.startMiniCluster(3);
75      REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
76      client = new Client(new Cluster().add("localhost", 
77        REST_TEST_UTIL.getServletPort()));
78      context = JAXBContext.newInstance(
79          TableModel.class,
80          TableInfoModel.class,
81          TableListModel.class,
82          TableRegionModel.class);
83      HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
84      if (admin.tableExists(TABLE)) {
85        return;
86      }
87      HTableDescriptor htd = new HTableDescriptor(TABLE);
88      htd.addFamily(new HColumnDescriptor(COLUMN_FAMILY));
89      admin.createTable(htd);
90      HTable table = new HTable(TEST_UTIL.getConfiguration(), TABLE);
91      byte[] k = new byte[3];
92      byte [][] famAndQf = KeyValue.parseColumn(Bytes.toBytes(COLUMN));
93      for (byte b1 = 'a'; b1 < 'z'; b1++) {
94        for (byte b2 = 'a'; b2 < 'z'; b2++) {
95          for (byte b3 = 'a'; b3 < 'z'; b3++) {
96            k[0] = b1;
97            k[1] = b2;
98            k[2] = b3;
99            Put put = new Put(k);
100           put.setWriteToWAL(false);
101           put.add(famAndQf[0], famAndQf[1], k);
102           table.put(put);
103         }
104       }
105     }
106     table.flushCommits();
107     // get the initial layout (should just be one region)
108     Map<HRegionInfo,HServerAddress> m = table.getRegionsInfo();
109     assertEquals(m.size(), 1);
110     // tell the master to split the table
111     admin.split(TABLE);
112     // give some time for the split to happen
113 
114     long timeout = System.currentTimeMillis() + (15 * 1000);
115     while (System.currentTimeMillis() < timeout && m.size()!=2){
116       try {
117         Thread.sleep(250);
118       } catch (InterruptedException e) {
119         LOG.warn(StringUtils.stringifyException(e));
120       }
121       // check again
122       m = table.getRegionsInfo();
123     }
124 
125     // should have two regions now
126     assertEquals(m.size(), 2);
127     regionMap = m;
128     LOG.info("regions: " + regionMap);
129   }
130 
131   @AfterClass
132   public static void tearDownAfterClass() throws Exception {
133     REST_TEST_UTIL.shutdownServletContainer();
134     TEST_UTIL.shutdownMiniCluster();
135   }
136 
137   private static void checkTableList(TableListModel model) {
138     boolean found = false;
139     Iterator<TableModel> tables = model.getTables().iterator();
140     assertTrue(tables.hasNext());
141     while (tables.hasNext()) {
142       TableModel table = tables.next();
143       if (table.getName().equals(TABLE)) {
144         found = true;
145         break;
146       }
147     }
148     assertTrue(found);
149   }
150 
151   void checkTableInfo(TableInfoModel model) {
152     assertEquals(model.getName(), TABLE);
153     Iterator<TableRegionModel> regions = model.getRegions().iterator();
154     assertTrue(regions.hasNext());
155     while (regions.hasNext()) {
156       TableRegionModel region = regions.next();
157       boolean found = false;
158       for (Map.Entry<HRegionInfo,HServerAddress> e: regionMap.entrySet()) {
159         HRegionInfo hri = e.getKey();
160         String hriRegionName = hri.getRegionNameAsString();
161         String regionName = region.getName();
162         if (hriRegionName.equals(regionName)) {
163           found = true;
164           byte[] startKey = hri.getStartKey();
165           byte[] endKey = hri.getEndKey();
166           InetSocketAddress sa = e.getValue().getInetSocketAddress();
167           String location = sa.getHostName() + ":" +
168             Integer.valueOf(sa.getPort());
169           assertEquals(hri.getRegionId(), region.getId());
170           assertTrue(Bytes.equals(startKey, region.getStartKey()));
171           assertTrue(Bytes.equals(endKey, region.getEndKey()));
172           assertEquals(location, region.getLocation());
173           break;
174         }
175       }
176       assertTrue(found);
177     }
178   }
179 
180   @Test
181   public void testTableListText() throws IOException {
182     Response response = client.get("/", Constants.MIMETYPE_TEXT);
183     assertEquals(response.getCode(), 200);
184   }
185 
186   @Test
187   public void testTableListXML() throws IOException, JAXBException {
188     Response response = client.get("/", Constants.MIMETYPE_XML);
189     assertEquals(response.getCode(), 200);
190     TableListModel model = (TableListModel)
191       context.createUnmarshaller()
192         .unmarshal(new ByteArrayInputStream(response.getBody()));
193     checkTableList(model);
194   }
195 
196   @Test
197   public void testTableListJSON() throws IOException {
198     Response response = client.get("/", Constants.MIMETYPE_JSON);
199     assertEquals(response.getCode(), 200);
200   }
201 
202   @Test
203   public void testTableListPB() throws IOException, JAXBException {
204     Response response = client.get("/", Constants.MIMETYPE_PROTOBUF);
205     assertEquals(response.getCode(), 200);
206     TableListModel model = new TableListModel();
207     model.getObjectFromMessage(response.getBody());
208     checkTableList(model);
209   }
210 
211   @Test
212   public void testTableInfoText() throws IOException {
213     Response response = client.get("/" + TABLE + "/regions",
214       Constants.MIMETYPE_TEXT);
215     assertEquals(response.getCode(), 200);
216   }
217 
218   @Test
219   public void testTableInfoXML() throws IOException, JAXBException {
220     Response response = client.get("/" + TABLE + "/regions", 
221       Constants.MIMETYPE_XML);
222     assertEquals(response.getCode(), 200);
223     TableInfoModel model = (TableInfoModel)
224       context.createUnmarshaller()
225         .unmarshal(new ByteArrayInputStream(response.getBody()));
226     checkTableInfo(model);
227   }
228 
229   @Test
230   public void testTableInfoJSON() throws IOException {
231     Response response = client.get("/" + TABLE + "/regions", 
232       Constants.MIMETYPE_JSON);
233     assertEquals(response.getCode(), 200);
234   }
235 
236   @Test
237   public void testTableInfoPB() throws IOException, JAXBException {
238     Response response = client.get("/" + TABLE + "/regions",
239       Constants.MIMETYPE_PROTOBUF);
240     assertEquals(response.getCode(), 200);
241     TableInfoModel model = new TableInfoModel();
242     model.getObjectFromMessage(response.getBody());
243     checkTableInfo(model);
244   }
245 }