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.services;
007
008import static org.apache.jena.rdf.model.ResourceFactory.createResource;
009import static org.fcrepo.kernel.api.RdfCollectors.toModel;
010import static org.fcrepo.kernel.api.RdfLexicon.CONTAINS;
011import static org.junit.Assert.assertEquals;
012import static org.junit.Assert.assertTrue;
013import static org.mockito.Mockito.when;
014import static org.springframework.test.util.ReflectionTestUtils.setField;
015
016import java.util.UUID;
017
018import javax.inject.Inject;
019
020import org.fcrepo.kernel.api.ContainmentIndex;
021import org.fcrepo.kernel.api.ReadOnlyTransaction;
022import org.fcrepo.kernel.api.Transaction;
023import org.fcrepo.kernel.api.identifiers.FedoraId;
024import org.fcrepo.kernel.api.models.FedoraResource;
025import org.fcrepo.kernel.impl.TestTransactionHelper;
026
027import org.apache.jena.rdf.model.Model;
028import org.apache.jena.rdf.model.ModelFactory;
029import org.apache.jena.rdf.model.Statement;
030import org.apache.jena.rdf.model.StmtIterator;
031import org.junit.After;
032import org.junit.Before;
033import org.junit.Test;
034import org.junit.runner.RunWith;
035import org.mockito.InjectMocks;
036import org.mockito.Mock;
037import org.mockito.MockitoAnnotations;
038import org.springframework.test.context.ContextConfiguration;
039import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
040
041/**
042 * @author whikloj
043 */
044@RunWith(SpringJUnit4ClassRunner.class)
045@ContextConfiguration("/containmentIndexTest.xml")
046public class ContainmentTriplesServiceImplTest {
047
048    @Mock
049    private FedoraResource parentResource;
050
051    private Transaction transaction;
052
053    private Transaction transaction2;
054
055    @Inject
056    private ContainmentIndex containmentIndex;
057
058    @InjectMocks
059    private ContainmentTriplesServiceImpl containmentTriplesService;
060
061    private Transaction readOnlyTx;
062
063    @Before
064    public void setup() {
065        MockitoAnnotations.openMocks(this);
066        final FedoraId parentId = FedoraId.create(UUID.randomUUID().toString());
067        final String txId = UUID.randomUUID().toString();
068        transaction = TestTransactionHelper.mockTransaction(txId, false);
069        when(parentResource.getFedoraId()).thenReturn(parentId);
070        setField(containmentTriplesService, "containmentIndex", containmentIndex);
071        readOnlyTx = ReadOnlyTransaction.INSTANCE;
072    }
073
074    @After
075    public void cleanUp() {
076        containmentIndex.reset();
077    }
078
079    @Test
080    public void testNoContains() {
081        assertEquals(0, containmentTriplesService.get(transaction, parentResource).count());
082    }
083
084    @Test
085    public void testOneChild() {
086        final FedoraId child = FedoraId.create(UUID.randomUUID().toString());
087        containmentIndex.addContainedBy(transaction, parentResource.getFedoraId(), child);
088        assertEquals(1, containmentTriplesService.get(transaction, parentResource).count());
089        final Model expectedModel = ModelFactory.createDefaultModel();
090        expectedModel.add(createResource(parentResource.getFedoraId().getFullId()), CONTAINS,
091                createResource(child.getFullId()));
092        final Model received = containmentTriplesService.get(transaction, parentResource).collect(toModel());
093        matchModels(expectedModel, received);
094    }
095
096    @Test
097    public void testTwoChildren() {
098        final FedoraId child1 = FedoraId.create(UUID.randomUUID().toString());
099        final FedoraId child2 = FedoraId.create(UUID.randomUUID().toString());
100        containmentIndex.addContainedBy(transaction, parentResource.getFedoraId(), child1);
101        containmentIndex.addContainedBy(transaction, parentResource.getFedoraId(), child2);
102        assertEquals(2, containmentTriplesService.get(transaction, parentResource).count());
103        final Model expectedModel = ModelFactory.createDefaultModel();
104        expectedModel.add(createResource(parentResource.getFedoraId().getFullId()), CONTAINS,
105                createResource(child1.getFullId()));
106        expectedModel.add(createResource(parentResource.getFedoraId().getFullId()), CONTAINS,
107                createResource(child2.getFullId()));
108        final Model received = containmentTriplesService.get(transaction, parentResource).collect(toModel());
109        matchModels(expectedModel, received);
110    }
111
112    @Test
113    public void testTenChildren() {
114        final Model expectedModel = ModelFactory.createDefaultModel();
115        for (var foo = 0; foo < 10; foo += 1) {
116            final FedoraId child = FedoraId.create(UUID.randomUUID().toString());
117            containmentIndex.addContainedBy(transaction, parentResource.getFedoraId(), child);
118            expectedModel.add(createResource(parentResource.getFedoraId().getFullId()), CONTAINS,
119                    createResource(child.getFullId()));
120        }
121        assertEquals(10, containmentTriplesService.get(transaction, parentResource).count());
122        final Model received = containmentTriplesService.get(transaction, parentResource).collect(toModel());
123        matchModels(expectedModel, received);
124    }
125
126    @Test
127    public void testAddAndRemove() {
128        final FedoraId child = FedoraId.create(UUID.randomUUID().toString());
129        final String otherTransactionId = UUID.randomUUID().toString();
130
131        transaction2 = TestTransactionHelper.mockTransaction(otherTransactionId, false);
132        containmentIndex.addContainedBy(transaction, parentResource.getFedoraId(), child);
133        assertEquals(1, containmentTriplesService.get(transaction, parentResource).count());
134        final Model expectedModel = ModelFactory.createDefaultModel();
135        expectedModel.add(createResource(parentResource.getFedoraId().getFullId()), CONTAINS,
136                createResource(child.getFullId()));
137        final Model received = containmentTriplesService.get(transaction, parentResource).collect(toModel());
138        matchModels(expectedModel, received);
139        // Commit and ensure we can see the child.
140        containmentIndex.commitTransaction(transaction);
141        final Model received2 = containmentTriplesService.get(readOnlyTx, parentResource).collect(toModel());
142        matchModels(expectedModel, received2);
143        // Now remove the child in a transaction, but verify we can still see it outside the transaction.
144        containmentIndex.removeResource(transaction2, child);
145        final Model received3 = containmentTriplesService.get(readOnlyTx, parentResource).collect(toModel());
146        matchModels(expectedModel, received3);
147        // Now commit the transaction and ensure it disappears.
148        containmentIndex.commitTransaction(transaction2);
149        assertEquals(0, containmentTriplesService.get(readOnlyTx, parentResource).count());
150    }
151
152    /**
153     * Ensure the test model contains all the expected statements from the expected model.
154     * @param expected The expected model.
155     * @param test The model to be tested.
156     */
157    private void matchModels(final Model expected, final Model test) {
158        for (final StmtIterator it = expected.listStatements(); it.hasNext(); ) {
159            final Statement t = it.next();
160            assertTrue(test.contains(t));
161        }
162    }
163}