org.trellisldp.triplestore.TriplestoreResourceServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.trellisldp.triplestore.TriplestoreResourceServiceTest.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.triplestore;

import static java.time.Instant.now;
import static java.util.concurrent.CompletableFuture.allOf;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.function.Predicate.isEqual;
import static org.apache.jena.query.DatasetFactory.wrap;
import static org.apache.jena.rdfconnection.RDFConnectionFactory.connect;
import static org.awaitility.Awaitility.await;
import static org.awaitility.Awaitility.setDefaultPollInterval;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.trellisldp.api.Metadata.builder;
import static org.trellisldp.api.Resource.SpecialResources.DELETED_RESOURCE;
import static org.trellisldp.api.Resource.SpecialResources.MISSING_RESOURCE;
import static org.trellisldp.api.TrellisUtils.TRELLIS_DATA_PREFIX;

import java.io.File;
import java.time.Instant;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.apache.commons.rdf.api.BlankNode;
import org.apache.commons.rdf.api.Dataset;
import org.apache.commons.rdf.api.IRI;
import org.apache.commons.rdf.api.Literal;
import org.apache.commons.rdf.jena.JenaDataset;
import org.apache.commons.rdf.jena.JenaRDF;
import org.apache.jena.rdfconnection.RDFConnection;
import org.apache.jena.rdfconnection.RDFConnectionLocal;
import org.apache.jena.rdfconnection.RDFConnectionRemote;
import org.apache.jena.update.UpdateRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.Mock;
import org.trellisldp.api.BinaryMetadata;
import org.trellisldp.api.Resource;
import org.trellisldp.api.ResourceService;
import org.trellisldp.vocabulary.AS;
import org.trellisldp.vocabulary.DC;
import org.trellisldp.vocabulary.LDP;
import org.trellisldp.vocabulary.PROV;
import org.trellisldp.vocabulary.RDF;
import org.trellisldp.vocabulary.RDFS;
import org.trellisldp.vocabulary.SKOS;
import org.trellisldp.vocabulary.Trellis;
import org.trellisldp.vocabulary.XSD;

/**
 * Test the TriplestoreResourceService class.
 */
public class TriplestoreResourceServiceTest {

    private static final JenaRDF rdf = new JenaRDF();
    private static final IRI root = rdf.createIRI(TRELLIS_DATA_PREFIX);
    private static final IRI resource = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource");
    private static final IRI resource2 = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource2");
    private static final IRI members = rdf.createIRI(TRELLIS_DATA_PREFIX + "members");
    private static final IRI child = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource/child");
    private static final IRI child2 = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource2/child");

    static {
        setDefaultPollInterval(100L, MILLISECONDS);
    }

    @Mock
    private RDFConnection mockRdfConnection;

    @BeforeEach
    public void setUp() {
        initMocks(this);
    }

    @Test
    public void testIdentifierService() {
        final ResourceService svc = new TriplestoreResourceService();
        assertNotEquals(svc.generateIdentifier(), svc.generateIdentifier(), "Not unique identifiers!");
        assertNotEquals(svc.generateIdentifier(), svc.generateIdentifier(), "Not unique identifiers!");
    }

    @Test
    public void testResourceNotFound() {
        final ResourceService svc = new TriplestoreResourceService();
        assertEquals(MISSING_RESOURCE,
                svc.get(rdf.createIRI(TRELLIS_DATA_PREFIX + "missing")).toCompletableFuture().join(),
                "Not a missing resource!");
    }

    @Test
    public void testNoRoot() {
        final ResourceService svc = new TriplestoreResourceService();

        assertEquals(MISSING_RESOURCE, svc.get(rdf.createIRI(TRELLIS_DATA_PREFIX)).toCompletableFuture().join(),
                "Not a missing resource!");
    }

    @Test
    public void testInitializeRoot() {
        final Instant early = now();
        final TriplestoreResourceService svc = new TriplestoreResourceService();
        svc.initialize();

        final Resource res = svc.get(root).toCompletableFuture().join();
        assertAll("Check resource", checkResource(res, root, LDP.BasicContainer, early));
        assertAll("Check resource stream", checkResourceStream(res, 0L, 5L, 0L, 0L, 0L));
    }

    @Test
    public void testInitializeRoot2() {
        final Instant early = now();
        final JenaDataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferServerManaged, root, RDF.type, LDP.BasicContainer);
        dataset.add(Trellis.PreferServerManaged, root, DC.modified,
                rdf.createLiteral(early.toString(), XSD.dateTime));

        final RDFConnection rdfConnection = connect(wrap(dataset.asJenaDatasetGraph()));
        final TriplestoreResourceService svc = new TriplestoreResourceService(rdfConnection);
        svc.initialize();

