/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.monkeytalk.processor.report;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import com.gorillalogic.monkeytalk.Command;
import com.gorillalogic.monkeytalk.processor.PlaybackResult;
import com.gorillalogic.monkeytalk.utils.Base64;
import com.gorillalogic.monkeytalk.utils.FileUtils;
/**
* JUnit-compatible XML report generator.
*/
public class Report {
private static final String SCREENSHOTS_DIR = "screenshots";
private Suite mainSuite;
private Test currTest;
private File reportFile;
private File reportDirectory;
/**
* Instantiate a new report with the given suite name.
*
* @param name
* the suite name
*/
public Report(String name) {
mainSuite = new Suite(name);
}
/**
* Instantiate a new report with the given mainSuite.
*
* @param mainSuite
* the main suite
*/
public Report(Suite mainSuite) {
this.mainSuite = mainSuite;
}
/**
* Get the suite.
*
* @return the suite
*/
public Suite getMainSuite() {
return mainSuite;
}
/**
* Get the current test.
*/
public Test getCurrentTest() {
return currTest;
}
/**
* Get the saved report file. Valid only after {@link Report#saveReport(File)} has been called.
*
* @return the report file
*/
public File getReportFile() {
return reportFile;
}
/**
* Start a test with the given MonkeyTalk {@code Test} command (and any args). For example,
* {@code Test foo.mt Run} starts test {@code foo.mt}.
*
* @param cmd
* the MonkeyTalk test command
*/
public void startTest(Command cmd) {
currTest = new Test(getName(cmd));
currTest.startTimer();
currTest.stopTimer();
mainSuite.addTest(currTest);
}
/**
* Start a new test (and start the test timer) from the given MonkeyTalk test command and a row
* of test data.
*
* @param cmd
* the MonkeyTalk test command
* @param datum
* the test data
*/
public void startTest(Command cmd, Map<String, String> datum) {
currTest = new Test(getName(cmd, datum));
currTest.startTimer();
currTest.stopTimer();
mainSuite.addTest(currTest);
}
/**
* Stop the current test (and stop its timer) and set the test result from given the given
* MonkeyTalk test command and its playback result.
*
* @see Test#setResult(Command, PlaybackResult)
*
* @param cmd
* the MonkeyTalk test command
* @param result
* the playback result
*/
public void stopTest(Command cmd, PlaybackResult result) {
if (currTest != null) {
currTest.stopTimer();
currTest.setResult(cmd, result);
currTest = null;
}
}
/**
* Save the suite report to the given folder. Saves both the JUnit-compatible XML report and the
* more user friendly HTML report. Also, saves any screenshots to the {@code screenshots} child
* folder.
*
* @param reportDir
* the report folder
* @throws IOException
*/
public void saveReport(File reportDir) throws IOException {
FileUtils.makeDir(reportDir, "reportDir");
reportDirectory = reportDir;
String name = "TEST-" + mainSuite.getName();
// write the XML report
reportFile = new File(reportDir, name + ".xml");
FileUtils.writeFile(reportFile, mainSuite.toXML());
// write the HTML report
FileUtils.writeFile(new File(reportDir, name + ".html"), mainSuite.toHTML());
// save all screenshots
if (mainSuite.hasScreenshots()) {
saveScreenshots(new File(reportDir, SCREENSHOTS_DIR));
}
}
private void saveErrorScreenshot(File dir, Test t) throws IOException {
// Save and add error screenshot to screenshots.html
if (t.getScreenshot() != null) {
String screenshot = t.getScreenshot();
if (screenshot != null) {
File f = new File(dir, t.getScreenshotFilename());
// Save on error screenshot to /reports/screenshots
Base64.decodeToFile(screenshot, f.getAbsolutePath());
}
}
}
private void saveScreenshots(File dir) throws IOException {
File directory = new File(reportDirectory.getParent(), SCREENSHOTS_DIR);
// FileUtils.makeDir(directory, SCREENSHOTS_DIR);
FileUtils.makeDir(dir, "screenshotDir");
ArrayList<String> screenshots = new ArrayList<String>();
for (IReport ro : mainSuite.getTests()) {
if (ro instanceof Test) {
Test t = (Test) ro;
// Save and add screenshots to screenshots.heml
if (t.getScreenshots() != null && t.getScreenshots().size() > 0) {
for (String screenshot : t.getScreenshots()) {
if (screenshot != null) {
// Add screenshot to html
screenshots.add(screenshot);
}
}
}
// Save screenshot for report
saveErrorScreenshot(dir, t);
} else if (ro instanceof Suite) {
Suite s = (Suite) ro;
for (IReport r : s.getTests()) {
if (r instanceof Test) {
Test t = (Test) r;
// Save screenshot for report
saveErrorScreenshot(dir, t);
}
}
}
}
if (!directory.exists())
return;
}
public void saveScreenshotsToHTML(ArrayList<String> screenshots, File dir) throws IOException {
if (screenshots == null || screenshots.size()==0) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("<!doctype html>\n<html lang=\"en\">\n<head>\n");
sb.append("<title>").append(getMainSuite().getName()).append(" Screenshots</title>\n");
sb.append("<meta charset=\"UTF-8\" />\n");
// Lightbox ToDo: Save lightbox to gl server and access it from there
// sb.append("<script src=\"http://lokeshdhakar.com/projects/lightbox2/js/jquery-1.7.2.min.js\"></script>\n");
// sb.append("<script src=\"http://lokeshdhakar.com/projects/lightbox2/js/lightbox.js\"></script>\n");
// sb.append("<link href=\"http://lokeshdhakar.com/projects/lightbox2/css/lightbox.css\" rel=\"stylesheet\" />\n");
sb.append("<style type=\"text/css\">\n");
sb.append("body { font-family: Cambria, Georgia, serif; font-size:14pt; margin:0;\n");
sb.append("padding:20px; background-color:#eee; width:900px; margin-left:auto;\n");
sb.append("margin-right:auto; }\n");
sb.append("ul { list-style-type: none; padding:0px; margin-top:5px; margin-bottom:5px;\n");
sb.append("height:300px; overflow-x: scroll; overflow-y:hidden; white-space:nowrap;\n");
sb.append("padding-top:5px; padding-bottom:5px; border-top:1px solid #555;\n");
sb.append("border-bottom:1px solid #555; }\n");
sb.append("li { display:inline; padding-right:10px; }\n");
sb.append("</style>\n");
sb.append("</head>\n<body>\n");
sb.append(getMainSuite().getName() + " Screenshots\n");
sb.append("<ul>\n");
// String name = "SCREENSHOTS-" + mainSuite.getName();
String name = "screenshots";
for (String screenshot : screenshots) {
sb.append("<li><a rel=\"lightbox\" href=\"" + screenshot + "\">");
sb.append("<img height=\"300px\" src=\"" + screenshot + "\" title=\"" + screenshot
+ "\" /></a></li>\n");
}
sb.append("</ul>\n</body>\n</html>");
if (!dir.exists()) {
dir.mkdirs();
if (!dir.exists()) {
System.err.println("canot create screenshots directory at " + dir.getAbsolutePath());;
}
}
// write the screenshot to screenshots.html
FileUtils.writeFile(new File(dir, name + ".html"), sb.toString());
}
@Override
public String toString() {
return mainSuite.toString();
}
/**
* Helper to get the name of a test given the MonkeyTalk test command (and any args).
*
* @param cmd
* the MonkeyTalk test command
* @return the name of the test
*/
private String getName(Command cmd) {
if (cmd == null) {
return null;
}
String name = cmd.getMonkeyId();
if (cmd.getArgs().size() > 0) {
name += "[" + cmd.getArgsAsString().replaceAll("\"", "'") + "]";
}
return name;
}
/**
* Helper to get the name of a test given the MonkeyTalk test command and row of test data.
*
* @param cmd
* the MonkeyTalk test command
* @param datum
* the test data
* @return the name of the test
*/
private String getName(Command cmd, Map<String, String> datum) {
if (cmd == null) {
return null;
}
String name = cmd.getMonkeyId();
if (datum == null) {
name += "[null]";
} else if (datum.size() == 0) {
name += "[empty]";
} else {
StringBuilder sb = new StringBuilder();
for (String key : datum.keySet()) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(key).append("='").append(datum.get(key)).append("'");
}
name += "[" + sb.toString() + "]";
}
return name;
}
}