org.trellisldp.test.LdpDirectContainerTests.java Source code

Java tutorial

Introduction

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

import static javax.ws.rs.client.Entity.entity;
import static javax.ws.rs.core.HttpHeaders.LINK;
import static javax.ws.rs.core.Link.TYPE;
import static javax.ws.rs.core.Link.fromUri;
import static javax.ws.rs.core.Response.Status.Family.CLIENT_ERROR;
import static javax.ws.rs.core.Response.Status.Family.SUCCESSFUL;
import static org.apache.commons.rdf.api.RDFSyntax.TURTLE;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.trellisldp.api.TrellisUtils.getInstance;
import static org.trellisldp.http.core.HttpConstants.PREFER;
import static org.trellisldp.http.core.HttpConstants.SLUG;
import static org.trellisldp.http.core.RdfMediaType.APPLICATION_SPARQL_UPDATE;
import static org.trellisldp.http.core.RdfMediaType.TEXT_TURTLE;
import static org.trellisldp.http.core.RdfMediaType.TEXT_TURTLE_TYPE;
import static org.trellisldp.test.TestUtils.getLinks;
import static org.trellisldp.test.TestUtils.getResourceAsString;
import static org.trellisldp.test.TestUtils.hasConstrainedBy;
import static org.trellisldp.test.TestUtils.hasType;
import static org.trellisldp.test.TestUtils.readEntityAsGraph;

import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.Response;

import org.apache.commons.rdf.api.Graph;
import org.apache.commons.rdf.api.IRI;
import org.apache.commons.rdf.api.RDF;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.trellisldp.vocabulary.DC;
import org.trellisldp.vocabulary.LDP;
import org.trellisldp.vocabulary.SKOS;
import org.trellisldp.vocabulary.Trellis;

/**
 * Run LDP-related tests on a Trellis application.
 */
@TestInstance(PER_CLASS)
@DisplayName("Direct Container Tests")
public interface LdpDirectContainerTests extends CommonTests {

    String MEMBER_RESOURCE1 = "/members1";
    String MEMBER_RESOURCE2 = "/members2";
    String MEMBER_RESOURCE_HASH = "#members";
    String BASIC_CONTAINER = "/basicContainer.ttl";
    String DIRECT_CONTAINER = "/directContainer.ttl";
    String SIMPLE_RESOURCE = "/simpleResource.ttl";
    String DIRECT_CONTAINER_INVERSE = "/directContainerInverse.ttl";
    String DIRECT_CONTAINER_IS_PART_OF = "/directContainerIsPartOf.ttl";

    /**
     * Set the location of the test resource.
     * @param location the location
     */
    void setMemberLocation(String location);

    /**
     * Get the location of the test resource.
     * @return the test resource location
     */
    String getMemberLocation();

    /**
     * Set the location of the test container.
     * @param location the location
     */
    void setContainerLocation(String location);

    /**
     * Get the location of the test container.
     * @return the test container location
     */
    String getContainerLocation();

    /**
     * Set the location of the other direct container.
     * @param location the location
     */
    void setDirectContainerLocation(String location);

    /**
     * Get the location of the other direct container.
     * @return the test container location
     */
    String getDirectContainerLocation();

    /**
     * Initialize Direct Container tests.
     */
    @BeforeAll
    @DisplayName("Initialize Direct Container tests")
    default void beforeAllTests() {
        final String containerContent = getResourceAsString(BASIC_CONTAINER);
        final String dcUnsupported = "Creation of DirectContainer appears to be unsupported";
        final String notDcType = "New resource was not of expected DirectContainer type";

        // POST an LDP-BC
        try (final Response res = target().request().header(SLUG, generateRandomValue(getClass().getSimpleName()))
                .header(LINK, fromUri(LDP.BasicContainer.getIRIString()).rel(TYPE).build())
                .post(entity(containerContent, TEXT_TURTLE))) {
            assumeTrue(SUCCESSFUL.equals(res.getStatusInfo().getFamily()),
                    "Creation of BasicContainer appears to be unsupported");
            assumeTrue(getLinks(res).stream().anyMatch(hasType(LDP.BasicContainer)),
                    "New resource was not of expected BasicContainer type");

            setContainerLocation(res.getLocation().toString());
        }

        setMemberLocation(getContainerLocation() + MEMBER_RESOURCE1);

        // PUT an LDP-RS
        try (final Response res = target(getMemberLocation()).request()
                .put(entity(containerContent, TEXT_TURTLE))) {
            assumeTrue(SUCCESSFUL.equals(res.getStatusInfo().getFamily()),
                    "Creation of RDFSource appears to be unsupported");
            assumeTrue(getLinks(res).stream().anyMatch(hasType(LDP.RDFSource)),
                    "New resource was not of expected RDFSource type");
        }

        final String simpleContent = getResourceAsString(DIRECT_CONTAINER)
                + membershipResource(MEMBER_RESOURCE_HASH);

        // POST an LDP-DC
        try (final Response res = target(getContainerLocation()).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .post(entity(simpleContent, TEXT_TURTLE))) {
            assumeTrue(SUCCESSFUL.equals(res.getStatusInfo().getFamily()), dcUnsupported);
            assumeTrue(getLinks(res).stream().anyMatch(hasType(LDP.DirectContainer)), notDcType);

            setDirectContainerLocation(res.getLocation().toString());
        }

    }

