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