org.trellisldp.rosid.file.FileResourceServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.trellisldp.rosid.file.FileResourceServiceTest.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.trellisldp.rosid.file;

import static java.io.File.separator;
import static java.time.Instant.now;
import static java.time.Instant.parse;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonMap;
import static java.util.Optional.of;
import static java.util.stream.Collectors.toList;
import static org.apache.curator.framework.CuratorFrameworkFactory.newClient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.trellisldp.vocabulary.RDF.type;
import static org.trellisldp.rosid.file.TestUtils.rdf;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

import org.apache.commons.rdf.api.Dataset;
import org.apache.commons.rdf.api.IRI;
import org.apache.commons.rdf.api.Quad;
import org.apache.commons.rdf.api.Triple;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.retry.RetryNTimes;
import org.apache.curator.test.TestingServer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.MockProducer;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.trellisldp.api.Resource;
import org.trellisldp.api.VersionRange;
import org.trellisldp.spi.EventService;
import org.trellisldp.spi.ResourceService;
import org.trellisldp.vocabulary.DC;
import org.trellisldp.vocabulary.LDP;
import org.trellisldp.vocabulary.RDFS;
import org.trellisldp.vocabulary.Trellis;
import org.trellisldp.vocabulary.XSD;

/**
 * @author acoburn
 */
@RunWith(MockitoJUnitRunner.class)
public class FileResourceServiceTest {

    private static TestingServer zkServer;

    private final IRI identifier = rdf.createIRI("trellis:repository/resource");
    private final IRI other = rdf.createIRI("trellis:repository/other");
    private final IRI testResource = rdf.createIRI("trellis:repository/testResource");
    private final Producer<String, String> mockProducer = new MockProducer<>(true, new StringSerializer(),
            new StringSerializer());

    private CuratorFramework curator;
    private ResourceService service;
    private Map<String, String> partitions = new HashMap<>();

    @Mock
    private EventService mockEventService;

    @Mock
    private Supplier<String> mockIdSupplier;

    @BeforeClass
    public static void initialize() throws Exception {
        zkServer = new TestingServer(true);
    }

    @Before
    public void setUp() throws Exception {
        partitions.clear();
        partitions.put("repository", getClass().getResource("/root").toURI().toString());
        curator = newClient(zkServer.getConnectString(), new RetryNTimes(10, 1000));
        curator.start();
        service = new FileResourceService(partitions, curator, mockProducer, mockEventService, mockIdSupplier,
                false);
    }

    @Test
    public void testNewRoot() throws IOException {
        final Instant time = parse("2017-02-16T11:15:03Z");
        final Map<String, String> config = new HashMap<>();
        config.put("repository", partitions.get("repository") + "/root2/a");
        final File root = new File(URI.create(config.get("repository")));
        assertFalse(root.exists());
        final ResourceService altService = new FileResourceService(config, curator, mockProducer, mockEventService,
                mockIdSupplier, false);
        assertFalse(altService.get(identifier, time).isPresent());
        assertTrue(root.exists());
        assertFalse(altService.get(identifier, time).isPresent());
    }

    @Test(expected = IOException.class)
    public void testUnwritableRoot() throws IOException {
        final Map<String, String> config = new HashMap<>();
        config.put("repository", partitions.get("repository") + "/root3");
        final File root = new File(URI.create(config.get("repository")));
        assertTrue(root.mkdir());
        assumeTrue(root.setReadOnly());
        final ResourceService altService = new FileResourceService(config, curator, mockProducer, mockEventService,
                mockIdSupplier, false);
    }

    @Test
    public void testWriteResource() {
        final Dataset data = rdf.createDataset();
        data.add(rdf.createQuad(Trellis.PreferUserManaged, testResource, DC.title, rdf.createLiteral("A title")));
        data.add(rdf.createQuad(Trellis.PreferServerManaged, testResource, type, LDP.RDFSource));
        assertFalse(service.get(testResource).isPresent());
        assertFalse(service.get(testResource, now()).isPresent());

        assertTrue(service.put(testResource, data));
        final Optional<Resource> res = service.get(testResource, now());
        assertTrue(res.isPresent());
        res.ifPresent(r -> {
            assertEquals(LDP.RDFSource, r.getInteractionModel());
            assertEquals(testResource, r.getIdentifier());
            assertTrue(r.stream().anyMatch(q -> q.getPredicate().equals(DC.title)));
            assertTrue(r.getModified().isBefore(now()));
        });
        final Optional<Resource> res2 = service.get(testResource);
        assertTrue(res2.isPresent());
        res2.ifPresent(r -> {
            assertEquals(LDP.RDFSource, r.getInteractionModel());
            assertEquals(testResource, r.getIdentifier());
            assertTrue(r.stream().anyMatch(q -> q.getPredicate().equals(DC.title)));
            assertTrue(r.getModified().isBefore(now()));
        });
    }

