View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.rest;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.IOException;
25  import java.io.StringWriter;
26  import java.net.URLEncoder;
27  import java.util.HashMap;
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.testclassification.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.UserProvider;
41  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
42  import org.apache.hadoop.hbase.util.Bytes;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  @Category(MediumTests.class)
47  public class TestGetAndPutResource extends RowResourceBase {
48    private static final MetricsAssertHelper METRICS_ASSERT =
49        CompatibilityFactory.getInstance(MetricsAssertHelper.class);
50  
51    @Test
52    public void testForbidden() throws IOException, JAXBException {
53      conf.set("hbase.rest.readonly", "true");
54  
55      Response response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
56      assertEquals(403, response.getCode());
57      response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
58      assertEquals(403, response.getCode());
59      response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
60      assertEquals(403, response.getCode());
61      response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
62      assertEquals(403, response.getCode());
63      response = deleteValue(TABLE, ROW_1, COLUMN_1);
64      assertEquals(403, response.getCode());
65      response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
66      assertEquals(403, response.getCode());
67      response = deleteRow(TABLE, ROW_1);
68      assertEquals(403, response.getCode());
69  
70      conf.set("hbase.rest.readonly", "false");
71  
72      response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
73      assertEquals(200, response.getCode());
74      response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
75      assertEquals(200, response.getCode());
76      response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
77      assertEquals(200, response.getCode());
78      response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
79      assertEquals(200, response.getCode());
80      response = deleteValue(TABLE, ROW_1, COLUMN_1);
81      assertEquals(200, response.getCode());
82      response = deleteRow(TABLE, ROW_1);
83      assertEquals(200, response.getCode());
84    }
85  
86    @Test
87    public void testSingleCellGetPutXML() throws IOException, JAXBException {
88      Response response = getValueXML(TABLE, ROW_1, COLUMN_1);
89      assertEquals(404, response.getCode());
90  
91      response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
92      assertEquals(200, response.getCode());
93      checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
94      response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
95      assertEquals(200, response.getCode());
96      checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
97      response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
98      assertEquals(200, response.getCode());
99      checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
100     response = checkAndDeleteXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
101     assertEquals(200, response.getCode());
102 
103     response = deleteRow(TABLE, ROW_1);
104     assertEquals(200, response.getCode());
105   }
106 
107   @Test
108   public void testSingleCellGetPutPB() throws IOException, JAXBException {
109     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
110     assertEquals(404, response.getCode());
111 
112     response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
113     assertEquals(200, response.getCode());
114     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
115     response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
116     assertEquals(200, response.getCode());
117     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2);
118 
119     response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
120     assertEquals(200, response.getCode());
121     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
122     response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3, VALUE_4);
123     assertEquals(200, response.getCode());
124     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_4);
125 
126     response = deleteRow(TABLE, ROW_1);
127     assertEquals(200, response.getCode());
128   }
129 
130   @Test
131   public void testMultipleCellCheckPutPB() throws IOException {
132     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
133     assertEquals(404, response.getCode());
134 
135     // Add 2 Columns to setup the test
136     response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
137     assertEquals(200, response.getCode());
138     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
139 
140     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
141     assertEquals(200, response.getCode());
142     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
143 
144     HashMap<String,String> otherCells = new HashMap<>();
145     otherCells.put(COLUMN_2,VALUE_3);
146 
147     // On Success update both the cells
148     response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
149     assertEquals(200, response.getCode());
150     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
151     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
152 
153     // On Failure, we dont update any cells
154     response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
155     assertEquals(304, response.getCode());
156     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
157     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
158 
159     response = deleteRow(TABLE, ROW_1);
160     assertEquals(200, response.getCode());
161   }
162 
163   @Test
164   public void testMultipleCellCheckPutXML() throws IOException, JAXBException {
165     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
166     assertEquals(404, response.getCode());
167 
168     // Add 2 Columns to setup the test
169     response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
170     assertEquals(200, response.getCode());
171     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
172 
173     response = putValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
174     assertEquals(200, response.getCode());
175     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
176 
177     HashMap<String,String> otherCells = new HashMap<>();
178     otherCells.put(COLUMN_2,VALUE_3);
179 
180     // On Success update both the cells
181     response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
182     assertEquals(200, response.getCode());
183     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
184     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
185 
186     // On Failure, we dont update any cells
187     response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
188     assertEquals(304, response.getCode());
189     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
190     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
191 
192     response = deleteRow(TABLE, ROW_1);
193     assertEquals(200, response.getCode());
194   }
195 
196   @Test
197   public void testMultipleCellCheckDeletePB() throws IOException {
198     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
199     assertEquals(404, response.getCode());
200 
201     // Add 3 Columns to setup the test
202     response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
203     assertEquals(200, response.getCode());
204     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
205 
206     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
207     assertEquals(200, response.getCode());
208     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
209 
210     response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
211     assertEquals(200, response.getCode());
212     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
213 
214     // Deletes the following columns based on Column1 check
215     HashMap<String,String> cellsToDelete = new HashMap<>();
216     cellsToDelete.put(COLUMN_2,VALUE_2); // Value does not matter
217     cellsToDelete.put(COLUMN_3,VALUE_3); // Value does not matter
218 
219     // On Success update both the cells
220     response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1, cellsToDelete);
221     assertEquals(200, response.getCode());
222 
223     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
224 
225     response = getValuePB(TABLE, ROW_1, COLUMN_2);
226     assertEquals(404, response.getCode());
227 
228     response = getValuePB(TABLE, ROW_1, COLUMN_3);
229     assertEquals(404, response.getCode());
230 
231     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
232     assertEquals(200, response.getCode());
233     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
234 
235     response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
236     assertEquals(200, response.getCode());
237     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
238 
239     // On Failure, we dont update any cells
240     response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_3, cellsToDelete);
241     assertEquals(304, response.getCode());
242     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
243     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
244     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
245 
246     response = deleteRow(TABLE, ROW_1);
247     assertEquals(200, response.getCode());
248   }
249 
250   @Test
251   public void testSingleCellGetPutBinary() throws IOException {
252     final String path = "/" + TABLE + "/" + ROW_3 + "/" + COLUMN_1;
253     final byte[] body = Bytes.toBytes(VALUE_3);
254     Response response = client.put(path, Constants.MIMETYPE_BINARY, body);
255     assertEquals(200, response.getCode());
256     Thread.yield();
257 
258     response = client.get(path, Constants.MIMETYPE_BINARY);
259     assertEquals(200, response.getCode());
260     assertEquals(Constants.MIMETYPE_BINARY, response.getHeader("content-type"));
261     assertTrue(Bytes.equals(response.getBody(), body));
262     boolean foundTimestampHeader = false;
263     for (Header header: response.getHeaders()) {
264       if (header.getName().equals("X-Timestamp")) {
265         foundTimestampHeader = true;
266         break;
267       }
268     }
269     assertTrue(foundTimestampHeader);
270 
271     response = deleteRow(TABLE, ROW_3);
272     assertEquals(200, response.getCode());
273   }
274 
275   @Test
276   public void testSingleCellGetJSON() throws IOException {
277     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
278     Response response = client.put(path, Constants.MIMETYPE_BINARY,
279       Bytes.toBytes(VALUE_4));
280     assertEquals(200, response.getCode());
281     Thread.yield();
282     response = client.get(path, Constants.MIMETYPE_JSON);
283     assertEquals(200, response.getCode());
284     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
285     response = deleteRow(TABLE, ROW_4);
286     assertEquals(200, response.getCode());
287   }
288 
289   @Test
290   public void testLatestCellGetJSON() throws IOException {
291     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
292     CellSetModel cellSetModel = new CellSetModel();
293     RowModel rowModel = new RowModel(ROW_4);
294     CellModel cellOne = new CellModel(Bytes.toBytes(COLUMN_1), 1L,
295       Bytes.toBytes(VALUE_1));
296     CellModel cellTwo = new CellModel(Bytes.toBytes(COLUMN_1), 2L,
297       Bytes.toBytes(VALUE_2));
298     rowModel.addCell(cellOne);
299     rowModel.addCell(cellTwo);
300     cellSetModel.addRow(rowModel);
301     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
302     Response response = client.put(path, Constants.MIMETYPE_JSON,
303       Bytes.toBytes(jsonString));
304     assertEquals(200, response.getCode());
305     Thread.yield();
306     response = client.get(path, Constants.MIMETYPE_JSON);
307     assertEquals(200, response.getCode());
308     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
309     CellSetModel cellSet = jsonMapper.readValue(response.getBody(), CellSetModel.class);
310     assertTrue(cellSet.getRows().size() == 1);
311     assertTrue(cellSet.getRows().get(0).getCells().size() == 1);
312     CellModel cell = cellSet.getRows().get(0).getCells().get(0);
313     assertEquals(VALUE_2 , Bytes.toString(cell.getValue()));
314     assertEquals(2L , cell.getTimestamp());
315     response = deleteRow(TABLE, ROW_4);
316     assertEquals(200, response.getCode());
317   }
318 
319   @Test
320   public void testURLEncodedKey() throws IOException, JAXBException {
321     String urlKey = "http://example.com/foo";
322     StringBuilder path = new StringBuilder();
323     path.append('/');
324     path.append(TABLE);
325     path.append('/');
326     path.append(URLEncoder.encode(urlKey, HConstants.UTF8_ENCODING));
327     path.append('/');
328     path.append(COLUMN_1);
329     Response response;
330     response = putValueXML(path.toString(), TABLE, urlKey, COLUMN_1,
331       VALUE_1);
332     assertEquals(200, response.getCode());
333     checkValueXML(path.toString(), TABLE, urlKey, COLUMN_1, VALUE_1);
334   }
335 
336   @Test
337   public void testNoSuchCF() throws IOException {
338     final String goodPath = "/" + TABLE + "/" + ROW_1 + "/" + CFA+":";
339     final String badPath = "/" + TABLE + "/" + ROW_1 + "/" + "BAD";
340     Response response = client.post(goodPath, Constants.MIMETYPE_BINARY,
341       Bytes.toBytes(VALUE_1));
342     assertEquals(200, response.getCode());
343     assertEquals(200, client.get(goodPath, Constants.MIMETYPE_BINARY).getCode());
344     assertEquals(404, client.get(badPath, Constants.MIMETYPE_BINARY).getCode());
345     assertEquals(200, client.get(goodPath, Constants.MIMETYPE_BINARY).getCode());
346   }
347 
348   @Test
349   public void testMultiCellGetPutXML() throws IOException, JAXBException {
350     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
351 
352     CellSetModel cellSetModel = new CellSetModel();
353     RowModel rowModel = new RowModel(ROW_1);
354     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
355       Bytes.toBytes(VALUE_1)));
356     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
357       Bytes.toBytes(VALUE_2)));
358     cellSetModel.addRow(rowModel);
359     rowModel = new RowModel(ROW_2);
360     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
361       Bytes.toBytes(VALUE_3)));
362     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
363       Bytes.toBytes(VALUE_4)));
364     cellSetModel.addRow(rowModel);
365     StringWriter writer = new StringWriter();
366     xmlMarshaller.marshal(cellSetModel, writer);
367     Response response = client.put(path, Constants.MIMETYPE_XML,
368       Bytes.toBytes(writer.toString()));
369     Thread.yield();
370 
371     // make sure the fake row was not actually created
372     response = client.get(path, Constants.MIMETYPE_XML);
373     assertEquals(404, response.getCode());
374 
375     // check that all of the values were created
376     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
377     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
378     checkValueXML(TABLE, ROW_2, COLUMN_1, VALUE_3);
379     checkValueXML(TABLE, ROW_2, COLUMN_2, VALUE_4);
380 
381     response = deleteRow(TABLE, ROW_1);
382     assertEquals(200, response.getCode());
383     response = deleteRow(TABLE, ROW_2);
384     assertEquals(200, response.getCode());
385   }
386 
387   @Test
388   public void testMultiCellGetPutPB() throws IOException {
389     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
390 
391     CellSetModel cellSetModel = new CellSetModel();
392     RowModel rowModel = new RowModel(ROW_1);
393     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
394       Bytes.toBytes(VALUE_1)));
395     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
396       Bytes.toBytes(VALUE_2)));
397     cellSetModel.addRow(rowModel);
398     rowModel = new RowModel(ROW_2);
399     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
400       Bytes.toBytes(VALUE_3)));
401     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
402       Bytes.toBytes(VALUE_4)));
403     cellSetModel.addRow(rowModel);
404     Response response = client.put(path, Constants.MIMETYPE_PROTOBUF,
405       cellSetModel.createProtobufOutput());
406     Thread.yield();
407 
408     // make sure the fake row was not actually created
409     response = client.get(path, Constants.MIMETYPE_PROTOBUF);
410     assertEquals(404, response.getCode());
411 
412     // check that all of the values were created
413     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
414     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
415     checkValuePB(TABLE, ROW_2, COLUMN_1, VALUE_3);
416     checkValuePB(TABLE, ROW_2, COLUMN_2, VALUE_4);
417 
418     response = deleteRow(TABLE, ROW_1);
419     assertEquals(200, response.getCode());
420     response = deleteRow(TABLE, ROW_2);
421     assertEquals(200, response.getCode());
422   }
423 
424   @Test
425   public void testStartEndRowGetPutXML() throws IOException, JAXBException {
426     String[] rows = { ROW_1, ROW_2, ROW_3 };
427     String[] values = { VALUE_1, VALUE_2, VALUE_3 };
428     Response response = null;
429     for (int i = 0; i < rows.length; i++) {
430       response = putValueXML(TABLE, rows[i], COLUMN_1, values[i]);
431       assertEquals(200, response.getCode());
432       checkValueXML(TABLE, rows[i], COLUMN_1, values[i]);
433     }
434     response = getValueXML(TABLE, rows[0], rows[2], COLUMN_1);
435     assertEquals(200, response.getCode());
436     CellSetModel cellSet = (CellSetModel)
437       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
438     assertEquals(2, cellSet.getRows().size());
439     for (int i = 0; i < cellSet.getRows().size()-1; i++) {
440       RowModel rowModel = cellSet.getRows().get(i);
441       for (CellModel cell: rowModel.getCells()) {
442         assertEquals(COLUMN_1, Bytes.toString(cell.getColumn()));
443         assertEquals(values[i], Bytes.toString(cell.getValue()));
444       }
445     }
446     for (String row : rows) {
447       response = deleteRow(TABLE, row);
448       assertEquals(200, response.getCode());
449     }
450   }
451 
452   @Test
453   public void testInvalidCheckParam() throws IOException, JAXBException {
454     CellSetModel cellSetModel = new CellSetModel();
455     RowModel rowModel = new RowModel(ROW_1);
456     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
457       Bytes.toBytes(VALUE_1)));
458     cellSetModel.addRow(rowModel);
459     StringWriter writer = new StringWriter();
460     xmlMarshaller.marshal(cellSetModel, writer);
461 
462     final String path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "?check=blah";
463 
464     Response response = client.put(path, Constants.MIMETYPE_XML,
465       Bytes.toBytes(writer.toString()));
466     assertEquals(400, response.getCode());
467   }
468 
469   @Test
470   public void testInvalidColumnPut() throws IOException, JAXBException {
471     String dummyColumn = "doesnot:exist";
472     CellSetModel cellSetModel = new CellSetModel();
473     RowModel rowModel = new RowModel(ROW_1);
474     rowModel.addCell(new CellModel(Bytes.toBytes(dummyColumn),
475       Bytes.toBytes(VALUE_1)));
476     cellSetModel.addRow(rowModel);
477     StringWriter writer = new StringWriter();
478     xmlMarshaller.marshal(cellSetModel, writer);
479 
480     final String path = "/" + TABLE + "/" + ROW_1 + "/" + dummyColumn;
481 
482     Response response = client.put(path, Constants.MIMETYPE_XML,
483       Bytes.toBytes(writer.toString()));
484     assertEquals(404, response.getCode());
485   }
486 
487   @Test
488   public void testMultiCellGetJson() throws IOException, JAXBException {
489     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
490 
491     CellSetModel cellSetModel = new CellSetModel();
492     RowModel rowModel = new RowModel(ROW_1);
493     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
494       Bytes.toBytes(VALUE_1)));
495     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
496       Bytes.toBytes(VALUE_2)));
497     cellSetModel.addRow(rowModel);
498     rowModel = new RowModel(ROW_2);
499     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
500       Bytes.toBytes(VALUE_3)));
501     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
502       Bytes.toBytes(VALUE_4)));
503     cellSetModel.addRow(rowModel);
504     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
505 
506     Response response = client.put(path, Constants.MIMETYPE_JSON,
507       Bytes.toBytes(jsonString));
508     Thread.yield();
509 
510     // make sure the fake row was not actually created
511     response = client.get(path, Constants.MIMETYPE_JSON);
512     assertEquals(404, response.getCode());
513 
514     // check that all of the values were created
515     checkValueJSON(TABLE, ROW_1, COLUMN_1, VALUE_1);
516     checkValueJSON(TABLE, ROW_1, COLUMN_2, VALUE_2);
517     checkValueJSON(TABLE, ROW_2, COLUMN_1, VALUE_3);
518     checkValueJSON(TABLE, ROW_2, COLUMN_2, VALUE_4);
519 
520     response = deleteRow(TABLE, ROW_1);
521     assertEquals(200, response.getCode());
522     response = deleteRow(TABLE, ROW_2);
523     assertEquals(200, response.getCode());
524   }
525 
526   @Test
527   public void testMetrics() throws IOException {
528     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
529     Response response = client.put(path, Constants.MIMETYPE_BINARY,
530         Bytes.toBytes(VALUE_4));
531     assertEquals(200, response.getCode());
532     Thread.yield();
533     response = client.get(path, Constants.MIMETYPE_JSON);
534     assertEquals(200, response.getCode());
535     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
536     response = deleteRow(TABLE, ROW_4);
537     assertEquals(200, response.getCode());
538 
539     UserProvider userProvider = UserProvider.instantiate(conf);
540     METRICS_ASSERT.assertCounterGt("requests", 2L,
541       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
542 
543     METRICS_ASSERT.assertCounterGt("successfulGet", 0L,
544       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
545 
546     METRICS_ASSERT.assertCounterGt("successfulPut", 0L,
547       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
548 
549     METRICS_ASSERT.assertCounterGt("successfulDelete", 0L,
550       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
551   }
552 
553   @Test
554   public void testMultiColumnGetXML() throws Exception {
555     String path = "/" + TABLE + "/fakerow";
556     CellSetModel cellSetModel = new CellSetModel();
557     RowModel rowModel = new RowModel(ROW_1);
558     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1), Bytes.toBytes(VALUE_1)));
559     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2), Bytes.toBytes(VALUE_2)));
560     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_3), Bytes.toBytes(VALUE_2)));
561     cellSetModel.addRow(rowModel);
562     StringWriter writer = new StringWriter();
563     xmlMarshaller.marshal(cellSetModel, writer);
564 
565     Response response = client.put(path, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
566     Thread.yield();
567 
568     // make sure the fake row was not actually created
569     response = client.get(path, Constants.MIMETYPE_XML);
570     assertEquals(404, response.getCode());
571 
572     // Try getting all the column values at once.
573     path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "," + COLUMN_2 + "," + COLUMN_3;
574     response = client.get(path, Constants.MIMETYPE_XML);
575     assertEquals(200, response.getCode());
576     CellSetModel cellSet =
577       (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
578     assertTrue(cellSet.getRows().size() == 1);
579     assertTrue(cellSet.getRows().get(0).getCells().size() == 3);
580     List<CellModel> cells = cellSet.getRows().get(0).getCells();
581 
582     assertTrue(containsCellModel(cells, COLUMN_1, VALUE_1));
583     assertTrue(containsCellModel(cells, COLUMN_2, VALUE_2));
584     assertTrue(containsCellModel(cells, COLUMN_3, VALUE_2));
585     response = deleteRow(TABLE, ROW_1);
586     assertEquals(200, response.getCode());
587   }
588 
589   private boolean containsCellModel(List<CellModel> cells, String column, String value) {
590     boolean contains = false;
591     for (CellModel cell : cells) {
592       if (Bytes.toString(cell.getColumn()).equals(column)
593           && Bytes.toString(cell.getValue()).equals(value)) {
594         contains = true;
595         return contains;
596       }
597     }
598     return contains;
599   }
600 
601   @Test
602   public void testSuffixGlobbingXMLWithNewScanner() throws IOException, JAXBException {
603     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
604 
605     CellSetModel cellSetModel = new CellSetModel();
606     RowModel rowModel = new RowModel(ROW_1);
607     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
608       Bytes.toBytes(VALUE_1)));
609     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
610       Bytes.toBytes(VALUE_2)));
611     cellSetModel.addRow(rowModel);
612     rowModel = new RowModel(ROW_2);
613     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
614       Bytes.toBytes(VALUE_3)));
615     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
616       Bytes.toBytes(VALUE_4)));
617     cellSetModel.addRow(rowModel);
618     StringWriter writer = new StringWriter();
619     xmlMarshaller.marshal(cellSetModel, writer);
620     Response response = client.put(path, Constants.MIMETYPE_XML,
621       Bytes.toBytes(writer.toString()));
622     Thread.yield();
623 
624     // make sure the fake row was not actually created
625     response = client.get(path, Constants.MIMETYPE_XML);
626     assertEquals(404, response.getCode());
627 
628     // check that all of the values were created
629     StringBuilder query = new StringBuilder();
630     query.append('/');
631     query.append(TABLE);
632     query.append('/');
633     query.append("testrow*");
634     response = client.get(query.toString(), Constants.MIMETYPE_XML);
635     assertEquals(200, response.getCode());
636     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
637     CellSetModel cellSet = (CellSetModel)
638       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
639     assertTrue(cellSet.getRows().size() == 2);
640 
641     response = deleteRow(TABLE, ROW_1);
642     assertEquals(200, response.getCode());
643     response = deleteRow(TABLE, ROW_2);
644     assertEquals(200, response.getCode());
645   }
646 
647   @Test
648   public void testSuffixGlobbingXML() throws IOException, JAXBException {
649     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
650 
651     CellSetModel cellSetModel = new CellSetModel();
652     RowModel rowModel = new RowModel(ROW_1);
653     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
654       Bytes.toBytes(VALUE_1)));
655     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
656       Bytes.toBytes(VALUE_2)));
657     cellSetModel.addRow(rowModel);
658     rowModel = new RowModel(ROW_2);
659     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
660       Bytes.toBytes(VALUE_3)));
661     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
662       Bytes.toBytes(VALUE_4)));
663     cellSetModel.addRow(rowModel);
664     StringWriter writer = new StringWriter();
665     xmlMarshaller.marshal(cellSetModel, writer);
666     Response response = client.put(path, Constants.MIMETYPE_XML,
667       Bytes.toBytes(writer.toString()));
668     Thread.yield();
669 
670     // make sure the fake row was not actually created
671     response = client.get(path, Constants.MIMETYPE_XML);
672     assertEquals(404, response.getCode());
673 
674     // check that all of the values were created
675     StringBuilder query = new StringBuilder();
676     query.append('/');
677     query.append(TABLE);
678     query.append('/');
679     query.append("testrow*");
680     query.append('/');
681     query.append(COLUMN_1);
682     response = client.get(query.toString(), Constants.MIMETYPE_XML);
683     assertEquals(200, response.getCode());
684     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
685     CellSetModel cellSet = (CellSetModel)
686       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
687     List<RowModel> rows = cellSet.getRows();
688     assertTrue(rows.size() == 2);
689     for (RowModel row : rows) {
690       assertTrue(row.getCells().size() == 1);
691       assertEquals(COLUMN_1, Bytes.toString(row.getCells().get(0).getColumn()));
692     }
693     response = deleteRow(TABLE, ROW_1);
694     assertEquals(200, response.getCode());
695     response = deleteRow(TABLE, ROW_2);
696     assertEquals(200, response.getCode());
697   }
698 
699   @Test
700   public void testAppendXML() throws IOException, JAXBException {
701     Response response = getValueXML(TABLE, ROW_1, COLUMN_1);
702     assertEquals(404, response.getCode());
703 
704     //append cell
705     response = appendValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
706     assertEquals(200, response.getCode());
707     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
708     response = appendValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
709     assertEquals(200, response.getCode());
710     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1 + VALUE_2);
711 
712     response = deleteRow(TABLE, ROW_1);
713     assertEquals(200, response.getCode());
714   }
715 
716   @Test
717   public void testAppendPB() throws IOException, JAXBException {
718     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
719     assertEquals(404, response.getCode());
720 
721     //append cell
722     response = appendValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
723     assertEquals(200, response.getCode());
724     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
725     response = appendValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2);
726     assertEquals(200, response.getCode());
727     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1 + VALUE_2);
728 
729     response = deleteRow(TABLE, ROW_1);
730     assertEquals(200, response.getCode());
731   }
732 
733   @Test
734   public void testAppendJSON() throws IOException, JAXBException {
735     Response response = getValueJson(TABLE, ROW_1, COLUMN_1);
736     assertEquals(404, response.getCode());
737 
738     //append cell
739     response = appendValueJson(TABLE, ROW_1, COLUMN_1, VALUE_1);
740     assertEquals(200, response.getCode());
741     putValueJson(TABLE, ROW_1, COLUMN_1, VALUE_1);
742     response = appendValueJson(TABLE, ROW_1, COLUMN_1, VALUE_2);
743     assertEquals(200, response.getCode());
744     putValueJson(TABLE, ROW_1, COLUMN_1, VALUE_1 + VALUE_2);
745 
746     response = deleteRow(TABLE, ROW_1);
747     assertEquals(200, response.getCode());
748   }
749 
750   @Test
751   public void testIncrementXML() throws IOException, JAXBException {
752     Response response = getValueXML(TABLE, ROW_1, COLUMN_1);
753     assertEquals(404, response.getCode());
754 
755     //append single cell
756     response = incrementValueXML(TABLE, ROW_1, COLUMN_1, VALUE_5);
757     assertEquals(200, response.getCode());
758     checkIncrementValueXML(TABLE, ROW_1, COLUMN_1, Long.parseLong(VALUE_5));
759     response = incrementValueXML(TABLE, ROW_1, COLUMN_1, VALUE_6);
760     assertEquals(200, response.getCode());
761     checkIncrementValueXML(TABLE, ROW_1, COLUMN_1,
762         Long.parseLong(VALUE_5) + Long.parseLong(VALUE_6));
763 
764     response = deleteRow(TABLE, ROW_1);
765     assertEquals(200, response.getCode());
766   }
767 
768   @Test
769   public void testIncrementPB() throws IOException, JAXBException {
770     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
771     assertEquals(404, response.getCode());
772 
773     //append cell
774     response = incrementValuePB(TABLE, ROW_1, COLUMN_1, VALUE_5);
775     assertEquals(200, response.getCode());
776     checkIncrementValuePB(TABLE, ROW_1, COLUMN_1, Long.parseLong(VALUE_5));
777     response = incrementValuePB(TABLE, ROW_1, COLUMN_1, VALUE_6);
778     assertEquals(200, response.getCode());
779     checkIncrementValuePB(TABLE, ROW_1, COLUMN_1,
780         Long.parseLong(VALUE_5) + Long.parseLong(VALUE_6));
781 
782     response = deleteRow(TABLE, ROW_1);
783     assertEquals(200, response.getCode());
784   }
785 
786   @Test
787   public void testIncrementJSON() throws IOException, JAXBException {
788     Response response = getValueJson(TABLE, ROW_1, COLUMN_1);
789     assertEquals(404, response.getCode());
790 
791     //append cell
792     response = incrementValueJson(TABLE, ROW_1, COLUMN_1, VALUE_5);
793     assertEquals(200, response.getCode());
794     checkIncrementValueJSON(TABLE, ROW_1, COLUMN_1, Long.parseLong(VALUE_5));
795     response = incrementValueJson(TABLE, ROW_1, COLUMN_1, VALUE_6);
796     assertEquals(200, response.getCode());
797     checkIncrementValueJSON(TABLE, ROW_1, COLUMN_1,
798         Long.parseLong(VALUE_5) + Long.parseLong(VALUE_6));
799 
800     response = deleteRow(TABLE, ROW_1);
801     assertEquals(200, response.getCode());
802   }
803 }