1 package org.apache.maven.plugin.surefire.runorder;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import org.apache.maven.surefire.report.ReportEntry;
24
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.FileReader;
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.io.Reader;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.Comparator;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42
43
44
45
46 public class RunEntryStatisticsMap
47 {
48 private final Map<String, RunEntryStatistics> runEntryStatistics;
49
50 public RunEntryStatisticsMap( Map<String, RunEntryStatistics> runEntryStatistics )
51 {
52 this.runEntryStatistics = Collections.synchronizedMap( runEntryStatistics );
53 }
54
55 public RunEntryStatisticsMap()
56 {
57 runEntryStatistics = new ConcurrentHashMap<String, RunEntryStatistics>();
58 }
59
60 public static RunEntryStatisticsMap fromFile( File file )
61 {
62 if ( file.exists() )
63 {
64 try
65 {
66 return fromReader( new FileReader( file ) );
67 }
68 catch ( FileNotFoundException e )
69 {
70 throw new RuntimeException( e );
71 }
72 catch ( IOException e1 )
73 {
74 throw new RuntimeException( e1 );
75 }
76 }
77 else
78 {
79 return new RunEntryStatisticsMap();
80 }
81 }
82
83 static RunEntryStatisticsMap fromReader( Reader fileReader )
84 throws IOException
85 {
86 Map<String, RunEntryStatistics> result = new HashMap<String, RunEntryStatistics>();
87 BufferedReader bufferedReader = new BufferedReader( fileReader );
88 String line = bufferedReader.readLine();
89 while ( line != null )
90 {
91 if ( !line.startsWith( "#" ) )
92 {
93 final RunEntryStatistics stats = RunEntryStatistics.fromString( line );
94 result.put( stats.getTestName(), stats );
95 }
96 line = bufferedReader.readLine();
97 }
98 return new RunEntryStatisticsMap( result );
99 }
100
101 public void serialize( File file )
102 throws FileNotFoundException
103 {
104 FileOutputStream fos = new FileOutputStream( file );
105 PrintWriter printWriter = new PrintWriter( fos );
106 List<RunEntryStatistics> items = new ArrayList<RunEntryStatistics>( runEntryStatistics.values() );
107 Collections.sort( items, new RunCountComparator() );
108 for ( RunEntryStatistics item : items )
109 {
110 printWriter.println( item.toString() );
111 }
112 printWriter.close();
113 }
114
115 public RunEntryStatistics findOrCreate( ReportEntry reportEntry )
116 {
117 final RunEntryStatistics item = runEntryStatistics.get( reportEntry.getName() );
118 return item != null ? item : RunEntryStatistics.fromReportEntry( reportEntry );
119 }
120
121 public RunEntryStatistics createNextGeneration( ReportEntry reportEntry )
122 {
123 final RunEntryStatistics newItem = findOrCreate( reportEntry );
124 final Integer elapsed = reportEntry.getElapsed();
125 return newItem.nextGeneration( elapsed != null ? elapsed : 0 );
126 }
127
128 public RunEntryStatistics createNextGenerationFailure( ReportEntry reportEntry )
129 {
130 final RunEntryStatistics newItem = findOrCreate( reportEntry );
131 final Integer elapsed = reportEntry.getElapsed();
132 return newItem.nextGenerationFailure( elapsed != null ? elapsed : 0 );
133 }
134
135 public void add( RunEntryStatistics item )
136 {
137 runEntryStatistics.put( item.getTestName(), item );
138 }
139
140 class RunCountComparator
141 implements Comparator<RunEntryStatistics>
142 {
143 public int compare( RunEntryStatistics o, RunEntryStatistics o1 )
144 {
145 int runtime = o.getSuccessfulBuilds() - o1.getSuccessfulBuilds();
146 return runtime == 0 ? o.getRunTime() - o1.getRunTime() : runtime;
147 }
148 }
149
150 public List<Class<?>> getPrioritizedTestsClassRunTime( List<Class<?>> testsToRun, int threadCount )
151 {
152 List<PrioritizedTest> prioritizedTests = getPrioritizedTests( testsToRun, new TestRuntimeComparator() );
153 ThreadedExecutionScheduler threadedExecutionScheduler = new ThreadedExecutionScheduler( threadCount );
154 for ( Object prioritizedTest1 : prioritizedTests )
155 {
156 threadedExecutionScheduler.addTest( (PrioritizedTest) prioritizedTest1 );
157 }
158
159 return threadedExecutionScheduler.getResult();
160 }
161
162 public List<Class<?>> getPrioritizedTestsByFailureFirst( List<Class<?>> testsToRun )
163 {
164 List<PrioritizedTest> prioritizedTests = getPrioritizedTests( testsToRun, new LeastFailureComparator() );
165 return transformToClasses( prioritizedTests );
166 }
167
168 private List<PrioritizedTest> getPrioritizedTests( List<Class<?>> testsToRun,
169 Comparator<Priority> priorityComparator )
170 {
171 Map classPriorities = getPriorities( priorityComparator );
172
173 List<PrioritizedTest> tests = new ArrayList<PrioritizedTest>();
174 for ( Class<?> clazz : testsToRun )
175 {
176 Priority pri = (Priority) classPriorities.get( clazz.getName() );
177 if ( pri == null )
178 {
179 pri = Priority.newTestClassPriority( clazz.getName() );
180 }
181 PrioritizedTest prioritizedTest = new PrioritizedTest( clazz, pri );
182 tests.add( prioritizedTest );
183 }
184 Collections.sort( tests, new PrioritizedTestComparator() );
185 return tests;
186 }
187
188 private List<Class<?>> transformToClasses( List<PrioritizedTest> tests )
189 {
190 List<Class<?>> result = new ArrayList<Class<?>>();
191 for ( PrioritizedTest test : tests )
192 {
193 result.add( test.getClazz() );
194 }
195 return result;
196 }
197
198 public Map getPriorities( Comparator<Priority> priorityComparator )
199 {
200 Map<String, Priority> priorities = new HashMap<String, Priority>();
201 for ( Object o : runEntryStatistics.keySet() )
202 {
203 String testNames = (String) o;
204 String clazzName = extractClassName( testNames );
205 Priority priority = priorities.get( clazzName );
206 if ( priority == null )
207 {
208 priority = new Priority( clazzName );
209 priorities.put( clazzName, priority );
210 }
211
212 RunEntryStatistics itemStat = runEntryStatistics.get( testNames );
213 priority.addItem( itemStat );
214 }
215
216 List<Priority> items = new ArrayList<Priority>( priorities.values() );
217 Collections.sort( items, priorityComparator );
218 Map<String, Priority> result = new HashMap<String, Priority>();
219 int i = 0;
220 for ( Priority pri : items )
221 {
222 pri.setPriority( i++ );
223 result.put( pri.getClassName(), pri );
224 }
225 return result;
226 }
227
228 class PrioritizedTestComparator
229 implements Comparator<PrioritizedTest>
230 {
231 public int compare( PrioritizedTest o, PrioritizedTest o1 )
232 {
233 return o.getPriority() - o1.getPriority();
234 }
235 }
236
237 class TestRuntimeComparator
238 implements Comparator<Priority>
239 {
240 public int compare( Priority o, Priority o1 )
241 {
242 return o1.getTotalRuntime() - o.getTotalRuntime();
243 }
244 }
245
246 class LeastFailureComparator
247 implements Comparator<Priority>
248 {
249 public int compare( Priority o, Priority o1 )
250 {
251 return o.getMinSuccessRate() - o1.getMinSuccessRate();
252 }
253 }
254
255
256 private static final Pattern PARENS = Pattern.compile( "^" + "[^\\(\\)]+"
257 + "\\(("
258 + "[^\\\\(\\\\)]+"
259 + ")\\)" + "$" );
260
261 String extractClassName( String displayName )
262 {
263 Matcher m = PARENS.matcher( displayName );
264 return m.find() ? m.group( 1 ) : displayName;
265 }
266 }