001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.kernel.impl.models; 007 008import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_ID_PREFIX; 009import static org.junit.Assert.assertFalse; 010import static org.junit.Assert.assertTrue; 011import static org.mockito.Mockito.when; 012import static org.springframework.test.util.ReflectionTestUtils.setField; 013 014import javax.inject.Inject; 015 016import java.util.UUID; 017 018import org.fcrepo.kernel.api.ContainmentIndex; 019import org.fcrepo.kernel.api.ReadOnlyTransaction; 020import org.fcrepo.kernel.api.Transaction; 021import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 022import org.fcrepo.kernel.api.identifiers.FedoraId; 023import org.fcrepo.kernel.impl.TestTransactionHelper; 024import org.fcrepo.persistence.api.PersistentStorageSession; 025import org.fcrepo.persistence.api.PersistentStorageSessionManager; 026import org.fcrepo.persistence.api.exceptions.PersistentSessionClosedException; 027import org.junit.Before; 028import org.junit.Test; 029import org.junit.runner.RunWith; 030import org.mockito.InjectMocks; 031import org.mockito.Mock; 032import org.mockito.MockitoAnnotations; 033import org.springframework.test.context.ContextConfiguration; 034import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 035 036/** 037 * Test for ResourceHelper 038 * @author whikloj 039 * @since 6.0.0 040 */ 041@RunWith(SpringJUnit4ClassRunner.class) 042@ContextConfiguration("/containmentIndexTest.xml") 043public class ResourceHelperImplTest { 044 045 @Mock 046 private PersistentStorageSessionManager sessionManager; 047 048 @Mock 049 private PersistentStorageSession psSession; 050 051 private Transaction mockTx; 052 053 @Inject 054 private ContainmentIndex containmentIndex; 055 056 @InjectMocks 057 private ResourceHelperImpl resourceHelper; 058 059 private String fedoraIdStr; 060 061 private String sessionId; 062 063 private final FedoraId rootId = FedoraId.getRepositoryRootId(); 064 065 private FedoraId fedoraId; 066 067 private String fedoraMementoIdStr; 068 069 private FedoraId fedoraMementoId; 070 071 private Transaction readOnlyTx; 072 073 @Before 074 public void setup() throws Exception { 075 MockitoAnnotations.openMocks(this); 076 fedoraIdStr = FEDORA_ID_PREFIX + "/" + UUID.randomUUID().toString(); 077 fedoraId = FedoraId.create(fedoraIdStr); 078 fedoraMementoIdStr = fedoraIdStr + "/fcr:versions/20000102120000"; 079 fedoraMementoId = FedoraId.create(fedoraMementoIdStr); 080 081 sessionId = UUID.randomUUID().toString(); 082 mockTx = TestTransactionHelper.mockTransaction(sessionId, false); 083 084 resourceHelper = new ResourceHelperImpl(); 085 086 setField(resourceHelper, "persistentStorageSessionManager", sessionManager); 087 setField(resourceHelper, "containmentIndex", containmentIndex); 088 089 when(sessionManager.getSession(mockTx)).thenReturn(psSession); 090 when(sessionManager.getReadOnlySession()).thenReturn(psSession); 091 092 readOnlyTx = ReadOnlyTransaction.INSTANCE; 093 } 094 095 @Test 096 public void doesResourceExist_Exists_WithSession() throws Exception { 097 containmentIndex.addContainedBy(mockTx, rootId, fedoraId); 098 final boolean answerIn = resourceHelper.doesResourceExist(mockTx, fedoraId, false); 099 assertTrue(answerIn); 100 final boolean answerOut = resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false); 101 assertFalse(answerOut); 102 } 103 104 @Test 105 public void doesResourceExist_Exists_Description_WithSession() { 106 containmentIndex.addContainedBy(mockTx, rootId, fedoraId); 107 final FedoraId descId = fedoraId.asDescription(); 108 final boolean answerIn = resourceHelper.doesResourceExist(mockTx, descId, false); 109 assertTrue(answerIn); 110 final boolean answerOut = resourceHelper.doesResourceExist(readOnlyTx, descId, false); 111 assertFalse(answerOut); 112 } 113 114 @Test 115 public void doesResourceExist_Exists_WithoutSession() throws Exception { 116 containmentIndex.addContainedBy(mockTx, rootId, fedoraId); 117 containmentIndex.commitTransaction(mockTx); 118 final boolean answer = resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false); 119 assertTrue(answer); 120 } 121 122 @Test 123 public void doesResourceExist_Exists_Description_WithoutSession() { 124 containmentIndex.addContainedBy(mockTx, rootId, fedoraId); 125 containmentIndex.commitTransaction(mockTx); 126 final FedoraId descId = fedoraId.asDescription(); 127 final boolean answer = resourceHelper.doesResourceExist(readOnlyTx, descId, false); 128 assertTrue(answer); 129 } 130 131 @Test 132 public void doesResourceExist_DoesntExist_WithSession() throws Exception { 133 final boolean answer = resourceHelper.doesResourceExist(mockTx, fedoraId, false); 134 assertFalse(answer); 135 } 136 137 @Test 138 public void doesResourceExist_DoesntExists_Description_WithSession() { 139 final FedoraId descId = fedoraId.asDescription(); 140 final boolean answer = resourceHelper.doesResourceExist(mockTx, descId, false); 141 assertFalse(answer); 142 } 143 144 @Test 145 public void doesResourceExist_DoesntExist_WithoutSession() throws Exception { 146 final boolean answer = resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false); 147 assertFalse(answer); 148 } 149 150 @Test 151 public void doesResourceExist_DoesntExists_Description_WithoutSession() { 152 final FedoraId descId = fedoraId.asDescription(); 153 final boolean answer = resourceHelper.doesResourceExist(readOnlyTx, descId, false); 154 assertFalse(answer); 155 } 156 157 /** 158 * Only Mementos go to the persistence layer. 159 */ 160 @Test(expected = RepositoryRuntimeException.class) 161 public void doesResourceExist_Exception_WithSession() throws Exception { 162 when(psSession.getHeaders(fedoraMementoId, fedoraMementoId.getMementoInstant())) 163 .thenThrow(PersistentSessionClosedException.class); 164 resourceHelper.doesResourceExist(mockTx, fedoraMementoId, false); 165 } 166 167 /** 168 * Only Mementos go to the persistence layer. 169 */ 170 @Test(expected = RepositoryRuntimeException.class) 171 public void doesResourceExist_Exception_WithoutSession() throws Exception { 172 when(psSession.getHeaders(fedoraMementoId, fedoraMementoId.getMementoInstant())) 173 .thenThrow(PersistentSessionClosedException.class); 174 resourceHelper.doesResourceExist(readOnlyTx, fedoraMementoId, false); 175 } 176 177 /** 178 * Test an item is not a ghost node because it exists. 179 */ 180 @Test 181 public void testGhostNodeFailure() { 182 containmentIndex.addContainedBy(mockTx, rootId, fedoraId); 183 // Inside the transaction the resource exists, so its not a ghost node. 184 assertTrue(resourceHelper.doesResourceExist(mockTx, fedoraId, false)); 185 assertFalse(resourceHelper.isGhostNode(mockTx, fedoraId)); 186 // Outside the transaction the resource does not exist. 187 assertFalse(resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false)); 188 // Because there are no other items it is not a ghost node. 189 assertFalse(resourceHelper.isGhostNode(readOnlyTx, fedoraId)); 190 191 containmentIndex.commitTransaction(mockTx); 192 193 // Now it exists outside the transaction. 194 assertTrue(resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false)); 195 // So it can't be a ghost node. 196 assertFalse(resourceHelper.isGhostNode(readOnlyTx, fedoraId)); 197 } 198 199 /** 200 * Test that when the resource that does exist shares the ID of a resource that does not, then we have a ghost node. 201 */ 202 @Test 203 public void testGhostNodeSuccess() { 204 final var resourceId = fedoraId.resolve("the/child/path"); 205 containmentIndex.addContainedBy(mockTx, rootId, resourceId); 206 assertTrue(resourceHelper.doesResourceExist(mockTx, resourceId, false)); 207 assertFalse(resourceHelper.doesResourceExist(mockTx, fedoraId, false)); 208 assertTrue(resourceHelper.isGhostNode(mockTx, fedoraId)); 209 assertFalse(resourceHelper.doesResourceExist(readOnlyTx, resourceId, false)); 210 assertFalse(resourceHelper.doesResourceExist(readOnlyTx, fedoraId, false)); 211 assertFalse(resourceHelper.isGhostNode(readOnlyTx, fedoraId)); 212 213 containmentIndex.commitTransaction(mockTx); 214 215 assertTrue(resourceHelper.doesResourceExist(readOnlyTx, resourceId, false)); 216 assertFalse(resourceHelper.doesResourceExist(readOnlyTx, fedoraId,false)); 217 assertTrue(resourceHelper.isGhostNode(readOnlyTx, fedoraId)); 218 } 219}