1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.rest;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.IOException;
29 import java.io.StringWriter;
30 import java.util.ArrayList;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Random;
34
35 import javax.xml.bind.JAXBContext;
36 import javax.xml.bind.JAXBException;
37 import javax.xml.bind.Marshaller;
38 import javax.xml.bind.Unmarshaller;
39
40 import org.apache.commons.httpclient.Header;
41 import org.apache.hadoop.conf.Configuration;
42 import org.apache.hadoop.hbase.HBaseTestingUtility;
43 import org.apache.hadoop.hbase.HColumnDescriptor;
44 import org.apache.hadoop.hbase.HTableDescriptor;
45 import org.apache.hadoop.hbase.KeyValue;
46 import org.apache.hadoop.hbase.TableName;
47 import org.apache.hadoop.hbase.client.Admin;
48 import org.apache.hadoop.hbase.client.Connection;
49 import org.apache.hadoop.hbase.client.ConnectionFactory;
50 import org.apache.hadoop.hbase.client.Durability;
51 import org.apache.hadoop.hbase.client.Put;
52 import org.apache.hadoop.hbase.client.Table;
53 import org.apache.hadoop.hbase.rest.client.Client;
54 import org.apache.hadoop.hbase.rest.client.Cluster;
55 import org.apache.hadoop.hbase.rest.client.Response;
56 import org.apache.hadoop.hbase.rest.model.CellModel;
57 import org.apache.hadoop.hbase.rest.model.CellSetModel;
58 import org.apache.hadoop.hbase.rest.model.RowModel;
59 import org.apache.hadoop.hbase.rest.model.ScannerModel;
60 import org.apache.hadoop.hbase.testclassification.MediumTests;
61 import org.apache.hadoop.hbase.util.Bytes;
62 import org.junit.AfterClass;
63 import org.junit.BeforeClass;
64 import org.junit.Test;
65 import org.junit.experimental.categories.Category;
66
67 @Category(MediumTests.class)
68 public class TestScannerResource {
69
70 private static final TableName TABLE = TableName.valueOf("TestScannerResource");
71 private static final TableName TABLE_TO_BE_DISABLED = TableName.valueOf("ScannerResourceDisable");
72 private static final String NONEXISTENT_TABLE = "ThisTableDoesNotExist";
73 private static final String CFA = "a";
74 private static final String CFB = "b";
75 private static final String COLUMN_1 = CFA + ":1";
76 private static final String COLUMN_2 = CFB + ":2";
77
78 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
79 private static final HBaseRESTTestingUtility REST_TEST_UTIL =
80 new HBaseRESTTestingUtility();
81 private static Client client;
82 private static JAXBContext context;
83 private static Marshaller marshaller;
84 private static Unmarshaller unmarshaller;
85 private static int expectedRows1;
86 private static int expectedRows2;
87 private static Configuration conf;
88
89 static int insertData(Configuration conf, TableName tableName, String column, double prob)
90 throws IOException {
91 Random rng = new Random();
92 byte[] k = new byte[3];
93 byte [][] famAndQf = KeyValue.parseColumn(Bytes.toBytes(column));
94 List<Put> puts = new ArrayList<>();
95 for (byte b1 = 'a'; b1 < 'z'; b1++) {
96 for (byte b2 = 'a'; b2 < 'z'; b2++) {
97 for (byte b3 = 'a'; b3 < 'z'; b3++) {
98 if (rng.nextDouble() < prob) {
99 k[0] = b1;
100 k[1] = b2;
101 k[2] = b3;
102 Put put = new Put(k);
103 put.setDurability(Durability.SKIP_WAL);
104 put.add(famAndQf[0], famAndQf[1], k);
105 puts.add(put);
106 }
107 }
108 }
109 }
110 try (Connection conn = ConnectionFactory.createConnection(conf);
111 Table table = conn.getTable(tableName)) {
112 table.put(puts);
113 }
114 return puts.size();
115 }
116
117 static int countCellSet(CellSetModel model) {
118 int count = 0;
119 Iterator<RowModel> rows = model.getRows().iterator();
120 while (rows.hasNext()) {
121 RowModel row = rows.next();
122 Iterator<CellModel> cells = row.getCells().iterator();
123 while (cells.hasNext()) {
124 cells.next();
125 count++;
126 }
127 }
128 return count;
129 }
130
131 private static int fullTableScan(ScannerModel model) throws IOException {
132 model.setBatch(100);
133 Response response = client.put("/" + TABLE + "/scanner",
134 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
135 assertEquals(201, response.getCode());
136 String scannerURI = response.getLocation();
137 assertNotNull(scannerURI);
138 int count = 0;
139 while (true) {
140 response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
141 assertTrue(response.getCode() == 200 || response.getCode() == 204);
142 if (response.getCode() == 200) {
143 assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
144 CellSetModel cellSet = new CellSetModel();
145 cellSet.getObjectFromMessage(response.getBody());
146 Iterator<RowModel> rows = cellSet.getRows().iterator();
147 while (rows.hasNext()) {
148 RowModel row = rows.next();
149 Iterator<CellModel> cells = row.getCells().iterator();
150 while (cells.hasNext()) {
151 cells.next();
152 count++;
153 }
154 }
155 } else {
156 break;
157 }
158 }
159
160 response = client.delete(scannerURI);
161 assertEquals(200, response.getCode());
162 return count;
163 }
164
165 @BeforeClass
166 public static void setUpBeforeClass() throws Exception {
167 conf = TEST_UTIL.getConfiguration();
168 TEST_UTIL.startMiniCluster();
169 REST_TEST_UTIL.startServletContainer(conf);
170 client = new Client(new Cluster().add("localhost",
171 REST_TEST_UTIL.getServletPort()));
172 context = JAXBContext.newInstance(
173 CellModel.class,
174 CellSetModel.class,
175 RowModel.class,
176 ScannerModel.class);
177 marshaller = context.createMarshaller();
178 unmarshaller = context.createUnmarshaller();
179 Admin admin = TEST_UTIL.getHBaseAdmin();
180 if (admin.tableExists(TABLE)) {
181 return;
182 }
183 HTableDescriptor htd = new HTableDescriptor(TABLE);
184 htd.addFamily(new HColumnDescriptor(CFA));
185 htd.addFamily(new HColumnDescriptor(CFB));
186 admin.createTable(htd);
187 expectedRows1 = insertData(TEST_UTIL.getConfiguration(), TABLE, COLUMN_1, 1.0);
188 expectedRows2 = insertData(TEST_UTIL.getConfiguration(), TABLE, COLUMN_2, 0.5);
189
190 htd = new HTableDescriptor(TABLE_TO_BE_DISABLED);
191 htd.addFamily(new HColumnDescriptor(CFA));
192 htd.addFamily(new HColumnDescriptor(CFB));
193 admin.createTable(htd);
194 }
195
196 @AfterClass
197 public static void tearDownAfterClass() throws Exception {
198 REST_TEST_UTIL.shutdownServletContainer();
199 TEST_UTIL.shutdownMiniCluster();
200 }
201
202 @Test
203 public void testSimpleScannerXML() throws IOException, JAXBException {
204 final int BATCH_SIZE = 5;
205
206 ScannerModel model = new ScannerModel();
207 model.setBatch(BATCH_SIZE);
208 model.addColumn(Bytes.toBytes(COLUMN_1));
209 StringWriter writer = new StringWriter();
210 marshaller.marshal(model, writer);
211 byte[] body = Bytes.toBytes(writer.toString());
212
213
214 conf.set("hbase.rest.readonly", "true");
215 Response response = client.put("/" + TABLE + "/scanner",
216 Constants.MIMETYPE_XML, body);
217 assertEquals(403, response.getCode());
218 String scannerURI = response.getLocation();
219 assertNull(scannerURI);
220
221
222 conf.set("hbase.rest.readonly", "false");
223 response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML,
224 body);
225 assertEquals(201, response.getCode());
226 scannerURI = response.getLocation();
227 assertNotNull(scannerURI);
228
229
230 response = client.get(scannerURI, Constants.MIMETYPE_XML);
231 assertEquals(200, response.getCode());
232 assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
233 CellSetModel cellSet = (CellSetModel)
234 unmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
235
236 assertEquals(BATCH_SIZE, countCellSet(cellSet));
237
238
239 conf.set("hbase.rest.readonly", "true");
240 response = client.delete(scannerURI);
241 assertEquals(403, response.getCode());
242
243
244 conf.set("hbase.rest.readonly", "false");
245 response = client.delete(scannerURI);
246 assertEquals(200, response.getCode());
247 }
248
249 @Test
250 public void testSimpleScannerPB() throws IOException {
251 final int BATCH_SIZE = 10;
252
253 ScannerModel model = new ScannerModel();
254 model.setBatch(BATCH_SIZE);
255 model.addColumn(Bytes.toBytes(COLUMN_1));
256
257
258 conf.set("hbase.rest.readonly", "true");
259 Response response = client.put("/" + TABLE + "/scanner",
260 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
261 assertEquals(403, response.getCode());
262 String scannerURI = response.getLocation();
263 assertNull(scannerURI);
264
265
266 conf.set("hbase.rest.readonly", "false");
267 response = client.put("/" + TABLE + "/scanner",
268 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
269 assertEquals(201, response.getCode());
270 scannerURI = response.getLocation();
271 assertNotNull(scannerURI);
272
273
274 response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
275 assertEquals(200, response.getCode());
276 assertEquals(Constants.MIMETYPE_PROTOBUF, response.getHeader("content-type"));
277 CellSetModel cellSet = new CellSetModel();
278 cellSet.getObjectFromMessage(response.getBody());
279
280 assertEquals(BATCH_SIZE, countCellSet(cellSet));
281
282
283 conf.set("hbase.rest.readonly", "true");
284 response = client.delete(scannerURI);
285 assertEquals(403, response.getCode());
286
287
288 conf.set("hbase.rest.readonly", "false");
289 response = client.delete(scannerURI);
290 assertEquals(200, response.getCode());
291 }
292
293 @Test
294 public void testSimpleScannerBinary() throws IOException {
295
296 ScannerModel model = new ScannerModel();
297 model.setBatch(1);
298 model.addColumn(Bytes.toBytes(COLUMN_1));
299
300
301 conf.set("hbase.rest.readonly", "true");
302 Response response = client.put("/" + TABLE + "/scanner",
303 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
304 assertEquals(403, response.getCode());
305 String scannerURI = response.getLocation();
306 assertNull(scannerURI);
307
308
309 conf.set("hbase.rest.readonly", "false");
310 response = client.put("/" + TABLE + "/scanner",
311 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
312 assertEquals(201, response.getCode());
313 scannerURI = response.getLocation();
314 assertNotNull(scannerURI);
315
316
317 response = client.get(scannerURI, Constants.MIMETYPE_BINARY);
318 assertEquals(200, response.getCode());
319 assertEquals(Constants.MIMETYPE_BINARY, response.getHeader("content-type"));
320
321 assertTrue(response.getBody().length > 0);
322
323 boolean foundRowHeader = false, foundColumnHeader = false,
324 foundTimestampHeader = false;
325 for (Header header: response.getHeaders()) {
326 if (header.getName().equals("X-Row")) {
327 foundRowHeader = true;
328 } else if (header.getName().equals("X-Column")) {
329 foundColumnHeader = true;
330 } else if (header.getName().equals("X-Timestamp")) {
331 foundTimestampHeader = true;
332 }
333 }
334 assertTrue(foundRowHeader);
335 assertTrue(foundColumnHeader);
336 assertTrue(foundTimestampHeader);
337
338
339 conf.set("hbase.rest.readonly", "true");
340 response = client.delete(scannerURI);
341 assertEquals(403, response.getCode());
342
343
344 conf.set("hbase.rest.readonly", "false");
345 response = client.delete(scannerURI);
346 assertEquals(200, response.getCode());
347 }
348
349 @Test
350 public void testFullTableScan() throws IOException {
351 ScannerModel model = new ScannerModel();
352 model.addColumn(Bytes.toBytes(COLUMN_1));
353 assertEquals(expectedRows1, fullTableScan(model));
354
355 model = new ScannerModel();
356 model.addColumn(Bytes.toBytes(COLUMN_2));
357 assertEquals(expectedRows2, fullTableScan(model));
358 }
359
360 @Test
361 public void testTableDoesNotExist() throws IOException, JAXBException {
362 ScannerModel model = new ScannerModel();
363 StringWriter writer = new StringWriter();
364 marshaller.marshal(model, writer);
365 byte[] body = Bytes.toBytes(writer.toString());
366 Response response = client.put("/" + NONEXISTENT_TABLE +
367 "/scanner", Constants.MIMETYPE_XML, body);
368 String scannerURI = response.getLocation();
369 assertNotNull(scannerURI);
370 response = client.get(scannerURI, Constants.MIMETYPE_XML);
371 assertEquals(404, response.getCode());
372 }
373
374
375
376 @Test
377 public void testTableScanWithTableDisable() throws IOException {
378 ScannerModel model = new ScannerModel();
379 model.addColumn(Bytes.toBytes(COLUMN_1));
380 model.setCaching(1);
381 Response response = client.put("/" + TABLE_TO_BE_DISABLED + "/scanner",
382 Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
383 assertEquals(201, response.getCode());
384 String scannerURI = response.getLocation();
385 assertNotNull(scannerURI);
386 TEST_UTIL.getHBaseAdmin().disableTable(TABLE_TO_BE_DISABLED);
387 response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
388 assertTrue("got " + response.getCode(), response.getCode() == 410);
389 }
390
391 }
392