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