getParent() {
+ return ofNullable(parent);
+ }
}
\ No newline at end of file
diff --git a/rre-core/src/main/java/io/sease/rre/persistence/PersistenceConfiguration.java b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceConfiguration.java
new file mode 100644
index 00000000..ad3de425
--- /dev/null
+++ b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceConfiguration.java
@@ -0,0 +1,110 @@
+package io.sease.rre.persistence;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Configuration details for the persistence manager.
+ *
+ * Configuration consists of a set of handler names, mapped to their
+ * implementation classes. The handler names are then used to refer to
+ * specific sets of configuration details, allowing the same implementation
+ * to be used multiple times with separate destinations (for example).
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class PersistenceConfiguration {
+
+ /**
+ * Default configuration object, with configuration for persisting to
+ * a single JSON output file.
+ */
+ public static final PersistenceConfiguration DEFAULT_CONFIG = defaultConfiguration();
+
+ private boolean useTimestampAsVersion = false;
+ private Map handlers;
+ // Supplying type params for nested map breaks Maven initialisation
+ private Map handlerConfiguration;
+
+ @SuppressWarnings("unused")
+ public PersistenceConfiguration() {
+ // Do nothing - required for Maven initialisation
+ }
+
+ private PersistenceConfiguration(boolean useTimestampAsVersion,
+ Map handlers,
+ Map handlerConfiguration) {
+ this.useTimestampAsVersion = useTimestampAsVersion;
+ this.handlers = handlers;
+ this.handlerConfiguration = handlerConfiguration;
+ }
+
+ /**
+ * Should the persistence framework use a timestamp in place of the
+ * configuration version? This timestamp should be consistent for
+ * the duration of the evaluation.
+ *
+ * This will take effect when there is only one configuration set
+ * available - eg. for users who modify the same configuration set
+ * rather than creating a separate one each iteration.
+ *
+ * @return {@code true} if a timestamp should be used in place of the
+ * version string when persisting query output.
+ */
+ public boolean isUseTimestampAsVersion() {
+ return useTimestampAsVersion;
+ }
+
+ /**
+ * @return a map of handler name to implementation classes.
+ */
+ public Map getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * @return a map of handler name to a map containing configuration
+ * details for the handler.
+ */
+ public Map getHandlerConfiguration() {
+ return handlerConfiguration;
+ }
+
+ /**
+ * Get the configuration for an individual handler, returning a map of
+ * configuration items keyed by the String value of their name. If there
+ * is no configuration, an empty map will be returned.
+ *
+ * @param name the name of the handler whose configuration is required.
+ * @return a String:Object map containing the configuration. Never
+ * {@code null}.
+ */
+ @SuppressWarnings("unchecked")
+ public Map getHandlerConfigurationByName(String name) {
+ Map configMap = new HashMap<>();
+
+ if (handlerConfiguration.get(name) != null) {
+ handlerConfiguration.get(name).forEach((k, v) -> configMap.put(String.valueOf(k), v));
+ }
+
+ return configMap;
+ }
+
+ /**
+ * Build a default PersistenceConfiguration, with handlers set to write
+ * to the standard JSON output file.
+ *
+ * @return a PersistenceConfiguration object.
+ */
+ private static PersistenceConfiguration defaultConfiguration() {
+ final String jsonKey = "json";
+ Map handlers = new HashMap<>();
+ handlers.put(jsonKey, "io.sease.rre.persistence.impl.JsonPersistenceHandler");
+ Map jsonConfig = new HashMap<>();
+ jsonConfig.put("outputFile", "target/rre/evaluation.json");
+ Map handlerConfig = new HashMap<>();
+ handlerConfig.put(jsonKey, jsonConfig);
+
+ return new PersistenceConfiguration(false, handlers, handlerConfig);
+ }
+}
diff --git a/rre-core/src/main/java/io/sease/rre/persistence/PersistenceException.java b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceException.java
new file mode 100644
index 00000000..5eb275c0
--- /dev/null
+++ b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceException.java
@@ -0,0 +1,25 @@
+package io.sease.rre.persistence;
+
+/**
+ * Exception thrown by the persistence framework.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class PersistenceException extends Exception {
+
+ public PersistenceException() {
+ super();
+ }
+
+ public PersistenceException(String message) {
+ super(message);
+ }
+
+ public PersistenceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PersistenceException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/rre-core/src/main/java/io/sease/rre/persistence/PersistenceHandler.java b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceHandler.java
new file mode 100644
index 00000000..03a9362a
--- /dev/null
+++ b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceHandler.java
@@ -0,0 +1,69 @@
+package io.sease.rre.persistence;
+
+import io.sease.rre.core.domain.Query;
+
+import java.util.Map;
+
+/**
+ * A persistence handler can be used to record the output from all queries
+ * run during an evaluation.
+ *
+ * Exceptions during processing are expected to be handled internally.
+ * Exceptions thrown during the {@link #beforeStart()} and {@link #start()}
+ * stages may be passed up the stack, to alert the PersistenceManager that
+ * the handler could not be started for some reason.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public interface PersistenceHandler {
+
+ /**
+ * Configure the persistence handler implementation.
+ *
+ * @param name the name given to the handler in the main configuration.
+ * @param configuration the configuration parameters specific to the
+ * handler.
+ */
+ void configure(String name, Map configuration);
+
+ /**
+ * @return the configuration name for this handler instance.
+ */
+ String getName();
+
+ /**
+ * Execute any necessary tasks required to initialise the handler.
+ *
+ * @throws PersistenceException if any pre-start checks fail. This should
+ * be used to report breaking failures - eg. issues that will stop the
+ * handler from starting.
+ */
+ void beforeStart() throws PersistenceException;
+
+ /**
+ * Execute any necessary start-up tasks.
+ *
+ * @throws PersistenceException if the handler cannot be started for any
+ * reason.
+ */
+ void start() throws PersistenceException;
+
+ /**
+ * Record a query.
+ *
+ * @param q the query.
+ */
+ void recordQuery(Query q);
+
+ /**
+ * Execute any tasks necessary before stopping - for example, writing out
+ * buffered content.
+ */
+ void beforeStop();
+
+ /**
+ * Execute any necessary shutdown tasks - for example, closing output
+ * streams.
+ */
+ void stop();
+}
diff --git a/rre-core/src/main/java/io/sease/rre/persistence/PersistenceManager.java b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceManager.java
new file mode 100644
index 00000000..58053b78
--- /dev/null
+++ b/rre-core/src/main/java/io/sease/rre/persistence/PersistenceManager.java
@@ -0,0 +1,82 @@
+package io.sease.rre.persistence;
+
+import io.sease.rre.core.domain.Query;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The general manager class for all persistence handlers. This provides
+ * methods for starting, processing, and shutting down a number of handlers
+ * via single method calls.
+ *
+ * Persistence handlers should be constructed outside the manager, including
+ * any required initialisation via the {@link PersistenceHandler#configure(String, Map)}
+ * method, then registered using {@link #registerHandler(PersistenceHandler)}.
+ *
+ * Most other methods apply to all registered handlers.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class PersistenceManager {
+
+ private static final Logger LOGGER = LogManager.getLogger(PersistenceManager.class);
+
+ private final List handlers = new ArrayList<>();
+
+ public void registerHandler(PersistenceHandler handler) {
+ LOGGER.info("Registering handler " + handler.getName() + " -> " + handler.getClass().getCanonicalName());
+ handlers.add(handler);
+ }
+
+ public void beforeStart() {
+ for (Iterator it = handlers.iterator(); it.hasNext(); ) {
+ PersistenceHandler h = it.next();
+ try {
+ h.beforeStart();
+ } catch (PersistenceException e) {
+ LOGGER.error("beforeStart failed for handler [" + h.getName() + "] :: " + e.getMessage());
+ it.remove();
+ }
+ }
+
+ // Check that there are handlers available
+ checkHandlers();
+ }
+
+ public void start() {
+ for (Iterator it = handlers.iterator(); it.hasNext(); ) {
+ PersistenceHandler h = it.next();
+ try {
+ h.start();
+ } catch (PersistenceException e) {
+ LOGGER.error("[" + h.getName() + "] failed to start :: " + e.getMessage());
+ it.remove();
+ }
+ }
+
+ checkHandlers();
+ }
+
+ private void checkHandlers() {
+ if (handlers.size() == 0) {
+ throw new RuntimeException("No running persistence handlers!");
+ }
+ }
+
+ public void recordQuery(Query query) {
+ handlers.parallelStream().forEach(h -> h.recordQuery(query));
+ }
+
+ public void beforeStop() {
+ handlers.parallelStream().forEach(PersistenceHandler::beforeStop);
+ }
+
+ public void stop() {
+ handlers.parallelStream().forEach(PersistenceHandler::stop);
+ }
+}
diff --git a/rre-core/src/main/java/io/sease/rre/persistence/impl/JsonPersistenceHandler.java b/rre-core/src/main/java/io/sease/rre/persistence/impl/JsonPersistenceHandler.java
new file mode 100644
index 00000000..bb23d0cf
--- /dev/null
+++ b/rre-core/src/main/java/io/sease/rre/persistence/impl/JsonPersistenceHandler.java
@@ -0,0 +1,134 @@
+package io.sease.rre.persistence.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import io.sease.rre.core.domain.DomainMember;
+import io.sease.rre.core.domain.Evaluation;
+import io.sease.rre.core.domain.Query;
+import io.sease.rre.persistence.PersistenceException;
+import io.sease.rre.persistence.PersistenceHandler;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * JSON implementation of the {@link PersistenceHandler} interface.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class JsonPersistenceHandler implements PersistenceHandler {
+
+ static final String DESTINATION_FILE_CONFIGKEY = "destinationFile";
+ static final String PRETTY_CONFIGKEY = "pretty";
+
+ public static final String DEFAULT_OUTPUT_FILE = "target/rre/evaluation.json";
+
+ private static final Logger LOGGER = LogManager.getLogger(JsonPersistenceHandler.class);
+
+ private String name;
+ private String outputFilepath;
+ private boolean pretty;
+
+ private List queries = new ArrayList<>();
+
+ @Override
+ public void configure(String name, Map configuration) {
+ this.name = name;
+ this.outputFilepath = configuration.getOrDefault(DESTINATION_FILE_CONFIGKEY, DEFAULT_OUTPUT_FILE).toString();
+ this.pretty = Boolean.valueOf(configuration.getOrDefault(PRETTY_CONFIGKEY, "false").toString());
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void beforeStart() throws PersistenceException {
+ // Delete the output file if it already exists
+ Path outPath = Paths.get(outputFilepath);
+ if (Files.exists(outPath)) {
+ try {
+ Files.delete(outPath);
+ } catch (IOException e) {
+ throw new PersistenceException("Cannot delete pre-existing output file " + outputFilepath, e);
+ }
+ } else {
+ // Make sure the file's parent directory exists
+ if (outPath.getParent() != null) {
+ try {
+ Files.createDirectories(outPath.getParent());
+ } catch (IOException e) {
+ throw new PersistenceException("Cannot create output directory " + outPath.getParent(), e);
+ }
+ }
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(outPath.toFile())) {
+ fos.write(new byte[0]);
+ } catch (IOException e) {
+ throw new PersistenceException("Cannot write to output file " + outputFilepath, e);
+ }
+ }
+
+ @Override
+ public void start() {
+ // Nothing to start
+ }
+
+ @Override
+ public void recordQuery(Query q) {
+ queries.add(q);
+ }
+
+ @Override
+ public void beforeStop() {
+ // Collect the metrics for all of the queries
+ queries.forEach(Query::notifyCollectedMetrics);
+
+ // Retrieve the top level item
+ DomainMember topLevel = findTopLevel();
+ try {
+ // Write out the JSON object
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectWriter writer = (pretty ? mapper.writerWithDefaultPrettyPrinter() : mapper.writer());
+ writer.writeValue(new File(outputFilepath), topLevel);
+ } catch (IOException e) {
+ LOGGER.error("Caught IOException writing queries to JSON :: " + e.getMessage());
+ }
+ }
+
+ private Optional> retrieveParent(DomainMember> dm) {
+ if (dm.getParent().isPresent()) {
+ return retrieveParent(dm.getParent().get());
+ } else {
+ return Optional.of(dm);
+ }
+ }
+
+ private DomainMember findTopLevel() {
+ if (queries.size() > 0) {
+ // Get the first query, then iterate through the parents to the top
+ return retrieveParent(queries.get(0)).orElse(new Evaluation());
+ } else {
+ // No queries - return an empty Evaluation object
+ LOGGER.warn("No queries recorded - returning empty evaluation");
+ return new Evaluation();
+ }
+ }
+
+ @Override
+ public void stop() {
+ // Nothing to stop
+ }
+}
diff --git a/rre-core/src/test/java/io/sease/rre/persistence/PersistenceManagerTest.java b/rre-core/src/test/java/io/sease/rre/persistence/PersistenceManagerTest.java
new file mode 100644
index 00000000..ac3521c1
--- /dev/null
+++ b/rre-core/src/test/java/io/sease/rre/persistence/PersistenceManagerTest.java
@@ -0,0 +1,87 @@
+package io.sease.rre.persistence;
+
+import io.sease.rre.core.domain.Query;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ConcurrentModificationException;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for the PersistenceManager class.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class PersistenceManagerTest {
+
+ private PersistenceManager persistenceManager;
+
+ @Before
+ public void setupManager() {
+ this.persistenceManager = new PersistenceManager();
+ }
+
+ @After
+ public void tearDownManager() {
+ this.persistenceManager = null;
+ }
+
+ @Test
+ public void managerThrowsRuntimeException_whenAllHandlersFailBeforeStart() {
+ try {
+ persistenceManager.registerHandler(failingHandler);
+ persistenceManager.beforeStart();
+ } catch (ConcurrentModificationException e) {
+ fail("Unexpected ConcurrentModificationException: " + e.getMessage());
+ } catch (RuntimeException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void managerThrowsRuntimeException_whenAllHandlersFailStart() {
+ try {
+ persistenceManager.registerHandler(failingHandler);
+ persistenceManager.start();
+ } catch (ConcurrentModificationException e) {
+ fail("Unexpected ConcurrentModificationException: " + e.getMessage());
+ } catch (RuntimeException e) {
+ // Expected
+ }
+ }
+
+ private PersistenceHandler failingHandler = new PersistenceHandler() {
+ @Override
+ public void configure(String name, Map configuration) { }
+
+ @Override
+ public String getName() {
+ return "failingHandler";
+ }
+
+ @Override
+ public void beforeStart() throws PersistenceException {
+ throw new PersistenceException();
+ }
+
+ @Override
+ public void start() throws PersistenceException {
+ throw new PersistenceException();
+ }
+
+ @Override
+ public void recordQuery(Query q) { }
+
+ @Override
+ public void beforeStop() { }
+
+ @Override
+ public void stop() { }
+ };
+
+
+
+}
diff --git a/rre-core/src/test/java/io/sease/rre/persistence/impl/JsonPersistenceHandlerTest.java b/rre-core/src/test/java/io/sease/rre/persistence/impl/JsonPersistenceHandlerTest.java
new file mode 100644
index 00000000..b240e6c7
--- /dev/null
+++ b/rre-core/src/test/java/io/sease/rre/persistence/impl/JsonPersistenceHandlerTest.java
@@ -0,0 +1,96 @@
+package io.sease.rre.persistence.impl;
+
+import io.sease.rre.persistence.PersistenceException;
+import io.sease.rre.persistence.PersistenceHandler;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for the JSON PersistenceHandler implementation.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class JsonPersistenceHandlerTest {
+
+ private static final String HANDLER_NAME = "jsonTest";
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private PersistenceHandler handler;
+
+ @Before
+ public void setupHandler() {
+ this.handler = new JsonPersistenceHandler();
+ }
+
+ @After
+ public void tearDownHandler() {
+ this.handler = null;
+ }
+
+ @Test
+ public void beforeStartThrowsException_whenFileCannotBeDeleted() throws Exception {
+ File outFile = folder.newFile();
+ outFile.setReadOnly();
+
+ Map config = new HashMap<>();
+ config.put(JsonPersistenceHandler.DESTINATION_FILE_CONFIGKEY, outFile.getAbsolutePath());
+ handler.configure(HANDLER_NAME, config);
+
+ try {
+ handler.beforeStart();
+ fail("Expected PersistenceException");
+ } catch (PersistenceException e) {
+ // Expected behaviour
+ }
+ }
+
+ @Test
+ public void beforeStartPasses_whenFileExists() throws Exception {
+ File outFile = folder.newFile();
+
+ Map config = new HashMap<>();
+ config.put(JsonPersistenceHandler.DESTINATION_FILE_CONFIGKEY, outFile.getAbsolutePath());
+ handler.configure(HANDLER_NAME, config);
+
+ handler.beforeStart();
+ }
+
+ @Test
+ public void beforeStartPasses_whenDestinationDirNotExist() throws Exception {
+ Map config = new HashMap<>();
+ config.put(JsonPersistenceHandler.DESTINATION_FILE_CONFIGKEY, folder.getRoot().getAbsolutePath() + "/target/rre/evaluation.json");
+ handler.configure(HANDLER_NAME, config);
+
+ handler.beforeStart();
+
+ File target = new File(folder.getRoot(), "target/rre/evaluation.json");
+ assertTrue(target.exists());
+ assertTrue(target.canWrite());
+ }
+
+ @Test
+ public void beforeStop_handlesEmptyQueryList() throws Exception {
+ File outFile = folder.newFile();
+ Map config = new HashMap<>();
+ config.put(JsonPersistenceHandler.DESTINATION_FILE_CONFIGKEY, outFile.getAbsolutePath());
+ config.put(JsonPersistenceHandler.PRETTY_CONFIGKEY, true);
+ handler.configure(HANDLER_NAME, config);
+
+ handler.beforeStop();
+
+ assertTrue(outFile.exists());
+ assertTrue(outFile.length() != 0);
+ }
+}
diff --git a/rre-maven-plugin/pom.xml b/rre-maven-plugin/pom.xml
index 30f3d5dd..478b4dbe 100644
--- a/rre-maven-plugin/pom.xml
+++ b/rre-maven-plugin/pom.xml
@@ -83,7 +83,7 @@
junit
junit
- 3.8.1
+ 4.12
test
diff --git a/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/main/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojo.java b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/main/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojo.java
index 889b8279..b025b92a 100644
--- a/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/main/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojo.java
+++ b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/main/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojo.java
@@ -1,8 +1,7 @@
package io.sease.rre.maven.plugin.elasticsearch;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.sease.rre.core.Engine;
-import io.sease.rre.core.domain.Evaluation;
+import io.sease.rre.persistence.PersistenceConfiguration;
import io.sease.rre.search.api.SearchPlatform;
import io.sease.rre.search.api.impl.Elasticsearch;
import org.apache.maven.plugin.AbstractMojo;
@@ -61,6 +60,9 @@ public class RREvaluateMojo extends AbstractMojo {
@Parameter(name = "port", defaultValue = "9200")
private int port;
+ @Parameter(name = "persistence")
+ private PersistenceConfiguration persistence = PersistenceConfiguration.DEFAULT_CONFIG;
+
@Override
public void execute() throws MojoExecutionException {
final URL [] urls = compilePaths.stream()
@@ -88,30 +90,22 @@ public void execute() throws MojoExecutionException {
metrics,
fields.split(","),
exclude,
- include);
+ include,
+ persistence);
final Map configuration = new HashMap<>();
configuration.put("path.home", "/tmp");
configuration.put("network.host", port);
configuration.put("plugins", plugins);
- write(engine.evaluate(configuration));
+ engine.evaluate(configuration);
} catch (final IOException exception) {
throw new MojoExecutionException(exception.getMessage(), exception);
}
}
- /**
- * Writes out the evaluation result.
- *
- * @param evaluation the evaluation result.
- * @throws IOException in case of I/O failure.
- */
- private void write(final Evaluation evaluation) throws IOException {
- final File outputFolder = new File("target/rre");
- outputFolder.mkdirs();
-
- final ObjectMapper mapper = new ObjectMapper();
- mapper.writerWithDefaultPrettyPrinter().writeValue(new File(outputFolder, "evaluation.json"), evaluation);
+ // Used by unit test
+ PersistenceConfiguration getPersistence() {
+ return persistence;
}
}
\ No newline at end of file
diff --git a/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojoTest.java b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojoTest.java
new file mode 100644
index 00000000..4c63b8e9
--- /dev/null
+++ b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/java/io/sease/rre/maven/plugin/elasticsearch/RREvaluateMojoTest.java
@@ -0,0 +1,61 @@
+package io.sease.rre.maven.plugin.elasticsearch;
+
+import io.sease.rre.persistence.PersistenceConfiguration;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.testing.MojoRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Basic configuration tests for the ES Evaluate plugin.
+ *
+ * @author Matt Pearce (matt@flax.co.uk)
+ */
+public class RREvaluateMojoTest {
+
+ @Rule
+ public MojoRule rule = new MojoRule()
+ {
+ @Override
+ protected void before() throws Throwable
+ {
+ }
+
+ @Override
+ protected void after()
+ {
+ }
+ };
+
+ @Test
+ public void testBuildsDefaultPersistenceConfig_whenNoPersistenceConfigInPom() throws Exception {
+ Mojo mojo = rule.lookupMojo("evaluate", "src/test/resources/persistence/no_persistence_pom.xml");
+ assertNotNull(mojo);
+
+ RREvaluateMojo rreMojo = (RREvaluateMojo) mojo;
+ PersistenceConfiguration persist = rreMojo.getPersistence();
+ assertNotNull(persist);
+ assertFalse(persist.isUseTimestampAsVersion());
+ assertEquals(persist.getHandlers().size(), 1);
+ assertTrue(persist.getHandlers().containsKey("json"));
+ assertTrue(persist.getHandlerConfiguration().containsKey("json"));
+ }
+
+ @Test
+ public void testBuildsCorrectPersistenceConfig_whenPersistenceConfigInPom() throws Exception {
+ Mojo mojo = rule.lookupMojo("evaluate", "src/test/resources/persistence/persistence_pom.xml");
+ assertNotNull(mojo);
+
+ RREvaluateMojo rreMojo = (RREvaluateMojo) mojo;
+ PersistenceConfiguration persist = rreMojo.getPersistence();
+ assertNotNull(persist);
+ assertTrue(persist.isUseTimestampAsVersion());
+ assertEquals(persist.getHandlers().size(), 1);
+ assertTrue(persist.getHandlers().containsKey("testJson"));
+ assertTrue(persist.getHandlerConfiguration().containsKey("testJson"));
+ assertNotNull(persist.getHandlerConfiguration().get("testJson"));
+ assertEquals(persist.getHandlerConfiguration().get("testJson").get("destinationFile"), "blah.txt");
+ }
+}
diff --git a/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/no_persistence_pom.xml b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/no_persistence_pom.xml
new file mode 100644
index 00000000..a4a248c7
--- /dev/null
+++ b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/no_persistence_pom.xml
@@ -0,0 +1,41 @@
+
+ 4.0.0
+ io.sease
+ rre-maven-elasticsearch-plugin
+ 6.3.2
+ pom
+
+
+ 1.8
+ 1.8
+
+
+
+
+ sease
+ https://raw.github.com/SeaseLtd/rated-ranking-evaluator/mvn-repo
+
+
+
+
+
+ io.sease
+ rre-maven-elasticsearch-plugin
+ ${esVersion}
+
+
+
+
+
+ search-quality-evaluation
+ package
+
+ evaluate
+
+
+
+
+
+
+
diff --git a/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/persistence_pom.xml b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/persistence_pom.xml
new file mode 100644
index 00000000..96b50850
--- /dev/null
+++ b/rre-maven-plugin/rre-maven-elasticsearch-plugin/src/test/resources/persistence/persistence_pom.xml
@@ -0,0 +1,51 @@
+
+ 4.0.0
+ io.sease
+ rre-maven-elasticsearch-plugin
+ 6.3.2
+ pom
+
+
+ 1.8
+ 1.8
+
+
+
+
+ sease
+ https://raw.github.com/SeaseLtd/rated-ranking-evaluator/mvn-repo
+
+
+
+
+
+ io.sease
+ rre-maven-elasticsearch-plugin
+ ${esVersion}
+
+
+ true
+
+ io.sease.rre.persistence.impl.JsonPersistenceHandler
+
+
+
+ blah.txt
+
+
+
+
+
+
+ search-quality-evaluation
+ package
+
+ evaluate
+
+
+
+
+
+
+
diff --git a/rre-maven-plugin/rre-maven-report-plugin/src/main/java/io/sease/rre/maven/plugin/report/RREMavenReport.java b/rre-maven-plugin/rre-maven-report-plugin/src/main/java/io/sease/rre/maven/plugin/report/RREMavenReport.java
index 8df4ddbb..23e7d129 100644
--- a/rre-maven-plugin/rre-maven-report-plugin/src/main/java/io/sease/rre/maven/plugin/report/RREMavenReport.java
+++ b/rre-maven-plugin/rre-maven-report-plugin/src/main/java/io/sease/rre/maven/plugin/report/RREMavenReport.java
@@ -2,11 +2,11 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import io.sease.rre.maven.plugin.report.domain.EvaluationMetadata;
import io.sease.rre.maven.plugin.report.formats.OutputFormat;
import io.sease.rre.maven.plugin.report.formats.impl.RREOutputFormat;
import io.sease.rre.maven.plugin.report.formats.impl.SpreadsheetOutputFormat;
+import io.sease.rre.persistence.impl.JsonPersistenceHandler;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.reporting.AbstractMavenReport;
@@ -35,6 +35,9 @@ public class RREMavenReport extends AbstractMavenReport {
@Parameter(name = "endpoint", defaultValue = "http://127.0.0.1:8080")
String endpoint;
+ @Parameter(name="evaluationFile", defaultValue = JsonPersistenceHandler.DEFAULT_OUTPUT_FILE)
+ String evaluationFile;
+
private Map formatters = new HashMap<>();
{
@@ -131,7 +134,7 @@ private JsonNode evaluationAsJson() {
* @return a file reference to the evaluation output.
*/
File evaluationOutputFile() {
- final File file = new File("target/rre/evaluation.json");
+ final File file = new File(evaluationFile);
if (!file.canRead()) {
throw new RuntimeException("Unable to read RRE evaluation output file. Are you sure RRE executed successfully?");
}
diff --git a/rre-maven-plugin/rre-maven-solr-plugin/src/main/java/io/sease/rre/maven/plugin/solr/RREvaluateMojo.java b/rre-maven-plugin/rre-maven-solr-plugin/src/main/java/io/sease/rre/maven/plugin/solr/RREvaluateMojo.java
index 5b61a10d..be2b4bd3 100644
--- a/rre-maven-plugin/rre-maven-solr-plugin/src/main/java/io/sease/rre/maven/plugin/solr/RREvaluateMojo.java
+++ b/rre-maven-plugin/rre-maven-solr-plugin/src/main/java/io/sease/rre/maven/plugin/solr/RREvaluateMojo.java
@@ -1,8 +1,7 @@
package io.sease.rre.maven.plugin.solr;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.sease.rre.core.Engine;
-import io.sease.rre.core.domain.Evaluation;
+import io.sease.rre.persistence.PersistenceConfiguration;
import io.sease.rre.search.api.SearchPlatform;
import io.sease.rre.search.api.impl.ApacheSolr;
import org.apache.maven.plugin.AbstractMojo;
@@ -11,7 +10,6 @@
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
-import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
@@ -50,6 +48,9 @@ public class RREvaluateMojo extends AbstractMojo {
@Parameter(name = "exclude")
private List exclude;
+ @Parameter(name = "persistence")
+ private PersistenceConfiguration persistence = PersistenceConfiguration.DEFAULT_CONFIG;
+
@Override
public void execute() throws MojoExecutionException {
try (final SearchPlatform platform = new ApacheSolr()) {
@@ -62,28 +63,15 @@ public void execute() throws MojoExecutionException {
metrics,
fields.split(","),
exclude,
- include);
+ include,
+ persistence);
final Map configuration = new HashMap<>();
configuration.put("solr.home", "/tmp");
- write(engine.evaluate(configuration));
+ engine.evaluate(configuration);
} catch (final IOException exception) {
throw new MojoExecutionException(exception.getMessage(), exception);
}
}
-
- /**
- * Writes out the evaluation result.
- *
- * @param evaluation the evaluation result.
- * @throws IOException in case of I/O failure.
- */
- private void write(final Evaluation evaluation) throws IOException {
- final File outputFolder = new File("target/rre");
- outputFolder.mkdirs();
-
- final ObjectMapper mapper = new ObjectMapper();
- mapper.writerWithDefaultPrettyPrinter().writeValue(new File(outputFolder, "evaluation.json"), evaluation);
- }
}
\ No newline at end of file