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.connector.file; 017 018import static java.nio.file.Files.createTempDirectory; 019import static java.nio.file.Files.createTempFile; 020import static org.fcrepo.kernel.api.FedoraTypes.CONTENT_DIGEST; 021import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertNotNull; 024import static org.junit.Assert.assertNull; 025import static org.junit.Assert.assertTrue; 026import static org.mockito.Matchers.any; 027import static org.mockito.Matchers.anyString; 028import static org.mockito.Matchers.eq; 029import static org.mockito.Mockito.doReturn; 030import static org.mockito.Mockito.mock; 031import static org.mockito.Mockito.spy; 032import static org.mockito.Mockito.verify; 033import static org.mockito.Mockito.when; 034import static org.modeshape.jcr.api.JcrConstants.JCR_DATA; 035import static org.modeshape.jcr.api.JcrConstants.NT_FILE; 036import static org.modeshape.jcr.api.JcrConstants.NT_FOLDER; 037import static org.modeshape.jcr.api.JcrConstants.NT_RESOURCE; 038import static org.slf4j.LoggerFactory.getLogger; 039import static org.springframework.test.util.ReflectionTestUtils.setField; 040 041import java.io.File; 042import java.io.FileOutputStream; 043import java.io.IOException; 044import java.nio.file.Path; 045 046import javax.jcr.NamespaceRegistry; 047 048import org.infinispan.schematic.document.Document; 049import org.junit.Before; 050import org.junit.BeforeClass; 051import org.junit.Test; 052import org.junit.runner.RunWith; 053import org.mockito.Mock; 054import org.mockito.runners.MockitoJUnitRunner; 055import org.modeshape.jcr.ExecutionContext; 056import org.modeshape.jcr.api.nodetype.NodeTypeManager; 057import org.modeshape.jcr.cache.document.DocumentTranslator; 058import org.modeshape.jcr.spi.federation.DocumentReader; 059import org.modeshape.jcr.spi.federation.ExtraPropertiesStore; 060import org.modeshape.jcr.value.BinaryValue; 061import org.modeshape.jcr.value.NameFactory; 062import org.modeshape.jcr.value.Property; 063import org.modeshape.jcr.value.ValueFactories; 064import org.modeshape.jcr.value.basic.BasicName; 065import org.modeshape.jcr.value.basic.BasicSingleValueProperty; 066import org.slf4j.Logger; 067 068/** 069 * @author Andrew Woods 070 * Date: 2/3/14 071 */ 072@RunWith(MockitoJUnitRunner.class) 073public class FedoraFileSystemConnectorTest { 074 075 private FedoraFileSystemConnector connector; 076 077 private static Path directoryPath; 078 079 private static File tmpFile; 080 private static File tmpFile2; 081 private static final String ROOT_PATH = "/"; 082 private static final String PARENT_FIELD = "parent"; 083 private static final String CHILD_FIELD = "children"; 084 085 @Mock 086 private NamespaceRegistry mockRegistry; 087 088 @Mock 089 private NodeTypeManager mockNodeTypeManager; 090 091 @Mock 092 private DocumentTranslator mockTranslator; 093 094 @Mock 095 private NameFactory mockNameFactory; 096 097 @Mock 098 private ValueFactories mockValueFactories; 099 100 @Mock 101 private ExtraPropertiesStore mockExtraPropertiesStore; 102 103 @Mock 104 private Property binaryProperty; 105 106 @Mock 107 private BinaryValue binaryValue; 108 109 private final ExecutionContext mockContext = new ExecutionContext(); 110 111 private static final Logger logger = 112 getLogger(FedoraFileSystemConnectorTest.class); 113 114 @BeforeClass 115 public static void beforeClass() throws IOException { 116 directoryPath = createTempDirectory("fedora-filesystemtest"); 117 tmpFile = 118 createTempFile(directoryPath, "fedora-filesystemtestfile", 119 "txt").toFile(); 120 tmpFile.deleteOnExit(); 121 try (FileOutputStream outputStream = new FileOutputStream(tmpFile)) { 122 outputStream.write("hello".getBytes()); 123 } catch (final IOException e) { 124 logger.error("Error creating: {} - {}", tmpFile.getAbsolutePath(), 125 e.getMessage()); 126 } 127 128 tmpFile2 = 129 createTempFile(directoryPath, "fedora-filesystemtestfile", 130 "txt").toFile(); 131 tmpFile2.deleteOnExit(); 132 try (FileOutputStream outputStream = new FileOutputStream(tmpFile2)) { 133 outputStream.write("goodbye".getBytes()); 134 } catch (final IOException e) { 135 logger.error("Error creating: {} - {}", tmpFile2.getAbsolutePath(), 136 e.getMessage()); 137 } 138 } 139 140 @Before 141 public void setUp() throws IOException { 142 143 connector = new FedoraFileSystemConnector(); 144 setField(connector, "directoryPath", directoryPath.toString()); 145 setField(connector, "translator", mockTranslator); 146 setField(connector, "context", mockContext); 147 setField(connector, "extraPropertiesStore", mockExtraPropertiesStore); 148 setField(mockTranslator, "names", mockNameFactory); 149 setField(connector, "readonly", true); 150 connector.initialize(mockRegistry, mockNodeTypeManager); 151 mockContext.getNamespaceRegistry().register("fedora", REPOSITORY_NAMESPACE); 152 mockContext.getNamespaceRegistry().register("premis", "http://www.loc.gov/premis/rdf/v1#"); 153 } 154 155 @Test 156 public void testGetDocumentByIdNull() { 157 final Document doc = connector.getDocumentById(null); 158 assertNull(doc); 159 } 160 161 @Test 162 public void testGetDocumentByIdDatastream() { 163 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 164 .thenReturn(NT_FILE); 165 when(mockNameFactory.create(anyString())).thenReturn( 166 new BasicName("", tmpFile.getName())); 167 168 final Document doc = connector.getDocumentById(ROOT_PATH + tmpFile.getName()); 169 assertNotNull(doc); 170 assertTrue(doc.containsField(PARENT_FIELD)); 171 assertTrue(doc.containsField(CHILD_FIELD)); 172 assertEquals(ROOT_PATH, doc.getString(PARENT_FIELD)); 173 assertNull(doc.getString(CHILD_FIELD)); 174 } 175 176 @Test 177 public void testGetDocumentByIdObject() { 178 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 179 .thenReturn(NT_FOLDER); 180 when(mockNameFactory.create(anyString())).thenReturn( 181 new BasicName("", tmpFile.getName())); 182 183 final Document doc = connector.getDocumentById(ROOT_PATH + tmpFile.getName()); 184 assertNotNull(doc); 185 assertTrue(doc.containsField(PARENT_FIELD)); 186 assertTrue(doc.containsField(CHILD_FIELD)); 187 assertEquals(ROOT_PATH, doc.getString(PARENT_FIELD)); 188 assertNull(doc.getString(CHILD_FIELD)); 189 } 190 191 @Test 192 public void testGetDocumentByIdNone() { 193 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 194 .thenReturn(""); 195 when(mockNameFactory.create(anyString())).thenReturn( 196 new BasicName("", tmpFile.getName())); 197 198 final Document doc = connector.getDocumentById(ROOT_PATH + tmpFile.getName()); 199 assertNotNull(doc); 200 assertTrue(doc.containsField(PARENT_FIELD)); 201 assertTrue(doc.containsField(CHILD_FIELD)); 202 assertEquals(ROOT_PATH, doc.getString(PARENT_FIELD)); 203 assertNull(doc.getString(CHILD_FIELD)); 204 } 205 206 @Test 207 public void testGetDocumentByIdContent() { 208 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 209 .thenReturn(NT_RESOURCE); 210 when(mockNameFactory.create(anyString())).thenReturn( 211 new BasicName("", tmpFile.getName())); 212 213 when(binaryProperty.getFirstValue()).thenReturn(binaryValue); 214 when(mockTranslator.getProperty(any(Document.class), eq(JCR_DATA))) 215 .thenReturn(binaryProperty); 216 217 final Document doc = connector.getDocumentById(ROOT_PATH + tmpFile.getName()); 218 219 assertNotNull(doc); 220 assertTrue(doc.containsField(PARENT_FIELD)); 221 assertTrue(doc.containsField(CHILD_FIELD)); 222 assertEquals(ROOT_PATH, doc.getString(PARENT_FIELD)); 223 assertNull(doc.getString(CHILD_FIELD)); 224 } 225 226 @Test 227 public void testSha1WhenContentDigestIsCached() { 228 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 229 .thenReturn(NT_RESOURCE); 230 when(mockNameFactory.create(anyString())).thenReturn(new BasicName("", tmpFile.getName())); 231 when(binaryProperty.getFirstValue()).thenReturn(binaryValue); 232 when(mockTranslator.getProperty(any(Document.class), eq(JCR_DATA))) 233 .thenReturn(binaryProperty); 234 235 final String chksum = "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"; 236 237 when(mockTranslator.getProperty(any(Document.class), eq(CONTENT_DIGEST))) 238 .thenReturn(new BasicSingleValueProperty(new BasicName("", CONTENT_DIGEST.toString()), 239 chksum)); 240 241 final String sha1 = connector.sha1(tmpFile); 242 243 assertNotNull(sha1); 244 assert(sha1.contains(chksum)); 245 } 246 247 @Test 248 public void testSha1ContentDigestIsNotCached() { 249 when(mockTranslator.getPrimaryTypeName(any(Document.class))) 250 .thenReturn(NT_RESOURCE); 251 when(mockNameFactory.create(anyString())).thenReturn(new BasicName("", tmpFile.getName())); 252 when(binaryProperty.getFirstValue()).thenReturn(binaryValue); 253 when(mockTranslator.getProperty(any(Document.class), eq(JCR_DATA))) 254 .thenReturn(binaryProperty); 255 256 final String chksum = "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"; 257 258 when(mockTranslator.getProperty(any(Document.class), eq(CONTENT_DIGEST))) 259 .thenReturn(null); 260 261 final String sha1 = connector.sha1(tmpFile); 262 263 assertNotNull(sha1); 264 assert(sha1.contains(chksum)); 265 } 266 267 @Test 268 public void testRemoveDocument() { 269 final String id = "/" + tmpFile2.getName(); 270 final FedoraFileSystemConnector spy = spy(connector); 271 assertTrue("Removing document should return true!", spy.removeDocument(id)); 272 verify(spy).touchParent(id); 273 } 274 275 @Test 276 public void testStoreDocument() { 277 final String id = "/" + tmpFile.getName(); 278 final DocumentReader reader = mock(DocumentReader.class); 279 final FedoraFileSystemConnector spy = spy(connector); 280 doReturn(tmpFile).when(spy).fileFor(anyString()); 281 doReturn(reader).when(spy).readDocument(any(Document.class)); 282 doReturn(id).when(reader).getDocumentId(); 283 doReturn(NT_FILE).when(reader).getPrimaryTypeName(); 284 spy.storeDocument(spy.getDocumentById(id)); 285 verify(spy).touchParent(id); 286 } 287 288 @Test 289 public void testFileSystemConnectorReadOnly() { 290 assertTrue("FedoraFileSystemConnector is not read-only!", connector.isReadonly()); 291 } 292}