001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance 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.fcrepo.client; 019 020import static java.net.URI.create; 021import static org.fcrepo.client.FedoraHeaderConstants.CONTENT_TYPE; 022import static org.fcrepo.client.FedoraHeaderConstants.LOCATION; 023import static org.fcrepo.client.TestUtils.RDF_XML; 024import static org.fcrepo.client.TestUtils.SPARQL_UPDATE; 025import static org.fcrepo.client.TestUtils.TEXT_TURTLE; 026import static org.fcrepo.client.TestUtils.baseUrl; 027import static org.fcrepo.client.TestUtils.rdfXml; 028import static org.fcrepo.client.TestUtils.setField; 029import static org.fcrepo.client.TestUtils.sparqlUpdate; 030import static org.junit.Assert.assertEquals; 031import static org.mockito.ArgumentMatchers.any; 032import static org.mockito.Mockito.when; 033 034import java.io.ByteArrayInputStream; 035import java.io.IOException; 036import java.io.InputStream; 037import java.net.URI; 038 039import org.apache.commons.io.IOUtils; 040import org.apache.http.Header; 041import org.apache.http.HttpEntity; 042import org.apache.http.StatusLine; 043import org.apache.http.client.methods.CloseableHttpResponse; 044import org.apache.http.client.methods.HttpUriRequest; 045import org.apache.http.entity.ByteArrayEntity; 046import org.apache.http.impl.client.CloseableHttpClient; 047import org.apache.http.message.BasicHeader; 048import org.junit.Before; 049import org.junit.Ignore; 050import org.junit.Test; 051import org.junit.runner.RunWith; 052import org.mockito.Mock; 053import org.mockito.junit.MockitoJUnitRunner; 054 055/** 056 * @author acoburn 057 */ 058@RunWith(MockitoJUnitRunner.class) 059public class FcrepoClientTest { 060 061 private FcrepoClient testClient; 062 063 @Mock 064 private CloseableHttpClient mockHttpclient; 065 066 @Mock 067 private CloseableHttpResponse mockResponse; 068 069 @Mock 070 private StatusLine mockStatus; 071 072 @Mock 073 private HttpEntity mockEntity; 074 075 @Before 076 public void setUp() throws IOException { 077 testClient = FcrepoClient.client().throwExceptionOnFailure().build(); 078 setField(testClient, "httpclient", mockHttpclient); 079 } 080 081 @Test 082 public void testGet() throws IOException, FcrepoOperationFailedException { 083 final int status = 200; 084 final URI uri = create(baseUrl); 085 final ByteArrayEntity entity = new ByteArrayEntity(rdfXml.getBytes()); 086 entity.setContentType(RDF_XML); 087 088 doSetupMockRequest(RDF_XML, entity, status); 089 090 final FcrepoResponse response = testClient.get(uri) 091 .accept(RDF_XML) 092 .perform(); 093 094 assertEquals(response.getUrl(), uri); 095 assertEquals(response.getStatusCode(), status); 096 assertEquals(response.getContentType(), RDF_XML); 097 assertEquals(response.getLocation(), null); 098 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), rdfXml); 099 } 100 101 @Test(expected = FcrepoOperationFailedException.class) 102 public void testGetError() throws Exception { 103 final int status = 400; 104 final URI uri = create(baseUrl); 105 final ByteArrayEntity entity = new ByteArrayEntity(rdfXml.getBytes()); 106 entity.setContentType(RDF_XML); 107 108 doSetupMockRequest(RDF_XML, entity, status); 109 testClient.get(uri) 110 .accept(RDF_XML) 111 .preferRepresentation() 112 .perform(); 113 } 114 115 @Test(expected = FcrepoOperationFailedException.class) 116 public void testGet100() throws Exception { 117 final int status = 100; 118 final URI uri = create(baseUrl); 119 final ByteArrayEntity entity = new ByteArrayEntity(rdfXml.getBytes()); 120 entity.setContentType(RDF_XML); 121 122 doSetupMockRequest(RDF_XML, entity, status); 123 testClient.get(uri) 124 .accept(RDF_XML) 125 .perform(); 126 } 127 128 @Test 129 public void testGet300() throws Exception { 130 final int status = 300; 131 final URI uri = create(baseUrl); 132 final String redirect = baseUrl + "/bar"; 133 final Header linkHeader = new BasicHeader("Link", "<" + redirect + ">; rel=\"describedby\""); 134 final Header contentType = new BasicHeader(CONTENT_TYPE, RDF_XML); 135 final Header[] headers = new Header[] { contentType, linkHeader }; 136 final CloseableHttpResponse mockResponse = doSetupMockRequest(RDF_XML, null, status); 137 138 when(mockResponse.getAllHeaders()).thenReturn(headers); 139 140 final FcrepoResponse response = testClient.get(uri) 141 .accept(RDF_XML) 142 .perform(); 143 144 assertEquals(response.getUrl(), uri); 145 assertEquals(response.getStatusCode(), status); 146 assertEquals(response.getContentType(), RDF_XML); 147 assertEquals(response.getLocation(), create(redirect)); 148 assertEquals(response.getBody(), null); 149 } 150 151 @Test 152 public void testGetNoAccept() throws Exception { 153 final int status = 200; 154 final URI uri = create(baseUrl); 155 156 doSetupMockRequest(RDF_XML, null, status); 157 158 final FcrepoResponse response = testClient.get(uri).perform(); 159 160 assertEquals(response.getUrl(), uri); 161 assertEquals(response.getStatusCode(), status); 162 assertEquals(response.getContentType(), RDF_XML); 163 assertEquals(response.getLocation(), null); 164 assertEquals(response.getBody(), null); 165 } 166 167 @Test 168 public void testHead() throws IOException, FcrepoOperationFailedException { 169 final int status = 200; 170 final URI uri = create(baseUrl); 171 172 doSetupMockRequest(TEXT_TURTLE, null, status); 173 174 final FcrepoResponse response = testClient.head(uri).perform(); 175 176 assertEquals(response.getUrl(), uri); 177 assertEquals(response.getStatusCode(), status); 178 assertEquals(response.getContentType(), TEXT_TURTLE); 179 assertEquals(response.getLocation(), null); 180 assertEquals(response.getBody(), null); 181 } 182 183 @Test 184 public void testHeadersCaseInsensitive() throws Exception { 185 final int status = 200; 186 final URI uri = create(baseUrl); 187 188 doSetupMockRequest(TEXT_TURTLE, null, status); 189 190 final FcrepoResponse response = testClient.head(uri).perform(); 191 192 // Verify that the case of header names returned by server doesn't impact retrieval 193 assertEquals(response.getHeaderValue("content-type"), TEXT_TURTLE); 194 } 195 196 @Test(expected = FcrepoOperationFailedException.class) 197 public void testHeadError() throws IOException, FcrepoOperationFailedException { 198 doSetupMockRequest(TEXT_TURTLE, null, 404); 199 testClient.head(create(baseUrl)).perform(); 200 } 201 202 @Test 203 public void testPut() throws IOException, FcrepoOperationFailedException { 204 final int status = 204; 205 final URI uri = create(baseUrl); 206 final InputStream body = new ByteArrayInputStream(rdfXml.getBytes()); 207 208 doSetupMockRequest(RDF_XML, null, status); 209 210 final FcrepoResponse response = testClient.put(uri) 211 .body(body, RDF_XML) 212 .perform(); 213 214 assertEquals(response.getUrl(), uri); 215 assertEquals(response.getStatusCode(), status); 216 assertEquals(response.getContentType(), RDF_XML); 217 assertEquals(response.getLocation(), null); 218 assertEquals(response.getBody(), null); 219 } 220 221 @Test 222 public void testPutNoBody() throws IOException, FcrepoOperationFailedException { 223 final int status = 204; 224 final URI uri = create(baseUrl); 225 226 doSetupMockRequest(null, null, status); 227 228 final FcrepoResponse response = testClient.put(uri).perform(); 229 230 assertEquals(response.getUrl(), uri); 231 assertEquals(response.getStatusCode(), status); 232 assertEquals(response.getContentType(), null); 233 assertEquals(response.getLocation(), null); 234 assertEquals(response.getBody(), null); 235 } 236 237 @Test 238 public void testPutWithResponseBody() throws IOException, FcrepoOperationFailedException { 239 final int status = 201; 240 final URI uri = create(baseUrl); 241 242 doSetupMockRequest(null, new ByteArrayEntity(uri.toString().getBytes()), status); 243 244 final FcrepoResponse response = testClient.put(uri).perform(); 245 246 assertEquals(response.getUrl(), uri); 247 assertEquals(response.getStatusCode(), status); 248 assertEquals(response.getContentType(), null); 249 assertEquals(response.getLocation(), null); 250 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), uri.toString()); 251 } 252 253 @Test(expected = FcrepoOperationFailedException.class) 254 public void testPutError() throws IOException, FcrepoOperationFailedException { 255 final int status = 500; 256 final URI uri = create(baseUrl); 257 final InputStream body = new ByteArrayInputStream(rdfXml.getBytes()); 258 259 doSetupMockRequest(RDF_XML, null, status); 260 testClient.put(uri) 261 .body(body, RDF_XML) 262 .perform(); 263 } 264 265 @Test 266 public void testDelete() throws IOException, FcrepoOperationFailedException { 267 final int status = 204; 268 final URI uri = create(baseUrl); 269 270 doSetupMockRequest(SPARQL_UPDATE, null, status); 271 272 final FcrepoResponse response = testClient.delete(uri).perform(); 273 274 assertEquals(response.getUrl(), uri); 275 assertEquals(response.getStatusCode(), status); 276 assertEquals(response.getContentType(), SPARQL_UPDATE); 277 assertEquals(response.getLocation(), null); 278 assertEquals(response.getBody(), null); 279 } 280 281 @Test 282 public void testDeleteWithResponseBody() throws IOException, FcrepoOperationFailedException { 283 final int status = 204; 284 final URI uri = create(baseUrl); 285 final String responseText = "tombstone found"; 286 287 doSetupMockRequest(null, new ByteArrayEntity(responseText.getBytes()), status); 288 289 final FcrepoResponse response = testClient.delete(uri).perform(); 290 291 assertEquals(response.getUrl(), uri); 292 assertEquals(response.getStatusCode(), status); 293 assertEquals(response.getContentType(), null); 294 assertEquals(response.getLocation(), null); 295 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), responseText); 296 } 297 298 @Test(expected = FcrepoOperationFailedException.class) 299 public void testDeleteError() throws IOException, FcrepoOperationFailedException { 300 final int status = 401; 301 final URI uri = create(baseUrl); 302 303 doSetupMockRequest(SPARQL_UPDATE, null, status); 304 testClient.delete(uri).perform(); 305 } 306 307 @Test 308 public void testPatch() throws IOException, FcrepoOperationFailedException { 309 final int status = 204; 310 final URI uri = create(baseUrl); 311 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 312 313 doSetupMockRequest(SPARQL_UPDATE, null, status); 314 315 final FcrepoResponse response = testClient.patch(uri) 316 .body(body) 317 .perform(); 318 319 assertEquals(response.getUrl(), uri); 320 assertEquals(response.getStatusCode(), status); 321 assertEquals(response.getContentType(), SPARQL_UPDATE); 322 assertEquals(response.getLocation(), null); 323 assertEquals(response.getBody(), null); 324 } 325 326 @Ignore 327 @Test(expected = IllegalArgumentException.class) 328 public void testPatchNoContent() throws IOException, FcrepoOperationFailedException { 329 final int status = 204; 330 final URI uri = create(baseUrl); 331 332 doSetupMockRequest(SPARQL_UPDATE, null, status); 333 testClient.patch(uri).perform(); 334 } 335 336 @Test 337 public void testPatchResponseBody() throws IOException, FcrepoOperationFailedException { 338 final int status = 204; 339 final URI uri = create(baseUrl); 340 final String responseText = "Sparql-update response"; 341 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 342 343 doSetupMockRequest(SPARQL_UPDATE, new ByteArrayEntity(responseText.getBytes()), status); 344 345 final FcrepoResponse response = testClient.patch(uri) 346 .body(body) 347 .perform(); 348 349 assertEquals(response.getUrl(), uri); 350 assertEquals(response.getStatusCode(), status); 351 assertEquals(response.getContentType(), SPARQL_UPDATE); 352 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), responseText); 353 } 354 355 @Test(expected = FcrepoOperationFailedException.class) 356 public void testPatchError() throws IOException, FcrepoOperationFailedException { 357 final int status = 415; 358 final URI uri = create(baseUrl); 359 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 360 361 doSetupMockRequest(SPARQL_UPDATE, null, status); 362 testClient.patch(uri) 363 .body(body) 364 .perform(); 365 } 366 367 @Test 368 public void testPost() throws IOException, FcrepoOperationFailedException { 369 final int status = 204; 370 final URI uri = create(baseUrl); 371 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 372 373 doSetupMockRequest(SPARQL_UPDATE, null, status); 374 375 final FcrepoResponse response = testClient.post(uri) 376 .body(body, SPARQL_UPDATE) 377 .perform(); 378 379 assertEquals(response.getUrl(), uri); 380 assertEquals(response.getStatusCode(), status); 381 assertEquals(response.getContentType(), SPARQL_UPDATE); 382 assertEquals(response.getLocation(), null); 383 assertEquals(response.getBody(), null); 384 } 385 386 @Test 387 public void testPostResponseBody() throws IOException, FcrepoOperationFailedException { 388 final int status = 204; 389 final URI uri = create(baseUrl); 390 final String responseText = baseUrl + "/bar"; 391 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 392 393 doSetupMockRequest(SPARQL_UPDATE, new ByteArrayEntity(responseText.getBytes()), status); 394 395 final FcrepoResponse response = testClient.post(uri) 396 .body(body, SPARQL_UPDATE) 397 .perform(); 398 399 assertEquals(response.getUrl(), uri); 400 assertEquals(response.getStatusCode(), status); 401 assertEquals(response.getContentType(), SPARQL_UPDATE); 402 assertEquals(response.getLocation(), null); 403 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), responseText); 404 } 405 406 @Test 407 public void testPostNoBody() throws IOException, FcrepoOperationFailedException { 408 final int status = 204; 409 final URI uri = create(baseUrl); 410 final String responseText = baseUrl + "/bar"; 411 412 doSetupMockRequest(null, new ByteArrayEntity(responseText.getBytes()), status); 413 414 final FcrepoResponse response = testClient.post(uri).perform(); 415 416 assertEquals(response.getUrl(), uri); 417 assertEquals(response.getStatusCode(), status); 418 assertEquals(response.getContentType(), null); 419 assertEquals(response.getLocation(), null); 420 assertEquals(IOUtils.toString(response.getBody(), "UTF-8"), responseText); 421 } 422 423 @Test(expected = FcrepoOperationFailedException.class) 424 public void testPostError() throws IOException, FcrepoOperationFailedException { 425 final int status = 415; 426 final URI uri = create(baseUrl); 427 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 428 429 doSetupMockRequest(SPARQL_UPDATE, null, status); 430 testClient.post(uri) 431 .body(body, SPARQL_UPDATE) 432 .perform(); 433 } 434 435 @Test(expected = IllegalArgumentException.class) 436 public void testPostErrorNullUrl() throws Exception { 437 final int status = 401; 438 final String statusPhrase = "Unauthorized"; 439 final String response = "Response error"; 440 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 441 final ByteArrayEntity responseBody = new ByteArrayEntity(response.getBytes()); 442 443 doSetupMockRequest(SPARQL_UPDATE, responseBody, status, statusPhrase); 444 445 testClient.post(null) 446 .body(body, SPARQL_UPDATE) 447 .perform(); 448 } 449 450 @Test 451 public void testBadRequest() throws IOException, FcrepoOperationFailedException { 452 final URI uri = create(baseUrl); 453 final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes()); 454 455 when(mockHttpclient.execute(any(HttpUriRequest.class))).thenThrow(new IOException("Expected error")); 456 457 try { 458 testClient.post(uri) 459 .body(body, SPARQL_UPDATE) 460 .perform(); 461 } catch (final FcrepoOperationFailedException ex) { 462 assertEquals(ex.getUrl(), uri); 463 assertEquals(ex.getStatusText(), "Expected error"); 464 assertEquals(ex.getStatusCode(), -1); 465 } 466 } 467 468 @Test 469 public void testBadResponseBody() throws IOException, FcrepoOperationFailedException { 470 final int status = 200; 471 final URI uri = create(baseUrl); 472 final ByteArrayEntity entity = new ByteArrayEntity(rdfXml.getBytes()); 473 entity.setContentType(RDF_XML); 474 475 doSetupMockRequest(RDF_XML, entity, status); 476 when(mockResponse.getEntity()).thenReturn(mockEntity); 477 when(mockEntity.getContent()).thenThrow(new IOException("Expected IO error")); 478 479 final FcrepoResponse response = testClient.get(uri) 480 .accept(RDF_XML) 481 .perform(); 482 assertEquals(response.getUrl(), uri); 483 assertEquals(response.getStatusCode(), status); 484 assertEquals(response.getContentType(), RDF_XML); 485 assertEquals(response.getLocation(), null); 486 assertEquals(response.getBody(), null); 487 } 488 489 private CloseableHttpResponse doSetupMockRequest(final String contentType, final ByteArrayEntity entity, 490 final int status) throws IOException { 491 return doSetupMockRequest(contentType, entity, status, null); 492 } 493 494 private CloseableHttpResponse doSetupMockRequest(final String contentType, final ByteArrayEntity entity, 495 final int status, final String statusPhrase) throws IOException { 496 final Header contentTypeHeader = new BasicHeader("Content-Type", contentType); 497 final Header locationHeader = new BasicHeader(LOCATION, null); 498 final Header[] responseHeaders = new Header[] { locationHeader, contentTypeHeader }; 499 500 when(mockHttpclient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse); 501 when(mockResponse.getAllHeaders()).thenReturn(responseHeaders); 502 when(mockResponse.getEntity()).thenReturn(entity); 503 when(mockResponse.getStatusLine()).thenReturn(mockStatus); 504 when(mockStatus.getStatusCode()).thenReturn(status); 505 when(mockStatus.getReasonPhrase()).thenReturn(statusPhrase); 506 507 return mockResponse; 508 } 509}