diff --git a/indexing-solr/pom.xml b/indexing-solr/pom.xml index 9ef5e8c9..4584cc81 100644 --- a/indexing-solr/pom.xml +++ b/indexing-solr/pom.xml @@ -16,6 +16,7 @@ + io.fabric8 docker-maven-plugin @@ -30,7 +31,6 @@ - compose src/test/docker @@ -39,7 +39,42 @@ + + + start-docker-its + pre-integration-test + + start + + + + stop-docker-its + post-integration-test + + stop + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + http://${docker.host.address}:8983/solr + + + + + + integration-test + verify + + + + diff --git a/indexing-solr/src/main/resources/http-solr.properties b/indexing-solr/src/main/resources/http-solr.properties new file mode 100644 index 00000000..164eb7a4 --- /dev/null +++ b/indexing-solr/src/main/resources/http-solr.properties @@ -0,0 +1 @@ +rmap.solr.url = http://localhost:8983/solr \ No newline at end of file diff --git a/indexing-solr/src/main/resources/rmap-indexing-solr.xml b/indexing-solr/src/main/resources/rmap-indexing-solr.xml index f28db250..4dc3f856 100644 --- a/indexing-solr/src/main/resources/rmap-indexing-solr.xml +++ b/indexing-solr/src/main/resources/rmap-indexing-solr.xml @@ -2,23 +2,28 @@ + http://www.springframework.org/schema/data/solr http://www.springframework.org/schema/data/solr/spring-solr-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - - - + - - - + - - + + + + - + + - + + + + + + \ No newline at end of file diff --git a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/AbstractSpringIndexingTest.java b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/AbstractSpringIndexingTest.java index b771d52d..418beeb5 100644 --- a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/AbstractSpringIndexingTest.java +++ b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/AbstractSpringIndexingTest.java @@ -15,7 +15,7 @@ * @author Elliot Metsger (emetsger@jhu.edu) */ @RunWith(SpringJUnit4ClassRunner.class) -@ActiveProfiles({"default", "inmemory-triplestore", "inmemory-idservice"}) +@ActiveProfiles({"default", "inmemory-triplestore", "inmemory-idservice", "http-solr"}) @ContextConfiguration({"classpath:/rmap-indexing-solr.xml", "classpath:/spring-rmapcore-context.xml"}) public abstract class AbstractSpringIndexingTest { diff --git a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/TestUtils.java b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/TestUtils.java index 092b528b..6eacae16 100644 --- a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/TestUtils.java +++ b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/TestUtils.java @@ -3,9 +3,14 @@ import info.rmapproject.core.model.RMapIri; import info.rmapproject.core.model.RMapObject; import info.rmapproject.core.model.RMapObjectType; +import info.rmapproject.core.model.agent.RMapAgent; +import info.rmapproject.core.model.disco.RMapDiSCO; +import info.rmapproject.core.model.event.RMapEvent; import info.rmapproject.core.rdfhandler.RDFHandler; import info.rmapproject.core.rdfhandler.RDFType; import info.rmapproject.core.rdfhandler.impl.openrdf.RioRDFHandler; +import info.rmapproject.indexing.solr.repository.IndexDTO; +import info.rmapproject.indexing.solr.repository.SimpleSolrTest; import org.openrdf.model.IRI; import org.openrdf.model.Statement; import org.openrdf.rio.RDFFormat; @@ -21,13 +26,19 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.ReadableByteChannel; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import static info.rmapproject.indexing.solr.IndexUtils.findEventIri; +import static info.rmapproject.indexing.solr.IndexUtils.irisEqual; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -184,7 +195,78 @@ public static List getRmapObjects(MapAssumptions: + *
    + *
  • {@code resourcePath} names a classpath resource that resolves to a directory on the filesystem. The + * directory contains RMap objects serialized in N-Quads format. Each file contains one RMap object, and + * ends with an {@code .n4} file extension
  • + *
  • The supplied {@code rdfHandler} is able to de-serialize N-Quad RDF
  • + *
  • Each {@code RMapEvent} under {@code resourcePath} forms a connected graph, a requirement of the + * {@link IndexDTO}. That means that with every event, there ought to be an object for the agent, and at + * least one source and/or target disco.
  • + *
+ *

+ * The {@code assertions} are applied on the deserialized objects prior to preparing the {@code IndexDTO} stream. + * The caller may use these assertions to verify the type, number, or contents of the RMap objects that have been + * deserialized from the filesystem. + *