    /**
     * Test fetch a self-contained direct container.
     */
    @Test
    @DisplayName("Test fetch a self-contained direct container")
    default void testSimpleDirectContainer() {
        final RDF rdf = getInstance();
        final String memberContent = getResourceAsString(SIMPLE_RESOURCE);
        final String child;

        // POST an LDP-RS
        try (final Response res = target(getDirectContainerLocation()).request()
                .post(entity(memberContent, TEXT_TURTLE))) {
            assumeTrue(SUCCESSFUL.equals(res.getStatusInfo().getFamily()),
                    "Creation of RDFSource appears to be unsupported");
            assumeTrue(getLinks(res).stream().anyMatch(hasType(LDP.RDFSource)),
                    "New resource was not of expected RDFSource type");

            child = res.getLocation().toString();
        }

        // Fetch the member resource
        try (final Response res = target(getDirectContainerLocation()).request().get()) {
            assertAll("Check the member resource", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            assertTrue(g.contains(rdf.createIRI(getDirectContainerLocation()), LDP.contains, rdf.createIRI(child)),
                    "Verify an ldp:contains triple");
            assertTrue(g.contains(rdf.createIRI(getDirectContainerLocation() + MEMBER_RESOURCE_HASH), LDP.member,
                    rdf.createIRI(child)), "Verify a member triple");
        }
    }

    /**
     * Test adding resources to the direct container.
     */
    @Test
    @DisplayName("Test adding resources to the direct container")
    default void testAddingMemberResources() {
        final RDF rdf = getInstance();
        final String dcLocation;
        final String child1;
        final String child2;
        final EntityTag etag1;
        final EntityTag etag2;
        final EntityTag etag3;
        final EntityTag etag4;
        final EntityTag etag5;
        final EntityTag etag6;
        final String childContent = getResourceAsString(SIMPLE_RESOURCE);

        final String content = getResourceAsString(DIRECT_CONTAINER) + membershipResource(getMemberLocation());

        // POST an LDP-DC
        try (final Response res = target(getContainerLocation()).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .post(entity(content, TEXT_TURTLE))) {
            assertAll("Check the LDP-DC was created", checkRdfResponse(res, LDP.DirectContainer, null));
            dcLocation = res.getLocation().toString();
        }

        // Fetch the member resource
        try (final Response res = target(getMemberLocation()).request().get()) {
            assertAll("Check the member resource", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            assertFalse(g.contains(rdf.createIRI(getMemberLocation()), LDP.member, null),
                    "Check that an ldp:contains triple is not present");
            etag1 = res.getEntityTag();
            assertTrue(etag1.isWeak(), "Check for a weak ETag");
        }

        // Fetch the container resource
        try (final Response res = target(dcLocation).request().get()) {
            assertAll("Check the container resource", checkRdfResponse(res, LDP.DirectContainer, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            assertFalse(g.contains(rdf.createIRI(dcLocation), LDP.contains, null),
                    "Check that the given ldp:contains triple isn't present");
            etag4 = res.getEntityTag();
            assertTrue(etag4.isWeak(), "Verify that the ETag is weak");
        }

        // POST an LDP-RS child
        try (final Response res = target(dcLocation).request().post(entity(childContent, TEXT_TURTLE))) {
            assertAll("Check POSTing a child", checkRdfResponse(res, LDP.RDFSource, null));
            child1 = res.getLocation().toString();
            assertTrue(child1.startsWith(dcLocation), "Check the Location header");
            assertTrue(child1.length() > dcLocation.length(), "Re-check the Location header");
        }

        // POST an LDP-RS child
        try (final Response res = target(dcLocation).request().post(entity(childContent, TEXT_TURTLE))) {
            assertAll("Check POSTing a child", checkRdfResponse(res, LDP.RDFSource, null));
            child2 = res.getLocation().toString();
            assertTrue(child2.startsWith(dcLocation), "Check the Location header of the LDP-DC");
            assertTrue(child2.length() > dcLocation.length(), "Re-check the Location header");
        }

        await().until(() -> !etag4.equals(getETag(dcLocation)));
        await().until(() -> !etag1.equals(getETag(getMemberLocation())));

        // Fetch the member resource
        try (final Response res = target(getMemberLocation()).request().get()) {
            assertAll("Check fetching the member resource", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertTrue(g.contains(identifier, LDP.member, rdf.createIRI(child1)), "Check for a member property");
            assertTrue(g.contains(identifier, LDP.member, rdf.createIRI(child2)),
                    "Check for another member property");
            etag2 = res.getEntityTag();
            assertTrue(etag2.isWeak(), "Check for a weak ETag value");
            assertNotEquals(etag1, etag2, "Establish that the first two ETag values don't match");
        }

        // Fetch the container resource
        try (final Response res = target(dcLocation).request().get()) {
            assertAll("Check the container resource", checkRdfResponse(res, LDP.DirectContainer, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(dcLocation);
            assertTrue(g.contains(identifier, LDP.contains, rdf.createIRI(child1)),
                    "Check for an ldp:contains triple");
            assertTrue(g.contains(identifier, LDP.contains, rdf.createIRI(child2)),
                    "Check for an ldp:contains triple");
            etag5 = res.getEntityTag();
            assertTrue(etag5.isWeak(), "Verify that the ETag value is weak");
            assertNotEquals(etag4, etag5, "Check that ETags 4 and 5 are different");
        }

        // Delete one of the child resources
        try (final Response res = target(child1).request().delete()) {
            assertEquals(SUCCESSFUL, res.getStatusInfo().getFamily(), "Check for a successful response");
        }

        await().until(() -> !etag5.equals(getETag(dcLocation)));
        await().until(() -> !etag2.equals(getETag(getMemberLocation())));

        // Try fetching the deleted resource
        try (final Response res = target(child1).request().get()) {
            assertEquals(CLIENT_ERROR, res.getStatusInfo().getFamily(), "Check for an expected 4xx response");
        }

        // Fetch the member resource
        try (final Response res = target(getMemberLocation()).request().get()) {
            assertAll("Check fetching the member resource", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertFalse(g.contains(identifier, LDP.member, rdf.createIRI(child1)),
                    "Check for the absense of a member triple");
            assertTrue(g.contains(identifier, LDP.member, rdf.createIRI(child2)),
                    "Check for the presence of a member triple");
            etag3 = res.getEntityTag();
            assertTrue(etag3.isWeak(), "Verify that the third ETag is weak");
            assertNotEquals(etag1, etag3, "Compare ETags 1 and 3");
            assertNotEquals(etag2, etag3, "Compare ETags 2 and 3");
        }

        // Fetch the container resource
        try (final Response res = target(dcLocation).request().get()) {
            assertAll("Check the container resource", checkRdfResponse(res, LDP.DirectContainer, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(dcLocation);
            assertFalse(g.contains(identifier, LDP.contains, rdf.createIRI(child1)),
                    "Check that child1 is no longer contained by the parent");
            assertTrue(g.contains(identifier, LDP.contains, rdf.createIRI(child2)),
                    "Verify that the second child is still contained by the parent");
            etag6 = res.getEntityTag();
            assertTrue(etag6.isWeak(), "Confirm that the 6th ETag value is weak");
            assertNotEquals(etag5, etag6, "Compare ETags 5 and 6");
            assertNotEquals(etag4, etag6, "Compare ETags 4 and 6");
        }

        // Now change the membership property
        final String updateContent = "PREFIX dc: <http://purl.org/dc/terms/>\n"
                + "PREFIX ldp: <http://www.w3.org/ns/ldp#>\n\n" + "DELETE WHERE { <> ldp:hasMemberRelation ?o };"
                + "INSERT { <> ldp:hasMemberRelation dc:relation } WHERE {}";

        // Patch the direct container
        try (final Response res = target(dcLocation).request().method("PATCH",
                entity(updateContent, APPLICATION_SPARQL_UPDATE))) {
            assertAll("Check PATCHing the container", checkRdfResponse(res, LDP.DirectContainer, null));
        }

        // Fetch the member resource
        try (final Response res = target(getMemberLocation()).request().get()) {
            assertAll("Check fetching the member resource", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertTrue(g.contains(identifier, DC.relation, rdf.createIRI(child2)),
                    "Confirm that the graph contains a dc:relation member triple");
        }
    }

    /**
     * Test creating a direct container via PUT.
     */
    @Test
    @DisplayName("Test creating a direct container via PUT")
    default void testCreateDirectContainerViaPut() {
        final String other2 = getContainerLocation() + "/other2";
        final String content = getResourceAsString(DIRECT_CONTAINER)
                + membershipResource(getContainerLocation() + MEMBER_RESOURCE2);

        // PUT an LDP-DC
        try (final Response res = target(other2).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertAll("Check PUTting a container resource", checkRdfResponse(res, LDP.DirectContainer, null));
        }
    }

    /**
     * Test updating a direct container via PUT.
     */
    @Test
    @DisplayName("Test updating a direct container via PUT")
    default void testUpdateDirectContainerViaPut() {
        final String dcLocation = createSimpleDirectContainer(MEMBER_RESOURCE2);
        final String content = getResourceAsString("/directContainerIsPartOf.ttl")
                + membershipResource(getContainerLocation() + MEMBER_RESOURCE1);

        // PUT an LDP-DC
        try (final Response res = target(dcLocation).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertAll("Check PUTting a container resource", checkRdfResponse(res, LDP.DirectContainer, null));
        }
    }

    /**
     * Test updating a direct container with too many member-related properties.
     */
    @Test
    @DisplayName("Test updating a direct container with too many member-related properties")
    default void testUpdateDirectContainerTooManyMemberProps() {
        final String dcLocation = createSimpleDirectContainer(MEMBER_RESOURCE2);
        final String content = getResourceAsString(DIRECT_CONTAINER)
                + membershipResource(getContainerLocation() + MEMBER_RESOURCE2)
                + "<> ldp:isMemberOfRelation dc:isPartOf .";

        // PUT an LDP-DC
        try (final Response res = target(dcLocation).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertEquals(CLIENT_ERROR, res.getStatusInfo().getFamily(), "Confirm that a 4xx error is thrown");
            assertTrue(getLinks(res).stream().anyMatch(hasConstrainedBy(Trellis.InvalidCardinality)),
                    "Confirm the correct constraint IRI is referenced");
        }
    }

    /**
     * Test updating a direct container with too many membership resources.
     */
    @Test
    @DisplayName("Test updating a direct container with too many membership resources")
    default void testUpdateDirectContainerMultipleMemberResources() {
        final String dcLocation = createSimpleDirectContainer(MEMBER_RESOURCE2);

        final String content = getResourceAsString("/directContainer.ttl")
                + membershipResource(getContainerLocation() + MEMBER_RESOURCE2)
                + membershipResource(getContainerLocation() + "/member3");

        // PUT an LDP-DC
        try (final Response res = target(dcLocation).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertEquals(CLIENT_ERROR, res.getStatusInfo().getFamily(), "Confirm that a 4xx error is thrown");
            assertTrue(getLinks(res).stream().anyMatch(hasConstrainedBy(Trellis.InvalidCardinality)),
                    "Confirm the correct constraint IRI is referenced");
        }
    }

    /**
     * Test updating a direct container with no member relation property.
     */
    @Test
    @DisplayName("Test updating a direct container with no member relation property")
    default void testUpdateDirectContainerMissingMemberRelation() {
        final String dcLocation = createSimpleDirectContainer(MEMBER_RESOURCE2);
        final String content = "PREFIX skos: <http://www.w3.org/2004/02/skos/core#> \n"
                + "PREFIX ldp: <http://www.w3.org/ns/ldp#> \n" + "PREFIX dc: <http://purl.org/dc/terms/> \n\n"
                + "<> skos:prefLabel \"Direct Container\"@eng ; " + "   ldp:membershipResource <"
                + getContainerLocation() + MEMBER_RESOURCE2 + "> ; "
                + "   dc:description \"This is a Direct Container for testing.\"@eng .";

        // PUT an LDP-DC
        try (final Response res = target(dcLocation).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertEquals(CLIENT_ERROR, res.getStatusInfo().getFamily(), "Confirm that a 4xx error is returned");
            assertTrue(getLinks(res).stream().anyMatch(hasConstrainedBy(Trellis.InvalidCardinality)),
                    "Confirm that the trellis:InvalidCardinality constraint IRI is referenced");
        }
    }

    /**
     * Test updating a direct container with no member resource.
     */
    @Test
    @DisplayName("Test updating a direct container with no member resource")
    default void testUpdateDirectContainerMissingMemberResource() {
        final String dcLocation = createSimpleDirectContainer(MEMBER_RESOURCE2);
        final String content = getResourceAsString("/directContainer.ttl");

        // PUT an LDP-DC
        try (final Response res = target(dcLocation).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .put(entity(content, TEXT_TURTLE))) {
            assertEquals(CLIENT_ERROR, res.getStatusInfo().getFamily(), "Verify that a 4xx status is returned");
            assertTrue(getLinks(res).stream().anyMatch(hasConstrainedBy(Trellis.InvalidCardinality)),
                    "Make sure that an InvalidCardinality constraint is referenced");
        }
    }

    /**
     * Test fetching inverse member properties on a direct container.
     */
    @Test
    @DisplayName("Test with inverse direct containment")
    default void testDirectContainerWithInverseMembership() {
        final RDF rdf = getInstance();
        final String dcLocation;
        final String rsLocation;
        final String directContainerInverse = getResourceAsString(DIRECT_CONTAINER_INVERSE)
                + membershipResource(getMemberLocation());

        // POST an LDP-DC
        try (final Response res = target(getContainerLocation()).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .post(entity(directContainerInverse, TEXT_TURTLE))) {
            assertAll("Check creating an LDP-DC", checkRdfResponse(res, LDP.DirectContainer, null));

            dcLocation = res.getLocation().toString();
        }

        // Create an LDP-RS
        try (final Response res = target(dcLocation).request().post(entity("", TEXT_TURTLE))) {
            assertAll("Check creating an LDP-RS", checkRdfResponse(res, LDP.RDFSource, null));
            rsLocation = res.getLocation().toString();
        }

        try (final Response res = target(rsLocation).request().get()) {
            assertAll("Check the LDP-RS", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertTrue(g.contains(rdf.createIRI(rsLocation), DC.isPartOf, identifier),
                    "Check that dc:isPartOf is present in the graph");
        }
    }

    /**
     * Test with ldp:PreferMinimalContainer Prefer header.
     */
    @Test
    @DisplayName("Test with ldp:PreferMinimalContainer Prefer header")
    default void testGetEmptyMember() {
        final RDF rdf = getInstance();
        try (final Response res = target(getMemberLocation()).request()
                .header(PREFER,
                        "return=representation; include=\"" + LDP.PreferMinimalContainer.getIRIString() + "\"")
                .get()) {
            assertAll("Check the LDP-RS with Prefer", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertTrue(g.contains(identifier, SKOS.prefLabel, null), "Check for a skos:prefLabel triple");
            assertFalse(g.contains(identifier, LDP.member, null), "Check for no ldp:member triples");
            assertFalse(g.contains(identifier, DC.relation, null), "Check for no dc:relation triples");
        }
    }

    /**
     * Test with ldp:PreferMinimalContainer Prefer header.
     */
    @Test
    @DisplayName("Test with ldp:PreferMinimalContainer Prefer header")
    default void testGetInverseEmptyMember() {
        final RDF rdf = getInstance();
        try (final Response res = target(getMemberLocation()).request()
                .header(PREFER, "return=representation; omit=\"" + LDP.PreferMinimalContainer.getIRIString() + "\"")
                .get()) {
            assertAll("Check the LDP-RS with Prefer", checkRdfResponse(res, LDP.RDFSource, TEXT_TURTLE_TYPE));
            final Graph g = readEntityAsGraph(res.getEntity(), getBaseURL(), TURTLE);
            final IRI identifier = rdf.createIRI(getMemberLocation());
            assertFalse(g.contains(identifier, SKOS.prefLabel, null), "Check for no skos:prefLabel triples");
            assertTrue(g.contains(identifier, LDP.member, null) || g.contains(identifier, DC.relation, null),
                    "Check for either an ldp:member or dc:relation triple");
        }
    }

    /**
     * Create an ldp:membershipResource triple.
     * @param iri the IRI
     * @return the triple
     */
    default String membershipResource(final String iri) {
        return "<> ldp:membershipResource <" + iri + ">.\n";
    }

    /**
     * Create a simple direct container.
     * @param memberResource the member resource to use
     * @return the location of the new LDP-DC
     */
    default String createSimpleDirectContainer(final String memberResource) {
        final String content = getResourceAsString(DIRECT_CONTAINER_IS_PART_OF)
                + membershipResource(getContainerLocation() + memberResource);

        // POST an LDP-DC
        try (final Response res = target(getContainerLocation()).request()
                .header(LINK, fromUri(LDP.DirectContainer.getIRIString()).rel(TYPE).build())
                .post(entity(content, TEXT_TURTLE))) {
            assertAll("Check POSTing an LDP-DC", checkRdfResponse(res, LDP.DirectContainer, null));
            return res.getLocation().toString();
        }
    }
}