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 try
107 {
108 List<RunEntryStatistics> items = new ArrayList<RunEntryStatistics>( runEntryStatistics.values() );
109 Collections.sort( items, new RunCountComparator() );
110 for ( RunEntryStatistics item : items )
111 {
112 printWriter.println( item.toString() );
113 }
114 }
115 finally
116 {
117 printWriter.close();
118 }
119 }
120
121 public RunEntryStatistics findOrCreate( ReportEntry reportEntry )
122 {
123 final RunEntryStatistics item = runEntryStatistics.get( reportEntry.getName() );
124 return item != null ? item : RunEntryStatistics.fromReportEntry( reportEntry );
125 }
126
127 public RunEntryStatistics createNextGeneration( ReportEntry reportEntry )
128 {
129 final RunEntryStatistics newItem = findOrCreate( reportEntry );
130 final Integer elapsed = reportEntry.getElapsed();
131 return newItem.nextGeneration( elapsed != null ? elapsed : 0 );
132 }
133
134 public RunEntryStatistics createNextGenerationFailure( ReportEntry reportEntry )
135 {
136 final RunEntryStatistics newItem = findOrCreate( reportEntry );
137 final Integer elapsed = reportEntry.getElapsed();
138 return newItem.nextGenerationFailure( elapsed != null ? elapsed : 0 );
139 }
140
141 public void add( RunEntryStatistics item )
142 {
143 runEntryStatistics.put( item.getTestName(), item );
144 }
145
146 class RunCountComparator
147 implements Comparator<RunEntryStatistics>
148 {
149 public int compare( RunEntryStatistics o, RunEntryStatistics o1 )
150 {
151 int runtime = o.getSuccessfulBuilds() - o1.getSuccessfulBuilds();
152 return runtime == 0 ? o.getRunTime() - o1.getRunTime() : runtime;
153 }
154 }
155
156 public List<Class<?>> getPrioritizedTestsClassRunTime( List<Class<?>> testsToRun, int threadCount )
157 {
158 List<PrioritizedTest> prioritizedTests = getPrioritizedTests( testsToRun, new TestRuntimeComparator() );
159 ThreadedExecutionScheduler threadedExecutionScheduler = new ThreadedExecutionScheduler( threadCount );
160 for ( Object prioritizedTest1 : prioritizedTests )
161 {
162 threadedExecutionScheduler.addTest( (PrioritizedTest) prioritizedTest1 );
163 }
164
165 return threadedExecutionScheduler.getResult();
166 }
167
168 public List<Class<?>> getPrioritizedTestsByFailureFirst( List<Class<?>> testsToRun )
169 {
170 List<PrioritizedTest> prioritizedTests = getPrioritizedTests( testsToRun, new LeastFailureComparator() );
171 return transformToClasses( prioritizedTests );
172 }
173
174 private List<PrioritizedTest> getPrioritizedTests( List<Class<?>> testsToRun,
175 Comparator<Priority> priorityComparator )
176 {
177 Map classPriorities = getPriorities( priorityComparator );
178
179 List<PrioritizedTest> tests = new ArrayList<PrioritizedTest>();
180 for ( Class<?> clazz : testsToRun )
181 {
182 Priority pri = (Priority) classPriorities.get( clazz.getName() );
183 if ( pri == null )
184 {
185 pri = Priority.newTestClassPriority( clazz.getName() );
186 }
187 PrioritizedTest prioritizedTest = new PrioritizedTest( clazz, pri );
188 tests.add( prioritizedTest );
189 }
190 Collections.sort( tests, new PrioritizedTestComparator() );
191 return tests;
192 }
193
194 private List<Class<?>> transformToClasses( List<PrioritizedTest> tests )
195 {
196 List<Class<?>> result = new ArrayList<Class<?>>();
197 for ( PrioritizedTest test : tests )
198 {
199 result.add( test.getClazz() );
200 }
201 return result;
202 }
203
204 public Map getPriorities( Comparator<Priority> priorityComparator )
205 {
206 Map<String, Priority> priorities = new HashMap<String, Priority>();
207 for ( Object o : runEntryStatistics.keySet() )
208 {
209 String testNames = (String) o;
210 String clazzName = extractClassName( testNames );
211 Priority priority = priorities.get( clazzName );
212 if ( priority == null )
213 {
214 priority = new Priority( clazzName );
215 priorities.put( clazzName, priority );
216 }
217
218 RunEntryStatistics itemStat = runEntryStatistics.get( testNames );
219 priority.addItem( itemStat );
220 }
221
222 List<Priority> items = new ArrayList<Priority>( priorities.values() );
223 Collections.sort( items, priorityComparator );
224 Map<String, Priority> result = new HashMap<String, Priority>();
225 int i = 0;
226 for ( Priority pri : items )
227 {
228 pri.setPriority( i++ );
229 result.put( pri.getClassName(), pri );
230 }
231 return result;
232 }
233
234 class PrioritizedTestComparator
235 implements Comparator<PrioritizedTest>
236 {
237 public int compare( PrioritizedTest o, PrioritizedTest o1 )
238 {
239 return o.getPriority() - o1.getPriority();
240 }
241 }
242
243 class TestRuntimeComparator
244 implements Comparator<Priority>
245 {
246 public int compare( Priority o, Priority o1 )
247 {
248 return o1.getTotalRuntime() - o.getTotalRuntime();
249 }
250 }
251
252 class LeastFailureComparator
253 implements Comparator<Priority>
254 {
255 public int compare( Priority o, Priority o1 )
256 {
257 return o.getMinSuccessRate() - o1.getMinSuccessRate();
258 }
259 }
260
261
262 private static final Pattern PARENS = Pattern.compile( "^" + "[^\\(\\)]+"
263 + "\\(("
264 + "[^\\\\(\\\\)]+"
265 + ")\\)" + "$" );
266
267 String extractClassName( String displayName )
268 {
269 Matcher m = PARENS.matcher( displayName );
270 return m.find() ? m.group( 1 ) : displayName;
271 }
272 }