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 java.lang.Integer.parseInt; 022import static javax.ws.rs.core.Response.Status.CREATED; 023import static javax.ws.rs.core.Response.Status.NO_CONTENT; 024import static javax.ws.rs.core.Response.Status.OK; 025import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; 026import static javax.ws.rs.core.HttpHeaders.ACCEPT; 027 028import static org.fcrepo.http.commons.test.util.TestHelpers.parseTriples; 029import static org.junit.Assert.assertEquals; 030import static org.slf4j.LoggerFactory.getLogger; 031 032import java.io.ByteArrayInputStream; 033import java.io.IOException; 034import java.io.UnsupportedEncodingException; 035import java.util.UUID; 036 037import org.apache.jena.query.Dataset; 038import org.apache.http.HttpHost; 039import org.apache.http.HttpResponse; 040import org.apache.http.auth.AuthScope; 041import org.apache.http.auth.UsernamePasswordCredentials; 042import org.apache.http.client.AuthCache; 043import org.apache.http.client.ClientProtocolException; 044import org.apache.http.client.CredentialsProvider; 045import org.apache.http.client.HttpClient; 046import org.apache.http.client.methods.CloseableHttpResponse; 047import org.apache.http.client.methods.HttpUriRequest; 048import org.apache.http.client.methods.HttpPost; 049import org.apache.http.client.methods.HttpPut; 050import org.apache.http.client.methods.HttpPatch; 051import org.apache.http.client.protocol.HttpClientContext; 052import org.apache.http.entity.BasicHttpEntity; 053import org.apache.http.entity.StringEntity; 054import org.apache.http.impl.auth.BasicScheme; 055 056import org.apache.http.impl.client.BasicAuthCache; 057import org.apache.http.impl.client.HttpClientBuilder; 058import org.apache.http.impl.client.BasicCredentialsProvider; 059import org.apache.http.impl.client.CloseableHttpClient; 060import org.apache.http.impl.client.HttpClients; 061 062import org.apache.http.util.EntityUtils; 063import org.junit.Before; 064import org.slf4j.Logger; 065 066/** 067 * Base class for ITs 068 * @author awoods 069 * @author escowles 070**/ 071public abstract class AbstractResourceIT { 072 073 protected Logger logger; 074 075 @Before 076 public void setLogger() { 077 logger = getLogger(this.getClass()); 078 } 079 080 protected static final int SERVER_PORT = parseInt(System.getProperty( 081 "fcrepo.dynamic.test.port", "8080")); 082 083 private static final String CONTEXT_PATH = System 084 .getProperty("fcrepo.test.context.path"); 085 086 protected static final String HOSTNAME = "localhost"; 087 088 protected static final String PROTOCOL = "http"; 089 090 protected static final String serverAddress = PROTOCOL + "://" + HOSTNAME + ":" + 091 SERVER_PORT + CONTEXT_PATH + "rest/"; 092 093 protected static HttpClient client = createClient(); 094 095 protected static HttpClient createClient() { 096 return HttpClientBuilder.create().setMaxConnPerRoute(MAX_VALUE) 097 .setMaxConnTotal(MAX_VALUE).build(); 098 } 099 100 protected static HttpPost postObjMethod(final String pid) { 101 return new HttpPost(serverAddress + pid); 102 } 103 104 protected static HttpPut putObjMethod(final String pid) { 105 return new HttpPut(serverAddress + pid); 106 } 107 108 protected static HttpPost postObjMethod(final String pid, final String query) { 109 if (query.equals("")) { 110 return new HttpPost(serverAddress + pid); 111 } 112 return new HttpPost(serverAddress + pid + "?" + query); 113 } 114 115 protected static HttpPost postDSMethod(final String pid, final String ds, 116 final String content) throws UnsupportedEncodingException { 117 final HttpPost post = 118 new HttpPost(serverAddress + pid + "/" + ds + 119 "/fcr:content"); 120 post.setEntity(new StringEntity(content)); 121 return post; 122 } 123 124 protected static HttpPut putDSMethod(final String pid, final String ds, 125 final String content) throws UnsupportedEncodingException { 126 final HttpPut put = 127 new HttpPut(serverAddress + pid + "/" + ds + 128 "/fcr:content"); 129 130 put.setEntity(new StringEntity(content)); 131 return put; 132 } 133 134 protected HttpResponse execute(final HttpUriRequest method) 135 throws ClientProtocolException, IOException { 136 logger.debug("Executing: " + method.getMethod() + " to " + 137 method.getURI()); 138 return client.execute(method); 139 } 140 141 // Executes requests with preemptive basic authentication 142 protected HttpResponse executeWithBasicAuth(final HttpUriRequest request, 143 final String username, 144 final String password) 145 throws IOException { 146 final HttpHost target = new HttpHost(HOSTNAME, SERVER_PORT, PROTOCOL); 147 final CredentialsProvider credsProvider = new BasicCredentialsProvider(); 148 credsProvider.setCredentials( 149 new AuthScope(target.getHostName(), target.getPort()), 150 new UsernamePasswordCredentials(username, password)); 151 try (final CloseableHttpClient httpclient = HttpClients.custom() 152 .setDefaultCredentialsProvider(credsProvider).build()) { 153 154 final AuthCache authCache = new BasicAuthCache(); 155 final BasicScheme basicAuth = new BasicScheme(); 156 authCache.put(target, basicAuth); 157 158 final HttpClientContext localContext = HttpClientContext.create(); 159 localContext.setAuthCache(authCache); 160 161 final CloseableHttpResponse response = httpclient.execute(request, localContext); 162 return response; 163 } 164 } 165 166 167 protected int getStatus(final HttpUriRequest method) 168 throws ClientProtocolException, IOException { 169 final HttpResponse response = execute(method); 170 final int result = response.getStatusLine().getStatusCode(); 171 if (!(result > 199) || !(result < 400)) { 172 logger.warn(EntityUtils.toString(response.getEntity())); 173 } 174 return result; 175 } 176 177 protected String getContentType(final HttpUriRequest method) 178 throws ClientProtocolException, IOException { 179 final HttpResponse response = execute(method); 180 final int result = response.getStatusLine().getStatusCode(); 181 assertEquals(OK.getStatusCode(), result); 182 return response.getFirstHeader(CONTENT_TYPE).getValue(); 183 } 184 185 protected Dataset getDataset(final HttpClient client, final HttpUriRequest method) throws IOException { 186 187 if (method.getFirstHeader(ACCEPT) == null) { 188 method.addHeader(ACCEPT, "application/n-triples"); 189 } else { 190 logger.debug("Retrieving RDF in mimeType: {}", method 191 .getFirstHeader(ACCEPT)); 192 } 193 194 final HttpResponse response = client.execute(method); 195 assertEquals(OK.getStatusCode(), response.getStatusLine() 196 .getStatusCode()); 197 final Dataset result = parseTriples(response.getEntity()); 198 logger.trace("Retrieved RDF: {}", result); 199 return result; 200 201 } 202 protected Dataset getDataset(final HttpResponse response) throws IOException { 203 assertEquals(OK.getStatusCode(), response.getStatusLine().getStatusCode()); 204 final Dataset result = parseTriples(response.getEntity()); 205 logger.trace("Retrieved RDF: {}", result); 206 return result; 207 } 208 209 protected Dataset getDataset(final HttpUriRequest method) throws IOException { 210 return getDataset(client, method); 211 } 212 213 protected HttpResponse createObject(final String pid) throws IOException { 214 final HttpPost httpPost = postObjMethod("/"); 215 if (pid.length() > 0) { 216 httpPost.addHeader("Slug", pid); 217 } 218 final HttpResponse response = client.execute(httpPost); 219 assertEquals(CREATED.getStatusCode(), response.getStatusLine().getStatusCode()); 220 return response; 221 } 222 223 protected HttpResponse createDatastream(final String pid, final String dsid, final String content) 224 throws IOException { 225 logger.trace( 226 "Attempting to create datastream for object: {} at datastream ID: {}", 227 pid, dsid); 228 final HttpResponse response = 229 client.execute(postDSMethod(pid, dsid, content)); 230 assertEquals(CREATED.getStatusCode(), response.getStatusLine().getStatusCode()); 231 return response; 232 } 233 234 protected HttpResponse setProperty(final String pid, 235 final String propertyUri, 236 final String value) throws IOException { 237 return setProperty(pid, null, propertyUri, value); 238 } 239 240 protected HttpResponse setProperty(final String pid, final String txId, 241 final String propertyUri, 242 final String value) throws IOException { 243 final HttpPatch postProp = new HttpPatch(serverAddress 244 + (txId != null ? txId + "/" : "") + pid); 245 postProp.setHeader(CONTENT_TYPE, "application/sparql-update"); 246 final String updateString = 247 "INSERT { <" 248 + serverAddress + pid 249 + "> <" + propertyUri + "> \"" + value + "\" } WHERE { }"; 250 postProp.setEntity(new StringEntity(updateString)); 251 final HttpResponse dcResp = execute(postProp); 252 assertEquals(dcResp.getStatusLine().toString(), 253 204, dcResp.getStatusLine().getStatusCode()); 254 postProp.releaseConnection(); 255 return dcResp; 256 } 257 258 protected static void addMixin(final String pid, final String mixinUrl) throws IOException { 259 final HttpPatch updateObjectGraphMethod = 260 new HttpPatch(serverAddress + pid); 261 updateObjectGraphMethod.addHeader(CONTENT_TYPE, 262 "application/sparql-update"); 263 final BasicHttpEntity e = new BasicHttpEntity(); 264 265 e.setContent(new ByteArrayInputStream( 266 ("INSERT DATA { <> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <" + mixinUrl + "> . } ") 267 .getBytes())); 268 updateObjectGraphMethod.setEntity(e); 269 final HttpResponse response = client.execute(updateObjectGraphMethod); 270 assertEquals(NO_CONTENT.getStatusCode(), response.getStatusLine() 271 .getStatusCode()); 272 } 273 274 /** 275 * Gets a random (but valid) pid for use in testing. This pid 276 * is guaranteed to be unique within runs of this application. 277 * 278 * @return a random UUID 279 */ 280 protected static String getRandomUniquePid() { 281 return UUID.randomUUID().toString(); 282 } 283 284 /** 285 * Gets a random (but valid) property name for use in testing. 286 * 287 * @return a random property name 288 */ 289 protected static String getRandomPropertyName() { 290 return UUID.randomUUID().toString(); 291 } 292 293 /** 294 * Gets a random (but valid) property value for use in testing. 295 * 296 * @return a random property value 297 */ 298 protected static String getRandomPropertyValue() { 299 return UUID.randomUUID().toString(); 300 } 301 302 303}