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