    @Test
    public void testWriteResourceWrongLocation() {
        final Dataset data = rdf.createDataset();
        data.add(rdf.createQuad(Trellis.PreferUserManaged, testResource, DC.title, rdf.createLiteral("A title")));
        data.add(rdf.createQuad(Trellis.PreferServerManaged, testResource, type, LDP.RDFSource));

        assertFalse(service.put(rdf.createIRI("trellis:foo/bar"), data));
    }

    @Test
    public void testVersionedResource() {
        final Instant time = parse("2017-02-16T11:15:03Z");
        final Resource res = service.get(identifier, time).get();
        assertEquals(identifier, res.getIdentifier());
        assertEquals(LDP.Container, res.getInteractionModel());
        final List<IRI> contained = res.stream(LDP.PreferContainment).map(Triple::getObject).map(x -> (IRI) x)
                .collect(toList());
        assertEquals(3L, contained.size());
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/1")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/2")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/3")));
        assertFalse(res.getMembershipResource().isPresent());
        assertFalse(res.getMemberRelation().isPresent());
        assertFalse(res.getMemberOfRelation().isPresent());
        assertFalse(res.getInsertedContentRelation().isPresent());
        assertFalse(res.getBinary().isPresent());
        assertTrue(res.isMemento());
        assertEquals(of(rdf.createIRI("http://example.org/receiver/inbox")), res.getInbox());
        assertEquals(parse("2017-02-16T11:15:03Z"), res.getModified());
        assertEquals(2L, res.getTypes().size());
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Foo")));
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Bar")));
        assertEquals(3L, res.stream().filter(TestUtils.isContainment).count());
        assertEquals(0L, res.stream().filter(TestUtils.isMembership).count());

        final List<VersionRange> mementos = res.getMementos();
        assertEquals(1L, mementos.size());
        assertEquals(parse("2017-02-15T10:05:00Z"), mementos.get(0).getFrom());
        assertEquals(parse("2017-02-15T11:15:00Z"), mementos.get(0).getUntil());

