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