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.integration;
007
008import static java.lang.Integer.MAX_VALUE;
009import static java.util.UUID.randomUUID;
010import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
011import static javax.ws.rs.core.HttpHeaders.LINK;
012import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
013import static org.apache.http.HttpStatus.SC_CONFLICT;
014import static org.apache.http.HttpStatus.SC_CREATED;
015import static org.apache.http.HttpStatus.SC_NO_CONTENT;
016import static org.apache.http.HttpStatus.SC_OK;
017import static org.fcrepo.kernel.api.RdfLexicon.CONSTRAINED_BY;
018import static org.junit.Assert.assertEquals;
019
020import java.io.IOException;
021import java.net.URI;
022import java.util.Objects;
023
024import com.google.common.base.Strings;
025import org.apache.http.HttpResponse;
026import org.apache.http.auth.AuthScope;
027import org.apache.http.client.CredentialsProvider;
028import org.apache.http.client.HttpClient;
029import org.apache.http.client.methods.HttpGet;
030import org.apache.http.client.methods.HttpPost;
031import org.apache.http.client.methods.HttpPut;
032import org.apache.http.client.methods.HttpUriRequest;
033import org.apache.http.entity.StringEntity;
034import org.apache.http.impl.client.HttpClientBuilder;
035import org.apache.http.util.EntityUtils;
036import org.junit.Before;
037import org.junit.Test;
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
042
043import javax.ws.rs.core.Link;
044
045/**
046 * <p>SanityCheckIT class.</p>
047 *
048 * @author fasseg
049 */
050public class SanityCheckIT {
051
052    /**
053     * The server port of the application, set as system property by
054     * maven-failsafe-plugin.
055     */
056    private static final String SERVER_PORT = Objects.requireNonNullElse(
057            Strings.emptyToNull(System.getProperty("fcrepo.dynamic.test.port")), "8080");
058
059    /**
060    * The context path of the application (including the leading "/"), set as
061    * system property by maven-failsafe-plugin.
062    */
063    private static final String CONTEXT_PATH = System.getProperty("fcrepo.test.context.path");
064
065    private Logger logger;
066
067    @Before
068    public void setLogger() {
069        logger = LoggerFactory.getLogger(this.getClass());
070    }
071
072    private static final String HOSTNAME = "localhost";
073
074    private static final String serverAddress = "http://" + HOSTNAME + ":" +
075            SERVER_PORT + CONTEXT_PATH + (CONTEXT_PATH.endsWith("/") ? "" : "/") + "rest";
076
077    private static final HttpClient client;
078
079    static {
080        final CredentialsProvider creds = new DefaultCredentialsProvider();
081        creds.setCredentials(AuthScope.ANY, AbstractResourceIT.FEDORA_ADMIN_CREDENTIALS);
082        client =
083                HttpClientBuilder.create().setMaxConnPerRoute(MAX_VALUE)
084                        .setMaxConnTotal(MAX_VALUE).setDefaultCredentialsProvider(creds).build();
085    }
086
087    @Test
088    public void doASanityCheck() throws IOException {
089        executeAndVerify(new HttpGet(serverAddress), SC_OK);
090    }
091
092    private HttpResponse executeAndVerify(final HttpUriRequest method, final int statusCode) throws IOException {
093        logger.debug("Executing: " + method.getMethod() + " to " + method.getURI());
094        final HttpResponse response = client.execute(method);
095
096        assertEquals(statusCode, response.getStatusLine().getStatusCode());
097        return response;
098    }
099
100    @Test
101    public void testConstraintLink() throws Exception {
102        // Create a resource
103        final HttpPost post = new HttpPost(serverAddress);
104        final HttpResponse postResponse = executeAndVerify(post, SC_CREATED);
105
106        final String location = postResponse.getFirstHeader("Location").getValue();
107        logger.debug("new resource location: {}", location);
108
109        // GET the new resource
110        final HttpGet get = new HttpGet(location);
111        final HttpResponse getResponse = executeAndVerify(get, SC_OK);
112
113        final String body = EntityUtils.toString(getResponse.getEntity());
114        logger.debug("new resource body: {}", body);
115
116        // PUT the exact body back to the new resource... successfully
117        final HttpPut put = new HttpPut(location);
118        put.setEntity(new StringEntity(body));
119        put.setHeader(CONTENT_TYPE, "text/turtle");
120        put.setHeader("Prefer", "handling=lenient");
121        executeAndVerify(put, SC_NO_CONTENT);
122
123        // Update a server managed property in the resource body... not allowed!
124        final String body2 = body.replaceFirst("fedora:created \"2\\d\\d\\d", "fedora:created \"1999");
125
126        // PUT the erroneous body back to the new resource... unsuccessfully
127        final HttpPut put2 = new HttpPut(location);
128        put2.setEntity(new StringEntity(body2));
129        put2.setHeader(CONTENT_TYPE, "text/turtle");
130        final HttpResponse put2Response = executeAndVerify(put2, SC_CONFLICT);
131
132        // Verify the returned LINK header
133        final String linkHeader = put2Response.getFirstHeader(LINK).getValue();
134        final Link link = Link.valueOf(linkHeader);
135        logger.debug("constraint linkHeader: {}", linkHeader);
136
137        // Verify the LINK rel
138        final String linkRel = link.getRel();
139        assertEquals(CONSTRAINED_BY.getURI(), linkRel);
140
141        // Verify the LINK URI by fetching it
142        final URI linkURI = link.getUri();
143        logger.debug("constraint linkURI: {}", linkURI);
144
145        final HttpGet getLink = new HttpGet(linkURI);
146        executeAndVerify(getLink, SC_OK);
147    }
148
149    @Test
150    public void testCannotCreateResourceConstraintLink() throws Exception {
151        // Create a ldp:Resource resource, this should fail
152        final HttpPost post = new HttpPost(serverAddress);
153        post.setHeader(LINK,"<http://www.w3.org/ns/ldp#Resource>; rel=\"type\"");
154        final HttpResponse postResponse = executeAndVerify(post, SC_BAD_REQUEST);
155
156        // Verify the returned LINK header
157        final String linkHeader = postResponse.getFirstHeader(LINK).getValue();
158        final Link link = Link.valueOf(linkHeader);
159        logger.debug("constraint linkHeader: {}", linkHeader);
160
161        // Verify the LINK rel
162        final String linkRel = link.getRel();
163        assertEquals(CONSTRAINED_BY.getURI(), linkRel);
164
165        // Verify the LINK URI by fetching it
166        final URI linkURI = link.getUri();
167        logger.debug("constraint linkURI: {}", linkURI);
168
169        final HttpGet getLink = new HttpGet(linkURI);
170        executeAndVerify(getLink, SC_OK);
171    }
172
173    @Test
174    public void testUnicodeCharsAllowed() throws Exception {
175        final var id = "ÅŤéșţ!";
176        final var url = serverAddress + "/" + id;
177
178        final HttpPut put = new HttpPut(url);
179        put.setEntity(new StringEntity("testing"));
180        put.setHeader(CONTENT_TYPE, "text/plain");
181        executeAndVerify(put, SC_CREATED);
182
183        executeAndVerify(new HttpGet(url), SC_OK);
184    }
185
186    @Test
187    public void testEncodedSlash() throws IOException {
188        final String targetResource = serverAddress + "/rest/" + randomUUID() + "/admin_set%2Fdefault";
189        final var putTest = new HttpPut(targetResource);
190        executeAndVerify(putTest, SC_CREATED);
191    }
192}