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 testHasResourcesStartingFailure() { 573 stubObject("parent1"); 574 stubObject("child1"); 575 stubObject("transaction1"); 576 // Nothing exists. 577 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 578 // Add the single resource. 579 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 580 containmentIndex.commitTransaction(transaction1); 581 // Still no similar paths. 582 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 583 // Add a contained resource that does NOT share the URI path. 584 assertFalse(child1.getFedoraId().getFullId().startsWith(parent1.getFedoraId().getFullId())); 585 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 586 containmentIndex.commitTransaction(transaction1); 587 // Still no similar paths. 588 assertFalse(containmentIndex.hasResourcesStartingWith(shortLivedTx, parent1.getFedoraId())); 589 } 590 591 @Test 592 public void testHasResourcesStartingSuccess() { 593 stubObject("parent1"); 594 final var subPathId = parent1.getFedoraId().resolve("a/layer/down"); 595 stubObject("transaction1"); 596 // Add a resource. 597 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), subPathId); 598 // That resource's ID starts with the ID we are checking. 599 assertTrue(subPathId.getFullId().startsWith(parent1.getFedoraId().getFullId())); 600 assertTrue(containmentIndex.hasResourcesStartingWith(transaction1, parent1.getFedoraId())); 601 } 602 603 @Test 604 public void testDeletedResourceExists() { 605 stubObject("parent1"); 606 stubObject("transaction1"); 607 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 608 containmentIndex.commitTransaction(transaction1); 609 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 610 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 611 containmentIndex.removeContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 612 containmentIndex.commitTransaction(transaction1); 613 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 614 assertTrue(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 615 containmentIndex.purgeResource(transaction1, parent1.getFedoraId()); 616 containmentIndex.commitTransaction(transaction1); 617 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), false)); 618 assertFalse(containmentIndex.resourceExists(shortLivedTx, parent1.getFedoraId(), true)); 619 } 620 621 @Test 622 public void testMementosContainment() throws Exception { 623 stubObject("parent1"); 624 stubObject("child1"); 625 stubObject("child2"); 626 stubObject("transaction1"); 627 628 // Parent contains child1 and child2 629 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 630 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), child2.getFedoraId()); 631 containmentIndex.commitTransaction(transaction1); 632 TimeUnit.SECONDS.sleep(1); 633 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 634 // get the current instant and make a FedoraId for a memento at this instant. 635 final var bothTime = Instant.now(); 636 final var mementoId = parent1.getFedoraId().resolve("fcr:versions/" + 637 bothTime.atZone(UTC).format(MEMENTO_LABEL_FORMATTER)); 638 // Wait. 639 TimeUnit.SECONDS.sleep(2); 640 // Delete child1 641 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), child1.getFedoraId()); 642 assertEquals(2, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 643 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 644 containmentIndex.commitTransaction(transaction1); 645 TimeUnit.SECONDS.sleep(1); 646 // Child1 is gone in the current view. 647 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 648 // Child1 remains in the memento view. 649 assertEquals(2, containmentIndex.getContains(shortLivedTx, mementoId).count()); 650 // purging child 1 651 containmentIndex.purgeResource(transaction1, child1.getFedoraId()); 652 // stays the same as we haven't committed yet. 653 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 654 assertEquals(2, containmentIndex.getContains(shortLivedTx, mementoId).count()); 655 containmentIndex.commitTransaction(transaction1); 656 // Now the memento loses track of child1. 657 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 658 assertEquals(1, containmentIndex.getContains(shortLivedTx, mementoId).count()); 659 } 660 661 @Test 662 public void testChecksum() throws Exception { 663 stubObject("parent1"); 664 stubObject("transaction1"); 665 // Need to add a containment record for the parent to hold the updated value. 666 containmentIndex.addContainedBy(transaction1, FedoraId.getRepositoryRootId(), parent1.getFedoraId()); 667 final var empty = containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId()); 668 assertNull(empty); 669 // Wait a half second as the ETag is based on the highest value of any child's start_time or end_time. 670 TimeUnit.MILLISECONDS.sleep(500); 671 final var firstBorn = parent1.getFedoraId().resolve("child1"); 672 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), firstBorn); 673 assertEquals(1, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 674 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 675 final var first = containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId()); 676 assertNotNull(first); 677 assertNotEquals(empty, first); 678 679 containmentIndex.commitTransaction(transaction1); 680 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 681 assertEquals(first, containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId())); 682 683 // Wait half a second, all these children will share a start_time. 684 TimeUnit.SECONDS.sleep(1); 685 for (var i = 0; i < 30; i += 1) { 686 final var kidId = parent1.getFedoraId().resolve("child-" + i); 687 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), kidId); 688 } 689 assertEquals(31, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 690 final var allTime = containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId()); 691 assertNotEquals(empty, allTime); 692 assertNotEquals(first, allTime); 693 694 containmentIndex.rollbackTransaction(transaction1); 695 assertEquals(1, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 696 assertEquals(first, containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId())); 697 698 TimeUnit.SECONDS.sleep(1); 699 700 containmentIndex.removeContainedBy(transaction1, parent1.getFedoraId(), firstBorn); 701 assertEquals(0, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 702 assertNotEquals(first, containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId())); 703 assertNotEquals(allTime, containmentIndex.containmentLastUpdated(transaction1, parent1.getFedoraId())); 704 705 containmentIndex.commitTransaction(transaction1); 706 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 707 final var last = containmentIndex.containmentLastUpdated(shortLivedTx, parent1.getFedoraId()); 708 assertNotNull(last); 709 assertNotEquals(first, last); 710 assertNotEquals(allTime, last); 711 } 712 713 @Test 714 public void testLargeContainment() { 715 stubObject("transaction1"); 716 stubObject("parent1"); 717 containmentIndex.setContainsLimit(5); 718 final List<String> expectedChildren = new ArrayList<>(10); 719 for (var i = 0; i < 10; i += 1) { 720 final FedoraId childId = parent1.getFedoraId().resolve("child_" + i); 721 expectedChildren.add(childId.getFullId()); 722 containmentIndex.addContainedBy(transaction1, parent1.getFedoraId(), childId); 723 } 724 assertEquals(10, containmentIndex.getContains(transaction1, parent1.getFedoraId()).count()); 725 assertEquals(0, containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()).count()); 726 containmentIndex.commitTransaction(transaction1); 727 final var foundChildren = containmentIndex.getContains(shortLivedTx, parent1.getFedoraId()) 728 .collect(toList()); 729 assertEquals(10, foundChildren.size()); 730 assertEquals(expectedChildren, foundChildren); 731 } 732} 733 734