1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.rest;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.io.StringWriter;
27 import java.net.URLEncoder;
28 import java.util.List;
29
30 import javax.xml.bind.JAXBException;
31
32 import org.apache.commons.httpclient.Header;
33 import org.apache.hadoop.hbase.CompatibilityFactory;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.MediumTests;
36 import org.apache.hadoop.hbase.rest.client.Response;
37 import org.apache.hadoop.hbase.rest.model.CellModel;
38 import org.apache.hadoop.hbase.rest.model.CellSetModel;
39 import org.apache.hadoop.hbase.rest.model.RowModel;
40 import org.apache.hadoop.hbase.security.User;
41 import org.apache.hadoop.hbase.test.MetricsAssertHelper;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.security.UserGroupInformation;
44 import org.junit.Test;
45 import org.junit.experimental.categories.Category;
46
47 @Category(MediumTests.class)
48 public class TestGetAndPutResource extends RowResourceBase {
49
50 private static final MetricsAssertHelper METRICS_ASSERT =
51 CompatibilityFactory.getInstance(MetricsAssertHelper.class);
52
53 @Test
54 public void testForbidden() throws IOException, JAXBException {
55 conf.set("hbase.rest.readonly", "true");
56
57 Response response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
58 assertEquals(response.getCode(), 403);
59 response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
60 assertEquals(response.getCode(), 403);
61 response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
62 assertEquals(response.getCode(), 403);
63 response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
64 assertEquals(response.getCode(), 403);
65 response = deleteValue(TABLE, ROW_1, COLUMN_1);
66 assertEquals(response.getCode(), 403);
67 response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
68 assertEquals(response.getCode(), 403);
69 response = deleteRow(TABLE, ROW_1);
70 assertEquals(response.getCode(), 403);
71
72 conf.set("hbase.rest.readonly", "false");
73
74 response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
75 assertEquals(response.getCode(), 200);
76 response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
77 assertEquals(response.getCode(), 200);
78 response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
79 assertEquals(response.getCode(), 200);
80 response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
81 assertEquals(response.getCode(), 200);
82 response = deleteValue(TABLE, ROW_1, COLUMN_1);
83 assertEquals(response.getCode(), 200);
84 response = deleteRow(TABLE, ROW_1);
85 assertEquals(response.getCode(), 200);
86 }
87
88 @Test
89 public void testSingleCellGetPutXML() throws IOException, JAXBException {
90 Response response = getValueXML(TABLE, ROW_1, COLUMN_1);
91 assertEquals(response.getCode(), 404);
92
93 response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
94 assertEquals(response.getCode(), 200);
95 checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
96 response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
97 assertEquals(response.getCode(), 200);
98 checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
99 response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
100 assertEquals(response.getCode(), 200);
101 checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
102 response = checkAndDeleteXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
103 assertEquals(response.getCode(), 200);
104
105 response = deleteRow(TABLE, ROW_1);
106 assertEquals(response.getCode(), 200);
107 }
108
109 @Test
110 public void testSingleCellGetPutPB() throws IOException, JAXBException {
111 Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
112 assertEquals(response.getCode(), 404);
113
114 response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
115 assertEquals(response.getCode(), 200);
116 checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
117 response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
118 assertEquals(response.getCode(), 200);
119 checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2);
120
121 response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
122 assertEquals(response.getCode(), 200);
123 checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
124 response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3, VALUE_4);
125 assertEquals(response.getCode(), 200);
126 checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_4);
127
128 response = deleteRow(TABLE, ROW_1);
129 assertEquals(response.getCode(), 200);
130 }
131
132 @Test
133 public void testSingleCellGetPutBinary() throws IOException {
134 final String path = "/" + TABLE + "/" + ROW_3 + "/" + COLUMN_1;
135 final byte[] body = Bytes.toBytes(VALUE_3);
136 Response response = client.put(path, Constants.MIMETYPE_BINARY, body);
137 assertEquals(response.getCode(), 200);
138 Thread.yield();
139
140 response = client.get(path, Constants.MIMETYPE_BINARY);
141 assertEquals(response.getCode(), 200);
142 assertEquals(Constants.MIMETYPE_BINARY, response.getHeader("content-type"));
143 assertTrue(Bytes.equals(response.getBody(), body));
144 boolean foundTimestampHeader = false;
145 for (Header header: response.getHeaders()) {
146 if (header.getName().equals("X-Timestamp")) {
147 foundTimestampHeader = true;
148 break;
149 }
150 }
151 assertTrue(foundTimestampHeader);
152
153 response = deleteRow(TABLE, ROW_3);
154 assertEquals(response.getCode(), 200);
155 }
156
157 @Test
158 public void testSingleCellGetJSON() throws IOException, JAXBException {
159 final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
160 Response response = client.put(path, Constants.MIMETYPE_BINARY,
161 Bytes.toBytes(VALUE_4));
162 assertEquals(response.getCode(), 200);
163 Thread.yield();
164 response = client.get(path, Constants.MIMETYPE_JSON);
165 assertEquals(response.getCode(), 200);
166 assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
167 response = deleteRow(TABLE, ROW_4);
168 assertEquals(response.getCode(), 200);
169 }
170
171 @Test
172 public void testLatestCellGetJSON() throws IOException, JAXBException {
173 final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
174 CellSetModel cellSetModel = new CellSetModel();
175 RowModel rowModel = new RowModel(ROW_4);
176 CellModel cellOne = new CellModel(Bytes.toBytes(COLUMN_1), 1L,
177 Bytes.toBytes(VALUE_1));
178 CellModel cellTwo = new CellModel(Bytes.toBytes(COLUMN_1), 2L,
179 Bytes.toBytes(VALUE_2));
180 rowModel.addCell(cellOne);
181 rowModel.addCell(cellTwo);
182 cellSetModel.addRow(rowModel);
183 String jsonString = jsonMapper.writeValueAsString(cellSetModel);
184 Response response = client.put(path, Constants.MIMETYPE_JSON,
185 Bytes.toBytes(jsonString));
186 assertEquals(response.getCode(), 200);
187 Thread.yield();
188 response = client.get(path, Constants.MIMETYPE_JSON);
189 assertEquals(response.getCode(), 200);
190 assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
191 CellSetModel cellSet = jsonMapper.readValue(response.getBody(), CellSetModel.class);
192 assertTrue(cellSet.getRows().size() == 1);
193 assertTrue(cellSet.getRows().get(0).getCells().size() == 1);
194 CellModel cell = cellSet.getRows().get(0).getCells().get(0);
195 assertEquals(VALUE_2 , Bytes.toString(cell.getValue()));
196 assertEquals(2L , cell.getTimestamp());
197 response = deleteRow(TABLE, ROW_4);
198 assertEquals(response.getCode(), 200);
199 }
200
201 @Test
202 public void testURLEncodedKey() throws IOException, JAXBException {
203 String urlKey = "http://example.com/foo";
204 StringBuilder path = new StringBuilder();
205 path.append('/');
206 path.append(TABLE);
207 path.append('/');
208 path.append(URLEncoder.encode(urlKey, HConstants.UTF8_ENCODING));
209 path.append('/');
210 path.append(COLUMN_1);
211 Response response;
212 response = putValueXML(path.toString(), TABLE, urlKey, COLUMN_1,
213 VALUE_1);
214 assertEquals(response.getCode(), 200);
215 checkValueXML(path.toString(), TABLE, urlKey, COLUMN_1, VALUE_1);
216 }
217
218 @Test
219 public void testNoSuchCF() throws IOException, JAXBException {
220 final String goodPath = "/" + TABLE + "/" + ROW_1 + "/" + CFA+":";
221 final String badPath = "/" + TABLE + "/" + ROW_1 + "/" + "BAD";
222 Response response = client.post(goodPath, Constants.MIMETYPE_BINARY,
223 Bytes.toBytes(VALUE_1));
224 assertEquals(response.getCode(), 200);
225 assertEquals(client.get(goodPath, Constants.MIMETYPE_BINARY).getCode(),
226 200);
227 assertEquals(client.get(badPath, Constants.MIMETYPE_BINARY).getCode(),
228 404);
229 assertEquals(client.get(goodPath, Constants.MIMETYPE_BINARY).getCode(),
230 200);
231 }
232
233 @Test
234 public void testMultiCellGetPutXML() throws IOException, JAXBException {
235 String path = "/" + TABLE + "/fakerow";
236
237 CellSetModel cellSetModel = new CellSetModel();
238 RowModel rowModel = new RowModel(ROW_1);
239 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
240 Bytes.toBytes(VALUE_1)));
241 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
242 Bytes.toBytes(VALUE_2)));
243 cellSetModel.addRow(rowModel);
244 rowModel = new RowModel(ROW_2);
245 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
246 Bytes.toBytes(VALUE_3)));
247 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
248 Bytes.toBytes(VALUE_4)));
249 cellSetModel.addRow(rowModel);
250 StringWriter writer = new StringWriter();
251 xmlMarshaller.marshal(cellSetModel, writer);
252 Response response = client.put(path, Constants.MIMETYPE_XML,
253 Bytes.toBytes(writer.toString()));
254 Thread.yield();
255
256
257 response = client.get(path, Constants.MIMETYPE_XML);
258 assertEquals(response.getCode(), 404);
259
260
261 checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
262 checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
263 checkValueXML(TABLE, ROW_2, COLUMN_1, VALUE_3);
264 checkValueXML(TABLE, ROW_2, COLUMN_2, VALUE_4);
265
266 response = deleteRow(TABLE, ROW_1);
267 assertEquals(response.getCode(), 200);
268 response = deleteRow(TABLE, ROW_2);
269 assertEquals(response.getCode(), 200);
270 }
271
272 @Test
273 public void testMultiCellGetPutPB() throws IOException {
274 String path = "/" + TABLE + "/fakerow";
275
276 CellSetModel cellSetModel = new CellSetModel();
277 RowModel rowModel = new RowModel(ROW_1);
278 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
279 Bytes.toBytes(VALUE_1)));
280 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
281 Bytes.toBytes(VALUE_2)));
282 cellSetModel.addRow(rowModel);
283 rowModel = new RowModel(ROW_2);
284 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
285 Bytes.toBytes(VALUE_3)));
286 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
287 Bytes.toBytes(VALUE_4)));
288 cellSetModel.addRow(rowModel);
289 Response response = client.put(path, Constants.MIMETYPE_PROTOBUF,
290 cellSetModel.createProtobufOutput());
291 Thread.yield();
292
293
294 response = client.get(path, Constants.MIMETYPE_PROTOBUF);
295 assertEquals(response.getCode(), 404);
296
297
298 checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
299 checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
300 checkValuePB(TABLE, ROW_2, COLUMN_1, VALUE_3);
301 checkValuePB(TABLE, ROW_2, COLUMN_2, VALUE_4);
302
303 response = deleteRow(TABLE, ROW_1);
304 assertEquals(response.getCode(), 200);
305 response = deleteRow(TABLE, ROW_2);
306 assertEquals(response.getCode(), 200);
307 }
308
309 @Test
310 public void testStartEndRowGetPutXML() throws IOException, JAXBException {
311 String[] rows = { ROW_1, ROW_2, ROW_3 };
312 String[] values = { VALUE_1, VALUE_2, VALUE_3 };
313 Response response = null;
314 for (int i = 0; i < rows.length; i++) {
315 response = putValueXML(TABLE, rows[i], COLUMN_1, values[i]);
316 assertEquals(200, response.getCode());
317 checkValueXML(TABLE, rows[i], COLUMN_1, values[i]);
318 }
319 response = getValueXML(TABLE, rows[0], rows[2], COLUMN_1);
320 assertEquals(200, response.getCode());
321 CellSetModel cellSet = (CellSetModel)
322 xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
323 assertEquals(2, cellSet.getRows().size());
324 for (int i = 0; i < cellSet.getRows().size()-1; i++) {
325 RowModel rowModel = cellSet.getRows().get(i);
326 for (CellModel cell: rowModel.getCells()) {
327 assertEquals(COLUMN_1, Bytes.toString(cell.getColumn()));
328 assertEquals(values[i], Bytes.toString(cell.getValue()));
329 }
330 }
331 for (String row : rows) {
332 response = deleteRow(TABLE, row);
333 assertEquals(200, response.getCode());
334 }
335 }
336
337 @Test
338 public void testInvalidCheckParam() throws IOException, JAXBException {
339 CellSetModel cellSetModel = new CellSetModel();
340 RowModel rowModel = new RowModel(ROW_1);
341 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
342 Bytes.toBytes(VALUE_1)));
343 cellSetModel.addRow(rowModel);
344 StringWriter writer = new StringWriter();
345 xmlMarshaller.marshal(cellSetModel, writer);
346
347 final String path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "?check=blah";
348
349 Response response = client.put(path, Constants.MIMETYPE_XML,
350 Bytes.toBytes(writer.toString()));
351 assertEquals(response.getCode(), 400);
352 }
353
354 @Test
355 public void testInvalidColumnPut() throws IOException, JAXBException {
356 String dummyColumn = "doesnot:exist";
357 CellSetModel cellSetModel = new CellSetModel();
358 RowModel rowModel = new RowModel(ROW_1);
359 rowModel.addCell(new CellModel(Bytes.toBytes(dummyColumn),
360 Bytes.toBytes(VALUE_1)));
361 cellSetModel.addRow(rowModel);
362 StringWriter writer = new StringWriter();
363 xmlMarshaller.marshal(cellSetModel, writer);
364
365 final String path = "/" + TABLE + "/" + ROW_1 + "/" + dummyColumn;
366
367 Response response = client.put(path, Constants.MIMETYPE_XML,
368 Bytes.toBytes(writer.toString()));
369 assertEquals(response.getCode(), 404);
370 }
371
372 @Test
373 public void testMultiCellGetJson() throws IOException, JAXBException {
374 String path = "/" + TABLE + "/fakerow";
375
376 CellSetModel cellSetModel = new CellSetModel();
377 RowModel rowModel = new RowModel(ROW_1);
378 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
379 Bytes.toBytes(VALUE_1)));
380 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
381 Bytes.toBytes(VALUE_2)));
382 cellSetModel.addRow(rowModel);
383 rowModel = new RowModel(ROW_2);
384 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
385 Bytes.toBytes(VALUE_3)));
386 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
387 Bytes.toBytes(VALUE_4)));
388 cellSetModel.addRow(rowModel);
389 String jsonString = jsonMapper.writeValueAsString(cellSetModel);
390
391 Response response = client.put(path, Constants.MIMETYPE_JSON,
392 Bytes.toBytes(jsonString));
393 Thread.yield();
394
395
396 response = client.get(path, Constants.MIMETYPE_JSON);
397 assertEquals(response.getCode(), 404);
398
399
400 checkValueJSON(TABLE, ROW_1, COLUMN_1, VALUE_1);
401 checkValueJSON(TABLE, ROW_1, COLUMN_2, VALUE_2);
402 checkValueJSON(TABLE, ROW_2, COLUMN_1, VALUE_3);
403 checkValueJSON(TABLE, ROW_2, COLUMN_2, VALUE_4);
404
405 response = deleteRow(TABLE, ROW_1);
406 assertEquals(response.getCode(), 200);
407 response = deleteRow(TABLE, ROW_2);
408 assertEquals(response.getCode(), 200);
409 }
410
411 @Test
412 public void testMetrics() throws IOException, JAXBException {
413 final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
414 Response response = client.put(path, Constants.MIMETYPE_BINARY,
415 Bytes.toBytes(VALUE_4));
416 assertEquals(response.getCode(), 200);
417 Thread.yield();
418 response = client.get(path, Constants.MIMETYPE_JSON);
419 assertEquals(response.getCode(), 200);
420 assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
421 response = deleteRow(TABLE, ROW_4);
422 assertEquals(response.getCode(), 200);
423
424 UserGroupInformation ugi = User.getCurrent().getUGI();
425 METRICS_ASSERT.assertCounterGt("requests", 2l,
426 RESTServlet.getInstance(conf, ugi).getMetrics().getSource());
427
428 METRICS_ASSERT.assertCounterGt("successfulGet", 0l,
429 RESTServlet.getInstance(conf, ugi).getMetrics().getSource());
430
431 METRICS_ASSERT.assertCounterGt("successfulPut", 0l,
432 RESTServlet.getInstance(conf, ugi).getMetrics().getSource());
433
434 METRICS_ASSERT.assertCounterGt("successfulDelete", 0l,
435 RESTServlet.getInstance(conf, ugi).getMetrics().getSource());
436 }
437
438 @Test
439 public void testMultiColumnGetXML() throws Exception {
440 String path = "/" + TABLE + "/fakerow";
441 CellSetModel cellSetModel = new CellSetModel();
442 RowModel rowModel = new RowModel(ROW_1);
443 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1), Bytes.toBytes(VALUE_1)));
444 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2), Bytes.toBytes(VALUE_2)));
445 rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_3), Bytes.toBytes(VALUE_2)));
446 cellSetModel.addRow(rowModel);
447 StringWriter writer = new StringWriter();
448 xmlMarshaller.marshal(cellSetModel, writer);
449
450 Response response = client.put(path, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
451 Thread.yield();
452
453
454 response = client.get(path, Constants.MIMETYPE_XML);
455 assertEquals(response.getCode(), 404);
456
457
458 path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "," + COLUMN_2 + "," + COLUMN_3;
459 response = client.get(path, Constants.MIMETYPE_XML);
460 assertEquals(200, response.getCode());
461 CellSetModel cellSet = (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response
462 .getBody()));
463 assertTrue(cellSet.getRows().size() == 1);
464 assertTrue(cellSet.getRows().get(0).getCells().size() == 3);
465 List<CellModel> cells = cellSet.getRows().get(0).getCells();
466
467 assertTrue(containsCellModel(cells, COLUMN_1, VALUE_1));
468 assertTrue(containsCellModel(cells, COLUMN_2, VALUE_2));
469 assertTrue(containsCellModel(cells, COLUMN_3, VALUE_2));
470 response = deleteRow(TABLE, ROW_1);
471 assertEquals(response.getCode(), 200);
472 }
473
474 private boolean containsCellModel(List<CellModel> cells, String column, String value) {
475 boolean contains = false;
476 for (CellModel cell : cells) {
477 if (Bytes.toString(cell.getColumn()).equals(column)
478 && Bytes.toString(cell.getValue()).equals(value)) {
479 contains = true;
480 return contains;
481 }
482 }
483 return contains;
484 }
485 }
486