1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.experimental.max; 2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.File; 4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.FileInputStream; 5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.FileOutputStream; 6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.IOException; 7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.ObjectInputStream; 8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.ObjectOutputStream; 9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.io.Serializable; 10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.Comparator; 11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.HashMap; 12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.Map; 13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runner.Description; 15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runner.Result; 16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runner.notification.Failure; 17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runner.notification.RunListener; 18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/** 20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Stores a subset of the history of each test: 21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * <ul> 22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * <li>Last failure timestamp 23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * <li>Duration of last execution 24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * </ul> 25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic class MaxHistory implements Serializable { 27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private static final long serialVersionUID= 1L; 28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Loads a {@link MaxHistory} from {@code file}, or generates a new one that 31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * will be saved to {@code file}. 32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public static MaxHistory forFolder(File file) { 34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (file.exists()) 35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot try { 36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return readHistory(file); 37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } catch (CouldNotReadCoreException e) { 38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot e.printStackTrace(); 39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot file.delete(); 40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return new MaxHistory(file); 42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private static MaxHistory readHistory(File storedResults) 45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot throws CouldNotReadCoreException { 46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot try { 47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot FileInputStream file= new FileInputStream(storedResults); 48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot try { 49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot ObjectInputStream stream= new ObjectInputStream(file); 50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot try { 51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return (MaxHistory) stream.readObject(); 52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } finally { 53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot stream.close(); 54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } finally { 56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot file.close(); 57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } catch (Exception e) { 59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot throw new CouldNotReadCoreException(e); 60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 61b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 62b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 63b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private final Map<String, Long> fDurations= new HashMap<String, Long>(); 64b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 65b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private final Map<String, Long> fFailureTimestamps= new HashMap<String, Long>(); 66b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 67b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private final File fHistoryStore; 68b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 69b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private MaxHistory(File storedResults) { 70b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fHistoryStore= storedResults; 71b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 72b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 73b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private void save() throws IOException { 74b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot ObjectOutputStream stream= new ObjectOutputStream(new FileOutputStream( 75b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fHistoryStore)); 76b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot stream.writeObject(this); 77b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot stream.close(); 78b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 79b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 80b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Long getFailureTimestamp(Description key) { 81b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fFailureTimestamps.get(key.toString()); 82b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 83b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 84b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot void putTestFailureTimestamp(Description key, long end) { 85b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fFailureTimestamps.put(key.toString(), end); 86b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 87b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 88b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot boolean isNewTest(Description key) { 89b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return !fDurations.containsKey(key.toString()); 90b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 91b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 92b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Long getTestDuration(Description key) { 93b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return fDurations.get(key.toString()); 94b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 95b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 96b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot void putTestDuration(Description description, long duration) { 97b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot fDurations.put(description.toString(), duration); 98b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 99b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 100b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private final class RememberingListener extends RunListener { 101b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private long overallStart= System.currentTimeMillis(); 102b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 103b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private Map<Description, Long> starts= new HashMap<Description, Long>(); 104b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 105b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot @Override 106b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public void testStarted(Description description) throws Exception { 107b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot starts.put(description, System.nanoTime()); // Get most accurate 108b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot // possible time 109b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 110b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 111b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot @Override 112b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public void testFinished(Description description) throws Exception { 113b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot long end= System.nanoTime(); 114b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot long start= starts.get(description); 115b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot putTestDuration(description, end - start); 116b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 117b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 118b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot @Override 119b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public void testFailure(Failure failure) throws Exception { 120b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot putTestFailureTimestamp(failure.getDescription(), overallStart); 121b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 122b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 123b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot @Override 124b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public void testRunFinished(Result result) throws Exception { 125b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot save(); 126b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 127b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 128b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 129b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private class TestComparator implements Comparator<Description> { 130b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public int compare(Description o1, Description o2) { 131b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot // Always prefer new tests 132b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (isNewTest(o1)) 133b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return -1; 134b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (isNewTest(o2)) 135b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return 1; 136b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot // Then most recently failed first 137b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot int result= getFailure(o2).compareTo(getFailure(o1)); 138b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return result != 0 ? result 139b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot // Then shorter tests first 140b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot : getTestDuration(o1).compareTo(getTestDuration(o2)); 141b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 142b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 143b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private Long getFailure(Description key) { 144b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot Long result= getFailureTimestamp(key); 145b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (result == null) 146b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return 0L; // 0 = "never failed (that I know about)" 147b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return result; 148b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 149b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 150b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 151b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 152b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * @return a listener that will update this history based on the test 153b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * results reported. 154b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 155b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public RunListener listener() { 156b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return new RememberingListener(); 157b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 158b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 159b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 160b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * @return a comparator that ranks tests based on the JUnit Max sorting 161b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * rules, as described in the {@link MaxCore} class comment. 162b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 163b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public Comparator<Description> testComparator() { 164b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return new TestComparator(); 165b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 166b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot} 167