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