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