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  
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.HashMap;
29  import java.util.List;
30  
31  import javax.xml.bind.JAXBException;
32  
33  import org.apache.http.Header;
34  import org.apache.hadoop.hbase.CompatibilityFactory;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.apache.hadoop.hbase.rest.client.Response;
38  import org.apache.hadoop.hbase.rest.model.CellModel;
39  import org.apache.hadoop.hbase.rest.model.CellSetModel;
40  import org.apache.hadoop.hbase.rest.model.RowModel;
41  import org.apache.hadoop.hbase.security.UserProvider;
42  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
43  import org.apache.hadoop.hbase.util.Bytes;
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 testMultipleCellCheckPutPB() throws IOException, JAXBException {
134     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
135     assertEquals(response.getCode(), 404);
136 
137     // Add 2 Columns to setup the test
138     response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
139     assertEquals(response.getCode(), 200);
140     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
141 
142     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
143     assertEquals(response.getCode(), 200);
144     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
145 
146     HashMap<String,String> otherCells = new HashMap<String, String>();
147     otherCells.put(COLUMN_2,VALUE_3);
148 
149     // On Success update both the cells
150     response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
151     assertEquals(response.getCode(), 200);
152     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
153     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
154 
155     // On Failure, we dont update any cells
156     response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
157     assertEquals(response.getCode(), 304);
158     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
159     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
160 
161     response = deleteRow(TABLE, ROW_1);
162     assertEquals(response.getCode(), 200);
163   }
164 
165   @Test
166   public void testMultipleCellCheckPutXML() throws IOException, JAXBException {
167     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
168     assertEquals(response.getCode(), 404);
169 
170     // Add 2 Columns to setup the test
171     response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
172     assertEquals(response.getCode(), 200);
173     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
174 
175     response = putValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
176     assertEquals(response.getCode(), 200);
177     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
178 
179     HashMap<String,String> otherCells = new HashMap<String, String>();
180     otherCells.put(COLUMN_2,VALUE_3);
181 
182     // On Success update both the cells
183     response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
184     assertEquals(response.getCode(), 200);
185     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
186     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
187 
188     // On Failure, we dont update any cells
189     response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
190     assertEquals(response.getCode(), 304);
191     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
192     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
193 
194     response = deleteRow(TABLE, ROW_1);
195     assertEquals(response.getCode(), 200);
196   }
197 
198   @Test
199   public void testMultipleCellCheckDeletePB() throws IOException, JAXBException {
200     Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
201     assertEquals(response.getCode(), 404);
202 
203     // Add 3 Columns to setup the test
204     response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
205     assertEquals(response.getCode(), 200);
206     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
207 
208     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
209     assertEquals(response.getCode(), 200);
210     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
211 
212     response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
213     assertEquals(response.getCode(), 200);
214     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
215 
216     // Deletes the following columns based on Column1 check
217     HashMap<String,String> cellsToDelete = new HashMap<String, String>();
218     cellsToDelete.put(COLUMN_2,VALUE_2); // Value does not matter
219     cellsToDelete.put(COLUMN_3,VALUE_3); // Value does not matter
220 
221     // On Success update both the cells
222     response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1, cellsToDelete);
223     assertEquals(response.getCode(), 200);
224 
225     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
226 
227     response = getValuePB(TABLE, ROW_1, COLUMN_2);
228     assertEquals(response.getCode(), 404);
229 
230     response = getValuePB(TABLE, ROW_1, COLUMN_3);
231     assertEquals(response.getCode(), 404);
232 
233     response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
234     assertEquals(response.getCode(), 200);
235     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
236 
237     response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
238     assertEquals(response.getCode(), 200);
239     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
240 
241     // On Failure, we dont update any cells
242     response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_3, cellsToDelete);
243     assertEquals(response.getCode(), 304);
244     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
245     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
246     checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
247 
248     response = deleteRow(TABLE, ROW_1);
249     assertEquals(response.getCode(), 200);
250   }
251   @Test
252   public void testSingleCellGetPutBinary() throws IOException {
253     final String path = "/" + TABLE + "/" + ROW_3 + "/" + COLUMN_1;
254     final byte[] body = Bytes.toBytes(VALUE_3);
255     Response response = client.put(path, Constants.MIMETYPE_BINARY, body);
256     assertEquals(response.getCode(), 200);
257     Thread.yield();
258 
259     response = client.get(path, Constants.MIMETYPE_BINARY);
260     assertEquals(response.getCode(), 200);
261     assertEquals(Constants.MIMETYPE_BINARY, response.getHeader("content-type"));
262     assertTrue(Bytes.equals(response.getBody(), body));
263     boolean foundTimestampHeader = false;
264     for (Header header: response.getHeaders()) {
265       if (header.getName().equals("X-Timestamp")) {
266         foundTimestampHeader = true;
267         break;
268       }
269     }
270     assertTrue(foundTimestampHeader);
271 
272     response = deleteRow(TABLE, ROW_3);
273     assertEquals(response.getCode(), 200);
274   }
275 
276   @Test
277   public void testSingleCellGetJSON() throws IOException, JAXBException {
278     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
279     Response response = client.put(path, Constants.MIMETYPE_BINARY,
280       Bytes.toBytes(VALUE_4));
281     assertEquals(response.getCode(), 200);
282     Thread.yield();
283     response = client.get(path, Constants.MIMETYPE_JSON);
284     assertEquals(response.getCode(), 200);
285     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
286     response = deleteRow(TABLE, ROW_4);
287     assertEquals(response.getCode(), 200);
288   }
289 
290   @Test
291   public void testLatestCellGetJSON() throws IOException, JAXBException {
292     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
293     CellSetModel cellSetModel = new CellSetModel();
294     RowModel rowModel = new RowModel(ROW_4);
295     CellModel cellOne = new CellModel(Bytes.toBytes(COLUMN_1), 1L,
296       Bytes.toBytes(VALUE_1));
297     CellModel cellTwo = new CellModel(Bytes.toBytes(COLUMN_1), 2L,
298       Bytes.toBytes(VALUE_2));
299     rowModel.addCell(cellOne);
300     rowModel.addCell(cellTwo);
301     cellSetModel.addRow(rowModel);
302     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
303     Response response = client.put(path, Constants.MIMETYPE_JSON,
304       Bytes.toBytes(jsonString));
305     assertEquals(response.getCode(), 200);
306     Thread.yield();
307     response = client.get(path, Constants.MIMETYPE_JSON);
308     assertEquals(response.getCode(), 200);
309     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
310     CellSetModel cellSet = jsonMapper.readValue(response.getBody(), CellSetModel.class);
311     assertTrue(cellSet.getRows().size() == 1);
312     assertTrue(cellSet.getRows().get(0).getCells().size() == 1);
313     CellModel cell = cellSet.getRows().get(0).getCells().get(0);
314     assertEquals(VALUE_2 , Bytes.toString(cell.getValue()));
315     assertEquals(2L , cell.getTimestamp());
316     response = deleteRow(TABLE, ROW_4);
317     assertEquals(response.getCode(), 200);
318   }
319 
320   @Test
321   public void testURLEncodedKey() throws IOException, JAXBException {
322     String urlKey = "http://example.com/foo";
323     StringBuilder path = new StringBuilder();
324     path.append('/');
325     path.append(TABLE);
326     path.append('/');
327     path.append(URLEncoder.encode(urlKey, HConstants.UTF8_ENCODING));
328     path.append('/');
329     path.append(COLUMN_1);
330     Response response;
331     response = putValueXML(path.toString(), TABLE, urlKey, COLUMN_1,
332       VALUE_1);
333     assertEquals(response.getCode(), 200);
334     checkValueXML(path.toString(), TABLE, urlKey, COLUMN_1, VALUE_1);
335   }
336 
337   @Test
338   public void testNoSuchCF() throws IOException, JAXBException {
339     final String goodPath = "/" + TABLE + "/" + ROW_1 + "/" + CFA+":";
340     final String badPath = "/" + TABLE + "/" + ROW_1 + "/" + "BAD";
341     Response response = client.post(goodPath, Constants.MIMETYPE_BINARY,
342       Bytes.toBytes(VALUE_1));
343     assertEquals(response.getCode(), 200);
344     assertEquals(client.get(goodPath, Constants.MIMETYPE_BINARY).getCode(),
345       200);
346     assertEquals(client.get(badPath, Constants.MIMETYPE_BINARY).getCode(),
347       404);
348     assertEquals(client.get(goodPath, Constants.MIMETYPE_BINARY).getCode(),
349       200);
350   }
351 
352   @Test
353   public void testMultiCellGetPutXML() throws IOException, JAXBException {
354     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
355 
356     CellSetModel cellSetModel = new CellSetModel();
357     RowModel rowModel = new RowModel(ROW_1);
358     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
359       Bytes.toBytes(VALUE_1)));
360     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
361       Bytes.toBytes(VALUE_2)));
362     cellSetModel.addRow(rowModel);
363     rowModel = new RowModel(ROW_2);
364     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
365       Bytes.toBytes(VALUE_3)));
366     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
367       Bytes.toBytes(VALUE_4)));
368     cellSetModel.addRow(rowModel);
369     StringWriter writer = new StringWriter();
370     xmlMarshaller.marshal(cellSetModel, writer);
371     Response response = client.put(path, Constants.MIMETYPE_XML,
372       Bytes.toBytes(writer.toString()));
373     Thread.yield();
374 
375     // make sure the fake row was not actually created
376     response = client.get(path, Constants.MIMETYPE_XML);
377     assertEquals(response.getCode(), 404);
378 
379     // check that all of the values were created
380     checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
381     checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
382     checkValueXML(TABLE, ROW_2, COLUMN_1, VALUE_3);
383     checkValueXML(TABLE, ROW_2, COLUMN_2, VALUE_4);
384 
385     response = deleteRow(TABLE, ROW_1);
386     assertEquals(response.getCode(), 200);
387     response = deleteRow(TABLE, ROW_2);
388     assertEquals(response.getCode(), 200);
389   }
390 
391   @Test
392   public void testMultiCellGetPutPB() throws IOException {
393     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
394 
395     CellSetModel cellSetModel = new CellSetModel();
396     RowModel rowModel = new RowModel(ROW_1);
397     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
398       Bytes.toBytes(VALUE_1)));
399     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
400       Bytes.toBytes(VALUE_2)));
401     cellSetModel.addRow(rowModel);
402     rowModel = new RowModel(ROW_2);
403     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
404       Bytes.toBytes(VALUE_3)));
405     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
406       Bytes.toBytes(VALUE_4)));
407     cellSetModel.addRow(rowModel);
408     Response response = client.put(path, Constants.MIMETYPE_PROTOBUF,
409       cellSetModel.createProtobufOutput());
410     Thread.yield();
411 
412     // make sure the fake row was not actually created
413     response = client.get(path, Constants.MIMETYPE_PROTOBUF);
414     assertEquals(response.getCode(), 404);
415 
416     // check that all of the values were created
417     checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
418     checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
419     checkValuePB(TABLE, ROW_2, COLUMN_1, VALUE_3);
420     checkValuePB(TABLE, ROW_2, COLUMN_2, VALUE_4);
421 
422     response = deleteRow(TABLE, ROW_1);
423     assertEquals(response.getCode(), 200);
424     response = deleteRow(TABLE, ROW_2);
425     assertEquals(response.getCode(), 200);
426   }
427 
428   @Test
429   public void testStartEndRowGetPutXML() throws IOException, JAXBException {
430     String[] rows = { ROW_1, ROW_2, ROW_3 };
431     String[] values = { VALUE_1, VALUE_2, VALUE_3 };
432     Response response = null;
433     for (int i = 0; i < rows.length; i++) {
434       response = putValueXML(TABLE, rows[i], COLUMN_1, values[i]);
435       assertEquals(200, response.getCode());
436       checkValueXML(TABLE, rows[i], COLUMN_1, values[i]);
437     }
438     response = getValueXML(TABLE, rows[0], rows[2], COLUMN_1);
439     assertEquals(200, response.getCode());
440     CellSetModel cellSet = (CellSetModel)
441       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
442     assertEquals(2, cellSet.getRows().size());
443     for (int i = 0; i < cellSet.getRows().size()-1; i++) {
444       RowModel rowModel = cellSet.getRows().get(i);
445       for (CellModel cell: rowModel.getCells()) {
446         assertEquals(COLUMN_1, Bytes.toString(cell.getColumn()));
447         assertEquals(values[i], Bytes.toString(cell.getValue()));
448       }
449     }
450     for (String row : rows) {
451       response = deleteRow(TABLE, row);
452       assertEquals(200, response.getCode());
453     }
454   }
455 
456   @Test
457   public void testInvalidCheckParam() throws IOException, JAXBException {
458     CellSetModel cellSetModel = new CellSetModel();
459     RowModel rowModel = new RowModel(ROW_1);
460     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
461       Bytes.toBytes(VALUE_1)));
462     cellSetModel.addRow(rowModel);
463     StringWriter writer = new StringWriter();
464     xmlMarshaller.marshal(cellSetModel, writer);
465 
466     final String path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "?check=blah";
467 
468     Response response = client.put(path, Constants.MIMETYPE_XML,
469       Bytes.toBytes(writer.toString()));
470     assertEquals(response.getCode(), 400);
471   }
472 
473   @Test
474   public void testInvalidColumnPut() throws IOException, JAXBException {
475     String dummyColumn = "doesnot:exist";
476     CellSetModel cellSetModel = new CellSetModel();
477     RowModel rowModel = new RowModel(ROW_1);
478     rowModel.addCell(new CellModel(Bytes.toBytes(dummyColumn),
479       Bytes.toBytes(VALUE_1)));
480     cellSetModel.addRow(rowModel);
481     StringWriter writer = new StringWriter();
482     xmlMarshaller.marshal(cellSetModel, writer);
483 
484     final String path = "/" + TABLE + "/" + ROW_1 + "/" + dummyColumn;
485 
486     Response response = client.put(path, Constants.MIMETYPE_XML,
487       Bytes.toBytes(writer.toString()));
488     assertEquals(response.getCode(), 404);
489   }
490 
491   @Test
492   public void testMultiCellGetJson() throws IOException, JAXBException {
493     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
494 
495     CellSetModel cellSetModel = new CellSetModel();
496     RowModel rowModel = new RowModel(ROW_1);
497     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
498       Bytes.toBytes(VALUE_1)));
499     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
500       Bytes.toBytes(VALUE_2)));
501     cellSetModel.addRow(rowModel);
502     rowModel = new RowModel(ROW_2);
503     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
504       Bytes.toBytes(VALUE_3)));
505     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
506       Bytes.toBytes(VALUE_4)));
507     cellSetModel.addRow(rowModel);
508     String jsonString = jsonMapper.writeValueAsString(cellSetModel);
509 
510     Response response = client.put(path, Constants.MIMETYPE_JSON,
511       Bytes.toBytes(jsonString));
512     Thread.yield();
513 
514     // make sure the fake row was not actually created
515     response = client.get(path, Constants.MIMETYPE_JSON);
516     assertEquals(response.getCode(), 404);
517 
518     // check that all of the values were created
519     checkValueJSON(TABLE, ROW_1, COLUMN_1, VALUE_1);
520     checkValueJSON(TABLE, ROW_1, COLUMN_2, VALUE_2);
521     checkValueJSON(TABLE, ROW_2, COLUMN_1, VALUE_3);
522     checkValueJSON(TABLE, ROW_2, COLUMN_2, VALUE_4);
523 
524     response = deleteRow(TABLE, ROW_1);
525     assertEquals(response.getCode(), 200);
526     response = deleteRow(TABLE, ROW_2);
527     assertEquals(response.getCode(), 200);
528   }
529   
530   @Test
531   public void testMetrics() throws IOException, JAXBException {
532     final String path = "/" + TABLE + "/" + ROW_4 + "/" + COLUMN_1;
533     Response response = client.put(path, Constants.MIMETYPE_BINARY,
534         Bytes.toBytes(VALUE_4));
535     assertEquals(response.getCode(), 200);
536     Thread.yield();
537     response = client.get(path, Constants.MIMETYPE_JSON);
538     assertEquals(response.getCode(), 200);
539     assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
540     response = deleteRow(TABLE, ROW_4);
541     assertEquals(response.getCode(), 200);
542 
543     UserProvider userProvider = UserProvider.instantiate(conf);
544     METRICS_ASSERT.assertCounterGt("requests", 2l,
545       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
546 
547     METRICS_ASSERT.assertCounterGt("successfulGet", 0l,
548       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
549 
550     METRICS_ASSERT.assertCounterGt("successfulPut", 0l,
551       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
552 
553     METRICS_ASSERT.assertCounterGt("successfulDelete", 0l,
554       RESTServlet.getInstance(conf, userProvider).getMetrics().getSource());
555   }
556   
557   @Test
558   public void testMultiColumnGetXML() throws Exception {
559     String path = "/" + TABLE + "/fakerow";
560     CellSetModel cellSetModel = new CellSetModel();
561     RowModel rowModel = new RowModel(ROW_1);
562     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1), Bytes.toBytes(VALUE_1)));
563     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2), Bytes.toBytes(VALUE_2)));
564     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_3), Bytes.toBytes(VALUE_2)));
565     cellSetModel.addRow(rowModel);
566     StringWriter writer = new StringWriter();
567     xmlMarshaller.marshal(cellSetModel, writer);
568 
569     Response response = client.put(path, Constants.MIMETYPE_XML, Bytes.toBytes(writer.toString()));
570     Thread.yield();
571 
572     // make sure the fake row was not actually created
573     response = client.get(path, Constants.MIMETYPE_XML);
574     assertEquals(response.getCode(), 404);
575 
576     // Try getting all the column values at once.
577     path = "/" + TABLE + "/" + ROW_1 + "/" + COLUMN_1 + "," + COLUMN_2 + "," + COLUMN_3;
578     response = client.get(path, Constants.MIMETYPE_XML);
579     assertEquals(200, response.getCode());
580     CellSetModel cellSet = (CellSetModel) xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response
581         .getBody()));
582     assertTrue(cellSet.getRows().size() == 1);
583     assertTrue(cellSet.getRows().get(0).getCells().size() == 3);
584     List<CellModel> cells = cellSet.getRows().get(0).getCells();
585 
586     assertTrue(containsCellModel(cells, COLUMN_1, VALUE_1));
587     assertTrue(containsCellModel(cells, COLUMN_2, VALUE_2));
588     assertTrue(containsCellModel(cells, COLUMN_3, VALUE_2));
589     response = deleteRow(TABLE, ROW_1);
590     assertEquals(response.getCode(), 200);
591   }
592 
593   private boolean containsCellModel(List<CellModel> cells, String column, String value) {
594     boolean contains = false;
595     for (CellModel cell : cells) {
596       if (Bytes.toString(cell.getColumn()).equals(column)
597           && Bytes.toString(cell.getValue()).equals(value)) {
598         contains = true;
599         return contains;
600       }
601     }
602     return contains;
603   }
604 
605   @Test
606   public void testSuffixGlobbingXMLWithNewScanner() throws IOException, JAXBException {
607     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
608 
609     CellSetModel cellSetModel = new CellSetModel();
610     RowModel rowModel = new RowModel(ROW_1);
611     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
612       Bytes.toBytes(VALUE_1)));
613     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
614       Bytes.toBytes(VALUE_2)));
615     cellSetModel.addRow(rowModel);
616     rowModel = new RowModel(ROW_2);
617     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
618       Bytes.toBytes(VALUE_3)));
619     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
620       Bytes.toBytes(VALUE_4)));
621     cellSetModel.addRow(rowModel);
622     StringWriter writer = new StringWriter();
623     xmlMarshaller.marshal(cellSetModel, writer);
624     Response response = client.put(path, Constants.MIMETYPE_XML,
625       Bytes.toBytes(writer.toString()));
626     Thread.yield();
627 
628     // make sure the fake row was not actually created
629     response = client.get(path, Constants.MIMETYPE_XML);
630     assertEquals(response.getCode(), 404);
631 
632     // check that all of the values were created
633     StringBuilder query = new StringBuilder();
634     query.append('/');
635     query.append(TABLE);
636     query.append('/');
637     query.append("testrow*");
638     response = client.get(query.toString(), Constants.MIMETYPE_XML);
639     assertEquals(response.getCode(), 200);
640     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
641     CellSetModel cellSet = (CellSetModel)
642       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
643     assertTrue(cellSet.getRows().size() == 2);
644 
645     response = deleteRow(TABLE, ROW_1);
646     assertEquals(response.getCode(), 200);
647     response = deleteRow(TABLE, ROW_2);
648     assertEquals(response.getCode(), 200);
649   }
650 
651   @Test
652   public void testSuffixGlobbingXML() throws IOException, JAXBException {
653     String path = "/" + TABLE + "/fakerow";  // deliberate nonexistent row
654 
655     CellSetModel cellSetModel = new CellSetModel();
656     RowModel rowModel = new RowModel(ROW_1);
657     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
658       Bytes.toBytes(VALUE_1)));
659     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
660       Bytes.toBytes(VALUE_2)));
661     cellSetModel.addRow(rowModel);
662     rowModel = new RowModel(ROW_2);
663     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_1),
664       Bytes.toBytes(VALUE_3)));
665     rowModel.addCell(new CellModel(Bytes.toBytes(COLUMN_2),
666       Bytes.toBytes(VALUE_4)));
667     cellSetModel.addRow(rowModel);
668     StringWriter writer = new StringWriter();
669     xmlMarshaller.marshal(cellSetModel, writer);
670     Response response = client.put(path, Constants.MIMETYPE_XML,
671       Bytes.toBytes(writer.toString()));
672     Thread.yield();
673 
674     // make sure the fake row was not actually created
675     response = client.get(path, Constants.MIMETYPE_XML);
676     assertEquals(response.getCode(), 404);
677 
678     // check that all of the values were created
679     StringBuilder query = new StringBuilder();
680     query.append('/');
681     query.append(TABLE);
682     query.append('/');
683     query.append("testrow*");
684     query.append('/');
685     query.append(COLUMN_1);
686     response = client.get(query.toString(), Constants.MIMETYPE_XML);
687     assertEquals(response.getCode(), 200);
688     assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
689     CellSetModel cellSet = (CellSetModel)
690       xmlUnmarshaller.unmarshal(new ByteArrayInputStream(response.getBody()));
691     List<RowModel> rows = cellSet.getRows();
692     assertTrue(rows.size() == 2);
693     for (RowModel row : rows) {
694       assertTrue(row.getCells().size() == 1);
695       assertEquals(COLUMN_1, Bytes.toString(row.getCells().get(0).getColumn()));
696     }
697     response = deleteRow(TABLE, ROW_1);
698     assertEquals(response.getCode(), 200);
699     response = deleteRow(TABLE, ROW_2);
700     assertEquals(response.getCode(), 200);
701   }
702 }
703