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