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