        final Resource res = svc.get(root).toCompletableFuture().join();
        assertAll("Check resource", checkResource(res, root, LDP.BasicContainer, early));
        assertAll("Check resource stream", checkResourceStream(res, 0L, 0L, 0L, 0L, 0L));
    }

    @Test
    public void testUpdateRoot() throws Exception {
        final Instant early = now();
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Resource res1 = svc.get(root).toCompletableFuture().join();
        assertAll("Check resource", checkResource(res1, root, LDP.BasicContainer, early));
        assertAll("Check resource stream", checkResourceStream(res1, 0L, 5L, 0L, 0L, 0L));

        final Dataset data = rdf.createDataset();
        svc.get(root)
                .thenAccept(res -> res.stream()
                        .filter(q -> !q.getGraphName().filter(Trellis.PreferServerManaged::equals).isPresent())
                        .forEach(data::add))
                .toCompletableFuture().join();
        data.add(Trellis.PreferUserManaged, root, RDFS.label, rdf.createLiteral("Resource Label"));
        data.add(Trellis.PreferUserManaged, root, RDFS.seeAlso, rdf.createIRI("http://example.com"));
        data.add(Trellis.PreferUserManaged, root, LDP.inbox, rdf.createIRI("http://ldn.example.com/"));
        data.add(Trellis.PreferUserManaged, root, RDF.type, rdf.createLiteral("Some weird type"));
        data.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Update);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> svc.replace(builder(root).interactionModel(LDP.BasicContainer).build(), data)
                .toCompletableFuture().join(), "Unsuccessful replace operation!");
        final Resource res2 = svc.get(root).toCompletableFuture().join();
        assertAll("Check resource", checkResource(res2, root, LDP.BasicContainer, later));
        assertAll("Check resource stream", checkResourceStream(res2, 4L, 5L, 1L, 0L, 0L));
    }

    @Test
    public void testRDFConnectionError() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(mockRdfConnection);
        svc.initialize();
        doThrow(new RuntimeException("Expected exception")).when(mockRdfConnection)
                .update(any(UpdateRequest.class));
        doThrow(new RuntimeException("Expected exception")).when(mockRdfConnection)
                .loadDataset(any(org.apache.jena.query.Dataset.class));

        assertThrows(ExecutionException.class,
                () -> svc.create(builder(resource).interactionModel(LDP.RDFSource).container(root).build(),
                        rdf.createDataset()).toCompletableFuture().get(),
                "No (create) exception with dropped backend connection!");
        assertThrows(ExecutionException.class,
                () -> svc.add(resource, rdf.createDataset()).toCompletableFuture().get(),
                "No (add) exception with dropped backend connection!");
        assertThrows(ExecutionException.class,
                () -> svc.delete(builder(resource).interactionModel(LDP.RDFSource).container(root).build())
                        .toCompletableFuture().get(),
                "No (delete) exception with dropped backend connection!");
        assertThrows(ExecutionException.class, () -> svc.touch(resource).toCompletableFuture().get(),
                "No (touch) exception with dropped backend connection!");
    }

    @Test
    public void testPutLdpRs() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        final BlankNode bnode = rdf.createBlankNode();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.RDFSource, 1L, 3L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpRsWithoutBaseUrl() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.RDFSource, 1L, 1L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpNr() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final IRI binaryIdentifier = rdf.createIRI("foo:binary");
        final Dataset dataset = rdf.createDataset();
        final BinaryMetadata binary = BinaryMetadata.builder(binaryIdentifier).mimeType("text/plain").build();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(
                        svc.create(builder(resource).interactionModel(LDP.NonRDFSource).container(root)
                                .binary(binary).build(), dataset).toCompletableFuture(),
                        svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.NonRDFSource, 1L, 1L, 0L))
                .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(
                                res -> assertAll("Check binary", checkBinary(res, binaryIdentifier, "text/plain")))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();

        final IRI resource3 = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource/notachild");
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, resource3, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(() -> svc.create(builder(resource3).interactionModel(LDP.RDFSource).build(), dataset)
                .toCompletableFuture().join(), "Unsuccessful create operation!");

        allOf(svc.get(resource3).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource3, LDP.RDFSource, evenLater));
            assertAll("Check resource stream", checkResourceStream(res, 1L, 0L, 1L, 0L, 0L));
            assertFalse(res.getBinaryMetadata().isPresent(), "Unexpected binary metadata!");
        }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater)).toCompletableFuture(),
                svc.get(root)
                        .thenAccept(res -> assertFalse(res.getBinaryMetadata().isPresent(),
                                "unexpected binary metadata!"))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.NonRDFSource, 1L, 1L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpC() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        final BlankNode bnode = rdf.createBlankNode();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("resource"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.alternative, rdf.createLiteral("alt title"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("description"));
        dataset.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.Container).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.Container, 3L, 3L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();

        // Now add a child resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("child"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater, 1L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater, LDP.Container, 3L, 3L, 1L))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater)).toCompletableFuture()).join();

        // Now update that child resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.description, rdf.createLiteral("a description"));
        dataset.add(Trellis.PreferUserManaged, child, RDFS.label, rdf.createLiteral("other title"));
        dataset.add(Trellis.PreferUserManaged, child, RDFS.seeAlso, rdf.createIRI("http://example.com"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Update);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> svc
                .replace(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                .toCompletableFuture().join(), "Unsuccessful create operation!");
        allOf(svc.get(child).thenAccept(checkChild(evenLater2, 3L, 2L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater, LDP.Container, 3L, 3L, 1L))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testAddAuditTriples() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset1 = rdf.createDataset();
        final Dataset dataset2 = rdf.createDataset();
        final BlankNode bnode = rdf.createBlankNode();
        dataset1.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("resource"));
        dataset1.add(Trellis.PreferUserManaged, resource, DC.alternative, rdf.createLiteral("alt title"));
        dataset2.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode);
        dataset2.add(Trellis.PreferAudit, bnode, RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource).interactionModel(LDP.Container).container(root).build(), dataset1)
                        .toCompletableFuture(),
                svc.add(resource, dataset2).toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.Container, 2L, 2L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();
    }

    @Test
    public void testPutDeleteLdpC() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("resource title"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("resource description"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.Container).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.Container, 2L, 1L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture()).join();

        // Now add a child resource
        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("child"));
        dataset.add(Trellis.PreferUserManaged, child, DC.description, rdf.createLiteral("nested resource"));

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater, 2L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater, LDP.Container, 2L, 1L, 1L))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater)).toCompletableFuture()).join();

        // Now delete the child resource
        final BlankNode bnode = rdf.createBlankNode();
        dataset.clear();
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, AS.Delete);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferServerManaged, child, RDF.type, LDP.Resource);

        final Instant preDelete = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc.delete(builder(child).interactionModel(LDP.RDFSource).container(resource).build())
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful delete operation!");

        allOf(svc.get(child).thenAccept(res -> assertEquals(DELETED_RESOURCE, res, "Incorrect resource object!"))
                .toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(preDelete, LDP.Container, 2L, 1L, 0L))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(preDelete)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpBc() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.alternative, rdf.createLiteral("alt title"));
        dataset.add(Trellis.PreferUserManaged, resource, RDFS.label, rdf.createLiteral("a label"));

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(
                        svc.create(builder(resource).interactionModel(LDP.BasicContainer).container(root).build(),
                                dataset).toCompletableFuture(),
                        svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.BasicContainer, 3L, 0L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add a child resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("title"));
        dataset.add(Trellis.PreferUserManaged, child, RDFS.label, rdf.createLiteral("label"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater, 2L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater, LDP.BasicContainer, 3L, 0L, 1L))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater)).toCompletableFuture()).join();

        // Now update the child resource
        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Update);
        dataset.add(Trellis.PreferUserManaged, child, RDFS.seeAlso, rdf.createIRI("http://www.example.com/"));
        dataset.add(Trellis.PreferUserManaged, child, RDFS.label, rdf.createLiteral("a label"));

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> svc
                .replace(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                .toCompletableFuture().join(), "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater2, 2L, 2L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater, LDP.BasicContainer, 3L, 0L, 1L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpDcSelf() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("direct container"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.alternative, rdf.createLiteral("alt title"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description,
                rdf.createLiteral("LDP-DC pointing to self"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, resource);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, DC.relation);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.DirectContainer).membershipResource(resource)
                                .memberRelation(DC.relation).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 5L, 0L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add the child resources to the ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("ldp-dc (self) child resource"));

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater, 1L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(res -> {
                    assertAll("Check resource", checkResource(res, resource, LDP.DirectContainer, evenLater));
                    assertAll("Check resource stream", checkResourceStream(res, 5L, 0L, 0L, 1L, 1L));
                    assertTrue(
                            res.stream(LDP.PreferContainment)
                                    .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                            "Missing contains triple!");
                    assertTrue(
                            res.stream(LDP.PreferMembership)
                                    .anyMatch(isEqual(rdf.createTriple(resource, DC.relation, child))),
                            "Missing membership triple!");
                }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpDc() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("direct container"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("LDP-DC test"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, DC.relation);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.DirectContainer).container(root)
                                .memberRelation(DC.relation).membershipResource(members).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 4L, 0L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add a membership resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("member resource"));

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(members).thenAccept(checkMember(evenLater, 1L, 0L, 0L)).toCompletableFuture(), svc
                .get(members)
                .thenAccept(res -> assertFalse(res.getBinaryMetadata().isPresent(), "Unexpected binary metadata!"))
                .toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 4L, 0L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("ldp-dc child resource"));

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater2, 1L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater2, LDP.DirectContainer, 4L, 0L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 0L, 1L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, DC.relation, child))),
                                "Missing membership triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpDcMultiple() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("direct container"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("multiple LDP-DC test"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, DC.relation);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.DirectContainer).container(root)
                                .membershipResource(members).memberRelation(DC.relation).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 4L, 1L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);
        dataset.add(Trellis.PreferUserManaged, resource2, DC.title, rdf.createLiteral("second LDP-DC"));
        dataset.add(Trellis.PreferUserManaged, resource2, DC.description, rdf.createLiteral("another LDP-DC"));
        dataset.add(Trellis.PreferUserManaged, resource2, RDFS.label, rdf.createLiteral("test multple LDP-DCs"));
        dataset.add(Trellis.PreferUserManaged, resource2, SKOS.prefLabel,
                rdf.createLiteral("test multple LDP-DCs"));
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.hasMemberRelation, DC.subject);

        final Instant later2 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource2).interactionModel(LDP.DirectContainer).container(root)
                                .membershipResource(members).memberRelation(DC.subject).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource2, LDP.DirectContainer, later2));
            assertAll("Check resource stream", checkResourceStream(res, 6L, 0L, 1L, 0L, 0L));
        }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later2, 2L)).toCompletableFuture()).join();

        // Now add a membership resource
        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("member resource"));
        dataset.add(Trellis.PreferUserManaged, members, DC.description,
                rdf.createLiteral("LDP-RS membership test"));

        final Instant later3 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(members).thenAccept(checkMember(later3, 2L, 1L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 4L, 1L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(later3)).toCompletableFuture(),
                svc.get(resource2).thenAccept(checkPredates(later3)).toCompletableFuture(),
                svc.get(resource2)
                        .thenAccept(res -> assertAll("Check resource stream",
                                checkResourceStream(res, 6L, 0L, 1L, 0L, 0L)))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later3, 3L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("ldp-dc (1) child resource"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later4 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(resource).toCompletableFuture(), svc.touch(members).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(later4, 1L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later2, LDP.DirectContainer, 4L, 1L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(later4, 2L, 1L, 1L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, DC.relation, child))),
                                "Missing membership triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later3, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(later4)).toCompletableFuture()).join();

        // Now add a child resources to the other ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);
        dataset.add(Trellis.PreferUserManaged, child2, DC.title, rdf.createLiteral("ldp-dc (2) child resource"));

        final Instant later5 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child2).interactionModel(LDP.RDFSource).container(resource2).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource2).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, child2, LDP.RDFSource, later5));
            assertAll("Check resource stream", checkResourceStream(res, 1L, 0L, 1L, 0L, 0L));
        }).toCompletableFuture(), svc.get(resource2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource2, LDP.DirectContainer, later5));
            assertAll("Check resource stream", checkResourceStream(res, 6L, 0L, 1L, 0L, 1L));
            assertTrue(
                    res.stream(LDP.PreferContainment)
                            .anyMatch(isEqual(rdf.createTriple(resource2, LDP.contains, child2))),
                    "Missing contains triple!");
        }).toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(later5, 2L, 1L, 2L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, DC.subject, child2))),
                                "Missing membership triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(later3, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(later5)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpDcMultipleInverse() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("direct container inverse"));
        dataset.add(Trellis.PreferUserManaged, resource, RDFS.label, rdf.createLiteral("LDP-DC test"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("LDP-DC inverse test"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.isMemberOfRelation, DC.relation);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource).interactionModel(LDP.DirectContainer).container(root)
                                .membershipResource(members).memberOfRelation(DC.relation).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 5L, 1L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, resource2, DC.title, rdf.createLiteral("Second LDP-DC"));
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.isMemberOfRelation, DC.subject);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(resource2).interactionModel(LDP.DirectContainer).container(root)
                                .membershipResource(members).memberOfRelation(DC.subject).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource2, LDP.DirectContainer, evenLater));
            assertAll("Check resource stream", checkResourceStream(res, 3L, 0L, 1L, 0L, 0L));
        }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add a membership resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("Membership resource"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful membership resource create operation!");

        allOf(svc.get(members).thenAccept(checkMember(evenLater2, 1L, 1L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.DirectContainer, 5L, 1L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(resource2).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(resource2)
                        .thenAccept(res -> assertAll("Check resource stream",
                                checkResourceStream(res, 3L, 0L, 1L, 0L, 0L)))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater2, 3L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, DC.title, rdf.createLiteral("Child resource"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater3 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, child, LDP.RDFSource, evenLater3));
            assertAll("Check resource stream", checkResourceStream(res, 1L, 0L, 1L, 1L, 0L));
        }).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater3, LDP.DirectContainer, 5L, 1L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 1L, 0L)).toCompletableFuture(),
                svc.get(members).thenAccept(checkPredates(evenLater3)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater2, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater3)).toCompletableFuture()).join();

        // Now add a child resources to the other ldp-dc
        dataset.clear();
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);
        dataset.add(Trellis.PreferUserManaged, child2, DC.title, rdf.createLiteral("Second child resource"));

        final Instant evenLater4 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc.create(builder(child2).interactionModel(LDP.RDFSource).container(resource2).build(),
                        dataset).toCompletableFuture(), svc.touch(resource2).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, child2, LDP.RDFSource, evenLater4));
            assertAll("Check resource stream", checkResourceStream(res, 1L, 0L, 1L, 1L, 0L));
        }).toCompletableFuture(), svc.get(resource2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource2, LDP.DirectContainer, evenLater4));
            assertAll("Check resource stream", checkResourceStream(res, 3L, 0L, 1L, 0L, 1L));
            assertTrue(
                    res.stream(LDP.PreferContainment)
                            .anyMatch(isEqual(rdf.createTriple(resource2, LDP.contains, child2))),
                    "Missing contains triple!");
        }).toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 1L, 0L)).toCompletableFuture(),
                svc.get(members).thenAccept(checkPredates(evenLater4)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater2, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater4)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpIc() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        final BlankNode bnode0 = rdf.createBlankNode();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("Indirect Container"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description, rdf.createLiteral("Test LDP-IC"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.subject, rdf.createIRI("http://example.com/subject"));
        dataset.add(Trellis.PreferUserManaged, resource, RDF.type, SKOS.Concept);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, RDFS.label);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.insertedContentRelation, SKOS.prefLabel);
        dataset.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode0);
        dataset.add(Trellis.PreferAudit, bnode0, PROV.atTime, rdf.createLiteral(now().toString(), XSD.dateTime));
        dataset.add(Trellis.PreferAudit, bnode0, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, bnode0, RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource).interactionModel(LDP.IndirectContainer).container(root)
                        .membershipResource(members).memberRelation(RDFS.label)
                        .insertedContentRelation(SKOS.prefLabel).build(), dataset).toCompletableFuture(),
                svc.touch(root).toCompletableFuture()).join(), "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 7L, 4L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add a membership resource
        final BlankNode bnode1 = rdf.createBlankNode();
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("Membership resource"));
        dataset.add(Trellis.PreferAudit, members, PROV.wasGeneratedBy, bnode1);
        dataset.add(Trellis.PreferAudit, bnode1, PROV.atTime, rdf.createLiteral(now().toString(), XSD.dateTime));
        dataset.add(Trellis.PreferAudit, bnode1, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, bnode1, RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(members).thenAccept(checkMember(evenLater, 1L, 4L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 7L, 4L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        final BlankNode bnode2 = rdf.createBlankNode();
        final Literal label = rdf.createLiteral("label-1");
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, SKOS.prefLabel, label);
        dataset.add(Trellis.PreferAudit, child, PROV.wasGeneratedBy, bnode2);
        dataset.add(Trellis.PreferAudit, bnode2, RDF.type, AS.Create);
        dataset.add(Trellis.PreferAudit, bnode2, RDF.type, PROV.Activity);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater2, 1L, 3L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater2, LDP.IndirectContainer, 7L, 4L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 4L, 1L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label))),
                                "Missing member triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpIcDefaultContent() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("Indirect Container"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description,
                rdf.createLiteral("LDP-IC with default content"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, RDFS.label);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.insertedContentRelation, LDP.MemberSubject);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource).interactionModel(LDP.IndirectContainer).container(root)
                        .membershipResource(members).memberRelation(RDFS.label)
                        .insertedContentRelation(LDP.MemberSubject).build(), dataset).toCompletableFuture(),
                svc.touch(root).toCompletableFuture()).join(), "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 5L, 1L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add a membership resource
        final BlankNode bnode = rdf.createBlankNode();
        dataset.clear();
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, AS.Create);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("Member resource"));

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 5L, 1L, 0L))
                .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater)).toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater, 1L, 2L, 0L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        final Literal label = rdf.createLiteral("label1");
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, SKOS.prefLabel, label);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater2, 1L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater2, LDP.IndirectContainer, 5L, 1L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 2L, 1L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, child))),
                                "Missing membership triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpIcMultipleStatements() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        final BlankNode bnode = rdf.createBlankNode();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("LDP-IC with multiple stmts"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, RDFS.label);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.insertedContentRelation, SKOS.prefLabel);
        dataset.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource).interactionModel(LDP.IndirectContainer).container(root)
                        .membershipResource(members).memberRelation(RDFS.label)
                        .insertedContentRelation(SKOS.prefLabel).build(), dataset).toCompletableFuture(),
                svc.touch(root).toCompletableFuture()).join(), "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 4L, 2L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        // Now add a membership resource
        dataset.clear();
        final BlankNode bnode2 = rdf.createBlankNode();
        dataset.add(Trellis.PreferAudit, bnode2, RDF.type, AS.Create);
        dataset.add(Trellis.PreferAudit, bnode2, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, members, PROV.wasGeneratedBy, bnode2);
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("Membership LDP-RS"));

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(members).thenAccept(checkMember(evenLater, 1L, 3L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 4L, 2L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater)).toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-dc
        final Literal label1 = rdf.createLiteral("Label", "en");
        final Literal label2 = rdf.createLiteral("Zeichnung", "de");
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, SKOS.prefLabel, label1);
        dataset.add(Trellis.PreferUserManaged, child, SKOS.prefLabel, label2);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(
                child).thenAccept(
                        checkChild(evenLater2, 2L, 1L))
                .toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater2, LDP.IndirectContainer, 4L, 2L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater2, 1L, 3L, 2L)).toCompletableFuture(),
                svc.get(members).thenAccept(res -> {
                    assertTrue(
                            res.stream(LDP.PreferMembership)
                                    .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label2))),
                            "Missing member triple (1)!");
                    assertTrue(
                            res.stream(LDP.PreferMembership)
                                    .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label1))),
                            "Missing member triple (2)!");
                }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater2)).toCompletableFuture()).join();
    }

    @Test
    public void testPutLdpIcMultipleResources() throws Exception {
        final TriplestoreResourceService svc = new TriplestoreResourceService(
                connect(wrap(rdf.createDataset().asJenaDatasetGraph())));
        svc.initialize();

        final Dataset dataset = rdf.createDataset();
        final BlankNode bnode = rdf.createBlankNode();
        dataset.add(Trellis.PreferUserManaged, resource, DC.title, rdf.createLiteral("First LDP-IC"));
        dataset.add(Trellis.PreferUserManaged, resource, DC.description,
                rdf.createLiteral("Test multiple LDP-ICs"));
        dataset.add(Trellis.PreferUserManaged, resource, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.hasMemberRelation, RDFS.label);
        dataset.add(Trellis.PreferUserManaged, resource, LDP.insertedContentRelation, SKOS.prefLabel);
        dataset.add(Trellis.PreferAudit, resource, PROV.wasGeneratedBy, bnode);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, PROV.Activity);
        dataset.add(Trellis.PreferAudit, bnode, RDF.type, AS.Create);

        final Instant later = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource).interactionModel(LDP.IndirectContainer).container(root)
                        .membershipResource(members).memberRelation(RDFS.label)
                        .insertedContentRelation(SKOS.prefLabel).build(), dataset).toCompletableFuture(),
                svc.touch(root).toCompletableFuture()).join(), "Unsuccessful create operation!");

        allOf(svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 5L, 3L, 0L))
                .toCompletableFuture(), svc.get(root).thenAccept(checkRoot(later, 1L)).toCompletableFuture())
                        .join();

        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, resource2, DC.title, rdf.createLiteral("Second LDP-IC"));
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.membershipResource, members);
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.hasMemberRelation, RDFS.label);
        dataset.add(Trellis.PreferUserManaged, resource2, LDP.insertedContentRelation, SKOS.prefLabel);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(resource2).interactionModel(LDP.IndirectContainer).container(root)
                        .membershipResource(members).memberRelation(RDFS.label)
                        .insertedContentRelation(SKOS.prefLabel).build(), dataset).toCompletableFuture(),
                svc.touch(root).toCompletableFuture()).join(), "Unsuccessful create operation!");

        allOf(svc.get(resource2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, resource2, LDP.IndirectContainer, evenLater));
            assertAll("Check resource stream", checkResourceStream(res, 4L, 0L, 1L, 0L, 0L));
        }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(evenLater, 2L)).toCompletableFuture()).join();

        // Now add a membership resource
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, members, DC.title, rdf.createLiteral("Shared member resource"));
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater2 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(svc
                        .create(builder(members).interactionModel(LDP.RDFSource).container(root).build(), dataset)
                        .toCompletableFuture(), svc.touch(root).toCompletableFuture()).join(),
                "Unsuccessful member resource creation operation!");

        allOf(svc.get(members).thenAccept(checkMember(evenLater2, 1L, 1L, 0L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(later, LDP.IndirectContainer, 5L, 3L, 0L))
                        .toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(resource2).thenAccept(checkPredates(evenLater2)).toCompletableFuture(),
                svc.get(resource2)
                        .thenAccept(res -> assertAll("Check resource stream",
                                checkResourceStream(res, 4L, 0L, 1L, 0L, 0L)))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 3L)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-ic
        final Literal label = rdf.createLiteral("first label");
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child, SKOS.prefLabel, label);
        dataset.add(Trellis.PreferAudit, rdf.createBlankNode(), RDF.type, AS.Create);

        final Instant evenLater3 = meanwhile();

        assertDoesNotThrow(
                () -> allOf(
                        svc.create(builder(child).interactionModel(LDP.RDFSource).container(resource).build(),
                                dataset).toCompletableFuture(),
                        svc.touch(members).toCompletableFuture(), svc.touch(resource).toCompletableFuture()).join(),
                "Unsuccessful child creation operation!");

        allOf(svc.get(child).thenAccept(checkChild(evenLater3, 1L, 1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater3, LDP.IndirectContainer, 5L, 3L, 1L))
                        .toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing contains triple!"))
                        .toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater3, 1L, 1L, 1L)).toCompletableFuture(),
                svc.get(members)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferMembership)
                                        .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label))),
                                "Missing membership triple!"))
                        .toCompletableFuture(),
                svc.get(root).thenAccept(checkRoot(evenLater, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater3)).toCompletableFuture()).join();

        // Now add the child resources to the ldp-ic
        final Literal label2 = rdf.createLiteral("second label");
        final BlankNode bnode2 = rdf.createBlankNode();
        dataset.clear();
        dataset.add(Trellis.PreferUserManaged, child2, SKOS.prefLabel, label2);
        dataset.add(Trellis.PreferAudit, child2, PROV.wasGeneratedBy, bnode2);
        dataset.add(Trellis.PreferAudit, bnode2, RDF.type, AS.Create);
        dataset.add(Trellis.PreferAudit, bnode2, PROV.atTime, rdf.createLiteral(now().toString(), XSD.dateTime));

        final Instant evenLater4 = meanwhile();

        assertDoesNotThrow(() -> allOf(
                svc.create(builder(child2).interactionModel(LDP.RDFSource).container(resource2).build(), dataset)
                        .toCompletableFuture(),
                svc.touch(members).toCompletableFuture(), svc.touch(resource2).toCompletableFuture()).join(),
                "Unsuccessful create operation!");

        allOf(svc.get(child2).thenAccept(res -> {
            assertAll("Check resource", checkResource(res, child2, LDP.RDFSource, evenLater4));
            assertAll("Check resource stream", checkResourceStream(res, 1L, 0L, 3L, 0L, 0L));
        }).toCompletableFuture(),
                svc.get(resource).thenAccept(checkResource(evenLater3, LDP.IndirectContainer, 5L, 3L,
                        1L)).toCompletableFuture(),
                svc.get(resource).thenAccept(checkPredates(evenLater4)).toCompletableFuture(),
                svc.get(resource)
                        .thenAccept(res -> assertTrue(
                                res.stream(LDP.PreferContainment)
                                        .anyMatch(isEqual(rdf.createTriple(resource, LDP.contains, child))),
                                "Missing containment triple!"))
                        .toCompletableFuture(),
                svc.get(resource2).thenAccept(res -> {
                    assertAll("Check resource", checkResource(res, resource2, LDP.IndirectContainer, evenLater4));
                    assertAll("Check resource stream", checkResourceStream(res, 4L, 0L, 1L, 0L, 1L));
                    assertTrue(
                            res.stream(LDP.PreferContainment)
                                    .anyMatch(isEqual(rdf.createTriple(resource2, LDP.contains, child2))),
                            "Missing containment triple!");
                }).toCompletableFuture(),
                svc.get(members).thenAccept(checkMember(evenLater4, 1L, 1L, 2L)).toCompletableFuture(),
                svc.get(members).thenAccept(res -> {
                    assertTrue(
                            res.stream(LDP.PreferMembership)
                                    .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label))),
                            "Missing member triple (1)!");
                    assertTrue(
                            res.stream(LDP.PreferMembership)
                                    .anyMatch(isEqual(rdf.createTriple(members, RDFS.label, label2))),
                            "Missing member triple (2)!");
                }).toCompletableFuture(), svc.get(root).thenAccept(checkRoot(evenLater, 3L)).toCompletableFuture(),
                svc.get(root).thenAccept(checkPredates(evenLater4)).toCompletableFuture()).join();
    }

    @Test
    public void testBuildRDFConnectionMemory() {

        final RDFConnection rdfConnection = TriplestoreResourceService.buildRDFConnection(null);
        assertNotNull(rdfConnection, "Missing RDFConnection, using in-memory dataset!");
        assertFalse(rdfConnection.isClosed(), "RDFConnection has been closed!");
        assertTrue(rdfConnection instanceof RDFConnectionLocal, "Incorrect type");
    }

    @Test
    public void testBuildRDFConnectionTDB() throws Exception {
        final File dir = new File(new File(getClass().getResource("/logback-test.xml").toURI()).getParent(),
                "data");
        final RDFConnection rdfConnection = TriplestoreResourceService.buildRDFConnection(dir.getAbsolutePath());
        assertNotNull(rdfConnection, "Missing RDFConnection, using local file!");
        assertFalse(rdfConnection.isClosed(), "RDFConnection has been closed!");
        assertTrue(rdfConnection instanceof RDFConnectionLocal, "Incorrect type");
    }

    @Test
    public void testBuildRDFConnectionRemote() {
        final RDFConnection rdfConnection = TriplestoreResourceService
                .buildRDFConnection("http://localhost/sparql");
        assertNotNull(rdfConnection, "Missing RDFConnection, using local HTTP!");
        assertFalse(rdfConnection.isClosed(), "RDFConnection has been closed!");
        assertTrue(rdfConnection instanceof RDFConnectionRemote, "Incorrect type");
    }

    @Test
    public void testBuildRDFConnectionRemoteHTTPS() {
        final RDFConnection rdfConnection = TriplestoreResourceService
                .buildRDFConnection("https://localhost/sparql");
        assertNotNull(rdfConnection, "Missing RDFConnection, using local HTTP!");
        assertFalse(rdfConnection.isClosed(), "RDFConnection has been closed!");
        assertTrue(rdfConnection instanceof RDFConnectionRemote, "Incorrect type");
    }

    private static Consumer<Resource> checkChild(final Instant time, final long properties, final long audit) {
        return res -> {
            assertAll("Check resource", checkResource(res, child, LDP.RDFSource, time));
            assertAll("Check resource stream", checkResourceStream(res, properties, 0L, audit, 0L, 0L));
        };
    }

    private static Consumer<Resource> checkRoot(final Instant time, final long children) {
        return res -> {
            assertAll("Check resource", checkResource(res, root, LDP.BasicContainer, time));
            assertAll("Check resource stream", checkResourceStream(res, 0L, 5L, 0L, 0L, children));
        };
    }

    private static Consumer<Resource> checkPredates(final Instant time) {
        return res -> assertTrue(res.getModified().isBefore(time), "Resource " + res.getIdentifier()
                + " has an unexpected lastModified date: " + res.getModified() + " !< " + time);
    }

    private static Consumer<Resource> checkResource(final Instant time, final IRI ldpType, final long properties,
            final long audit, final long children) {
        return res -> {
            assertAll("Check resource", checkResource(res, resource, ldpType, time));
            assertAll("Check resource stream", checkResourceStream(res, properties, 0L, audit, 0L, children));
        };
    }

    private static Consumer<Resource> checkMember(final Instant time, final long properties, final long audit,
            final long membership) {
        return res -> {
            assertAll("Check resource", checkResource(res, members, LDP.RDFSource, time));
            assertAll("Check resource stream", checkResourceStream(res, properties, 0L, audit, membership, 0L));
        };
    }

    private static Stream<Executable> checkResource(final Resource res, final IRI identifier, final IRI ldpType,
            final Instant time) {
        return Stream.of(() -> assertNotNull(res, "Missing resource!"),
                () -> assertEquals(identifier, res.getIdentifier(), "Incorrect identifier!"),
                () -> assertEquals(ldpType, res.getInteractionModel(), "Incorrect interaction model!"),
                () -> assertFalse(res.getModified().isBefore(time), "Non-sequential date!"),
                () -> assertFalse(res.getModified().isAfter(now().plusMillis(5L)),
                        "modification date in the future!"));
    }

    private static Stream<Executable> checkBinary(final Resource res, final IRI identifier, final String mimeType) {
        return Stream.of(() -> assertNotNull(res, "Missing resource!"),
                () -> assertTrue(res.getBinaryMetadata().isPresent(), "missing binary metadata!"),
                () -> assertEquals(identifier, res.getBinaryMetadata().get().getIdentifier(),
                        "Incorrect binary identifier!"),
                () -> assertEquals(mimeType,
                        res.getBinaryMetadata().flatMap(BinaryMetadata::getMimeType).orElse(null),
                        "Incorrect binary mimetype!"));
    }

    private static Stream<Executable> checkResourceStream(final Resource res, final long userManaged,
            final long accessControl, final long audit, final long membership, final long containment) {
        final long total = userManaged + accessControl + audit + membership + containment;
        return Stream.of(
                () -> assertEquals(userManaged, res.stream(Trellis.PreferUserManaged).count(),
                        "Incorrect user triple count!"),
                () -> assertEquals(accessControl, res.stream(Trellis.PreferAccessControl).count(),
                        "Incorrect ACL triple count!"),
                () -> assertEquals(audit, res.stream(Trellis.PreferAudit).count(), "Incorrect audit triple count!"),
                () -> assertEquals(membership, res.stream(LDP.PreferMembership).count(),
                        "Incorrect member triple count!"),
                () -> assertEquals(containment, res.stream(LDP.PreferContainment).count(),
                        "Incorrect containment triple count!"),
                () -> assertEquals(total, res.stream().count(), "Incorrect total triple count!"));
    }

    private static Instant meanwhile() {
        final Instant t1 = now();
        await().until(() -> isReallyLaterThan(t1));
        final Instant t2 = now();
        await().until(() -> isReallyLaterThan(t2));
        return t2;
    }

    private static boolean isReallyLaterThan(final Instant time) {
        final Instant t = now();
        return t.isAfter(time) && (t.toEpochMilli() > time.toEpochMilli() || t.getNano() > time.getNano());
    }
}