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