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