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  @ClassRule
050  public static final HBaseClassTestRule CLASS_RULE =
051      HBaseClassTestRule.forClass(TestGetAndPutResource.class);
052
053  private static final MetricsAssertHelper METRICS_ASSERT =
054      CompatibilityFactory.getInstance(MetricsAssertHelper.class);
055
056  @Test
057  public void testForbidden() throws IOException, JAXBException {
058    conf.set("hbase.rest.readonly", "true");
059
060    Response response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
061    assertEquals(403, response.getCode());
062    response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
063    assertEquals(403, response.getCode());
064    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
065    assertEquals(403, response.getCode());
066    response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
067    assertEquals(403, response.getCode());
068    response = deleteValue(TABLE, ROW_1, COLUMN_1);
069    assertEquals(403, response.getCode());
070    response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
071    assertEquals(403, response.getCode());
072    response = deleteRow(TABLE, ROW_1);
073    assertEquals(403, response.getCode());
074
075    conf.set("hbase.rest.readonly", "false");
076
077    response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
078    assertEquals(200, response.getCode());
079    response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
080    assertEquals(200, response.getCode());
081    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_2);
082    assertEquals(200, response.getCode());
083    response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
084    assertEquals(200, response.getCode());
085    response = deleteValue(TABLE, ROW_1, COLUMN_1);
086    assertEquals(200, response.getCode());
087    response = deleteRow(TABLE, ROW_1);
088    assertEquals(200, response.getCode());
089  }
090
091  @Test
092  public void testSingleCellGetPutXML() throws IOException, JAXBException {
093    Response response = getValueXML(TABLE, ROW_1, COLUMN_1);
094    assertEquals(404, response.getCode());
095
096    response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
097    assertEquals(200, response.getCode());
098    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
099    response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
100    assertEquals(200, response.getCode());
101    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
102    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
103    assertEquals(200, response.getCode());
104    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
105    response = checkAndDeleteXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
106    assertEquals(200, response.getCode());
107
108    response = deleteRow(TABLE, ROW_1);
109    assertEquals(200, response.getCode());
110  }
111
112  @Test
113  public void testSingleCellGetPutPB() throws IOException, JAXBException {
114    Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
115    assertEquals(404, response.getCode());
116
117    response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
118    assertEquals(200, response.getCode());
119    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
120    response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_2);
121    assertEquals(200, response.getCode());
122    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2);
123
124    response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_2, VALUE_3);
125    assertEquals(200, response.getCode());
126    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
127    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3, VALUE_4);
128    assertEquals(200, response.getCode());
129    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_4);
130
131    response = deleteRow(TABLE, ROW_1);
132    assertEquals(200, response.getCode());
133  }
134
135  @Test
136  public void testMultipleCellCheckPutPB() throws IOException {
137    Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
138    assertEquals(404, response.getCode());
139
140    // Add 2 Columns to setup the test
141    response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
142    assertEquals(200, response.getCode());
143    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
144
145    response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
146    assertEquals(200, response.getCode());
147    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
148
149    HashMap<String,String> otherCells = new HashMap<>();
150    otherCells.put(COLUMN_2,VALUE_3);
151
152    // On Success update both the cells
153    response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
154    assertEquals(200, response.getCode());
155    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
156    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
157
158    // On Failure, we dont update any cells
159    response = checkAndPutValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
160    assertEquals(304, response.getCode());
161    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_3);
162    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_3);
163
164    response = deleteRow(TABLE, ROW_1);
165    assertEquals(200, response.getCode());
166  }
167
168  @Test
169  public void testMultipleCellCheckPutXML() throws IOException, JAXBException {
170    Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
171    assertEquals(404, response.getCode());
172
173    // Add 2 Columns to setup the test
174    response = putValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
175    assertEquals(200, response.getCode());
176    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1);
177
178    response = putValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
179    assertEquals(200, response.getCode());
180    checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_2);
181
182    HashMap<String,String> otherCells = new HashMap<>();
183    otherCells.put(COLUMN_2,VALUE_3);
184
185    // On Success update both the cells
186    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_3, otherCells);
187    assertEquals(200, response.getCode());
188    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
189    checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
190
191    // On Failure, we dont update any cells
192    response = checkAndPutValueXML(TABLE, ROW_1, COLUMN_1, VALUE_1, VALUE_4, otherCells);
193    assertEquals(304, response.getCode());
194    checkValueXML(TABLE, ROW_1, COLUMN_1, VALUE_3);
195    checkValueXML(TABLE, ROW_1, COLUMN_2, VALUE_3);
196
197    response = deleteRow(TABLE, ROW_1);
198    assertEquals(200, response.getCode());
199  }
200
201  @Test
202  public void testMultipleCellCheckDeletePB() throws IOException {
203    Response response = getValuePB(TABLE, ROW_1, COLUMN_1);
204    assertEquals(404, response.getCode());
205
206    // Add 3 Columns to setup the test
207    response = putValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
208    assertEquals(200, response.getCode());
209    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
210
211    response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
212    assertEquals(200, response.getCode());
213    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
214
215    response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
216    assertEquals(200, response.getCode());
217    checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
218
219    // Deletes the following columns based on Column1 check
220    HashMap<String,String> cellsToDelete = new HashMap<>();
221    cellsToDelete.put(COLUMN_2,VALUE_2); // Value does not matter
222    cellsToDelete.put(COLUMN_3,VALUE_3); // Value does not matter
223
224    // On Success update both the cells
225    response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_1, cellsToDelete);
226    assertEquals(200, response.getCode());
227
228    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
229
230    response = getValuePB(TABLE, ROW_1, COLUMN_2);
231    assertEquals(404, response.getCode());
232
233    response = getValuePB(TABLE, ROW_1, COLUMN_3);
234    assertEquals(404, response.getCode());
235
236    response = putValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
237    assertEquals(200, response.getCode());
238    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
239
240    response = putValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
241    assertEquals(200, response.getCode());
242    checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
243
244    // On Failure, we dont update any cells
245    response = checkAndDeletePB(TABLE, ROW_1, COLUMN_1, VALUE_3, cellsToDelete);
246    assertEquals(304, response.getCode());
247    checkValuePB(TABLE, ROW_1, COLUMN_1, VALUE_1);
248    checkValuePB(TABLE, ROW_1, COLUMN_2, VALUE_2);
249    checkValuePB(TABLE, ROW_1, COLUMN_3, VALUE_3);
250
251    response = deleteRow(TABLE, ROW_1);
252    assertEquals(200, response.getCode());
253  }
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 {
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 {
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 {
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 {
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}