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