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