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.http.commons.exceptionhandlers;
007
008import org.fcrepo.http.commons.api.rdf.HttpIdentifierConverter;
009import org.fcrepo.kernel.api.exception.TombstoneException;
010import org.fcrepo.kernel.api.identifiers.FedoraId;
011import org.fcrepo.kernel.api.models.FedoraResource;
012import org.junit.Before;
013import org.junit.Test;
014import org.mockito.Mock;
015
016import javax.ws.rs.core.Link;
017import javax.ws.rs.core.Response;
018import javax.ws.rs.core.UriBuilder;
019import javax.ws.rs.ext.ExceptionMapper;
020import java.net.URI;
021import java.time.Instant;
022import java.util.Arrays;
023import java.util.List;
024import java.util.stream.Collectors;
025
026import static java.time.ZoneOffset.UTC;
027import static java.time.format.DateTimeFormatter.ISO_INSTANT;
028import static javax.ws.rs.core.HttpHeaders.LINK;
029import static javax.ws.rs.core.Response.Status.GONE;
030import static org.fcrepo.kernel.api.FedoraTypes.FCR_VERSIONS;
031import static org.junit.Assert.assertEquals;
032import static org.junit.Assert.assertNull;
033import static org.junit.Assert.fail;
034import static org.mockito.Mockito.when;
035import static org.mockito.MockitoAnnotations.initMocks;
036
037/**
038 * @author cabeer
039 */
040public class TombstoneExceptionMapperTest {
041
042    @Mock
043    private FedoraResource mockResource;
044
045    private final FedoraId fedoraId = FedoraId.create("/some:uri");
046
047    private final Instant deleteTime = Instant.now();
048
049    private ExceptionMapper<TombstoneException> testObj;
050
051    private static final String SERVER_URI = "http://localhost:8080/rest(.*)";
052
053    private final HttpIdentifierConverter idConverter = new HttpIdentifierConverter(UriBuilder.fromUri(SERVER_URI));
054
055    @Before
056    public void setUp() {
057        initMocks(this);
058        when(mockResource.getFedoraId()).thenReturn(fedoraId);
059        when(mockResource.getLastModifiedDate()).thenReturn(deleteTime);
060        testObj = new TombstoneExceptionMapper();
061    }
062
063    @Test
064    public void testUrilessException() {
065        final Response response = testObj.toResponse(new TombstoneException(mockResource));
066        assertEquals(GONE.getStatusCode(), response.getStatus());
067        assertTombstone(response, fedoraId.getFullIdPath(), null);
068    }
069
070    @Test
071    public void testExceptionWithUri() {
072        final String tombstone = idConverter.toExternalId(fedoraId.asTombstone().getFullId());
073        final String timemap = idConverter.toExternalId(fedoraId.resolve(FCR_VERSIONS).getFullId());
074        final Response response = testObj.toResponse(new TombstoneException(mockResource, tombstone, timemap));
075        assertEquals(GONE.getStatusCode(), response.getStatus());
076        assertTombstone(response, fedoraId.getFullIdPath(), tombstone);
077        final List<Link> links = Arrays.stream(response.getHeaderString(LINK).split(",")).map(Link::valueOf)
078                .collect(Collectors.toList());
079        assertLinkHeaderExists(links, timemap, "timemap");
080    }
081
082    private void assertTombstone(final Response response, final String tombstoneAt, final String tombstoneUri) {
083        if (tombstoneUri == null) {
084            assertNull(response.getHeaderString(LINK));
085        } else {
086            final List<Link> links = Arrays.stream(response.getHeaderString(LINK).split(",")).map(Link::valueOf)
087                    .collect(Collectors.toList());
088
089            assertLinkHeaderExists(links, tombstoneUri, "hasTombstone");
090        }
091        final String expectedString = "Discovered tombstone resource at " + tombstoneAt + ", departed at: " +
092                ISO_INSTANT.withZone(UTC).format(deleteTime);
093        assertEquals(expectedString, response.getEntity().toString());
094    }
095
096    private void assertLinkHeaderExists(final List<Link> links, final String uri, final String rel) {
097        final URI uriUri = URI.create(uri);
098        if (links.stream().noneMatch(l -> l.getUri().equals(uriUri) && l.getRel().equals(rel))) {
099            fail(String.format("Did not find expected Link header with uri (%s) and rel (%s)", uri, rel));
100        }
101    }
102}