aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/junit/experimental/max/MaxHistory.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/junit/experimental/max/MaxHistory.java')
-rw-r--r--src/main/java/org/junit/experimental/max/MaxHistory.java166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/main/java/org/junit/experimental/max/MaxHistory.java b/src/main/java/org/junit/experimental/max/MaxHistory.java
new file mode 100644
index 0000000..e091793
--- /dev/null
+++ b/src/main/java/org/junit/experimental/max/MaxHistory.java
@@ -0,0 +1,166 @@
+package org.junit.experimental.max;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+/**
+ * Stores a subset of the history of each test:
+ * <ul>
+ * <li>Last failure timestamp
+ * <li>Duration of last execution
+ * </ul>
+ */
+public class MaxHistory implements Serializable {
+ private static final long serialVersionUID= 1L;
+
+ /**
+ * Loads a {@link MaxHistory} from {@code file}, or generates a new one that
+ * will be saved to {@code file}.
+ */
+ public static MaxHistory forFolder(File file) {
+ if (file.exists())
+ try {
+ return readHistory(file);
+ } catch (CouldNotReadCoreException e) {
+ e.printStackTrace();
+ file.delete();
+ }
+ return new MaxHistory(file);
+ }
+
+ private static MaxHistory readHistory(File storedResults)
+ throws CouldNotReadCoreException {
+ try {
+ FileInputStream file= new FileInputStream(storedResults);
+ try {
+ ObjectInputStream stream= new ObjectInputStream(file);
+ try {
+ return (MaxHistory) stream.readObject();
+ } finally {
+ stream.close();
+ }
+ } finally {
+ file.close();
+ }
+ } catch (Exception e) {
+ throw new CouldNotReadCoreException(e);
+ }
+ }
+
+ private final Map<String, Long> fDurations= new HashMap<String, Long>();
+
+ private final Map<String, Long> fFailureTimestamps= new HashMap<String, Long>();
+
+ private final File fHistoryStore;
+
+ private MaxHistory(File storedResults) {
+ fHistoryStore= storedResults;
+ }
+
+ private void save() throws IOException {
+ ObjectOutputStream stream= new ObjectOutputStream(new FileOutputStream(
+ fHistoryStore));
+ stream.writeObject(this);
+ stream.close();
+ }
+
+ Long getFailureTimestamp(Description key) {
+ return fFailureTimestamps.get(key.toString());
+ }
+
+ void putTestFailureTimestamp(Description key, long end) {
+ fFailureTimestamps.put(key.toString(), end);
+ }
+
+ boolean isNewTest(Description key) {
+ return !fDurations.containsKey(key.toString());
+ }
+
+ Long getTestDuration(Description key) {
+ return fDurations.get(key.toString());
+ }
+
+ void putTestDuration(Description description, long duration) {
+ fDurations.put(description.toString(), duration);
+ }
+
+ private final class RememberingListener extends RunListener {
+ private long overallStart= System.currentTimeMillis();
+
+ private Map<Description, Long> starts= new HashMap<Description, Long>();
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ starts.put(description, System.nanoTime()); // Get most accurate
+ // possible time
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ long end= System.nanoTime();
+ long start= starts.get(description);
+ putTestDuration(description, end - start);
+ }
+
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ putTestFailureTimestamp(failure.getDescription(), overallStart);
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ save();
+ }
+ }
+
+ private class TestComparator implements Comparator<Description> {
+ public int compare(Description o1, Description o2) {
+ // Always prefer new tests
+ if (isNewTest(o1))
+ return -1;
+ if (isNewTest(o2))
+ return 1;
+ // Then most recently failed first
+ int result= getFailure(o2).compareTo(getFailure(o1));
+ return result != 0 ? result
+ // Then shorter tests first
+ : getTestDuration(o1).compareTo(getTestDuration(o2));
+ }
+
+ private Long getFailure(Description key) {
+ Long result= getFailureTimestamp(key);
+ if (result == null)
+ return 0L; // 0 = "never failed (that I know about)"
+ return result;
+ }
+ }
+
+ /**
+ * @return a listener that will update this history based on the test
+ * results reported.
+ */
+ public RunListener listener() {
+ return new RememberingListener();
+ }
+
+ /**
+ * @return a comparator that ranks tests based on the JUnit Max sorting
+ * rules, as described in the {@link MaxCore} class comment.
+ */
+ public Comparator<Description> testComparator() {
+ return new TestComparator();
+ }
+}