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.URL;
11 import java.text.DecimalFormat;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Iterator;
15 import java.util.LinkedList;
16 import java.util.List;
17 import java.util.Properties;
18 import java.util.ResourceBundle;
19
20 import org.apache.commons.io.IOUtils;
21 import org.apache.maven.shared.invoker.InvocationResult;
22 import org.apache.maven.shared.test.plugin.BuildTool;
23 import org.codehaus.plexus.util.FileUtils;
24 import org.jdom.Attribute;
25 import org.jdom.Document;
26 import org.jdom.Element;
27 import org.jdom.filter.ElementFilter;
28 import org.jdom.input.SAXBuilder;
29 import org.junit.After;
30 import org.junit.AfterClass;
31 import org.junit.Before;
32 import org.junit.BeforeClass;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.rules.TestName;
36 import org.openqa.selenium.By;
37 import org.openqa.selenium.WebDriver;
38 import org.openqa.selenium.WebElement;
39 import org.openqa.selenium.htmlunit.HtmlUnitDriver;
40
41 import com.google.code.jetm.maven.internal.SimpleAggregate;
42 import com.google.code.jetm.reporting.xml.XmlAggregateBinder;
43
44 import etm.core.aggregation.Aggregate;
45
46
47
48
49
50
51
52
53 public class TimingReportMojoITest {
54
55
56
57 @Rule
58 public TestName testName = new TestName();
59
60 private static final Properties originalSystemProperties = System.getProperties();
61 private final List<String> cleanTestSite = Arrays.asList("clean", "test", "site");
62 private WebDriver driver;
63 private BuildTool build;
64
65
66
67
68
69
70
71
72 @BeforeClass
73 public static void setUpBeforeClass() throws Exception {
74 final ResourceBundle systemPropsBundle = ResourceBundle.getBundle("system");
75 System.setProperty("maven.home", systemPropsBundle.getString("maven.home"));
76 }
77
78
79
80
81
82
83
84 @Before
85 public void setUp() throws Exception {
86 build = new BuildTool();
87 build.initialize();
88
89 driver = new HtmlUnitDriver();
90 }
91
92
93
94
95
96
97
98
99 @After
100 public void tearDown() throws Exception {
101 if (build != null)
102 build.dispose();
103
104 if (driver != null)
105 driver.close();
106 }
107
108
109
110
111
112
113
114 @AfterClass
115 public static void tearDownAfterClass() throws Exception {
116 System.setProperties(originalSystemProperties);
117 }
118
119
120
121
122
123
124
125 @Test
126 public void testEmptyReport() throws Exception {
127 final String projectName = "empty-project";
128 final File logFile = getLogFile();
129 final InvocationResult result = build.executeMaven(getPom(projectName), null, cleanTestSite, logFile);
130 assertThat(result.getExitCode()).isZero();
131
132 final WebDriver driver = getDriver();
133 driver.get(getSiteIndexLocation(projectName));
134 openJetmTimingReport(driver);
135 assertThat(driver.findElement(By.id("contentBox")).getText()).contains("There are no JETM timings available for reporting.");
136 }
137
138
139
140
141
142
143
144 @SuppressWarnings("unchecked")
145 @Test
146 public void testDemoProject() throws Exception {
147 final String projectName = "demo-project";
148 final File logFile = getLogFile();
149 final InvocationResult result = build.executeMaven(getPom(projectName), null, cleanTestSite, logFile);
150 assertThat(result.getExitCode()).isZero();
151
152 final WebDriver driver = getDriver();
153 driver.get(getSiteIndexLocation(projectName));
154 openJetmTimingReport(driver);
155
156 final Collection<Aggregate> reportData = getAggregateData();
157 for (File reportFile : (List<File>) FileUtils.getFiles(FileUtils.toFile(getClass().getResource("/example-projects/" + projectName + "/target/jetm")), "**/*.xml", null, true)) {
158 final Collection<Aggregate> aggregates = getAggregates(reportFile);
159
160 assertHasSection(reportFile.getName());
161
162 assertThat(reportData).contains(aggregates.toArray());
163 }
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 private void assertHasSection(String sectionName) {
236 for (WebElement element : driver.findElements(By.tagName("h4")))
237 if (sectionName.equals(element.getText()))
238 return;
239
240 throw new IllegalArgumentException("No section name found: " + sectionName + ". Page source: " + driver.getPageSource());
241 }
242
243
244
245
246
247
248
249 private Collection<Aggregate> getAggregateData() {
250 final Collection<Aggregate> aggregates = new LinkedList<Aggregate>();
251 final List<WebElement> htmlRows = driver.findElements(By.tagName("tr"));
252 for (WebElement htmlRow : htmlRows) {
253 final List<WebElement> htmlCells = htmlRow.findElements(By.tagName("td"));
254 if (htmlCells.size() == 6) {
255 final double average = Double.parseDouble(htmlCells.get(1).getText());
256 final double min = Double.parseDouble(htmlCells.get(3).getText());
257 final double max = Double.parseDouble(htmlCells.get(4).getText());
258 final double total = Double.parseDouble(htmlCells.get(5).getText());
259 final long measurements = Long.parseLong(htmlCells.get(2).getText());
260 aggregates.add(new SimpleAggregate(htmlCells.get(0).getText(), average, min, max, measurements, total));
261 }
262 }
263 return aggregates;
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 private Document getDocument(String xml) {
285 final int maxAttempts = 5;
286 final Exception[] caught = new Exception[maxAttempts];
287 for (int i = 0; i < maxAttempts; i++) {
288 try {
289 return new SAXBuilder().build(new StringReader(xml));
290 } catch (Exception e) {
291 caught[i] = e;
292 }
293 }
294
295 for (int i = 0; i < caught.length && caught[i] != null; i++)
296 caught[i].printStackTrace();
297
298 throw new IllegalStateException("Too many errors were encountered while trying to parse the document.");
299 }
300
301
302
303
304
305
306
307 private WebDriver getDriver() {
308 if (driver != null)
309 driver.close();
310
311 return driver = new HtmlUnitDriver();
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325 private Collection<Aggregate> getAggregates(File aggregateData) throws IOException {
326 final FileReader reader = new FileReader(aggregateData);
327 try {
328 final Collection<Aggregate> aggregates = new LinkedList<Aggregate>();
329 for (Aggregate original : new XmlAggregateBinder().unbind(reader)) {
330
331
332
333
334 final double average = round(original.getAverage() * 0.001);
335 final double min = round(original.getMin() * 0.001);
336 final double max = round(original.getMax() * 0.001);
337 final double total = round(original.getTotal() * 0.001);
338 aggregates.add(new SimpleAggregate(original.getName(), average, min, max, original.getMeasurements(), total));
339 }
340 return aggregates;
341 } finally {
342 reader.close();
343 }
344 }
345
346
347
348
349
350
351
352
353 private File getLogFile() throws IOException {
354 final File logFile = new File("target/failsafe-reports/" + testName.getMethodName() + "-maven.log");
355 FileUtils.forceMkdir(logFile.getParentFile());
356 return logFile;
357 }
358
359
360
361
362
363
364
365
366
367
368 private File getPom(String artifactId) {
369 final URL pomUrl = getClass().getResource("/example-projects/" + artifactId + "/pom.xml");
370 if (pomUrl == null)
371 throw new IllegalArgumentException("No POM found for artifact: " + artifactId);
372 return FileUtils.toFile(pomUrl);
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 private String getSiteIndexLocation(String artifactId) {
387 final URL pomUrl = getClass().getResource("/example-projects/" + artifactId + "/target/site/index.html");
388 if (pomUrl == null)
389 throw new IllegalArgumentException("No index.html found for artifact: " + artifactId);
390 return pomUrl.toExternalForm();
391 }
392
393
394
395
396
397
398
399 private void openJetmTimingReport(WebDriver driver) {
400 driver.findElement(By.linkText("Project Reports")).click();
401 driver.findElement(By.linkText("JETM Timing Report")).click();
402 }
403
404
405
406
407
408
409
410
411 private double round(double value) {
412 return Double.parseDouble(new DecimalFormat("0.00").format(value));
413 }
414 }