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; 007 008import static java.time.ZoneOffset.UTC; 009import static java.util.stream.Collectors.toList; 010import static org.fcrepo.kernel.api.services.VersionService.MEMENTO_LABEL_FORMATTER; 011import static org.junit.Assert.assertEquals; 012import static org.junit.Assert.assertFalse; 013import static org.junit.Assert.assertNotEquals; 014import static org.junit.Assert.assertNotNull; 015import static org.junit.Assert.assertNull; 016import static org.junit.Assert.assertTrue; 017import static org.mockito.Mockito.when; 018 019import java.time.Instant; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.UUID; 025import java.util.concurrent.TimeUnit; 026 027import javax.inject.Inject; 028 029import org.fcrepo.kernel.api.Transaction; 030import org.fcrepo.kernel.api.identifiers.FedoraId; 031import org.fcrepo.kernel.api.models.FedoraResource; 032 033import org.flywaydb.test.FlywayTestExecutionListener; 034import org.flywaydb.test.annotation.FlywayTest; 035import org.junit.Before; 036import org.junit.Rule; 037import org.junit.Test; 038import org.junit.runner.RunWith; 039import org.mockito.Mock; 040import org.mockito.junit.MockitoJUnit; 041import org.mockito.junit.MockitoRule; 042import org.springframework.test.context.ContextConfiguration; 043import org.springframework.test.context.TestExecutionListeners; 044import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 045import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 046 047/** 048 * @author peichman 049 */ 050@RunWith(SpringJUnit4ClassRunner.class) 051@ContextConfiguration("/containmentIndexTest.xml") 052@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, FlywayTestExecutionListener.class }) 053public class ContainmentIndexImplTest { 054 055 @Mock 056 private FedoraResource parent1; 057 058 @Mock 059 private FedoraResource child1; 060 061 @Mock 062 private FedoraResource parent2; 063 064 @Mock 065 private FedoraResource child2; 066 067 private Transaction transaction1; 068 069 private Transaction transaction2; 070 071 private Transaction shortLivedTx; 072 073 @Inject 074 private ContainmentIndexImpl containmentIndex; 075 076 @Rule 077 public MockitoRule rule = MockitoJUnit.rule().silent(); 078 079 private final Map<String, FedoraResource> id_to_resource = new HashMap<>(); 080 private final Map<String, Transaction> id_to_transaction = new HashMap<>(); 081 082 @Before 083 @FlywayTest 084 public void setUp() { 085 id_to_resource.put("parent1", parent1); 086 id_to_resource.put("parent2", parent2); 087 id_to_resource.put("child1", child1); 088 id_to_resource.put("child2", child2); 089 090 transaction1 = TestTransactionHelper.mockTransaction("transaction1", false); 091 transaction2 = TestTransactionHelper.mockTransaction("transaction2", false); 092 shortLivedTx = TestTransactionHelper.mockTransaction("shortLived", true); 093 094 id_to_transaction.put("transaction1", transaction1); 095 id_to_transaction.put("transaction2", transaction2); 096 } 097 098 /** 099 * Utility method to make it easier to stub the getFedoraId() method and avoid MockitoHints. 100 * @param id The resource|transaction ID/name 101 */ 102 private void stubObject(final String id) { 103 // Use unique ids for resources and transactions. 104 final String uuid = UUID.randomUUID().toString(); 105 if (id_to_resource.containsKey(id)) { 106 final FedoraId fID = FedoraId.create(uuid); 107 when(id_to_resource.get(id).getFedoraId()).thenReturn(fID); 108 } else if (id_to_transaction.containsKey(id)) { 109 when(id_to_transaction.get(id).getId()).thenReturn(uuid); 110 } 111 } 112 113 @Test 114 public void testAddChildInTransaction() { 115 stubObject("parent1"); 116 stubObject("child1"); 117 stubObject("transaction1"); 118 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 119 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 120 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 121 assertEquals(child1.getFedoraId().getFullId(), 122 containmentIndex.getContains(transaction1, parent1.getFedoraId()).findFirst().get()); 123 assertEquals(parent1.getFedoraId().getFullId(), 124 containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 125 // outside of the transaction, the containment shouldn't show up 126 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 127 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 128 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 129 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 130 } 131 132 @Test 133 public void testAddRemoveChildInSameTransaction() { 134 stubObject("parent1"); 135 stubObject("child1"); 136 stubObject("transaction1"); 137 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 138 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 139 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 140 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 141 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 142 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 143 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 144 assertEquals(parent1.getFedoraId().getFullId(), 145 containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 146 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 147 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 148 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 149 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 150 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 151 } 152 153 @Test 154 public void testAddRemoveChildInTwoTransactions() { 155 stubObject("parent1"); 156 stubObject("child1"); 157 stubObject("transaction1"); 158 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 159 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 160 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 161 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 162 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 163 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 164 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 165 assertEquals(parent1.getFedoraId().getFullId(), 166 containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 167 containmentIndex.commitTransaction(transaction1); 168 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 169 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 170 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 171 assertEquals(1, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 172 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 173 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 174 containmentIndex.commitTransaction(transaction1); 175 assertEquals(1, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 176 assertEquals(1, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 177 } 178 179 @Test 180 public void testAddRemovePurgeChildInTransaction() { 181 stubObject("parent1"); 182 stubObject("child1"); 183 stubObject("transaction1"); 184 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 185 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 186 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 187 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 188 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 189 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 190 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 191 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 192 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 193 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 194 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 195 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 196 containmentIndex.purgeResource(transaction1, child1.getFedoraId()); 197 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 198 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 199 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 200 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 201 } 202 203 @Test 204 public void testAddRemovePurgeChildThreeTransaction() { 205 stubObject("parent1"); 206 stubObject("child1"); 207 stubObject("transaction1"); 208 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 209 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 210 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 211 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 212 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 213 containmentIndex.commitTransaction(transaction1); 214 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 215 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 216 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 217 containmentIndex.commitTransaction(transaction1); 218 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 219 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 220 assertEquals(1, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 221 assertEquals(1, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 222 containmentIndex.purgeResource(transaction1, child1.getFedoraId()); 223 containmentIndex.commitTransaction(transaction1); 224 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 225 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 226 assertEquals(0, containmentIndex.getContainsDeleted(shortLivedTx, parent1.getFedoraId()).count()); 227 assertEquals(0, containmentIndex.getContainsDeleted(transaction1, parent1.getFedoraId()).count()); 228 } 229 230 @Test 231 public void testRollbackTransaction() { 232 stubObject("parent1"); 233 stubObject("child1"); 234 stubObject("transaction1"); 235 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 236 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 237 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 238 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 239 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 240 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 241 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 242 assertEquals(child1.getFedoraId().getFullId(), 243 containmentIndex.getContains(transaction1, parent1.getFedoraId()).findFirst().get()); 244 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 245 assertEquals(parent1.getFedoraId().getFullId(), 246 containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 247 containmentIndex.rollbackTransaction(transaction1); 248 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 249 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 250 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 251 assertNull(containmentIndex.getContainedBy(transaction1, child1.getFedoraId())); 252 } 253 254 @Test 255 public void testCommitTransaction() { 256 stubObject("parent1"); 257 stubObject("child2"); 258 stubObject("transaction1"); 259 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 260 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 261 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 262 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 263 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 264 assertEquals(child2.getFedoraId().getFullId(), 265 containmentIndex.getContains(transaction1, parent1.getFedoraId()).findFirst().get()); 266 assertEquals(parent1.getFedoraId().getFullId(), 267 containmentIndex.getContainedBy(transaction1, child2.getFedoraId())); 268 assertNull(containmentIndex.getContainedBy(shortLivedTx, child2.getFedoraId())); 269 containmentIndex.commitTransaction(transaction1); 270 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 271 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 272 assertEquals(child2.getFedoraId().getFullId(), 273 containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).findFirst().get()); 274 assertEquals(parent1.getFedoraId().getFullId(), 275 containmentIndex.getContainedBy(transaction1, child2.getFedoraId())); 276 assertEquals(child2.getFedoraId().getFullId(), 277 containmentIndex.getContains(transaction1, parent1.getFedoraId()).findFirst().get()); 278 assertEquals(parent1.getFedoraId().getFullId(), 279 containmentIndex.getContainedBy(shortLivedTx, child2.getFedoraId())); 280 } 281 282 @Test 283 public void testSwapContained() { 284 stubObject("parent1"); 285 stubObject("child1"); 286 stubObject("child2"); 287 stubObject("transaction1"); 288 stubObject("transaction2"); 289 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 290 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 291 containmentIndex.commitTransaction(transaction1); 292 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 293 assertEquals(child1.getFedoraId().getFullId(), 294 containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).findFirst().get()); 295 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 296 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 297 // Still the same outside 298 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 299 assertEquals(child1.getFedoraId().getFullId(), 300 containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).findFirst().get()); 301 // Still the same in a different transaction 302 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 303 assertEquals(child1.getFedoraId().getFullId(), 304 containmentIndex.getContains(transaction2, parent1.getFedoraId()).findFirst().get()); 305 // Inside it has changed 306 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 307 assertEquals(child2.getFedoraId().getFullId(), 308 containmentIndex.getContains(transaction1, parent1.getFedoraId()).findFirst().get()); 309 containmentIndex.commitTransaction(transaction1); 310 // After commit() it is the same outside transactions. 311 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 312 assertEquals(child2.getFedoraId().getFullId(), 313 containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).findFirst().get()); 314 // And now the same in a different transaction 315 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 316 assertEquals(child2.getFedoraId().getFullId(), 317 containmentIndex.getContains(transaction2, parent1.getFedoraId()).findFirst().get()); 318 } 319 320 @Test 321 public void testOnlyCommitOne() throws Exception { 322 stubObject("parent1"); 323 stubObject("child1"); 324 stubObject("child2"); 325 stubObject("transaction1"); 326 stubObject("transaction2"); 327 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 328 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 329 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 330 containmentIndex.commitTransaction(transaction1); 331 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 332 // Delete one object in separate transactions. 333 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 334 containmentIndex.removeContainedBy(transaction2, parent1.getFedoraId(), child2.getFedoraId()); 335 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 336 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 337 containmentIndex.commitTransaction(transaction1); 338 // Wait a second because containment end time is second accuracy. 339 TimeUnit.SECONDS.sleep(1); 340 // Now only one record was removed 341 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 342 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 343 // Except in the second transaction as it should now have 0 344 assertEquals(0, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 345 containmentIndex.commitTransaction(transaction2); 346 // Wait a second because containment end time is second accuracy. 347 TimeUnit.SECONDS.sleep(1); 348 // Now all are gone 349 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 350 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 351 assertEquals(0, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 352 } 353 354 @Test 355 public void testTwoTransactionDeleteSameChild() { 356 stubObject("parent1"); 357 stubObject("child1"); 358 stubObject("child2"); 359 stubObject("transaction1"); 360 stubObject("transaction2"); 361 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 362 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 363 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 364 containmentIndex.commitTransaction(transaction1); 365 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 366 // Delete one object in separate transactions. 367 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 368 containmentIndex.removeContainedBy(transaction2, parent1.getFedoraId(), child1.getFedoraId()); 369 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 370 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 371 containmentIndex.commitTransaction(transaction1); 372 // Now only one record was removed 373 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 374 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 375 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 376 containmentIndex.commitTransaction(transaction2); 377 // No change as the first transaction already committed. 378 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 379 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 380 assertEquals(1, containmentIndex.getContains(transaction2, parent1.getFedoraId()).count()); 381 } 382 383 @Test 384 public void testContainedByTwoSameTransactionException() { 385 stubObject("parent1"); 386 stubObject("parent2"); 387 stubObject("child1"); 388 stubObject("transaction1"); 389 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 390 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent2.getFedoraId()).count()); 391 // Add it to the first parent. 392 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 393 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 394 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent2.getFedoraId()).count()); 395 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 396 assertEquals(0, containmentIndex.getContains(transaction1, parent2.getFedoraId()).count()); 397 // When you add it to the second parent, it is altered and the first relationship is overwritten. 398 containmentIndex.addContainedBy(transaction1, parent2.getFedoraId(), child1.getFedoraId()); 399 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 400 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent2.getFedoraId()).count()); 401 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 402 assertEquals(1, containmentIndex.getContains(transaction1, parent2.getFedoraId()).count()); 403 containmentIndex.commitTransaction(transaction1); 404 // This should be rolled back so the additions should still be in the transaction operation table. 405 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 406 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent2.getFedoraId()).count()); 407 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 408 assertEquals(1, containmentIndex.getContains(transaction1, parent2.getFedoraId()).count()); 409 } 410 411 @Test 412 public void testExistsOutsideTransaction() { 413 stubObject("parent1"); 414 stubObject("child1"); 415 stubObject("transaction1"); 416 stubObject("transaction2"); 417 assertFalse(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 418 assertFalse(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 419 containmentIndex.addContainedBy(transaction2, parent1.getFedoraId(), child1.getFedoraId()); 420 containmentIndex.commitTransaction(transaction2); 421 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 422 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 423 } 424 425 @Test 426 public void testExistsInsideTransaction() { 427 stubObject("parent1"); 428 stubObject("child1"); 429 stubObject("transaction1"); 430 stubObject("transaction2"); 431 assertFalse(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 432 assertFalse(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 433 assertFalse(containmentIndex.resourceExists(transaction2, child1.getFedoraId(), false)); 434 // Only visible in the transaction. 435 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 436 assertFalse(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 437 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 438 assertFalse(containmentIndex.resourceExists(transaction2, child1.getFedoraId(), false)); 439 // Rollback transaction. 440 containmentIndex.rollbackTransaction(transaction1); 441 assertFalse(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 442 assertFalse(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 443 assertFalse(containmentIndex.resourceExists(transaction2, child1.getFedoraId(), false)); 444 // Add again in transaction. 445 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 446 assertFalse(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 447 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 448 assertFalse(containmentIndex.resourceExists(transaction2, child1.getFedoraId(), false)); 449 // Commit and visible everywhere. 450 containmentIndex.commitTransaction(transaction1); 451 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 452 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 453 assertTrue(containmentIndex.resourceExists(transaction2, child1.getFedoraId(), false)); 454 } 455 456 @Test 457 public void testRemoveResource() { 458 stubObject("parent1"); 459 stubObject("child1"); 460 stubObject("transaction1"); 461 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 462 containmentIndex.commitTransaction(transaction1); 463 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 464 assertEquals(parent1.getFedoraId().getFullId(), 465 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 466 containmentIndex.removeResource(transaction1, child1.getFedoraId()); 467 containmentIndex.commitTransaction(transaction1); 468 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 469 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 470 } 471 472 @Test 473 public void testRemoveNotFromTransaction() { 474 stubObject("parent1"); 475 stubObject("child1"); 476 stubObject("parent2"); 477 stubObject("transaction1"); 478 stubObject("transaction2"); 479 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 480 containmentIndex.addContainedBy(transaction2, parent1.getFedoraId(), child1.getFedoraId()); 481 containmentIndex.commitTransaction(transaction2); 482 containmentIndex.addContainedBy(transaction1, parent2.getFedoraId(), child1.getFedoraId()); 483 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 484 assertEquals(parent1.getFedoraId().getFullId(), 485 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 486 assertEquals(1, containmentIndex.getContains(transaction1, parent2.getFedoraId()).count()); 487 assertEquals(child1.getFedoraId().getFullId(), 488 containmentIndex.getContains(transaction1, parent2.getFedoraId()).findFirst().get()); 489 containmentIndex.removeResource(transaction2, child1.getFedoraId()); 490 containmentIndex.commitTransaction(transaction2); 491 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 492 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 493 assertEquals(1, containmentIndex.getContains(transaction1, parent2.getFedoraId()).count()); 494 assertEquals(child1.getFedoraId().getFullId(), 495 containmentIndex.getContains(transaction1, parent2.getFedoraId()).findFirst().get()); 496 } 497 498 @Test 499 public void testCommitRemoveFromTransaction() { 500 stubObject("parent1"); 501 stubObject("child1"); 502 stubObject("transaction1"); 503 stubObject("transaction2"); 504 containmentIndex.addContainedBy(transaction2, parent1.getFedoraId(), child1.getFedoraId()); 505 containmentIndex.commitTransaction(transaction2); 506 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 507 assertEquals(parent1.getFedoraId().getFullId(), 508 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 509 containmentIndex.removeResource(transaction1, child1.getFedoraId()); 510 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 511 assertEquals(parent1.getFedoraId().getFullId(), 512 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 513 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 514 containmentIndex.commitTransaction(transaction1); 515 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 516 assertNull(containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 517 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 518 } 519 520 /** 521 * Ensure match the id without a trailing slash. 522 */ 523 @Test 524 public void testResourceExistsFedoraIDNoTrailingSlash() { 525 stubObject("parent1"); 526 stubObject("child1"); 527 stubObject("transaction1"); 528 final FedoraId fedoraID = FedoraId.create(child1.getFedoraId().getFullId()); 529 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 530 containmentIndex.commitTransaction(transaction1); 531 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 532 assertEquals(parent1.getFedoraId().getFullId(), 533 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 534 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 535 assertTrue(containmentIndex.resourceExists(shortLivedTx, fedoraID, false)); 536 } 537 538 /** 539 * Ensure match the id with a trailing slash. 540 */ 541 @Test 542 public void testResourceExistsFedoraIDTrailingSlash() { 543 stubObject("parent1"); 544 stubObject("child1"); 545 stubObject("transaction1"); 546 final FedoraId fedoraID = FedoraId.create(child1.getFedoraId().getFullId() + "/"); 547 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 548 containmentIndex.commitTransaction(transaction1); 549 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 550 assertEquals(parent1.getFedoraId().getFullId(), 551 containmentIndex.getContainedBy(shortLivedTx, child1.getFedoraId())); 552 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 553 assertTrue(containmentIndex.resourceExists(shortLivedTx, fedoraID, false)); 554 } 555 556 @Test 557 public void clearIndexWhenReset() { 558 stubObject("parent1"); 559 stubObject("child1"); 560 stubObject("transaction1"); 561 562 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 563 564 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 565 566 containmentIndex.reset(); 567 568 assertFalse(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 569 } 570 571 @Test 572 public void clearAllTransactions() { 573 stubObject("parent1"); 574 stubObject("child1"); 575 stubObject("transaction1"); 576 stubObject("parent2"); 577 stubObject("child2"); 578 stubObject("transaction2"); 579 580 // Create two hierarchies, one in a committed transaction and the other in an uncommitted one 581 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 582 containmentIndex.addContainedBy(transaction2, parent2.getFedoraId(), child2.getFedoraId()); 583 containmentIndex.commitTransaction(transaction1); 584 585 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 586 assertTrue(containmentIndex.resourceExists(transaction1, child1.getFedoraId(), false)); 587 588 assertFalse(containmentIndex.resourceExists(shortLivedTx, child2.getFedoraId(), false)); 589 assertTrue(containmentIndex.resourceExists(transaction2, child2.getFedoraId(), false)); 590 591 containmentIndex.clearAllTransactions(); 592 593 // Committed containment should persist, but uncommitted should not 594 assertTrue(containmentIndex.resourceExists(shortLivedTx, child1.getFedoraId(), false)); 595 assertFalse(containmentIndex.resourceExists(shortLivedTx, child2.getFedoraId(), false)); 596 assertFalse(containmentIndex.resourceExists(transaction2, child2.getFedoraId(), false)); 597 } 598 599 @Test 600 public void testHasResourcesStartingFailure() { 601 stubObject("parent1"); 602 stubObject("child1"); 603 stubObject("transaction1"); 604 // Nothing exists. 605 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 606 // Add the single resource. 607 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 608 containmentIndex.commitTransaction(transaction1); 609 // Still no similar paths. 610 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 611 // Add a contained resource that does NOT share the URI path. 612 assertFalse(child1.getFedoraId().getFullId().startsWith(parent1.getFedoraId().getFullId())); 613 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 614 containmentIndex.commitTransaction(transaction1); 615 // Still no similar paths. 616 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 617 } 618 619 @Test 620 public void testHasResourcesStartingSuccess() { 621 stubObject("parent1"); 622 final var subPathId = parent1.getFedoraId().resolve("a/layer/down"); 623 stubObject("transaction1"); 624 // Add a resource. 625 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), subPathId); 626 // That resource's ID starts with the ID we are checking. 627 assertTrue(subPathId.getFullId().startsWith(parent1.getFedoraId().getFullId())); 628 assertTrue(containmentIndex.hasResourcesStartingWith(transaction1, parent1.getFedoraId())); 629 } 630 631 @Test 632 public void testDeletedResourceExists() { 633 stubObject("parent1"); 634 stubObject("transaction1"); 635 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 636 containmentIndex.commitTransaction(transaction1); 637 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 638 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 639 containmentIndex.removeContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 640 containmentIndex.commitTransaction(transaction1); 641 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 642 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 643 containmentIndex.purgeResource(transaction1, parent1.getFedoraId()); 644 containmentIndex.commitTransaction(transaction1); 645 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 646 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 647 } 648 649 @Test 650 public void testMementosContainment() throws Exception { 651 stubObject("parent1"); 652 stubObject("child1"); 653 stubObject("child2"); 654 stubObject("transaction1"); 655 656 // Parent contains child1 and child2 657 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 658 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 659 containmentIndex.commitTransaction(transaction1); 660 TimeUnit.SECONDS.sleep(1); 661 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 662 // get the current instant and make a FedoraId for a memento at this instant. 663 final var bothTime = Instant.now(); 664 final var mementoId = parent1.getFedoraId().resolve("fcr:versions/" + 665 bothTime.atZone(UTC).format(MEMENTO_LABEL_FORMATTER)); 666 // Wait. 667 TimeUnit.SECONDS.sleep(2); 668 // Delete child1 669 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 670 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 671 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 672 containmentIndex.commitTransaction(transaction1); 673 TimeUnit.SECONDS.sleep(1); 674 // Child1 is gone in the current view. 675 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 676 // Child1 remains in the memento view. 677 assertEquals(2, containmentIndex.getContains(shortLivedTx, mementoId).count()); 678 // purging child 1 679 containmentIndex.purgeResource(transaction1, child1.getFedoraId()); 680 // stays the same as we haven't committed yet. 681 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 682 assertEquals(2, containmentIndex.getContains(shortLivedTx, mementoId).count()); 683 containmentIndex.commitTransaction(transaction1); 684 // Now the memento loses track of child1. 685 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 686 assertEquals(1, containmentIndex.getContains(shortLivedTx, mementoId).count()); 687 } 688 689 @Test 690 public void testChecksum() throws Exception { 691 stubObject("parent1"); 692 stubObject("transaction1"); 693 // Need to add a containment record for the parent to hold the updated value. 694 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 695 final var empty = containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId()); 696 assertNull(empty); 697 // Wait a half second as the ETag is based on the highest value of any child's start_time or end_time. 698 TimeUnit.MILLISECONDS.sleep(500); 699 final var firstBorn = parent1.getFedoraId().resolve("child1"); 700 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), firstBorn); 701 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 702 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 703 final var first = containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId()); 704 assertNotNull(first); 705 assertNotEquals(empty, first); 706 707 containmentIndex.commitTransaction(transaction1); 708 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 709 assertEquals(first, containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId())); 710 711 // Wait half a second, all these children will share a start_time. 712 TimeUnit.SECONDS.sleep(1); 713 for (var i = 0; i < 30; i += 1) { 714 final var kidId = parent1.getFedoraId().resolve("child-" + i); 715 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), kidId); 716 } 717 assertEquals(31, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 718 final var allTime = containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId()); 719 assertNotEquals(empty, allTime); 720 assertNotEquals(first, allTime); 721 722 containmentIndex.rollbackTransaction(transaction1); 723 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 724 assertEquals(first, containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId())); 725 726 TimeUnit.SECONDS.sleep(1); 727 728 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), firstBorn); 729 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 730 assertNotEquals(first, containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId())); 731 assertNotEquals(allTime, containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId())); 732 733 containmentIndex.commitTransaction(transaction1); 734 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 735 final var last = containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId()); 736 assertNotNull(last); 737 assertNotEquals(first, last); 738 assertNotEquals(allTime, last); 739 } 740 741 @Test 742 public void testLargeContainment() { 743 stubObject("transaction1"); 744 stubObject("parent1"); 745 containmentIndex.setContainsLimit(5); 746 final List<String> expectedChildren = new ArrayList<>(10); 747 for (var i = 0; i < 10; i += 1) { 748 final FedoraId childId = parent1.getFedoraId().resolve("child_" + i); 749 expectedChildren.add(childId.getFullId()); 750 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), childId); 751 } 752 assertEquals(10, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 753 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 754 containmentIndex.commitTransaction(transaction1); 755 final var foundChildren = containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()) 756 .collect(toList()); 757 assertEquals(10, foundChildren.size()); 758 assertEquals(expectedChildren, foundChildren); 759 } 760 761 @Test 762 public void testAddAclInTransaction() { 763 stubObject("parent1"); 764 final FedoraId aclId = FedoraId.create("parent1/fcr:acl"); 765 stubObject("transaction1"); 766 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 767 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), aclId); 768 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 769 // outside of the transaction, it still shouldn't show up 770 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 771 } 772} 773 774