        final List<Triple> triples = res.stream().filter(TestUtils.isUserManaged).map(Quad::asTriple)
                .collect(toList());
        assertEquals(5L, triples.size());
        assertTrue(triples.contains(
                rdf.createTriple(identifier, LDP.inbox, rdf.createIRI("http://example.org/receiver/inbox"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Foo"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Bar"))));
        assertTrue(triples.contains(rdf.createTriple(identifier, RDFS.label, rdf.createLiteral("A label", "eng"))));
        assertTrue(triples.contains(rdf.createTriple(rdf.createIRI("http://example.org/some/other/resource"),
                RDFS.label, rdf.createLiteral("Some other resource", "eng"))));
    }

    @Test
    public void testResourceFuture() {
        final Instant time = parse("2017-03-15T11:15:00Z");
        final Resource res = service.get(identifier, time).get();
        assertEquals(identifier, res.getIdentifier());
        assertEquals(LDP.Container, res.getInteractionModel());
        final List<IRI> contained = res.stream(LDP.PreferContainment).map(Triple::getObject).map(x -> (IRI) x)
                .collect(toList());
        assertEquals(3L, contained.size());
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/1")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/2")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/3")));
        assertFalse(res.getMembershipResource().isPresent());
        assertFalse(res.getMemberRelation().isPresent());
        assertFalse(res.getMemberOfRelation().isPresent());
        assertFalse(res.getInsertedContentRelation().isPresent());
        assertFalse(res.getBinary().isPresent());
        assertTrue(res.isMemento());
        assertEquals(of(rdf.createIRI("http://example.org/receiver/inbox")), res.getInbox());
        assertEquals(parse("2017-02-16T11:15:03Z"), res.getModified());
        assertEquals(2L, res.getTypes().size());
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Foo")));
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Bar")));
        assertEquals(3L, res.stream().filter(TestUtils.isContainment).count());
        assertEquals(0L, res.stream().filter(TestUtils.isMembership).count());

        final List<Triple> triples = res.stream().filter(TestUtils.isUserManaged).map(Quad::asTriple)
                .collect(toList());
        assertEquals(5L, triples.size());
        assertTrue(triples.contains(
                rdf.createTriple(identifier, LDP.inbox, rdf.createIRI("http://example.org/receiver/inbox"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Foo"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Bar"))));
        assertTrue(triples.contains(rdf.createTriple(identifier, RDFS.label, rdf.createLiteral("A label", "eng"))));
        assertTrue(triples.contains(rdf.createTriple(rdf.createIRI("http://example.org/some/other/resource"),
                RDFS.label, rdf.createLiteral("Some other resource", "eng"))));

        final List<VersionRange> mementos = res.getMementos();
        assertEquals(1L, mementos.size());
        assertEquals(parse("2017-02-15T10:05:00Z"), mementos.get(0).getFrom());
        assertEquals(parse("2017-02-15T11:15:00Z"), mementos.get(0).getUntil());
    }

    @Test
    public void testResourcePast() {
        final Instant time = parse("2017-02-15T11:00:00Z");
        final Resource res = service.get(identifier, time).get();
        assertEquals(identifier, res.getIdentifier());
        assertEquals(LDP.Container, res.getInteractionModel());
        assertFalse(res.getMembershipResource().isPresent());
        assertFalse(res.getMemberRelation().isPresent());
        assertFalse(res.getMemberOfRelation().isPresent());
        assertFalse(res.getInsertedContentRelation().isPresent());
        assertFalse(res.getBinary().isPresent());
        assertTrue(res.isMemento());
        assertFalse(res.getInbox().isPresent());
        assertEquals(parse("2017-02-15T10:05:00Z"), res.getModified());
        assertEquals(0L, res.getTypes().size());
        assertEquals(0L, res.stream().filter(TestUtils.isContainment.or(TestUtils.isMembership)).count());

        final List<Triple> triples = res.stream().filter(TestUtils.isUserManaged).map(Quad::asTriple)
                .collect(toList());
        assertEquals(0L, triples.size());

        final List<VersionRange> mementos = res.getMementos();
        assertEquals(1L, mementos.size());
        assertEquals(parse("2017-02-15T10:05:00Z"), mementos.get(0).getFrom());
        assertEquals(parse("2017-02-15T11:15:00Z"), mementos.get(0).getUntil());
    }

    @Test
    public void testResourcePrehistory() {
        final Instant time = parse("2017-01-15T11:00:00Z");
        assertFalse(service.get(identifier, time).isPresent());
    }

    @Test
    public void testCachedResource() {
        final Resource res = service.get(identifier).get();
        assertEquals(identifier, res.getIdentifier());
        assertEquals(LDP.Container, res.getInteractionModel());
        final List<IRI> contained = res.stream(LDP.PreferContainment).map(Triple::getObject).map(x -> (IRI) x)
                .collect(toList());
        assertEquals(3L, contained.size());
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/1")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/2")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/resource/3")));
        assertFalse(res.getMembershipResource().isPresent());
        assertFalse(res.getMemberRelation().isPresent());
        assertFalse(res.getMemberOfRelation().isPresent());
        assertFalse(res.getInsertedContentRelation().isPresent());
        assertFalse(res.getBinary().isPresent());
        assertFalse(res.getAnnotationService().isPresent());
        assertFalse(res.isMemento());
        assertEquals(of(rdf.createIRI("http://example.org/receiver/inbox")), res.getInbox());
        assertEquals(parse("2017-02-16T11:15:03Z"), res.getModified());
        assertEquals(2L, res.getTypes().size());
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Foo")));
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Bar")));
        assertEquals(3L, res.stream().filter(TestUtils.isContainment).count());
        assertEquals(0L, res.stream().filter(TestUtils.isMembership).count());

        final List<Triple> triples = res.stream().filter(TestUtils.isUserManaged).map(Quad::asTriple)
                .collect(toList());
        assertEquals(5L, triples.size());
        assertTrue(triples.contains(
                rdf.createTriple(identifier, LDP.inbox, rdf.createIRI("http://example.org/receiver/inbox"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Foo"))));
        assertTrue(triples
                .contains(rdf.createTriple(identifier, type, rdf.createIRI("http://example.org/types/Bar"))));
        assertTrue(triples.contains(rdf.createTriple(identifier, RDFS.label, rdf.createLiteral("A label", "eng"))));
        assertTrue(triples.contains(rdf.createTriple(rdf.createIRI("http://example.org/some/other/resource"),
                RDFS.label, rdf.createLiteral("Some other resource", "eng"))));

        final List<VersionRange> mementos = res.getMementos();
        assertEquals(1L, mementos.size());
        assertEquals(parse("2017-02-15T10:05:00Z"), mementos.get(0).getFrom());
        assertEquals(parse("2017-02-15T11:15:00Z"), mementos.get(0).getUntil());
    }

    @Test
    public void testOtherCachedResource() {
        final Resource res = service.get(other).get();
        assertEquals(other, res.getIdentifier());
        assertEquals(LDP.Container, res.getInteractionModel());
        final List<IRI> contained = res.stream(LDP.PreferContainment).map(Triple::getObject).map(x -> (IRI) x)
                .collect(toList());
        assertEquals(3L, contained.size());
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/other/1")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/other/2")));
        assertTrue(contained.contains(rdf.createIRI("trellis:repository/other/3")));
        assertFalse(res.getMembershipResource().isPresent());
        assertFalse(res.getMemberRelation().isPresent());
        assertFalse(res.getMemberOfRelation().isPresent());
        assertFalse(res.getInsertedContentRelation().isPresent());
        assertFalse(res.getBinary().isPresent());
        assertFalse(res.getAnnotationService().isPresent());
        assertTrue(res.isMemento());
        assertEquals(of(rdf.createIRI("http://example.org/receiver/inbox")), res.getInbox());
        assertEquals(parse("2017-02-16T11:15:03Z"), res.getModified());
        assertEquals(2L, res.getTypes().size());
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Foo")));
        assertTrue(res.getTypes().contains(rdf.createIRI("http://example.org/types/Bar")));
        assertEquals(3L, res.stream().filter(TestUtils.isContainment).count());
        assertEquals(0L, res.stream().filter(TestUtils.isMembership).count());

        final List<Triple> triples = res.stream().filter(TestUtils.isUserManaged).map(Quad::asTriple)
                .collect(toList());
        assertEquals(5L, triples.size());
        assertTrue(triples
                .contains(rdf.createTriple(other, LDP.inbox, rdf.createIRI("http://example.org/receiver/inbox"))));
        assertTrue(triples.contains(rdf.createTriple(other, type, rdf.createIRI("http://example.org/types/Foo"))));
        assertTrue(triples.contains(rdf.createTriple(other, type, rdf.createIRI("http://example.org/types/Bar"))));
        assertTrue(triples.contains(rdf.createTriple(other, RDFS.label, rdf.createLiteral("A label", "eng"))));
        assertTrue(triples.contains(rdf.createTriple(rdf.createIRI("http://example.org/some/other/resource"),
                RDFS.label, rdf.createLiteral("Some other resource", "eng"))));

        final List<VersionRange> mementos = res.getMementos();
        assertEquals(1L, mementos.size());
        assertEquals(parse("2017-02-15T10:05:00Z"), mementos.get(0).getFrom());
        assertEquals(parse("2017-02-15T11:15:00Z"), mementos.get(0).getUntil());
    }

    @Test
    public void testList() throws Exception {
        final String path = new File(getClass().getResource("/rootList").toURI()).getAbsolutePath();
        partitions.put("repository", path);
        final List<Triple> triples = service.list("repository").collect(toList());
        assertEquals(3L, triples.size());
        assertTrue(triples.contains(rdf.createTriple(testResource, type, LDP.RDFSource)));
        assertTrue(triples.contains(rdf.createTriple(identifier, type, LDP.Container)));
        assertTrue(triples.contains(rdf.createTriple(rdf.createIRI("trellis:repository"), type, LDP.Container)));
    }

    @Test
    public void testExport() throws Exception {
        final String path = new File(getClass().getResource("/rootList").toURI()).getAbsolutePath();
        final IRI root = rdf.createIRI("trellis:repository");
        partitions.put("repository", path);
        final List<Quad> quads = service.export("repository", singleton(Trellis.PreferUserManaged))
                .collect(toList());
        assertEquals(6L, quads.size());
        assertTrue(
                quads.contains(rdf.createQuad(testResource, testResource, DC.title, rdf.createLiteral("A title"))));
        assertTrue(quads.contains(rdf.createQuad(identifier, identifier, LDP.inbox,
                rdf.createIRI("http://example.org/receiver/inbox"))));
        assertTrue(quads.contains(
                rdf.createQuad(identifier, identifier, type, rdf.createIRI("http://example.org/types/Foo"))));
        assertTrue(quads.contains(
                rdf.createQuad(identifier, identifier, type, rdf.createIRI("http://example.org/types/Bar"))));
        assertTrue(quads
                .contains(rdf.createQuad(identifier, identifier, RDFS.label, rdf.createLiteral("A label", "eng"))));
        assertTrue(
                quads.contains(rdf.createQuad(identifier, rdf.createIRI("http://example.org/some/other/resource"),
                        RDFS.label, rdf.createLiteral("Some other resource", "eng"))));

        // Test server managed expport
        final List<Quad> otherQuads = service.export("repository", singleton(Trellis.PreferServerManaged))
                .collect(toList());
        assertEquals(6L, otherQuads.size());
        assertTrue(otherQuads.contains(rdf.createQuad(testResource, testResource, type, LDP.RDFSource)));
        assertTrue(otherQuads.contains(rdf.createQuad(testResource, testResource, DC.modified,
                rdf.createLiteral("2017-09-05T13:49:58.417Z", XSD.dateTime))));
        assertTrue(otherQuads.contains(rdf.createQuad(root, root, type, LDP.Container)));
        assertTrue(otherQuads.contains(rdf.createQuad(root, root, DC.modified,
                rdf.createLiteral("2017-09-05T13:49:58.012Z", XSD.dateTime))));
        assertTrue(otherQuads.contains(rdf.createQuad(identifier, identifier, type, LDP.Container)));
        assertTrue(otherQuads.contains(rdf.createQuad(identifier, identifier, DC.modified,
                rdf.createLiteral("2017-02-16T11:15:03Z", XSD.dateTime))));
    }

    @Test
    public void testListNoPartition() {
        assertEquals(0L, service.list("non-existent").count());
    }

    @Test
    public void testListInvalidPath() throws Exception {
        final Map<String, String> myPartitions = singletonMap("foo",
                new File(getClass().getResource("/rootList").toURI()).getAbsolutePath() + separator
                        + "non-existent");
        service = new FileResourceService(myPartitions, curator, mockProducer, mockEventService, mockIdSupplier,
                false);
        assertEquals(1L, service.list("foo").count());
        assertEquals(of(rdf.createTriple(rdf.createIRI("trellis:foo"), type, LDP.Container)),
                service.list("foo").findFirst());
        assertEquals(0L, service.list("error").count());
    }

    @Test
    public void testPurge() throws Exception {
        final Map<String, String> myPartitions = singletonMap("repository",
                new File(getClass().getResource("/purgeable").toURI()).getAbsolutePath());
        service = new FileResourceService(myPartitions, curator, mockProducer, mockEventService, mockIdSupplier,
                false);
        assertTrue(service.get(identifier).isPresent());
        final List<IRI> binaries = service.purge(identifier).collect(toList());
        assertEquals(1L, binaries.size());
        assertEquals(rdf.createIRI("s3://bucket/some-resource"), binaries.get(0));

        assertFalse(service.get(identifier).isPresent());

        assertTrue(service.get(testResource).isPresent());
        assertEquals(0L, service.purge(testResource).count());
        assertFalse(service.get(testResource).isPresent());
    }

    @Test(expected = UnsupportedOperationException.class)
    public void testCompact() {
        service.compact(identifier, now(), now());
    }
}