package net.fortytwo.sesametools.caching; import info.aduna.iteration.CloseableIteration; import net.fortytwo.sesametools.replay.Handler; import net.fortytwo.sesametools.replay.RecorderSail; import net.fortytwo.sesametools.replay.SailConnectionCall; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openrdf.model.Statement; import org.openrdf.model.IRI; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.sail.SailRepository; import org.openrdf.rio.RDFFormat; import org.openrdf.sail.Sail; import org.openrdf.sail.SailConnection; import org.openrdf.sail.SailException; import org.openrdf.sail.memory.MemoryStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import static org.junit.Assert.assertEquals; /** * @author Joshua Shinavier (http://fortytwo.net) */ public class CachingSailTest { private static final Logger LOG = LoggerFactory.getLogger(CachingSailTest.class); private static final String NS = "http://example.org/ns/"; private static final long CAPACITY = 10000000l; private Sail baseSail; private SailCounter counter; private SailConnection sc; private CachingSail cachingSail; @Before public void setUp() throws Exception { counter = new SailCounter(); baseSail = new MemoryStore(); RecorderSail recorderSail = new RecorderSail(baseSail, counter); cachingSail = new CachingSail(recorderSail, true, false, false, CAPACITY); cachingSail.initialize(); Repository repo = new SailRepository(baseSail); RepositoryConnection rc = repo.getConnection(); InputStream is = CachingSailTest.class.getResourceAsStream("cachingSailTest.trig"); rc.add(is, "", RDFFormat.TRIG); rc.close(); sc = cachingSail.getConnection(); } @After public void tearDown() { try { sc.close(); } catch (SailException e) { LOG.error("Error closing connection", e); } sc = null; try { cachingSail.shutDown(); } catch (SailException e) { LOG.error("Error shutting down repository", e); } cachingSail = null; baseSail = null; counter = null; } @Test public void testSubjectCaching() throws Exception { int count; // Subject "one" is not yet cached. counter.reset(); count = countStatements(sc.getStatements(uri("one"), uri("two"), null, false)); assertEquals(1, count); assertEquals(1, counter.getGets()); // Subject "one" is now cached, so the base Sail should not be queried. counter.reset(); count = countStatements(sc.getStatements(uri("one"), uri("two"), null, false)); assertEquals(1, count); assertEquals(0, counter.getGets()); // Different query, same caching behavior. counter.reset(); count = countStatements(sc.getStatements(uri("one"), null, null, false)); assertEquals(2, count); assertEquals(0, counter.getGets()); // A query with a wildcard subject must be relayed to the base Sail. counter.reset(); count = countStatements(sc.getStatements(null, uri("two"), null, false)); assertEquals(1, count); assertEquals(1, counter.getGets()); } @Test public void testWrite() throws Exception { int count; IRI resA = uri("http://example.org/ns/resA"); sc.begin(); sc.addStatement(resA, resA, resA); sc.commit(); count = countStatements(sc.getStatements(resA, null, null, false)); assertEquals(1, count); sc.begin(); sc.removeStatements(null, resA, null); sc.commit(); count = countStatements(sc.getStatements(null, null, resA, false)); assertEquals(0, count); sc.begin(); sc.addStatement(resA, resA, resA, resA); sc.commit(); count = countStatements(sc.getStatements(null, null, null, false, resA)); assertEquals(1, count); sc.begin(); sc.removeStatements(null, null, null, resA); sc.commit(); count = countStatements(sc.getStatements(null, null, resA, false)); assertEquals(0, count); } private IRI uri(final String localName) { return baseSail.getValueFactory().createIRI(NS + localName); } private int countStatements(final CloseableIteration<? extends Statement, SailException> iter) throws SailException { int count = 0; while (iter.hasNext()) { count++; iter.next(); } return count; } private class SailCounter implements Handler<SailConnectionCall, SailException> { private int gets = 0; public void handle(final SailConnectionCall call) throws SailException { if (call.getType() == SailConnectionCall.Type.GET_STATEMENTS) { gets++; } } public void reset() { gets = 0; } public int getGets() { return gets; } } }