001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006
007package org.fcrepo.kernel.impl.cache;
008
009import static org.apache.jena.graph.NodeFactory.createURI;
010import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
011import static org.apache.jena.riot.RDFFormat.NTRIPLES;
012import static org.hamcrest.MatcherAssert.assertThat;
013import static org.hamcrest.Matchers.containsInAnyOrder;
014
015import java.net.URI;
016import java.nio.charset.StandardCharsets;
017import java.util.List;
018import java.util.UUID;
019import java.util.function.Supplier;
020
021import org.fcrepo.config.FedoraPropsConfig;
022import org.fcrepo.kernel.api.RdfStream;
023import org.fcrepo.kernel.api.identifiers.FedoraId;
024import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
025
026import org.apache.commons.io.IOUtils;
027import org.apache.jena.rdf.model.Model;
028import org.apache.jena.riot.RDFDataMgr;
029import org.junit.Before;
030import org.junit.Test;
031
032/**
033 * @author pwinckles
034 */
035public class UserTypesCacheImplTest {
036
037    private static final URI ANIMAL_TYPE = URI.create("http://example.org/#Animal");
038    private static final URI CAT_TYPE = URI.create("http://example.org/#Cat");
039
040    private UserTypesCacheImpl cache;
041
042    private FedoraId fedoraId;
043
044    private String sessionId;
045
046    private String sessionId2;
047
048    @Before
049    public void setup() {
050        final var props = new FedoraPropsConfig();
051        props.setUserTypesCacheSize(1024);
052        props.setUserTypesCacheTimeout(10);
053        cache = new UserTypesCacheImpl(props);
054
055        fedoraId = FedoraId.create(UUID.randomUUID().toString());
056        sessionId = UUID.randomUUID().toString();
057        sessionId2 = UUID.randomUUID().toString();
058    }
059
060    @Test
061    public void loadTriplesWhenNotCached() {
062        final var types = cache.getUserTypes(fedoraId, sessionId, rdfSupplier(ANIMAL_TYPE, CAT_TYPE));
063        assertThat(types, containsInAnyOrder(ANIMAL_TYPE, CAT_TYPE));
064    }
065
066    @Test
067    public void loadFromCacheWhenCached() {
068        cache.getUserTypes(fedoraId, sessionId, rdfSupplier(ANIMAL_TYPE, CAT_TYPE));
069
070        final var types = cache.getUserTypes(fedoraId, sessionId, noCallSupplier());
071        assertThat(types, containsInAnyOrder(ANIMAL_TYPE, CAT_TYPE));
072    }
073
074    @Test
075    public void manuallyCachedTypesAreOnlyAvailableInSession() {
076        cache.cacheUserTypes(fedoraId, List.of(ANIMAL_TYPE), sessionId);
077
078        var types = cache.getUserTypes(fedoraId, sessionId, noCallSupplier());
079        assertThat(types, containsInAnyOrder(ANIMAL_TYPE));
080
081        types = cache.getUserTypes(fedoraId, sessionId2, rdfSupplier(ANIMAL_TYPE, CAT_TYPE));
082        assertThat(types, containsInAnyOrder(ANIMAL_TYPE, CAT_TYPE));
083    }
084
085    @Test
086    public void mergeCacheMakesTypesGloballyAvailable() {
087        cache.cacheUserTypes(fedoraId, List.of(ANIMAL_TYPE), sessionId);
088        cache.mergeSessionCache(sessionId);
089
090        final var types = cache.getUserTypes(fedoraId, sessionId2, noCallSupplier());
091        assertThat(types, containsInAnyOrder(ANIMAL_TYPE));
092    }
093
094    @Test
095    public void droppingCacheRemovesSessionCache() {
096        cache.cacheUserTypes(fedoraId, List.of(ANIMAL_TYPE), sessionId);
097
098        var types = cache.getUserTypes(fedoraId, sessionId, noCallSupplier());
099        assertThat(types, containsInAnyOrder(ANIMAL_TYPE));
100
101        cache.dropSessionCache(sessionId);
102
103        types = cache.getUserTypes(fedoraId, sessionId, rdfSupplier(CAT_TYPE));
104        assertThat(types, containsInAnyOrder(CAT_TYPE));
105    }
106
107    private Supplier<RdfStream> noCallSupplier() {
108        return () -> {
109            throw new RuntimeException("Should not be called");
110        };
111    }
112
113    private Supplier<RdfStream> rdfSupplier(final URI... types) {
114        return () -> createRdfStream(types);
115    }
116
117    private RdfStream createRdfStream(final URI... types) {
118        final var builder = new StringBuilder();
119
120        for (final var type : types) {
121            builder.append("<> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <").append(type).append(">.\n");
122        }
123
124        final Model model = createDefaultModel();
125        RDFDataMgr.read(model, IOUtils.toInputStream(builder.toString(), StandardCharsets.UTF_8), NTRIPLES.getLang());
126        return DefaultRdfStream.fromModel(createURI(fedoraId.getFullId()), model);
127    }
128
129}