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.http.commons.test.util; 019 020import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel; 021import static org.apache.http.entity.ContentType.parse; 022import static java.net.URI.create; 023import static java.nio.charset.StandardCharsets.UTF_8; 024import static javax.ws.rs.core.UriBuilder.fromUri; 025import static org.fcrepo.kernel.api.utils.ContentDigest.DIGEST_ALGORITHM.SHA1; 026import static org.junit.Assert.assertNotNull; 027import static org.apache.jena.riot.RDFLanguages.contentTypeToLang; 028import static org.fcrepo.kernel.api.utils.ContentDigest.asURI; 029import static org.mockito.Matchers.anyString; 030import static org.mockito.Mockito.mock; 031import static org.mockito.Mockito.when; 032 033import java.io.IOException; 034import java.io.InputStream; 035import java.lang.reflect.Field; 036import java.net.URI; 037import java.security.MessageDigest; 038import java.security.NoSuchAlgorithmException; 039import java.security.Principal; 040import java.time.Instant; 041import java.util.Arrays; 042import java.util.Collection; 043 044import javax.jcr.LoginException; 045import javax.jcr.Node; 046import javax.jcr.NodeIterator; 047import javax.jcr.RepositoryException; 048import javax.jcr.Session; 049import javax.jcr.ValueFactory; 050import javax.jcr.Workspace; 051import javax.jcr.nodetype.NodeType; 052import javax.jcr.nodetype.NodeTypeIterator; 053import javax.jcr.nodetype.NodeTypeManager; 054import javax.jcr.query.Query; 055import javax.jcr.query.QueryResult; 056import javax.ws.rs.core.SecurityContext; 057import javax.ws.rs.core.UriBuilder; 058import javax.ws.rs.core.UriInfo; 059 060import org.apache.commons.io.IOUtils; 061import org.apache.http.HttpEntity; 062import org.apache.http.util.EntityUtils; 063import org.apache.jena.riot.Lang; 064 065import org.fcrepo.http.commons.AbstractResource; 066import org.fcrepo.kernel.api.models.NonRdfSourceDescription; 067import org.fcrepo.kernel.api.models.FedoraBinary; 068import org.fcrepo.kernel.api.services.functions.HierarchicalIdentifierSupplier; 069 070import org.mockito.Mockito; 071import org.mockito.invocation.InvocationOnMock; 072import org.mockito.stubbing.Answer; 073import org.modeshape.jcr.api.NamespaceRegistry; 074import org.modeshape.jcr.api.Repository; 075import org.modeshape.jcr.api.query.QueryManager; 076 077import org.apache.jena.rdf.model.Model; 078 079/** 080 * <p>Abstract TestHelpers class.</p> 081 * 082 * @author awoods 083 */ 084public abstract class TestHelpers { 085 086 public static String MOCK_PREFIX = "mockPrefix"; 087 088 public static String MOCK_URI_STRING = "mock.namespace.org"; 089 090 public static UriInfo getUriInfoImpl() { 091 // UriInfo ui = mock(UriInfo.class,withSettings().verboseLogging()); 092 final UriInfo ui = mock(UriInfo.class); 093 094 final Answer<UriBuilder> answer = new Answer<UriBuilder>() { 095 096 @Override 097 public UriBuilder answer(final InvocationOnMock invocation) { 098 return fromUri("http://localhost/fcrepo"); 099 } 100 }; 101 102 when(ui.getRequestUri()).thenReturn( 103 URI.create("http://localhost/fcrepo")); 104 when(ui.getBaseUri()).thenReturn(create("http://localhost/fcrepo")); 105 when(ui.getBaseUriBuilder()).thenAnswer(answer); 106 when(ui.getAbsolutePathBuilder()).thenAnswer(answer); 107 108 return ui; 109 } 110 111 public static Session getQuerySessionMock() { 112 final Session mock = mock(Session.class); 113 final Workspace mockWS = mock(Workspace.class); 114 final QueryManager mockQM = mock(QueryManager.class); 115 try { 116 final Query mockQ = getQueryMock(); 117 when(mockQM.createQuery(anyString(), anyString())) 118 .thenReturn((org.modeshape.jcr.api.query.Query) mockQ); 119 when(mockWS.getQueryManager()).thenReturn(mockQM); 120 } catch (final RepositoryException e) { 121 e.printStackTrace(); 122 } 123 when(mock.getWorkspace()).thenReturn(mockWS); 124 final ValueFactory mockVF = mock(ValueFactory.class); 125 try { 126 when(mock.getValueFactory()).thenReturn(mockVF); 127 } catch (final RepositoryException e) { 128 e.printStackTrace(); 129 } 130 return mock; 131 } 132 133 @SuppressWarnings("unchecked") 134 public static Query getQueryMock() { 135 final Query mockQ = mock(Query.class); 136 final QueryResult mockResults = mock(QueryResult.class); 137 final NodeIterator mockNodes = mock(NodeIterator.class); 138 when(mockNodes.getSize()).thenReturn(2L); 139 when(mockNodes.hasNext()).thenReturn(true, true, false); 140 final Node node1 = mock(Node.class); 141 final Node node2 = mock(Node.class); 142 try { 143 when(node1.getName()).thenReturn("node1"); 144 when(node2.getName()).thenReturn("node2"); 145 } catch (final RepositoryException e) { 146 e.printStackTrace(); 147 } 148 when(mockNodes.nextNode()).thenReturn(node1, node2).thenThrow( 149 IndexOutOfBoundsException.class); 150 try { 151 when(mockResults.getNodes()).thenReturn(mockNodes); 152 when(mockQ.execute()).thenReturn(mockResults); 153 } catch (final RepositoryException e) { 154 e.printStackTrace(); 155 } 156 return mockQ; 157 } 158 159 @SuppressWarnings("unchecked") 160 public static Session getSessionMock() throws RepositoryException { 161 final String[] mockPrefixes = {MOCK_PREFIX}; 162 final Session mockSession = mock(Session.class); 163 final Workspace mockWorkspace = mock(Workspace.class); 164 final NamespaceRegistry mockNameReg = mock(NamespaceRegistry.class); 165 final NodeTypeManager mockNTM = mock(NodeTypeManager.class); 166 final NodeTypeIterator mockNTI = mock(NodeTypeIterator.class); 167 final NodeType mockNodeType = mock(NodeType.class); 168 when(mockSession.getWorkspace()).thenReturn(mockWorkspace); 169 when(mockWorkspace.getNamespaceRegistry()).thenReturn(mockNameReg); 170 when(mockNameReg.getPrefixes()).thenReturn(mockPrefixes); 171 when(mockNameReg.getURI(MOCK_PREFIX)).thenReturn(MOCK_URI_STRING); 172 when(mockWorkspace.getNodeTypeManager()).thenReturn(mockNTM); 173 when(mockNodeType.getName()).thenReturn("mockName"); 174 when(mockNodeType.toString()).thenReturn("mockString"); 175 when(mockNTM.getAllNodeTypes()).thenReturn(mockNTI); 176 when(mockNTI.hasNext()).thenReturn(true, false); 177 when(mockNTI.nextNodeType()).thenReturn(mockNodeType).thenThrow( 178 ArrayIndexOutOfBoundsException.class); 179 return mockSession; 180 } 181 182 public static Collection<String> 183 parseChildren(final HttpEntity entity) throws IOException { 184 final String body = EntityUtils.toString(entity); 185 System.err.println(body); 186 final String[] names = 187 body.replace("[", "").replace("]", "").trim().split(",\\s?"); 188 return Arrays.asList(names); 189 } 190 191 public static Session mockSession(final AbstractResource testObj) { 192 193 final SecurityContext mockSecurityContext = mock(SecurityContext.class); 194 final Principal mockPrincipal = mock(Principal.class); 195 196 final String mockUser = "testuser"; 197 198 final Session mockSession = mock(Session.class); 199 when(mockSession.getUserID()).thenReturn(mockUser); 200 when(mockSecurityContext.getUserPrincipal()).thenReturn(mockPrincipal); 201 when(mockPrincipal.getName()).thenReturn(mockUser); 202 203 final Workspace mockWorkspace = mock(Workspace.class); 204 when(mockSession.getWorkspace()).thenReturn(mockWorkspace); 205 when(mockWorkspace.getName()).thenReturn("default"); 206 207 setField(testObj, "uriInfo", getUriInfoImpl()); 208 setField(testObj, "pidMinter", new PathMinterImpl()); 209 return mockSession; 210 211 } 212 213 public static Repository mockRepository() throws LoginException, 214 RepositoryException { 215 final Repository mockRepo = mock(Repository.class); 216 when(mockRepo.login()).thenReturn( 217 mock(org.modeshape.jcr.api.Session.class, Mockito.withSettings().extraInterfaces(Session.class))); 218 return mockRepo; 219 } 220 221 public static NonRdfSourceDescription mockDatastream(final String pid, 222 final String dsId, final String content) { 223 final FedoraBinary mockBinary = mockBinary(pid, dsId, content); 224 final NonRdfSourceDescription mockDs = mock(NonRdfSourceDescription.class); 225 when(mockDs.getDescribedResource()).thenReturn(mockBinary); 226 when(mockDs.getDescribedResource().getDescription()).thenReturn(mockDs); 227 when(mockDs.getPath()).thenReturn("/" + pid + "/" + dsId); 228 when(mockDs.getCreatedDate()).thenReturn(Instant.now()); 229 when(mockDs.getLastModifiedDate()).thenReturn(Instant.now()); 230 if (content != null) { 231 final MessageDigest md; 232 try { 233 md = MessageDigest.getInstance(SHA1.algorithm); 234 } catch (final NoSuchAlgorithmException e) { 235 throw new RuntimeException(e); 236 } 237 final byte[] digest = md.digest(content.getBytes()); 238 final URI cd = asURI(SHA1.algorithm, digest); 239 when(mockDs.getEtagValue()).thenReturn(cd.toString()); 240 } 241 return mockDs; 242 } 243 244 public static FedoraBinary mockBinary(final String pid, 245 final String dsId, final String content) { 246 final FedoraBinary mockBinary = mock(FedoraBinary.class); 247 when(mockBinary.getPath()).thenReturn("/" + pid + "/" + dsId + "/jcr:content"); 248 when(mockBinary.getMimeType()).thenReturn("application/octet-stream"); 249 when(mockBinary.getCreatedDate()).thenReturn(Instant.now()); 250 when(mockBinary.getLastModifiedDate()).thenReturn(Instant.now()); 251 if (content != null) { 252 final MessageDigest md; 253 try { 254 md = MessageDigest.getInstance(SHA1.algorithm); 255 } catch (final NoSuchAlgorithmException e) { 256 throw new RuntimeException(e); 257 } 258 final byte[] digest = md.digest(content.getBytes()); 259 final URI cd = asURI(SHA1.algorithm, digest); 260 when(mockBinary.getContent()).thenReturn( 261 IOUtils.toInputStream(content, UTF_8)); 262 when(mockBinary.getContentDigest()).thenReturn(cd); 263 when(mockBinary.getEtagValue()).thenReturn(cd.toString()); 264 } 265 return mockBinary; 266 } 267 268 private static String getRdfSerialization(final HttpEntity entity) { 269 final Lang lang = contentTypeToLang(parse(entity.getContentType().getValue()).getMimeType()); 270 assertNotNull("Entity is not an RDF serialization", lang); 271 return lang.getName(); 272 } 273 274 public static CloseableDataset parseTriples(final HttpEntity entity) throws IOException { 275 return parseTriples(entity.getContent(), getRdfSerialization(entity)); 276 } 277 278 public static CloseableDataset parseTriples(final InputStream content) { 279 return parseTriples(content, "N3"); 280 } 281 282 public static CloseableDataset parseTriples(final InputStream content, final String contentType) { 283 final Model model = createDefaultModel(); 284 model.read(content, "", contentType); 285 return new CloseableDataset(model); 286 } 287 288 /** 289 * Set a field via reflection 290 * 291 * @param parent the owner object of the field 292 * @param name the name of the field 293 * @param obj the value to set 294 */ 295 public static void setField(final Object parent, final String name, final Object obj) { 296 /* check the parent class too if the field could not be found */ 297 try { 298 final Field f = findField(parent.getClass(), name); 299 f.setAccessible(true); 300 f.set(parent, obj); 301 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) { 302 throw new RuntimeException(e); 303 } 304 } 305 306 private static Field findField(final Class<?> clazz, final String name) 307 throws NoSuchFieldException { 308 for (final Field f : clazz.getDeclaredFields()) { 309 if (f.getName().equals(name)) { 310 return f; 311 } 312 } 313 if (clazz.getSuperclass() == null) { 314 throw new NoSuchFieldException("Field " + name 315 + " could not be found"); 316 } 317 return findField(clazz.getSuperclass(), name); 318 } 319 320 private static class PathMinterImpl implements HierarchicalIdentifierSupplier { } 321}