/*
* Licensed to DuraSpace under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* DuraSpace licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.http.commons.test.util;
import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
import static org.apache.http.entity.ContentType.parse;
import static java.net.URI.create;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.ws.rs.core.UriBuilder.fromUri;
import static org.fcrepo.kernel.api.utils.ContentDigest.DIGEST_ALGORITHM.SHA1;
import static org.junit.Assert.assertNotNull;
import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
import static org.fcrepo.kernel.api.utils.ContentDigest.asURI;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import javax.jcr.LoginException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
import javax.servlet.ServletContext;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.apache.jena.riot.Lang;
import org.fcrepo.http.commons.AbstractResource;
import org.fcrepo.kernel.api.models.NonRdfSourceDescription;
import org.fcrepo.kernel.api.models.FedoraBinary;
import org.fcrepo.kernel.api.services.functions.HierarchicalIdentifierSupplier;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.modeshape.jcr.api.NamespaceRegistry;
import org.modeshape.jcr.api.Repository;
import org.modeshape.jcr.api.query.QueryManager;
import org.apache.jena.rdf.model.Model;
/**
* <p>Abstract TestHelpers class.</p>
*
* @author awoods
*/
public abstract class TestHelpers {
public static String MOCK_PREFIX = "mockPrefix";
public static String MOCK_URI_STRING = "mock.namespace.org";
public static ServletContext getServletContextImpl() {
final ServletContext sc = mock(ServletContext.class);
when(sc.getContextPath()).thenReturn("/fcrepo");
return sc;
}
public static UriInfo getUriInfoImpl() {
// UriInfo ui = mock(UriInfo.class,withSettings().verboseLogging());
final UriInfo ui = mock(UriInfo.class);
final Answer<UriBuilder> answer = new Answer<UriBuilder>() {
@Override
public UriBuilder answer(final InvocationOnMock invocation) {
return fromUri("http://localhost/fcrepo");
}
};
when(ui.getRequestUri()).thenReturn(
URI.create("http://localhost/fcrepo"));
when(ui.getBaseUri()).thenReturn(create("http://localhost/fcrepo"));
when(ui.getBaseUriBuilder()).thenAnswer(answer);
when(ui.getAbsolutePathBuilder()).thenAnswer(answer);
return ui;
}
public static Session getQuerySessionMock() {
final Session mock = mock(Session.class);
final Workspace mockWS = mock(Workspace.class);
final QueryManager mockQM = mock(QueryManager.class);
try {
final Query mockQ = getQueryMock();
when(mockQM.createQuery(anyString(), anyString()))
.thenReturn((org.modeshape.jcr.api.query.Query) mockQ);
when(mockWS.getQueryManager()).thenReturn(mockQM);
} catch (final RepositoryException e) {
e.printStackTrace();
}
when(mock.getWorkspace()).thenReturn(mockWS);
final ValueFactory mockVF = mock(ValueFactory.class);
try {
when(mock.getValueFactory()).thenReturn(mockVF);
} catch (final RepositoryException e) {
e.printStackTrace();
}
return mock;
}
@SuppressWarnings("unchecked")
public static Query getQueryMock() {
final Query mockQ = mock(Query.class);
final QueryResult mockResults = mock(QueryResult.class);
final NodeIterator mockNodes = mock(NodeIterator.class);
when(mockNodes.getSize()).thenReturn(2L);
when(mockNodes.hasNext()).thenReturn(true, true, false);
final Node node1 = mock(Node.class);
final Node node2 = mock(Node.class);
try {
when(node1.getName()).thenReturn("node1");
when(node2.getName()).thenReturn("node2");
} catch (final RepositoryException e) {
e.printStackTrace();
}
when(mockNodes.nextNode()).thenReturn(node1, node2).thenThrow(
IndexOutOfBoundsException.class);
try {
when(mockResults.getNodes()).thenReturn(mockNodes);
when(mockQ.execute()).thenReturn(mockResults);
} catch (final RepositoryException e) {
e.printStackTrace();
}
return mockQ;
}
@SuppressWarnings("unchecked")
public static Session getSessionMock() throws RepositoryException {
final String[] mockPrefixes = {MOCK_PREFIX};
final Session mockSession = mock(Session.class);
final Workspace mockWorkspace = mock(Workspace.class);
final NamespaceRegistry mockNameReg = mock(NamespaceRegistry.class);
final NodeTypeManager mockNTM = mock(NodeTypeManager.class);
final NodeTypeIterator mockNTI = mock(NodeTypeIterator.class);
final NodeType mockNodeType = mock(NodeType.class);
when(mockSession.getWorkspace()).thenReturn(mockWorkspace);
when(mockWorkspace.getNamespaceRegistry()).thenReturn(mockNameReg);
when(mockNameReg.getPrefixes()).thenReturn(mockPrefixes);
when(mockNameReg.getURI(MOCK_PREFIX)).thenReturn(MOCK_URI_STRING);
when(mockWorkspace.getNodeTypeManager()).thenReturn(mockNTM);
when(mockNodeType.getName()).thenReturn("mockName");
when(mockNodeType.toString()).thenReturn("mockString");
when(mockNTM.getAllNodeTypes()).thenReturn(mockNTI);
when(mockNTI.hasNext()).thenReturn(true, false);
when(mockNTI.nextNodeType()).thenReturn(mockNodeType).thenThrow(
ArrayIndexOutOfBoundsException.class);
return mockSession;
}
public static Collection<String>
parseChildren(final HttpEntity entity) throws IOException {
final String body = EntityUtils.toString(entity);
System.err.println(body);
final String[] names =
body.replace("[", "").replace("]", "").trim().split(",\\s?");
return Arrays.asList(names);
}
public static Session mockSession(final AbstractResource testObj) {
final SecurityContext mockSecurityContext = mock(SecurityContext.class);
final Principal mockPrincipal = mock(Principal.class);
final String mockUser = "testuser";
final Session mockSession = mock(Session.class);
when(mockSession.getUserID()).thenReturn(mockUser);
when(mockSecurityContext.getUserPrincipal()).thenReturn(mockPrincipal);
when(mockPrincipal.getName()).thenReturn(mockUser);
final Workspace mockWorkspace = mock(Workspace.class);
when(mockSession.getWorkspace()).thenReturn(mockWorkspace);
when(mockWorkspace.getName()).thenReturn("default");
setField(testObj, "uriInfo", getUriInfoImpl());
setField(testObj, "pidMinter", new PathMinterImpl());
return mockSession;
}
public static Repository mockRepository() throws LoginException,
RepositoryException {
final Repository mockRepo = mock(Repository.class);
when(mockRepo.login()).thenReturn(
mock(org.modeshape.jcr.api.Session.class, Mockito.withSettings().extraInterfaces(Session.class)));
return mockRepo;
}
public static NonRdfSourceDescription mockDatastream(final String pid,
final String dsId, final String content) {
final FedoraBinary mockBinary = mockBinary(pid, dsId, content);
final NonRdfSourceDescription mockDs = mock(NonRdfSourceDescription.class);
when(mockDs.getDescribedResource()).thenReturn(mockBinary);
when(mockDs.getDescribedResource().getDescription()).thenReturn(mockDs);
when(mockDs.getPath()).thenReturn("/" + pid + "/" + dsId);
when(mockDs.getCreatedDate()).thenReturn(Instant.now());
when(mockDs.getLastModifiedDate()).thenReturn(Instant.now());
if (content != null) {
final MessageDigest md;
try {
md = MessageDigest.getInstance(SHA1.algorithm);
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
final byte[] digest = md.digest(content.getBytes());
final URI cd = asURI(SHA1.algorithm, digest);
when(mockDs.getEtagValue()).thenReturn(cd.toString());
}
return mockDs;
}
public static FedoraBinary mockBinary(final String pid,
final String dsId, final String content) {
final FedoraBinary mockBinary = mock(FedoraBinary.class);
when(mockBinary.getPath()).thenReturn("/" + pid + "/" + dsId + "/jcr:content");
when(mockBinary.getMimeType()).thenReturn("application/octet-stream");
when(mockBinary.getCreatedDate()).thenReturn(Instant.now());
when(mockBinary.getLastModifiedDate()).thenReturn(Instant.now());
if (content != null) {
final MessageDigest md;
try {
md = MessageDigest.getInstance(SHA1.algorithm);
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
final byte[] digest = md.digest(content.getBytes());
final URI cd = asURI(SHA1.algorithm, digest);
when(mockBinary.getContent()).thenReturn(
IOUtils.toInputStream(content, UTF_8));
when(mockBinary.getContentDigest()).thenReturn(cd);
when(mockBinary.getEtagValue()).thenReturn(cd.toString());
}
return mockBinary;
}
private static String getRdfSerialization(final HttpEntity entity) {
final Lang lang = contentTypeToLang(parse(entity.getContentType().getValue()).getMimeType());
assertNotNull("Entity is not an RDF serialization", lang);
return lang.getName();
}
public static CloseableDataset parseTriples(final HttpEntity entity) throws IOException {
return parseTriples(entity.getContent(), getRdfSerialization(entity));
}
public static CloseableDataset parseTriples(final InputStream content) {
return parseTriples(content, "N3");
}
public static CloseableDataset parseTriples(final InputStream content, final String contentType) {
final Model model = createDefaultModel();
model.read(content, "", contentType);
return new CloseableDataset(model);
}
/**
* Set a field via reflection
*
* @param parent the owner object of the field
* @param name the name of the field
* @param obj the value to set
*/
public static void setField(final Object parent, final String name, final Object obj) {
/* check the parent class too if the field could not be found */
try {
final Field f = findField(parent.getClass(), name);
f.setAccessible(true);
f.set(parent, obj);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
private static Field findField(final Class<?> clazz, final String name)
throws NoSuchFieldException {
for (final Field f : clazz.getDeclaredFields()) {
if (f.getName().equals(name)) {
return f;
}
}
if (clazz.getSuperclass() == null) {
throw new NoSuchFieldException("Field " + name
+ " could not be found");
}
return findField(clazz.getSuperclass(), name);
}
private static class PathMinterImpl implements HierarchicalIdentifierSupplier { }
}