+ * + * @param rdfHandler the RDFHandler capable of deserializing N-Quads + * @param resourcePath a classpath resource that is expected to resolve to a directory containing RDF serializations + * of RMap objects in N-Quad format. One RMap object per file. + * @param assertions caller-supplied assertions that are run on the de-serialized RDF prior to assembling + * {@code IndexDTO} objects + * @return a stream of {@code IndexDTO} objects + */ + public static Stream prepareIndexableDtos(RDFHandler rdfHandler, String resourcePath, + Consumer>> assertions) { + Map> rmapObjects = new HashMap<>(); + getRmapResources(resourcePath, rdfHandler, RDFFormat.NQUADS, rmapObjects); + + assertions.accept(rmapObjects); + + List discos = getRmapObjects(rmapObjects, RMapObjectType.DISCO, rdfHandler); + List events = getRmapObjects(rmapObjects, RMapObjectType.EVENT, rdfHandler); + List agents = getRmapObjects(rmapObjects, RMapObjectType.AGENT, rdfHandler); + + return events.stream() + .sorted(Comparator.comparing(RMapEvent::getStartTime)) + .map(event -> { + RMapAgent agent = agents.stream() + .filter(a -> irisEqual(a.getId(), event.getAssociatedAgent())) + .findAny() + .orElseThrow(() -> + new RuntimeException("Missing expected agent " + + event.getAssociatedAgent().getStringValue())); + + Optional source = findEventIri(event, IndexUtils.EventDirection.SOURCE); + Optional target = findEventIri(event, IndexUtils.EventDirection.TARGET); + RMapDiSCO sourceDisco = null; + RMapDiSCO targetDisco = null; + + if (source.isPresent()) { + sourceDisco = discos.stream() + .filter(disco -> disco.getId().getStringValue().equals(source.get().getStringValue())) + .findAny().get(); + } + + if (target.isPresent()) { + targetDisco = discos.stream() + .filter(disco -> disco.getId().getStringValue().equals(target.get().getStringValue())) + .findAny().get(); + } + + IndexDTO indexDto = new IndexDTO(event, agent, sourceDisco, targetDisco); + + return indexDto; + }); + } + + /** + * A Spring Resource of RDF content. A {@code RDFResource} exposes the RDF serialization of the RDF, along with an + * {@code InputStream} to the content. This allows callers to determine which serialization to use when + * deserializing the content of the resource. */ public interface RDFResource extends Resource { diff --git a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrIT.java b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrIT.java new file mode 100644 index 00000000..171418e5 --- /dev/null +++ b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrIT.java @@ -0,0 +1,94 @@ +package info.rmapproject.indexing.solr.repository; + +import info.rmapproject.core.model.RMapObjectType; +import info.rmapproject.core.model.agent.RMapAgent; +import info.rmapproject.core.model.disco.RMapDiSCO; +import info.rmapproject.core.model.event.RMapEvent; +import info.rmapproject.core.rdfhandler.RDFHandler; +import info.rmapproject.indexing.solr.AbstractSpringIndexingTest; +import info.rmapproject.indexing.solr.TestUtils; +import info.rmapproject.indexing.solr.model.DiscoSolrDocument; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import static info.rmapproject.core.model.RMapStatus.ACTIVE; +import static info.rmapproject.core.model.RMapStatus.INACTIVE; +import static info.rmapproject.indexing.solr.TestUtils.prepareIndexableDtos; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Elliot Metsger (emetsger@jhu.edu) + */ +public class SimpleSolrIT extends AbstractSpringIndexingTest { + + @Autowired + private RDFHandler rdfHandler; + + @Autowired + private DiscoRepository discoRepository; + + /** + * Tests the {@link DiscoRepository#index(IndexDTO)} method by supplying three {@code IndexDTO}s for indexing from + * the {@code /data/discos/rmd18mddcw} directory: + *
    + *
  • a creation event
  • + *
  • followed by an update event
  • + *
  • followed by another update event
  • + *
+ * This test insures that the {@link DiscoSolrDocument}s in the index have the correct + * {@link DiscoSolrDocument#DISCO_STATUS} after the three events have been processed. + * + * @see README.MD + */ + @Test + public void testIndexingDiscoStatusCreateAndUpdateAndUpdate() { + LOG.debug("Deleting everything in the index."); + discoRepository.deleteAll(); + assertEquals(0, discoRepository.count()); + + Consumer>> assertions = (resources) -> { + List discos = TestUtils.getRmapObjects(resources, RMapObjectType.DISCO, rdfHandler); + assertEquals(3, discos.size()); + + List events = TestUtils.getRmapObjects(resources, RMapObjectType.EVENT, rdfHandler); + assertEquals(3, events.size()); + + List agents = TestUtils.getRmapObjects(resources, RMapObjectType.AGENT, rdfHandler); + assertEquals(1, agents.size()); + }; + + LOG.debug("Preparing indexable objects."); + Stream dtos = prepareIndexableDtos(rdfHandler,"/data/discos/rmd18mddcw", assertions); + + dtos.peek(dto -> LOG.debug("Indexing {}", dto)).forEach(dto -> discoRepository.index(dto)); + + // 5 documents should have been added + // - one document per DiSCO, Event tuple + assertEquals(5, discoRepository.count()); + + // 1 document should be active + Set docs = discoRepository.findDiscoSolrDocumentsByDiscoStatus(ACTIVE.toString()); + assertEquals(1, docs.size()); + + // assert it is the uri we expect + DiscoSolrDocument active = docs.iterator().next(); + assertTrue(active.getDiscoUri().endsWith("rmd18mddcw")); + + // the other four should be inactive + docs = discoRepository.findDiscoSolrDocumentsByDiscoStatus(INACTIVE.toString()); + assertEquals(4, docs.size()); + + // assert they have the uris we expect + assertEquals(2, docs.stream().filter(doc -> doc.getDiscoUri().endsWith("rmd18mdd8b")).count()); + assertEquals(2, docs.stream().filter(doc -> doc.getDiscoUri().endsWith("rmd18m7mr7")).count()); + } + + +} diff --git a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/SimpleSolrTest.java b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrTest.java similarity index 78% rename from indexing-solr/src/test/java/info/rmapproject/indexing/solr/SimpleSolrTest.java rename to indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrTest.java index ca82779c..f710581a 100644 --- a/indexing-solr/src/test/java/info/rmapproject/indexing/solr/SimpleSolrTest.java +++ b/indexing-solr/src/test/java/info/rmapproject/indexing/solr/repository/SimpleSolrTest.java @@ -1,4 +1,4 @@ -package info.rmapproject.indexing.solr; +package info.rmapproject.indexing.solr.repository; import info.rmapproject.core.model.RMapIri; import info.rmapproject.core.model.RMapObjectType; @@ -9,22 +9,18 @@ import info.rmapproject.core.model.event.RMapEventUpdate; import info.rmapproject.core.model.event.RMapEventWithNewObjects; import info.rmapproject.core.rdfhandler.RDFHandler; +import info.rmapproject.indexing.solr.AbstractSpringIndexingTest; +import info.rmapproject.indexing.solr.IndexUtils; +import info.rmapproject.indexing.solr.TestUtils; import info.rmapproject.indexing.solr.model.DiscoSolrDocument; import info.rmapproject.indexing.solr.model.DiscoVersionDocument; -import info.rmapproject.indexing.solr.repository.DiscoRepository; -import info.rmapproject.indexing.solr.repository.IndexDTO; -import info.rmapproject.indexing.solr.repository.VersionRepository; import org.apache.solr.client.solrj.response.SolrPingResponse; import org.apache.solr.client.solrj.response.UpdateResponse; import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.common.util.NamedList; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.junit.runner.RunWith; import org.openrdf.rio.RDFFormat; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.converter.Converter; import org.springframework.data.solr.core.DefaultQueryParser; @@ -32,39 +28,32 @@ import org.springframework.data.solr.core.query.PartialUpdate; import org.springframework.data.solr.core.query.Query; import org.springframework.lang.Nullable; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static info.rmapproject.core.model.RMapStatus.ACTIVE; -import static info.rmapproject.core.model.RMapStatus.INACTIVE; import static java.lang.Long.parseLong; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; /** * @author Elliot Metsger (emetsger@jhu.edu) */ +@Ignore("Move tests to ITs") public class SimpleSolrTest extends AbstractSpringIndexingTest { @Autowired @@ -436,48 +425,6 @@ public void indexDiscoRdf() throws Exception { .forEach(doc -> discoRepository.save(doc)); } - @Test - public void writableDiscoRepository() throws Exception { - LOG.debug("Deleting everything in the index."); - discoRepository.deleteAll(); - assertEquals(0, discoRepository.count()); - - Consumer>> assertions = (resources) -> { - List discos = TestUtils.getRmapObjects(resources, RMapObjectType.DISCO, rdfHandler); - assertEquals(3, discos.size()); - - List events = TestUtils.getRmapObjects(resources, RMapObjectType.EVENT, rdfHandler); - assertEquals(3, events.size()); - - List agents = TestUtils.getRmapObjects(resources, RMapObjectType.AGENT, rdfHandler); - assertEquals(1, agents.size()); - }; - - LOG.debug("Preparing indexable objects."); - Stream dtos = prepareIndexableDtos("/data/discos/rmd18mddcw", assertions); - - dtos.peek(dto -> LOG.debug("Indexing {}", dto)).forEach(dto -> discoRepository.index(dto)); - - // 5 documents should have been added - // - one document per DiSCO, Event tuple - assertEquals(5, discoRepository.count()); - - // 1 document should be active - Set docs = discoRepository.findDiscoSolrDocumentsByDiscoStatus(ACTIVE.toString()); - assertEquals(1, docs.size()); - - // assert it is the uri we expect - DiscoSolrDocument active = docs.iterator().next(); - assertTrue(active.getDiscoUri().endsWith("rmd18mddcw")); - - // the other four should be inactive - docs = discoRepository.findDiscoSolrDocumentsByDiscoStatus(INACTIVE.toString()); - assertEquals(4, docs.size()); - - // assert they have the uris we expect - assertEquals(2, docs.stream().filter(doc -> doc.getDiscoUri().endsWith("rmd18mdd8b")).count()); - assertEquals(2, docs.stream().filter(doc -> doc.getDiscoUri().endsWith("rmd18m7mr7")).count()); - } @Test @SuppressWarnings("unchecked") @@ -488,49 +435,6 @@ public void javabinTest() throws Exception { } } - private Stream prepareIndexableDtos(String resourcePath, Consumer>> assertions) { - Map> rmapObjects = new HashMap<>(); - TestUtils.getRmapResources(resourcePath, rdfHandler, RDFFormat.NQUADS, rmapObjects); - - assertions.accept(rmapObjects); - - List discos = TestUtils.getRmapObjects(rmapObjects, RMapObjectType.DISCO, rdfHandler); - List events = TestUtils.getRmapObjects(rmapObjects, RMapObjectType.EVENT, rdfHandler); - List agents = TestUtils.getRmapObjects(rmapObjects, RMapObjectType.AGENT, rdfHandler); - - return events.stream() - .sorted(Comparator.comparing(RMapEvent::getStartTime)) - .map(event -> { - RMapAgent agent = agents.stream() - .filter(a -> a.getId().getStringValue().equals(event.getAssociatedAgent().getStringValue())) - .findAny() - .orElseThrow(() -> - new RuntimeException("Missing expected agent " + - event.getAssociatedAgent().getStringValue())); - - Optional source = IndexUtils.findEventIri(event, IndexUtils.EventDirection.SOURCE); - Optional target = IndexUtils.findEventIri(event, IndexUtils.EventDirection.TARGET); - RMapDiSCO sourceDisco = null; - RMapDiSCO targetDisco = null; - - if (source.isPresent()) { - sourceDisco = discos.stream() - .filter(disco -> disco.getId().getStringValue().equals(source.get().getStringValue())) - .findAny().get(); - } - - if (target.isPresent()) { - targetDisco = discos.stream() - .filter(disco -> disco.getId().getStringValue().equals(target.get().getStringValue())) - .findAny().get(); - } - - IndexDTO indexDto = new IndexDTO(event, agent, sourceDisco, targetDisco); - - return indexDto; - }); - } - private static void registerUriConverter(SolrTemplate solrTemplate) { DefaultQueryParser queryParser = new DefaultQueryParser(); queryParser.registerConverter(new Converter() { @@ -575,15 +479,4 @@ private static DiscoSolrDocument discoDocument(String id, String testDescription return doc; } - /** - * Encapsulates an indexable unit. - */ - private class IndexableThing { - private RMapEvent event; - private RMapDiSCO disco; - private RMapAgent agent; - private RMapIri eventSource; - private RMapIri eventTarget; - } - }