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