1 package com.google.code.jetm.maven;
2
3 import static org.fest.assertions.Assertions.assertThat;
4
5 import java.io.File;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.StringReader;
10 import java.net.URI;
11 import java.net.URL;
12 import java.text.DecimalFormat;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.Iterator;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Properties;
19 import java.util.ResourceBundle;
20
21 import org.apache.commons.io.IOUtils;
22 import org.apache.maven.shared.invoker.InvocationResult;
23 import org.apache.maven.shared.test.plugin.BuildTool;
24 import org.codehaus.plexus.util.FileUtils;
25 import org.jdom.Attribute;
26 import org.jdom.Document;
27 import org.jdom.Element;
28 import org.jdom.filter.ElementFilter;
29 import org.jdom.input.SAXBuilder;
30 import org.junit.After;
31 import org.junit.AfterClass;
32 import org.junit.Before;
33 import org.junit.BeforeClass;
34 import org.junit.Rule;
35 import org.junit.Test;
36 import org.junit.rules.TestName;
37 import org.openqa.selenium.By;
38 import org.openqa.selenium.WebDriver;
39 import org.openqa.selenium.WebElement;
40 import org.openqa.selenium.htmlunit.HtmlUnitDriver;
41
42 import com.google.code.jetm.maven.data.TimeUnit;
43 import com.google.code.jetm.maven.internal.SimpleAggregate;
44 import com.google.code.jetm.reporting.xml.XmlAggregateBinder;
45
46 import etm.core.aggregation.Aggregate;
47
48
49
50
51
52
53
54
55 public class TimingReportMojoITest {
56
57
58
59 @Rule
60 public TestName testName = new TestName();
61
62 private static final Properties originalSystemProperties = System.getProperties();
63 private final List<String> cleanTestSite = Arrays.asList("clean", "test", "site");
64 private WebDriver driver;
65 private BuildTool build;
66
67
68
69
70
71
72
73
74 @BeforeClass
75 public static void setUpBeforeClass() throws Exception {
76 final ResourceBundle systemPropsBundle = ResourceBundle.getBundle("system");
77 System.setProperty("maven.home", systemPropsBundle.getString("maven.home"));
78 }
79
80
81
82
83
84
85
86 @Before
87 public void setUp() throws Exception {
88 build = new BuildTool();
89 build.initialize();
90
91 driver = new HtmlUnitDriver();
92 }
93
94
95
96
97
98
99
100
101 @After
102 public void tearDown() throws Exception {
103 if (build != null)
104 build.dispose();
105
106 if (driver != null)
107 driver.close();
108 }
109
110
111
112
113
114
115
116 @AfterClass
117 public static void tearDownAfterClass() throws Exception {
118 System.setProperties(originalSystemProperties);
119 }
120
121
122
123
124
125
126
127 @SuppressWarnings("unchecked")
128 @Test
129 public void testDemoProject() throws Exception {
130 final String projectName = "demo-project";
131 final File logFile = getLogFile();
132 final InvocationResult result = build.executeMaven(getPom(projectName), null, cleanTestSite, logFile);
133 assertThat(result.getExitCode()).isZero();
134
135 final WebDriver driver = getDriver();
136 driver.get(getSiteIndexLocation(projectName));
137 openJetmTimingReport(driver);
138
139 final Collection<Aggregate> reportData = getAggregateData();
140 for (File reportFile : (List<File>) FileUtils.getFiles(FileUtils.toFile(getClass().getResource("/example-projects/" + projectName + "/target/jetm")), "**/*.xml", null, true)) {
141 final Collection<Aggregate> aggregates = getAggregates(reportFile, TimeUnit.SECONDS);
142
143 assertHasSection(reportFile.getName());
144
145 assertThat(reportData).contains(aggregates.toArray());
146 }
147 }
148
149
150
151
152
153
154
155 @Test
156 public void testEmptyReport() throws Exception {
157 final String projectName = "empty-project";
158 final File logFile = getLogFile();
159 final InvocationResult result = build.executeMaven(getPom(projectName), null, cleanTestSite, logFile);
160 assertThat(result.getExitCode()).isZero();
161
162 final File siteIndex = new File(URI.create(getSiteIndexLocation(projectName)));
163 assertThat(new File(siteIndex.getParentFile(), "jetm-timing-report.html")).doesNotExist();
164 }
165
166
167
168
169
170
171
172
173
174
175 @Test
176 public void testMavenSitePluginCompatibility() throws Exception {
177 final String projectName = "maven-site-plugin-version";
178 final File baseLogFile = getLogFile();
179
180 for (String sitePluginVersion : new String[] { "2.0", "2.1", "2.2" }) {
181 final File logFile = new File(baseLogFile.getParentFile(), sitePluginVersion + "-" + baseLogFile.getName());
182
183 final Properties mavenProps = new Properties();
184 mavenProps.setProperty("site.plugin.version", sitePluginVersion);
185
186 final InvocationResult result = build.executeMaven(getPom(projectName), mavenProps, cleanTestSite, logFile);
187 assertThat(result.getExitCode()).as("Execution for version " + sitePluginVersion + " failed.").isZero();
188
189 final InputStream resourceStream = getClass().getResourceAsStream("/example-projects/maven-site-plugin-version/target/site/jetm-timing-report.html");
190 assertThat(resourceStream).as("Could not find timing report for plugin version " + sitePluginVersion).isNotNull();
191 try {
192 final Document document = getDocument(IOUtils.toString(resourceStream));
193 @SuppressWarnings("unchecked")
194 final Iterator<Element> headerElements = document.getDescendants(new ElementFilter("th"));
195 assertThat(headerElements.hasNext()).as("No header elements in version " + sitePluginVersion).isTrue();
196 while (headerElements.hasNext()) {
197 final Element tableHeader = headerElements.next();
198 final Element tableRow = tableHeader.getParentElement();
199 assertThat(tableRow.getName()).isEqualTo("tr");
200
201
202
203
204
205 Element tableElement = null;
206 if ("2.0".equals(sitePluginVersion)) {
207 final Element tableBody = tableRow.getParentElement();
208 assertThat(tableBody.getName()).isEqualTo("tbody");
209 assertThat((tableElement = tableBody.getParentElement()).getName()).isEqualTo("table");
210 } else
211 assertThat((tableElement = tableRow.getParentElement()).getName()).isEqualTo("table");
212
213
214
215
216
217 final Attribute borderAttribute = tableElement.getAttribute("border");
218 if (borderAttribute != null)
219 assertThat(borderAttribute.getValue()).isEqualTo("0");
220 }
221 } finally {
222 IOUtils.closeQuietly(resourceStream);
223 }
224
225 driver.close();
226 }
227 }
228
229
230
231
232
233
234
235 @SuppressWarnings("unchecked")
236 @Test
237 public void testRenderInMilliseconds() throws Exception {
238 final String projectName = "millisecond-project";
239 final File logFile = getLogFile();
240 final InvocationResult result = build.executeMaven(getPom(projectName), null, cleanTestSite, logFile);
241 assertThat(result.getExitCode()).isZero();
242
243 final WebDriver driver = getDriver();
244 driver.get(getSiteIndexLocation(projectName));
245 openJetmTimingReport(driver);
246
247 final Collection<Aggregate> reportData = getAggregateData();
248 for (File reportFile : (List<File>) FileUtils.getFiles(FileUtils.toFile(getClass().getResource("/example-projects/" + projectName + "/target/jetm")), "**/*.xml", null, true)) {
249 final Collection<Aggregate> aggregates = getAggregates(reportFile, TimeUnit.MILLISECONDS);
250
251 assertHasSection(reportFile.getName());
252
253 assertThat(reportData).contains(aggregates.toArray());
254 }
255 }
256
257
258
259
260
261
262
263 private void assertHasSection(String sectionName) {
264 for (WebElement element : driver.findElements(By.tagName("h4")))
265 if (sectionName.equals(element.getText()))
266 return;
267
268 throw new IllegalArgumentException("No section name found: " + sectionName + ". Page source: " + driver.getPageSource());
269 }
270
271
272
273
274
275
276
277 private Collection<Aggregate> getAggregateData() {
278 final Collection<Aggregate> aggregates = new LinkedList<Aggregate>();
279 final List<WebElement> htmlRows = driver.findElements(By.tagName("tr"));
280 for (WebElement htmlRow : htmlRows) {
281 final List<WebElement> htmlCells = htmlRow.findElements(By.tagName("td"));
282 if (htmlCells.size() == 6) {
283 final double average = Double.parseDouble(htmlCells.get(1).getText());
284 final double min = Double.parseDouble(htmlCells.get(3).getText());
285 final double max = Double.parseDouble(htmlCells.get(4).getText());
286 final double total = Double.parseDouble(htmlCells.get(5).getText());
287 final long measurements = Long.parseLong(htmlCells.get(2).getText());
288 aggregates.add(new SimpleAggregate(htmlCells.get(0).getText(), average, min, max, measurements, total));
289 }
290 }
291 return aggregates;
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 private Document getDocument(String xml) {
313 final int maxAttempts = 5;
314 final Exception[] caught = new Exception[maxAttempts];
315 for (int i = 0; i < maxAttempts; i++) {
316 try {
317 return new SAXBuilder().build(new StringReader(xml));
318 } catch (Exception e) {
319 caught[i] = e;
320 }
321 }
322
323 for (int i = 0; i < caught.length && caught[i] != null; i++)
324 caught[i].printStackTrace();
325
326 throw new IllegalStateException("Too many errors were encountered while trying to parse the document.");
327 }
328
329
330
331
332
333
334
335 private WebDriver getDriver() {
336 if (driver != null)
337 driver.close();
338
339 return driver = new HtmlUnitDriver();
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353 private Collection<Aggregate> getAggregates(File aggregateData, TimeUnit timeUnit) throws IOException {
354 final FileReader reader = new FileReader(aggregateData);
355 try {
356 final Collection<Aggregate> aggregates = new LinkedList<Aggregate>();
357 for (Aggregate original : new XmlAggregateBinder().unbind(reader)) {
358
359
360
361
362 final double average = round(original.getAverage() / timeUnit.getDivisionValue());
363 final double min = round(original.getMin() / timeUnit.getDivisionValue());
364 final double max = round(original.getMax() / timeUnit.getDivisionValue());
365 final double total = round(original.getTotal() / timeUnit.getDivisionValue());
366 aggregates.add(new SimpleAggregate(original.getName(), average, min, max, original.getMeasurements(), total));
367 }
368 return aggregates;
369 } finally {
370 reader.close();
371 }
372 }
373
374
375
376
377
378
379
380
381 private File getLogFile() throws IOException {
382 final File logFile = new File("target/failsafe-reports/" + testName.getMethodName() + "-maven.log");
383 FileUtils.forceMkdir(logFile.getParentFile());
384 return logFile;
385 }
386
387
388
389
390
391
392
393
394
395
396 private File getPom(String artifactId) {
397 final URL pomUrl = getClass().getResource("/example-projects/" + artifactId + "/pom.xml");
398 if (pomUrl == null)
399 throw new IllegalArgumentException("No POM found for artifact: " + artifactId);
400 return FileUtils.toFile(pomUrl);
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414 private String getSiteIndexLocation(String artifactId) {
415 final URL pomUrl = getClass().getResource("/example-projects/" + artifactId + "/target/site/index.html");
416 if (pomUrl == null)
417 throw new IllegalArgumentException("No index.html found for artifact: " + artifactId);
418 return pomUrl.toExternalForm();
419 }
420
421
422
423
424
425
426
427 private void openJetmTimingReport(WebDriver driver) {
428 driver.findElement(By.linkText("Project Reports")).click();
429 driver.findElement(By.linkText("JETM Timing Report")).click();
430 }
431
432
433
434
435
436
437
438
439 private double round(double value) {
440 return Double.parseDouble(new DecimalFormat("0.00").format(value));
441 }
442 }