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.integration;
007
008import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
009import static javax.ws.rs.core.Response.Status.CONFLICT;
010import static javax.ws.rs.core.Response.Status.CREATED;
011import static javax.ws.rs.core.Response.Status.GONE;
012import static javax.ws.rs.core.Response.Status.NOT_FOUND;
013import static javax.ws.rs.core.Response.Status.NOT_MODIFIED;
014import static javax.ws.rs.core.Response.Status.NO_CONTENT;
015import static javax.ws.rs.core.Response.Status.OK;
016import static javax.ws.rs.core.Response.Status.PARTIAL_CONTENT;
017import static javax.ws.rs.core.Response.Status.PRECONDITION_FAILED;
018import static javax.ws.rs.core.Response.Status.TEMPORARY_REDIRECT;
019import static org.fcrepo.client.FedoraHeaderConstants.CONTENT_DISPOSITION_FILENAME;
020import static org.fcrepo.client.FedoraHeaderConstants.CONTENT_TYPE;
021import static org.fcrepo.client.FedoraHeaderConstants.DIGEST;
022import static org.fcrepo.client.FedoraHeaderConstants.ETAG;
023import static org.fcrepo.client.FedoraHeaderConstants.LAST_MODIFIED;
024import static org.fcrepo.client.FedoraHeaderConstants.STATE_TOKEN;
025import static org.fcrepo.client.FedoraTypes.LDP_DIRECT_CONTAINER;
026import static org.fcrepo.client.TestUtils.TEXT_TURTLE;
027import static org.fcrepo.client.TestUtils.sparqlUpdate;
028import static org.junit.Assert.assertEquals;
029import static org.junit.Assert.assertNotEquals;
030import static org.junit.Assert.assertNotNull;
031import static org.junit.Assert.assertNull;
032import static org.junit.Assert.assertTrue;
033
034import java.io.ByteArrayInputStream;
035import java.io.IOException;
036import java.io.InputStream;
037import java.net.URI;
038import java.nio.file.Files;
039import java.nio.file.Path;
040import java.util.Arrays;
041import java.util.Calendar;
042import java.util.Date;
043import java.util.HashMap;
044import java.util.Map;
045import java.util.UUID;
046
047import javax.ws.rs.core.EntityTag;
048
049import org.apache.commons.io.FileUtils;
050import org.apache.commons.io.IOUtils;
051import org.apache.http.client.utils.DateUtils;
052import org.fcrepo.client.ExternalContentHandling;
053import org.fcrepo.client.FcrepoClient;
054import org.fcrepo.client.FcrepoOperationFailedException;
055import org.fcrepo.client.FcrepoResponse;
056import org.fcrepo.client.HeaderHelpers;
057import org.junit.AfterClass;
058import org.junit.Before;
059import org.junit.BeforeClass;
060import org.junit.Test;
061
062/**
063 * @author bbpennel
064 */
065public class FcrepoClientIT extends AbstractResourceIT {
066
067    private static FcrepoClient client;
068
069    private URI url;
070
071    final private String UNMODIFIED_DATE = "Mon, 1 Jan 2001 00:00:00 GMT";
072
073    @BeforeClass
074    public static void beforeClass() {
075        client = FcrepoClient.client()
076                .credentials("fedoraAdmin", "fedoraAdmin")
077                .authScope("localhost")
078                .build();
079    }
080
081    @AfterClass
082    public static void afterClass() throws IOException {
083        client.close();
084    }
085
086    @Before
087    public void before() {
088        url = URI.create(SERVER_ADDRESS + UUID.randomUUID().toString());
089    }
090
091    @Test
092    public void testPost() throws Exception {
093        try (final FcrepoResponse response =
094                client.post(new URI(SERVER_ADDRESS)).perform()) {
095            assertEquals(CREATED.getStatusCode(), response.getStatusCode());
096        }
097    }
098
099    @Test
100    public void testPostBinary() throws Exception {
101        final String slug = UUID.randomUUID().toString();
102        final String filename = "hello.txt";
103        final String mimetype = "text/plain";
104        final String bodyContent = "Hello world";
105
106        final URI createdResourceUri;
107        try (final FcrepoResponse response =
108                client.post(new URI(SERVER_ADDRESS))
109                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
110                .filename(filename)
111                .slug(slug)
112                .perform()) {
113
114            final String content = IOUtils.toString(response.getBody(), "UTF-8");
115            final int status = response.getStatusCode();
116            createdResourceUri = response.getLocation();
117
118            assertEquals("Didn't get a CREATED response! Got content:\n" + content,
119                    CREATED.getStatusCode(), status);
120            assertEquals("Location did not match slug", SERVER_ADDRESS + slug, createdResourceUri.toString());
121
122            assertNotNull("Didn't find linked description!", response.getLinkHeaders("describedby").get(0));
123        }
124
125        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
126            final Map<String, String> contentDisp = getResponse.getContentDisposition();
127            assertEquals(filename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
128
129            assertEquals(mimetype, getResponse.getContentType());
130
131            final String getContent = IOUtils.toString(getResponse.getBody(), "UTF-8");
132            assertEquals(bodyContent, getContent);
133        }
134    }
135
136    @Test
137    public void testPostExternalContent() throws Exception {
138        final String filename = "hello.txt";
139        final String mimetype = "text/plain";
140        final String fileContent = "Hello post world";
141
142        final Path contentPath = Files.createTempFile(null, ".txt");
143        FileUtils.write(contentPath.toFile(), fileContent, "UTF-8");
144
145        final URI createdResourceUri;
146        try (final FcrepoResponse response =
147                client.post(new URI(SERVER_ADDRESS))
148                .externalContent(contentPath.toUri(), mimetype, ExternalContentHandling.PROXY)
149                .filename(filename)
150                .perform()) {
151
152            final String content = IOUtils.toString(response.getBody(), "UTF-8");
153            final int status = response.getStatusCode();
154            createdResourceUri = response.getLocation();
155
156            assertEquals("Didn't get a CREATED response! Got content:\n" + content,
157                    CREATED.getStatusCode(), status);
158        }
159
160        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
161            final Map<String, String> contentDisp = getResponse.getContentDisposition();
162            assertEquals(filename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
163
164            assertEquals(mimetype, getResponse.getContentType());
165
166            final String getContent = IOUtils.toString(getResponse.getBody(), "UTF-8");
167            assertEquals(fileContent, getContent);
168        }
169    }
170
171    @Test
172    public void testPostDigestMismatch() throws Exception {
173        final String bodyContent = "Hello world";
174        final String invalidDigest = "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc";
175
176        try (final FcrepoResponse response =
177                client.post(new URI(SERVER_ADDRESS))
178                .body(new ByteArrayInputStream(bodyContent.getBytes()), "text/plain")
179                .digestSha1(invalidDigest)
180                .perform()) {
181
182            assertEquals("Invalid checksum was not rejected", CONFLICT.getStatusCode(), response.getStatusCode());
183        }
184    }
185
186    @Test
187    public void testPostDigestMultipleChecksums() throws Exception {
188        final String bodyContent = "Hello world";
189
190        try (final FcrepoResponse response =
191                client.post(new URI(SERVER_ADDRESS))
192                .body(new ByteArrayInputStream(bodyContent.getBytes()), "text/plain")
193                .digestMd5("3e25960a79dbc69b674cd4ec67a72c62")
194                .digestSha1("7b502c3a1f48c8609ae212cdfb639dee39673f5e")
195                .digestSha256("64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c")
196                .perform()) {
197
198            assertEquals("Checksums rejected", CREATED.getStatusCode(), response.getStatusCode());
199        }
200    }
201
202    @Test
203    public void testPostDigestMultipleChecksumsOneMismatch() throws Exception {
204        final String bodyContent = "Hello world";
205
206        try (final FcrepoResponse response =
207                client.post(new URI(SERVER_ADDRESS))
208                .body(new ByteArrayInputStream(bodyContent.getBytes()), "text/plain")
209                .digestMd5("3e25960a79dbc69b674cd4ec67a72c62")
210                .digestSha1("7b502c3a1f48c8609ae212cdfb639dee39673f5e")
211                // Incorrect sha256
212                .digestSha256("123488ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c")
213                .perform()) {
214
215            assertEquals("Invalid checksum was not rejected", CONFLICT.getStatusCode(), response.getStatusCode());
216        }
217    }
218
219    @Test
220    public void testPostBinaryNullFilename() throws Exception {
221        final String bodyContent = "Hello world";
222
223        try (final FcrepoResponse response =
224                client.post(new URI(SERVER_ADDRESS))
225                .body(new ByteArrayInputStream(bodyContent.getBytes()), "text/plain")
226                .filename(null)
227                .perform()) {
228
229            assertEquals("Empty filename rejected", CREATED.getStatusCode(), response.getStatusCode());
230        }
231    }
232
233    @Test
234    public void testPostDirectContainer() throws Exception {
235        final URI createdResourceUri;
236        try (final FcrepoResponse response =
237                client.post(new URI(SERVER_ADDRESS))
238                .addInteractionModel(LDP_DIRECT_CONTAINER)
239                .perform()) {
240
241            final int status = response.getStatusCode();
242            createdResourceUri = response.getLocation();
243
244            assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), status);
245        }
246
247        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
248            assertTrue("Did not have ldp:DirectContainer type", getResponse.hasType(LDP_DIRECT_CONTAINER));
249        }
250    }
251
252    @Test
253    public void testPostBinaryFilenameSpecialCharacters() throws Exception {
254        final String slug = UUID.randomUUID().toString();
255        final String filename = "hello world\nof_weird:+\tchar/acters.tx\rt";
256        final String expectedFilename = "hello world of_weird:+\tchar/acters.tx t";
257        final String mimetype = "text/plain";
258        final String bodyContent = "Hello world";
259
260        final URI createdResourceUri;
261        try (final FcrepoResponse response =
262                client.post(new URI(SERVER_ADDRESS))
263                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
264                .filename(filename)
265                .slug(slug)
266                .perform()) {
267
268            final String content = IOUtils.toString(response.getBody(), "UTF-8");
269            final int status = response.getStatusCode();
270            createdResourceUri = response.getLocation();
271
272            assertEquals("Didn't get a CREATED response! Got content:\n" + content,
273                    CREATED.getStatusCode(), status);
274            assertEquals("Location did not match slug", SERVER_ADDRESS + slug, response.getLocation().toString());
275
276            assertNotNull("Didn't find linked description!", response.getLinkHeaders("describedby").get(0));
277        }
278
279        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
280            final Map<String, String> contentDisp = getResponse.getContentDisposition();
281            assertEquals(expectedFilename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
282
283            assertEquals(mimetype, getResponse.getContentType());
284
285            final String getContent = IOUtils.toString(getResponse.getBody(), "UTF-8");
286            assertEquals(bodyContent, getContent);
287        }
288    }
289
290    @Test
291    public void testPutBinaryFilenameSpecialCharacters() throws Exception {
292        final String id = UUID.randomUUID().toString();
293        final String filename = "hello world\nof_weird:+\tchar/acters.tx\rt";
294        final String expectedFilename = "hello world of_weird:+\tchar/acters.tx t";
295        final String mimetype = "text/plain";
296        final String bodyContent = "Hello world";
297
298        final URI createdResourceUri;
299        try (final FcrepoResponse response =
300                client.put(new URI(SERVER_ADDRESS + id))
301                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
302                .filename(filename)
303                .perform()) {
304
305            final String content = IOUtils.toString(response.getBody(), "UTF-8");
306            final int status = response.getStatusCode();
307            createdResourceUri = response.getLocation();
308
309            assertEquals("Didn't get a CREATED response! Got content:\n" + content,
310                    CREATED.getStatusCode(), status);
311            assertEquals("Location did not match slug", SERVER_ADDRESS + id, response.getLocation().toString());
312
313            assertNotNull("Didn't find linked description!", response.getLinkHeaders("describedby").get(0));
314        }
315
316        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
317            final Map<String, String> contentDisp = getResponse.getContentDisposition();
318            assertEquals(expectedFilename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
319
320            assertEquals(mimetype, getResponse.getContentType());
321
322            final String getContent = IOUtils.toString(getResponse.getBody(), "UTF-8");
323            assertEquals(bodyContent, getContent);
324        }
325    }
326
327    @Test
328    public void testPut() throws Exception {
329        try (final FcrepoResponse response = create()) {
330            assertEquals(CREATED.getStatusCode(), response.getStatusCode());
331            assertEquals(url, response.getLocation());
332        }
333    }
334
335    @Test
336    public void testPutEtag() throws Exception {
337        // Create object
338        final EntityTag etag;
339        try (final FcrepoResponse response = create()) {
340            // Get the etag of the nearly created object
341            etag = EntityTag.valueOf(response.getHeaderValue(ETAG));
342        }
343
344        // Retrieve the body of the resource so we can modify it
345        String body = getTurtle(url);
346        body += "\n<> <http://purl.org/dc/elements/1.1/title> \"some-title\"";
347
348        // Check that etag is making it through and being rejected
349        try (final FcrepoResponse updateResp = client.put(url)
350                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
351                .ifMatch("\"bad-etag\"")
352                .perform()) {
353
354            assertEquals(PRECONDITION_FAILED.getStatusCode(), updateResp.getStatusCode());
355        }
356
357        // Verify that etag is retrieved and resubmitted correctly
358        try (final FcrepoResponse validResp = client.put(url)
359                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
360                .ifMatch("\"" + etag.getValue() + "\"")
361                .perform()) {
362            assertEquals(NO_CONTENT.getStatusCode(), validResp.getStatusCode());
363        }
364    }
365
366    @Test
367    public void testPutUnmodifiedSince() throws Exception {
368        // Create object
369        final String originalModified;
370        try (final FcrepoResponse response = create()) {
371            originalModified = response.getHeaderValue(LAST_MODIFIED);
372        }
373
374        // Retrieve the body of the resource so we can modify it
375        String body = getTurtle(url);
376        body += "\n<> <http://purl.org/dc/elements/1.1/title> \"some-title\"";
377
378        // Update the body the first time, which should succeed
379        try (final FcrepoResponse matchResponse = client.put(url)
380                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
381                .ifUnmodifiedSince(originalModified)
382                .perform()) {
383
384            assertEquals(NO_CONTENT.getStatusCode(), matchResponse.getStatusCode());
385        }
386
387        // Update the triples a second time with old timestamp
388        try (final FcrepoResponse mismatchResponse = client.put(url)
389                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
390                .ifUnmodifiedSince(UNMODIFIED_DATE)
391                .perform()) {
392
393            assertEquals(PRECONDITION_FAILED.getStatusCode(), mismatchResponse.getStatusCode());
394        }
395    }
396
397    @Test
398    public void testPutLenient() throws Exception {
399        // Create object
400        try (final FcrepoResponse response = create()) {
401        }
402
403        final String body = "<> <http://purl.org/dc/elements/1.1/title> \"some-title\"";
404
405        // try to update without lenient header
406        try (final FcrepoResponse strictResponse = client.put(url)
407                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
408                .perform()) {
409            assertEquals(NO_CONTENT.getStatusCode(), strictResponse.getStatusCode());
410        }
411
412        // try again with lenient header
413        try (final FcrepoResponse lenientResponse = client.put(url)
414                .body(new ByteArrayInputStream(body.getBytes()), TEXT_TURTLE)
415                .preferLenient()
416                .perform()) {
417            assertEquals(NO_CONTENT.getStatusCode(), lenientResponse.getStatusCode());
418        }
419    }
420
421    @Test
422    public void testPutExternalContent() throws Exception {
423        final String filename = "put.txt";
424        final String mimetype = "text/plain";
425        final String fileContent = "Hello put world";
426
427        final Path contentPath = Files.createTempFile(null, ".txt");
428        FileUtils.write(contentPath.toFile(), fileContent, "UTF-8");
429
430        final URI createdResourceUri;
431        try (final FcrepoResponse response = client.put(url)
432                .externalContent(contentPath.toUri(), mimetype, ExternalContentHandling.PROXY)
433                .filename(filename)
434                .perform()) {
435
436            final String content = IOUtils.toString(response.getBody(), "UTF-8");
437            final int status = response.getStatusCode();
438            createdResourceUri = response.getLocation();
439
440            assertEquals("Didn't get a CREATED response! Got content:\n" + content,
441                    CREATED.getStatusCode(), status);
442        }
443
444        try (final FcrepoResponse getResponse = client.get(createdResourceUri).perform()) {
445            final Map<String, String> contentDisp = getResponse.getContentDisposition();
446            assertEquals(filename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
447
448            assertEquals(mimetype, getResponse.getContentType());
449
450            final String getContent = IOUtils.toString(getResponse.getBody(), "UTF-8");
451            assertEquals(fileContent, getContent);
452        }
453    }
454
455    @Test
456    public void testPutBinaryNullFilename() throws Exception {
457        final String bodyContent = "Hello world";
458
459        try (final FcrepoResponse response = client.put(url)
460                .body(new ByteArrayInputStream(bodyContent.getBytes()), "text/plain")
461                .filename(null)
462                .perform()) {
463            assertEquals("Empty filename rejected", CREATED.getStatusCode(), response.getStatusCode());
464        }
465    }
466
467    @Test
468    public void testPatch() throws Exception {
469        // Create object
470        try (final FcrepoResponse response = create()) {
471        }
472
473        // Update triples with sparql update
474        final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes());
475        try (final FcrepoResponse response = client.patch(url)
476                .body(body)
477                .perform()) {
478
479            assertEquals(NO_CONTENT.getStatusCode(), response.getStatusCode());
480        }
481    }
482
483    @Test
484    public void testPatchEtagUpdated() throws Exception {
485        // Create object
486        final EntityTag createdEtag;
487        try (final FcrepoResponse createResp = create()) {
488            createdEtag = EntityTag.valueOf(createResp.getHeaderValue(ETAG));
489        }
490
491        // Update triples with sparql update
492        final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes());
493        try (final FcrepoResponse response = client.patch(url)
494                .body(body)
495                .ifMatch("\"" + createdEtag.getValue() + "\"")
496                .perform()) {
497
498            final EntityTag updateEtag = EntityTag.valueOf(response.getHeaderValue(ETAG));
499
500            assertEquals(NO_CONTENT.getStatusCode(), response.getStatusCode());
501            assertNotEquals("Etag did not change after patch", createdEtag, updateEtag);
502        }
503    }
504
505    @Test
506    public void testPatchNoBody() throws Exception {
507        try (final FcrepoResponse response = create()) {
508        }
509
510        try (final FcrepoResponse response = client.patch(url)
511                .perform()) {
512            assertEquals(BAD_REQUEST.getStatusCode(), response.getStatusCode());
513        }
514    }
515
516    @Test
517    public void testDelete() throws Exception {
518        try (final FcrepoResponse response = create()) {
519        }
520
521        try (final FcrepoResponse response = client.delete(url).perform()) {
522
523            assertEquals(NO_CONTENT.getStatusCode(), response.getStatusCode());
524
525            assertEquals(GONE.getStatusCode(), client.get(url).perform().getStatusCode());
526        }
527    }
528
529    @Test
530    public void testGet() throws Exception {
531        try (final FcrepoResponse response = create()) {
532        }
533
534        try (final FcrepoResponse response = client.get(url).perform()) {
535            assertEquals(OK.getStatusCode(), response.getStatusCode());
536        }
537    }
538
539    @Test
540    public void testGetNotFound() throws Exception {
541        try (final FcrepoResponse response = client.get(url).perform()) {
542            assertEquals(NOT_FOUND.getStatusCode(), response.getStatusCode());
543        }
544    }
545
546    @Test
547    public void testGetUnmodified() throws Exception {
548
549        final String lastModified;
550        try (final FcrepoResponse response = create()) {
551            lastModified = response.getHeaderValue(LAST_MODIFIED);
552        }
553
554        // Get tomorrows date to provide as the modified-since date
555        final Date modDate = DateUtils.parseDate(lastModified);
556        final Calendar cal = Calendar.getInstance();
557        cal.setTime(modDate);
558        cal.add(Calendar.DATE, 1);
559
560        // Check that get returns a 304 if the item hasn't changed according to last-modified
561        try (final FcrepoResponse modResp = client.get(url)
562                .ifModifiedSince(DateUtils.formatDate(cal.getTime()))
563                .perform()) {
564
565            assertEquals(NOT_MODIFIED.getStatusCode(), modResp.getStatusCode());
566            assertNull("Response body should not be returned when unmodified", modResp.getBody());
567        }
568    }
569
570    @Test
571    public void testGetModified() throws Exception {
572
573        final String lastModified;
574        try (final FcrepoResponse response = create()) {
575            lastModified = response.getHeaderValue(LAST_MODIFIED);
576        }
577
578        // Get yesterdays date to provide as the modified-since date
579        final Date modDate = DateUtils.parseDate(lastModified);
580        final Calendar cal = Calendar.getInstance();
581        cal.setTime(modDate);
582        cal.add(Calendar.DATE, -1);
583
584        // Check that get returns a 200 if the item has changed according to last-modified
585        try (final FcrepoResponse modResp = client.get(url)
586                .ifModifiedSince(DateUtils.formatDate(cal.getTime()))
587                .perform()) {
588
589            assertEquals(OK.getStatusCode(), modResp.getStatusCode());
590            assertNotNull("GET response body should be normal when modified", modResp.getBody());
591        }
592    }
593
594    @Test
595    public void testGetAccept() throws Exception {
596        try (final FcrepoResponse response = create()) {
597        }
598
599        try (final FcrepoResponse response = client.get(url)
600                .accept("application/n-triples")
601                .perform()) {
602
603            assertEquals("application/n-triples", response.getHeaderValue(CONTENT_TYPE));
604            assertEquals(OK.getStatusCode(), response.getStatusCode());
605        }
606    }
607
608    @Test
609    public void testGetPrefer() throws Exception {
610        try (final FcrepoResponse response = create()) {
611        }
612
613        try (final FcrepoResponse response = client.get(url)
614                .preferRepresentation(Arrays.asList(URI.create("http://www.w3.org/ns/ldp#PreferMinimalContainer")),
615                        Arrays.asList(URI.create("http://fedora.info/definitions/fcrepo#ServerManaged"))).perform()) {
616
617            assertEquals(OK.getStatusCode(), response.getStatusCode());
618            assertEquals("return=representation; include=\"http://www.w3.org/ns/ldp#PreferMinimalContainer\"; " +
619                    "omit=\"http://fedora.info/definitions/fcrepo#ServerManaged\"",
620                    response.getHeaderValue("Preference-Applied"));
621        }
622    }
623
624    @Test
625    public void testGetRange() throws Exception {
626        // Creating a binary for retrieval
627        final String mimetype = "text/plain";
628        final String bodyContent = "Hello world";
629        final URI createdResourceUri;
630        try (final FcrepoResponse response = client.post(new URI(SERVER_ADDRESS))
631                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
632                .perform()) {
633
634            createdResourceUri = response.getLocation();
635        }
636
637        // Get the content of the object after the first 6 bytes
638        try (final FcrepoResponse rangeResp = client.get(createdResourceUri)
639                .range(6L, null)
640                .perform()) {
641
642            final String content = IOUtils.toString(rangeResp.getBody(), "UTF-8");
643            assertEquals("Body did not contain correct range of original content", "world", content);
644            assertEquals(PARTIAL_CONTENT.getStatusCode(), rangeResp.getStatusCode());
645        }
646    }
647
648    @Test
649    public void testGetDisableRedirects() throws Exception {
650        final String filename = "example.html";
651        final String mimetype = "text/plain";
652
653        final URI externalURI = URI.create("http://example.com/");
654        final URI resourceLocation;
655
656        try (final FcrepoResponse response = client.post(new URI(SERVER_ADDRESS))
657                .externalContent(externalURI, mimetype, ExternalContentHandling.REDIRECT)
658                .filename(filename)
659                .perform()
660                ) {
661                    resourceLocation = response.getLocation();
662        }
663
664                try (final FcrepoResponse getResponse = client.get(resourceLocation)
665                .disableRedirects()
666                .perform();
667                ) {
668            assertEquals("Didn't get a REDIRECT response!",
669                    TEMPORARY_REDIRECT.getStatusCode(), getResponse.getStatusCode());
670            assertEquals(mimetype, getResponse.getContentType());
671
672            final Map<String, String> contentDisp = getResponse.getContentDisposition();
673            assertEquals(filename, contentDisp.get(CONTENT_DISPOSITION_FILENAME));
674
675            assertEquals(externalURI, getResponse.getLocation());
676        }
677    }
678
679    @Test
680    public void testGetWantDigest() throws Exception {
681        // Creating a binary for retrieval
682        final String mimetype = "text/plain";
683        final String bodyContent = "Hello world";
684
685        final URI createdResourceUri;
686        try (final FcrepoResponse response = client.post(new URI(SERVER_ADDRESS))
687                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
688                .perform()) {
689            createdResourceUri = response.getLocation();
690        }
691
692        // Request md5 digest with caching disabled
693        try (final FcrepoResponse getResp = client.get(createdResourceUri)
694                .wantDigest("md5")
695                .noCache()
696                .perform()) {
697            assertEquals(OK.getStatusCode(), getResp.getStatusCode());
698
699            final String digest = getResp.getHeaderValue(DIGEST);
700            assertTrue("Did not contain md5", digest.contains("md5=3e25960a79dbc69b674cd4ec67a72c62"));
701        }
702    }
703
704    @Test
705    public void testHead() throws Exception {
706        try (final FcrepoResponse response = create();
707                final FcrepoResponse headResp = client.head(url).perform()) {
708
709            assertEquals(OK.getStatusCode(), headResp.getStatusCode());
710            assertEquals(response.getHeaderValue(ETAG), headResp.getHeaderValue(ETAG));
711            assertNotNull(headResp.getHeaderValue("Allow"));
712        }
713    }
714
715    @Test
716    public void testHeadWantDigest() throws Exception {
717        // Creating a binary for retrieval
718        final String mimetype = "text/plain";
719        final String bodyContent = "Hello world";
720        final URI createdResourceUri;
721        try (final FcrepoResponse response = client.post(new URI(SERVER_ADDRESS))
722                .body(new ByteArrayInputStream(bodyContent.getBytes()), mimetype)
723                .perform()) {
724
725            createdResourceUri = response.getLocation();
726        }
727
728        final Map<String, Double> qualityMap = new HashMap<>();
729        qualityMap.put("md5", 1.0);
730        qualityMap.put("sha", 1.0);
731        qualityMap.put("sha-256", 0.4);
732
733        final String wantDigest = HeaderHelpers.formatQualityValues(qualityMap);
734        // Request multiple digests
735        try (final FcrepoResponse getResp = client.head(createdResourceUri)
736                .wantDigest(wantDigest)
737                .perform()) {
738            assertEquals(OK.getStatusCode(), getResp.getStatusCode());
739
740            final String digest = getResp.getHeaderValue(DIGEST);
741            assertTrue("Did not contain md5", digest.contains("md5=3e25960a79dbc69b674cd4ec67a72c62"));
742            assertTrue("Did not contain sha1", digest.contains("sha=7b502c3a1f48c8609ae212cdfb639dee39673f5e"));
743            assertTrue("Did not contain sha256", digest
744                    .contains("sha-256=64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c"));
745        }
746    }
747
748    @Test
749    public void testOptions() throws Exception {
750        try (final FcrepoResponse response = create()) {
751        }
752
753        try (final FcrepoResponse headResp = client.options(url).perform()) {
754
755            assertEquals(OK.getStatusCode(), headResp.getStatusCode());
756            assertNotNull(headResp.getHeaderValue("Allow"));
757            assertNotNull(headResp.getHeaderValue("Accept-Post"));
758            assertNotNull(headResp.getHeaderValue("Accept-Patch"));
759        }
760    }
761
762    @Test
763    public void testStateTokens() throws Exception {
764        try (final FcrepoResponse response = create()) {
765        }
766
767        final String stateToken;
768        try (final FcrepoResponse getResp = client.get(url).perform()) {
769            stateToken = getResp.getHeaderValue(STATE_TOKEN);
770        }
771
772        // Attempt to update triples with an incorrect state token
773        final InputStream body = new ByteArrayInputStream(sparqlUpdate.getBytes());
774        try (final FcrepoResponse badTokenResp = client.patch(url)
775                .body(body)
776                .ifStateToken("bad_state_token")
777                .perform()) {
778            assertEquals(PRECONDITION_FAILED.getStatusCode(), badTokenResp.getStatusCode());
779        }
780
781        // Update triples with the correct state token
782        body.reset();
783        try (final FcrepoResponse goodTokenResp = client.patch(url)
784                .body(body)
785                .ifStateToken(stateToken)
786                .perform()) {
787            assertEquals(NO_CONTENT.getStatusCode(), goodTokenResp.getStatusCode());
788        }
789    }
790
791    private FcrepoResponse create() throws FcrepoOperationFailedException {
792        return client.put(url).perform();
793    }
794
795    private String getTurtle(final URI url) throws Exception {
796        try (final FcrepoResponse getResponse = client.get(url)
797                .accept("text/turtle")
798                .preferRepresentation(Arrays.asList(URI.create("http://www.w3.org/ns/ldp#PreferMinimalContainer")),
799                        Arrays.asList(URI.create("http://fedora.info/definitions/fcrepo#ServerManaged"))).perform()) {
800            return IOUtils.toString(getResponse.getBody(), "UTF-8");
801        }
802    }
803}