From dbc5414793423ae4721e0001979ae21999d5487b Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Mon, 24 Jun 2013 17:49:22 -0700 Subject: resolved some common headless issues relating to (relatively) fixed paths in the source --- src/batchtools/headless/pom.xml | 9 + .../main/java/com/galois/fiveui/BatchRunner.java | 33 +- .../com/galois/fiveui/HeadlessRunDescription.java | 52 +- .../src/main/java/com/galois/fiveui/Reporter.java | 594 +++++++++++---------- .../java/com/galois/fiveui/drivers/Drivers.java | 14 +- 5 files changed, 386 insertions(+), 316 deletions(-) diff --git a/src/batchtools/headless/pom.xml b/src/batchtools/headless/pom.xml index 1b84aaa..7e85a75 100644 --- a/src/batchtools/headless/pom.xml +++ b/src/batchtools/headless/pom.xml @@ -24,6 +24,15 @@ + + + ../../js + + + src/main/resources + + + org.apache.maven.plugins diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java index 74bd109..345f997 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java @@ -19,6 +19,8 @@ package com.galois.fiveui; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,10 +55,6 @@ public class BatchRunner { private String _root; // FiveUI root directory private static final String JS_SRC_ROOT = "src/js/"; - - // Hard coded JS files, relative to the FiveUI root directory. - private static final String J_QUERY_JS = "lib/jquery/jquery.js"; - private static final String MD5_JS = "lib/md5.js"; private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchRunner"); @@ -144,7 +142,7 @@ public class BatchRunner { * Drive the browser(s) ***********************/ - for (WebDriver driver: getDrivers()) { + for (WebDriver driver: getDrivers(run.getFirefoxProfile())) { registerDriver(driver); for (String url: urls) { logger.info("loading " + url + " for ruleset run ..."); @@ -260,13 +258,20 @@ public class BatchRunner { */ private String wrapRule(RuleSet ruleSet) throws IOException { String injected = "fiveui = {};"; - injected += Utils.readFile(_root + JS_SRC_ROOT + J_QUERY_JS); - injected += Utils.readFile(_root + JS_SRC_ROOT + "lib/underscore.js"); - injected += Utils.readFile(_root + JS_SRC_ROOT + MD5_JS); - injected += Utils.readFile(_root + JS_SRC_ROOT + "fiveui/injected/prelude.js"); - injected += Utils.readFile(_root + JS_SRC_ROOT + "fiveui/injected/jquery-plugins.js"); - injected += Utils.readFile(_root + JS_SRC_ROOT + "selenium/selenium-injected-compute.js"); - injected += Utils.readFile(_root + JS_SRC_ROOT + "fiveui/injected/compute.js"); + Class cl = this.getClass(); + + try { + injected += Utils.readStream(cl.getResourceAsStream("/lib/jquery/jquery.js")); + injected += Utils.readStream(cl.getResourceAsStream("/lib/underscore.js")); + injected += Utils.readStream(cl.getResourceAsStream("/lib/md5.js")); + injected += Utils.readStream(cl.getResourceAsStream("/fiveui/injected/prelude.js")); + injected += Utils.readStream(cl.getResourceAsStream("/fiveui/injected/jquery-plugins.js")); + injected += Utils.readStream(cl.getResourceAsStream("/selenium/selenium-injected-compute.js")); + injected += Utils.readStream(cl.getResourceAsStream("/fiveui/injected/compute.js")); + } catch (NullPointerException e) { + logger.error("Could not access javascript resources"); + throw e; + } if (null != ruleSet.getDependencies()) { for (String dep : ruleSet.getDependencies()) { @@ -285,10 +290,10 @@ public class BatchRunner { * * @return list of initialized WebDriver objects */ - private static ImmutableList getDrivers() { + private static ImmutableList getDrivers(String ffProfile) { logger.debug("building webdrivers ..."); ImmutableList r = ImmutableList.of( - Drivers.buildFFDriver() + Drivers.buildFFDriver(ffProfile) // , Drivers.buildChromeDriver() ); logger.debug("built: " + r.toString()); diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java index c9b70de..8b41fe4 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java @@ -24,8 +24,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; +import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; /** * @author bjones @@ -36,6 +38,7 @@ public class HeadlessRunDescription { private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunDescription"); private static String _crawlType; private List _atoms; + private static String _firefoxProfile; public HeadlessRunDescription (List atoms) { _atoms = atoms; @@ -58,12 +61,28 @@ public class HeadlessRunDescription { */ public static HeadlessRunDescription parse(String runDescFileName) throws FileNotFoundException { - GsonBuilder gsonBuilder = new GsonBuilder(); - gsonBuilder.registerTypeAdapter(HeadlessRunDescription.class, - new HeadlessRunDescription.Deserializer(runDescFileName)); - Gson gson = gsonBuilder.create(); - Reader in = new InputStreamReader(new FileInputStream(runDescFileName)); - return gson.fromJson(in, HeadlessRunDescription.class); + HeadlessRunDescription runDescr = null; + try { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(HeadlessRunDescription.class, + new HeadlessRunDescription.Deserializer(runDescFileName)); + Gson gson = gsonBuilder.create(); + Reader in = new InputStreamReader(new FileInputStream(runDescFileName)); + runDescr = gson.fromJson(in, HeadlessRunDescription.class); + } catch (JsonSyntaxException e) { + System.err.println("We were unable to parse the run description at: "+runDescFileName); + System.err.println(e.getLocalizedMessage()); + + e.printStackTrace(); + throw new IllegalStateException("Could not parse run description"); + } catch (JsonIOException e) { + System.err.println("We were unable to load the run description at: "+runDescFileName); + System.err.println(e.getLocalizedMessage()); + + e.printStackTrace(); + throw new IllegalStateException("Could not parse run description"); + } + return runDescr; } public static class Deserializer implements JsonDeserializer { @@ -80,7 +99,7 @@ public class HeadlessRunDescription { } public static void reportError(JsonElement json) { - logger.error("HeadlessRunDescription.parse: ran into unexpected jsonElement type:"); + logger.error("HeadlessRunDescription.parse: ran into unexpected jsonElement type: \""+json+"\""); logger.error(" " + json.getAsString()); } @@ -114,6 +133,13 @@ public class HeadlessRunDescription { if (null != runDescDir) { ruleSetDir = runDescDir + File.separator + ruleSetDir; } + + String ffProfile = objGetString(obj, "firefoxProfile"); + if (null != ffProfile) { + ffProfile = runDescDir + File.separator + ffProfile; + } + _firefoxProfile = ffProfile; + _crawlType = objGetString(obj, "crawlType"); arr = obj.get("runs").getAsJsonArray(); } else if (json.isJsonArray()) { @@ -127,13 +153,20 @@ public class HeadlessRunDescription { Builder atoms = ImmutableList.builder(); for (JsonElement jsonElement : arr) { + // we only care about json objects, so if anything else is found, + // skip this loop: + if (!jsonElement.isJsonObject()) { + continue; + } try { + JsonObject obj = jsonElement.getAsJsonObject(); atoms.add(HeadlessAtom.fromJsonObject(obj, ruleSetDir)); } catch (IOException e) { logger.error("HeadlessAtom.parse: error parsing ruleSet file: " + e.getMessage()); System.exit(1); } catch (IllegalStateException e) { + e.printStackTrace(); reportError(jsonElement); } } @@ -151,6 +184,10 @@ public class HeadlessRunDescription { return gson.toJson(this); } + public String getFirefoxProfile() { + return _firefoxProfile; + } + @Override public int hashCode() { final int prime = 31; @@ -178,4 +215,5 @@ public class HeadlessRunDescription { return true; } + } diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java index cad8bee..80e024a 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.google.common.collect.Lists; import com.googlecode.jatl.Html; /** @@ -40,292 +41,317 @@ import com.googlecode.jatl.Html; * generated in HTML and returned as human readable strings by getSummaryPage(), * getURLPage(), and getRulePage(). The client is responsible for writing them * to .html files (or whatever). - * + * * @author bjones - * + * */ public class Reporter { - /** see sortBy* and computeSummaryStats methods for map semantics */ - private final Map> _byURLMap; - private final Map> _byRuleMap; - private final Map _passFailMap; - private Map _ruleNameToDesc; - private static String GLOBAL_CSS = - "h1 { font-size: 150%; }" + - "h2 { font-size: 110%; }" + - "li { margin: 5 0 0 0; }" + - "table { border: 1px solid grey; cellpadding: 5%; width: 200px; }\n" + - "td.pass-number{ text-align: right;color: green; }\n" + - "td.fail-number{ text-align: right;color: red; }\n" + - "td.text{ text-align: left; }\n" + - "th { font-weight: bold; }\n" + - "td, th { border: 1px solid grey; }\n" + - ".hlRow { background: #EEEEEE; }\n" + - ".regRow { background: #FFFFFF; }\n"; + /** see sortBy* and computeSummaryStats methods for map semantics */ + private final Map> _byURLMap; + private final Map> _byRuleMap; + private final Map _passFailMap; + private Map _ruleNameToDesc; + private static String GLOBAL_CSS = "h1 { font-size: 150%; }" + + "h2 { font-size: 110%; }" + + "li { margin: 5 0 0 0; }" + + "table { border: 1px solid grey; cellpadding: 5%; width: 200px; }\n" + + "td.pass-number{ text-align: right;color: green; }\n" + + "td.fail-number{ text-align: right;color: red; }\n" + + "td.text{ text-align: left; }\n" + "th { font-weight: bold; }\n" + + "td, th { border: 1px solid grey; }\n" + + ".hlRow { background: #EEEEEE; }\n" + + ".regRow { background: #FFFFFF; }\n"; + + /** + * Construct a Reporter object. The constructor takes a list of results and + * uses them to populate various maps used in reporting. + * + * @param results + * a list of Result objects + */ + public Reporter(List results) { + this._byURLMap = sortByURL(results); + this._byRuleMap = sortByRule(results); + this._passFailMap = computeSummaryStats(results); + this._ruleNameToDesc = extractRuleDesc(results); + } - /** - * Construct a Reporter object. The constructor takes a list of results - * and uses them to populate various maps used in reporting. - * - * @param results a list of Result objects - */ - public Reporter(List results) { - this._byURLMap = sortByURL(results); - this._byRuleMap = sortByRule(results); - this._passFailMap = computeSummaryStats(results); - this._ruleNameToDesc = extractRuleDesc(results); - } + /** + * Build the HTML markup for a summary page based on the precomputed map + * this._passFailMap. + * + * @return String containing human-readable HTML representing a summary page + */ + public String getSummary() { + StringWriter summaryPage = new StringWriter(); + final Map scopedMap = this._passFailMap; + Html page = new Html(summaryPage); + page = makeHead(page, "Summary of Results"); + page = new Html(page) { + { + h1().text("Headless Run Summary").end(); + p(); + ul(); + li().a().href("byURL.html").text("Results organized by URL") + .end().end(); + li().a().href("byRule.html").text("Results organized by Rule") + .end().end(); + end(); + end(); + p(); + div().id("stats"); + makeSummaryStats(scopedMap); + end(); + end(); + endAll(); + done(); + } - /** - * Build the HTML markup for a summary page based on the precomputed map - * this._passFailMap. - * - * @return String containing human-readable HTML representing a summary page - */ - public String getSummary() { - StringWriter summaryPage = new StringWriter(); - final Map scopedMap = this._passFailMap; - Html page = new Html(summaryPage); - page = makeHead(page, "Summary of Results"); - page = new Html(page) {{ - h1().text("Headless Run Summary").end(); - p(); - ul(); - li().a().href("byURL.html").text("Results organized by URL").end().end(); - li().a().href("byRule.html").text("Results organized by Rule").end().end(); - end(); - end(); - p(); - div().id ("stats"); - makeSummaryStats(scopedMap); - end(); - end(); - endAll(); - done(); - } - /** - * Report statistics on the headless run. Note, "pass" - * means the URL passed all tests in the ruleset, but "fail" can be - * reported for the same test on multiple offenders in the page. - */ - Html makeSummaryStats(Map passFailMap) { - int uniqueURLs = passFailMap.size(); - int[] passFailList; + /** + * Report statistics on the headless run. Note, "pass" means the URL + * passed all tests in the ruleset, but "fail" can be reported for + * the same test on multiple offenders in the page. + */ + Html makeSummaryStats(Map passFailMap) { + int uniqueURLs = passFailMap.size(); + int[] passFailList; - p(); - h3().text("Unique URLs: "); - span().classAttr("number").text(String.valueOf(uniqueURLs)).end(); - end().end(); + p(); + h3().text("Unique URLs: "); + span().classAttr("number").text(String.valueOf(uniqueURLs)) + .end(); + end().end(); - p(); - table().id("stats-table"); - tr(); - th().text("URL").end(); - th().text("Pass").end(); - th().text("Fail").end(); - end(); - int i = 0; // index for **alternate row highlighting** - List sortedKeys = new ArrayList(); - sortedKeys.addAll(passFailMap.keySet()); - Collections.sort(sortedKeys); - for (String key: sortedKeys) { - passFailList = passFailMap.get(key); - tr().classAttr(i % 2 == 0 ? "hlRow" : "regRow"); - td().classAttr("text").a().href(key).text(key).end().end(); - td().classAttr("pass-number").text(String.valueOf(passFailList[0])).end(); - td().classAttr("fail-number").text(String.valueOf(passFailList[1])).end(); - end(); - i++; - } - end(); // end - return end(); // end

- } - }; - return summaryPage.getBuffer().toString(); - } + p(); + table().id("stats-table"); + tr(); + th().text("URL").end(); + th().text("Pass").end(); + th().text("Fail").end(); + end(); + int i = 0; // index for **alternate row highlighting** + List sortedKeys = Lists.newArrayList(); + sortedKeys.addAll(passFailMap.keySet()); + Collections.sort(sortedKeys); + for (String key : sortedKeys) { + passFailList = passFailMap.get(key); + tr().classAttr(i % 2 == 0 ? "hlRow" : "regRow"); + td().classAttr("text").a().href(key).text(key).end().end(); + td().classAttr("pass-number") + .text(String.valueOf(passFailList[0])).end(); + td().classAttr("fail-number") + .text(String.valueOf(passFailList[1])).end(); + end(); + i++; + } + end(); // end

+ return end(); // end

+ } + }; + return summaryPage.getBuffer().toString(); + } - /** - * Build the HTML markup for a report page sorted by URL. - * - * @return String containing human-readable HTML representing a report page - */ - public String getByURL() { - StringWriter byURLPage = new StringWriter(); - final Map> scopedMap = this._byURLMap; - Html page = new Html(byURLPage); - page = makeHead(page, "Results sorted by URL"); - page = new Html(page) {{ - body(); - h1().text("Results by URL").end(); - ol(); - List sortedKeys = new ArrayList(); - sortedKeys.addAll(scopedMap.keySet()); - Collections.sort(sortedKeys); - for (String url: sortedKeys) { - li().h2().a().href(url).text(url).end().end(); - ul(); - int i = 0; - for (Result r: scopedMap.get(url)) { - li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); - text(r.getRuleName() + ": " + r.getRuleDesc()).br(); - text(r.getProblem()).end(); - i++; - } - end(); - end(); - } - endAll(); - done(); - }}; - return byURLPage.getBuffer().toString(); - } + /** + * Build the HTML markup for a report page sorted by URL. + * + * @return String containing human-readable HTML representing a report page + */ + public String getByURL() { + StringWriter byURLPage = new StringWriter(); + final Map> scopedMap = this._byURLMap; + Html page = new Html(byURLPage); + page = makeHead(page, "Results sorted by URL"); + page = new Html(page) { + { + body(); + h1().text("Results by URL").end(); + ol(); + List sortedKeys = Lists.newArrayList(); + sortedKeys.addAll(scopedMap.keySet()); + Collections.sort(sortedKeys); + for (String url : sortedKeys) { + li().h2().a().href(url).text(url).end().end(); + ul(); + int i = 0; + for (Result r : scopedMap.get(url)) { + li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); + // format an individual Result for this url: + ul().li().em().text(r.getRuleName()+ ": ").end(); + text(r.getRuleDesc()).end(); + li().text(r.getProblem()).end(); + end(); + i++; + } + end(); + end(); + } + endAll(); + done(); + } + }; + return byURLPage.getBuffer().toString(); + } - /** - * Build the HTML markup for a report page sorted by rule name. - * - * @return String containing human-readable HTML representing a report page - */ - public String getByRule() { - StringWriter byRulePage = new StringWriter(); - final Map> scopedMap = this._byRuleMap; - final Map scopedRuleNameToDesc = this._ruleNameToDesc; - Html page = new Html(byRulePage); - page = makeHead(page, "Results sorted by rule"); - page = new Html(page) {{ - h1().text("Results by Rule").end(); - ul(); - List sortedKeys = new ArrayList(); - sortedKeys.addAll(scopedMap.keySet()); - Collections.sort(sortedKeys); - for (String rule: sortedKeys) { - li(); - b().text(rule).end().text(": " + scopedRuleNameToDesc.get(rule)); - ul(); - int i = 0; - for (Result r: scopedMap.get(rule)) { - li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); - text("Problem: " + r.getProblem()).br(); - text("URL: ").a().href(r.getURL()).text(r.getURL()).end().end(); - i++; - } - end(); - end(); - } - endAll(); - done(); - }}; - return byRulePage.getBuffer().toString(); - } + /** + * Build the HTML markup for a report page sorted by rule name. + * + * @return String containing human-readable HTML representing a report page + */ + public String getByRule() { + StringWriter byRulePage = new StringWriter(); + final Map> scopedMap = this._byRuleMap; + final Map scopedRuleNameToDesc = this._ruleNameToDesc; + Html page = new Html(byRulePage); + page = makeHead(page, "Results sorted by rule"); + page = new Html(page) { + { + h1().text("Results by Rule").end(); + ul(); + List sortedKeys = new ArrayList(); + sortedKeys.addAll(scopedMap.keySet()); + Collections.sort(sortedKeys); + for (String rule : sortedKeys) { + li(); + b().text(rule).end() + .text(": " + scopedRuleNameToDesc.get(rule)); + ul(); + int i = 0; + for (Result r : scopedMap.get(rule)) { + li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); + text("Problem: " + r.getProblem()).br(); + text("URL: ").a().href(r.getURL()).text(r.getURL()) + .end().end(); + i++; + } + end(); + end(); + } + endAll(); + done(); + } + }; + return byRulePage.getBuffer().toString(); + } - /** - * Utility method to take all the reports and write them to standard file - * names under a given directory. - * - * @param dirName name of the directory where the reports should be written - * @throws IOException - */ - public void writeReportsToDir(String dirName) throws IOException { - PrintWriter summaryFile = new PrintWriter(new FileWriter(dirName + File.separator + "summary.html")); - PrintWriter byURLFile = new PrintWriter(new FileWriter(dirName + File.separator + "byURL.html")); - PrintWriter byRuleFile = new PrintWriter(new FileWriter(dirName + File.separator + "byRule.html")); - summaryFile.write(this.getSummary()); - summaryFile.close(); - byURLFile.write(this.getByURL()); - byURLFile.close(); - byRuleFile.write(this.getByRule()); - byRuleFile.close(); - } + /** + * Utility method to take all the reports and write them to standard file + * names under a given directory. + * + * @param dirName + * name of the directory where the reports should be written + * @throws IOException + */ + public void writeReportsToDir(String dirName) throws IOException { + PrintWriter summaryFile = new PrintWriter(new FileWriter(dirName + + File.separator + "summary.html")); + PrintWriter byURLFile = new PrintWriter(new FileWriter(dirName + + File.separator + "byURL.html")); + PrintWriter byRuleFile = new PrintWriter(new FileWriter(dirName + + File.separator + "byRule.html")); + summaryFile.write(this.getSummary()); + summaryFile.close(); + byURLFile.write(this.getByURL()); + byURLFile.close(); + byRuleFile.write(this.getByRule()); + byRuleFile.close(); + } - /** Private fields **/ + /** Private fields **/ - private Html makeHead(Html page, final String title) { - return new Html(page) {{ - html(); - head(); - title().text(title).end(); - style().type("text/css").text(GLOBAL_CSS).end(); - end(); - body(); - }}; - } + private Html makeHead(Html page, final String title) { + return new Html(page) { + { + html(); + head(); + title().text(title).end(); + style().type("text/css").text(GLOBAL_CSS).end(); + end(); + body(); + } + }; + } - /** - * Populate a Map> representing the results sorted by - * URL. - * - * @param results a list of results - * @return a map representing the results sorted by URL. - */ - private Map>sortByURL(List results) { - /** map semantics: Map< url, [rule1, rule2, ...] > */ - Map> map = new HashMap>(); - String url; - List list; - for (Result r: results) { - url = r.getURL(); - if (map.containsKey(url)) { - list = map.get(url); - list.add(r); - } else { - list = new ArrayList(); - list.add(r); - map.put(url, list); - } - } - return map; - } + /** + * Populate a Map> representing the results sorted by + * URL. + * + * @param results + * a list of results + * @return a map representing the results sorted by URL. + */ + private Map> sortByURL(List results) { + /** map semantics: Map< url, [rule1, rule2, ...] > */ + Map> map = new HashMap>(); + String url; + List list; + for (Result r : results) { + url = r.getURL(); + if (map.containsKey(url)) { + list = map.get(url); + list.add(r); + } else { + list = new ArrayList(); + list.add(r); + map.put(url, list); + } + } + return map; + } - /** - * Populate a Map> representing the results sorted by - * rule name. - * - * @param results a list of results - * @return a map representing the results sorted by rule name. - */ - private Map>sortByRule(List results) { - /** map semantics: Map< rule, [url1, url2, ...] > */ - Map> map = new HashMap>(); - String rule; - List list; - for (Result r: results) { - rule = r.getRuleName(); - if (map.containsKey(rule)) { - list = map.get(rule); - list.add(r); - } else { - list = new ArrayList(); - list.add(r); - map.put(rule, list); - } - } - return map; - } + /** + * Populate a Map> representing the results sorted by + * rule name. + * + * @param results + * a list of results + * @return a map representing the results sorted by rule name. + */ + private Map> sortByRule(List results) { + /** map semantics: Map< rule, [url1, url2, ...] > */ + Map> map = new HashMap>(); + String rule; + List list; + for (Result r : results) { + rule = r.getRuleName(); + if (map.containsKey(rule)) { + list = map.get(rule); + list.add(r); + } else { + list = new ArrayList(); + list.add(r); + map.put(rule, list); + } + } + return map; + } - /** - * Build a map of ruleName -> ruleDesc entries occurring in the given list of - * results. - * - * @param results a list of results - * @return a map associating rule names to rule descriptions - */ - private Map extractRuleDesc(List results) { - Map assoc = new HashMap(); - for (Result r: results) - if (!assoc.containsKey(r.getRuleName())) - assoc.put(r.getRuleName(), r.getRuleDesc()); - return assoc; - } + /** + * Build a map of ruleName -> ruleDesc entries occurring in the given list + * of results. + * + * @param results + * a list of results + * @return a map associating rule names to rule descriptions + */ + private Map extractRuleDesc(List results) { + Map assoc = new HashMap(); + for (Result r : results) + if (!assoc.containsKey(r.getRuleName())) + assoc.put(r.getRuleName(), r.getRuleDesc()); + return assoc; + } - /** + /** * Compute summary statistics from the results list. This includes number of * passes and fails for each URL checked. - * - * @param results a list of results + * + * @param results + * a list of results * @return a map representing the results sorted by rule name. */ private Map computeSummaryStats(List results) { - /** passFailMap semantics: Map */ + /** passFailMap semantics: Map */ Map passFailMap = new HashMap(); String url; int pass, fail; @@ -334,26 +360,28 @@ public class Reporter { Matcher matcher; for (Result result : results) { - pass = fail = 0; - url = result.getURL(); - if (result.getType() == ResType.Pass) { - // now we have to parse out how many tests passed - matcher = numberPassedPattern.matcher(result.getMsg()); - if (matcher.find()) - pass = Integer.parseInt(matcher.group(1)); // throws exception if parse fails - } else if (result.getType() == ResType.Error) { - // each error result corresponds to one test - fail = 1; - } + pass = fail = 0; + url = result.getURL(); + if (result.getType() == ResType.Pass) { + // now we have to parse out how many tests passed + matcher = numberPassedPattern.matcher(result.getMsg()); + if (matcher.find()) + pass = Integer.parseInt(matcher.group(1)); // throws + // exception if + // parse fails + } else if (result.getType() == ResType.Error) { + // each error result corresponds to one test + fail = 1; + } - if (passFailMap.containsKey(url)) { - passFailList = passFailMap.get(url); - } else { - passFailList = new int[] { 0, 0}; - passFailMap.put(url, passFailList); - } - passFailList[0] += pass; - passFailList[1] += fail; + if (passFailMap.containsKey(url)) { + passFailList = passFailMap.get(url); + } else { + passFailList = new int[] { 0, 0 }; + passFailMap.put(url, passFailList); + } + passFailList[0] += pass; + passFailList[1] += fail; } return passFailMap; } diff --git a/src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java b/src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java index 9dd0736..8ac41d1 100644 --- a/src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java +++ b/src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java @@ -42,8 +42,6 @@ public class Drivers { private static final String defaultFiveuiRootPath = "../../../"; private static final String firefoxProfilePath = "profiles/firefox"; private static final String chromeProfilePath = "profiles/chrome"; - private static final String firefoxExtensionPath = "build/fiveui.xpi"; - private static final String chromeExtensionPath = "build/fiveui.crx"; /** * Query the OS environment for the FiveUI root path, or return a default. @@ -53,21 +51,14 @@ public class Drivers { return (null != rootPath) ? rootPath + File.separator : defaultFiveuiRootPath; } - public static FirefoxDriver buildFFDriver() { + public static FirefoxDriver buildFFDriver(String ffProfile) { // Extracted into a method so we can set up profiles String rootPath = getRootPath(); - File profileDir = new File(rootPath+firefoxProfilePath); + File profileDir = new File(ffProfile); FirefoxProfile profile = new FirefoxProfile(profileDir); - File fiveuiXpi = new File(rootPath+firefoxExtensionPath); - try { - profile.addExtension(fiveuiXpi); - } catch (IOException e) { - System.err.println("could not load firefox with FiveUI"); - e.printStackTrace(); - } String ffBinaryPath = System.getProperty(FIREFOX_BIN_PATH); @@ -100,7 +91,6 @@ public class Drivers { options.addArguments("--user-data-dir=" + rootPath + chromeProfilePath); // , // "--enable-logging", // "--v=1"); - options.addExtensions(new File(rootPath + chromeExtensionPath)); String chromeBinaryPath = System.getProperty(CHROME_BIN_PATH); if (null == chromeBinaryPath) { -- cgit v1.2.3 From ec4915ec0f9d9ae6401ff50ccedb191550de5106 Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Mon, 24 Jun 2013 17:49:51 -0700 Subject: clarified the wording in the titleNonEmpty rule --- exampleData/ruleSets/accessibility/titleNonEmpty.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exampleData/ruleSets/accessibility/titleNonEmpty.js b/exampleData/ruleSets/accessibility/titleNonEmpty.js index 27e281f..ff3388e 100644 --- a/exampleData/ruleSets/accessibility/titleNonEmpty.js +++ b/exampleData/ruleSets/accessibility/titleNonEmpty.js @@ -1,6 +1,6 @@ -exports.name = "titleNonEmpty"; +exports.name = "titleExists"; -exports.description = "Title of page is non-empty"; +exports.description = "Title of page should not be empty"; exports.rule = function(report) { if (document.title == '') { -- cgit v1.2.3 From 40342e3311a773827c5ed30a4539675d9f6c0a3a Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Mon, 24 Jun 2013 18:11:25 -0700 Subject: minor reformatting of the headless results page --- .../src/main/java/com/galois/fiveui/Reporter.java | 19 ++++++++++++++++--- .../src/main/java/com/galois/fiveui/Result.java | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java index 80e024a..b1c60af 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java @@ -175,11 +175,24 @@ public class Reporter { ul(); int i = 0; for (Result r : scopedMap.get(url)) { - li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); + String cAttr = i % 2 == 0 ? "regRow" : "hlRow"; + // format an individual Result for this url: - ul().li().em().text(r.getRuleName()+ ": ").end(); + li().classAttr(cAttr).b().text(r.getRuleName()).end(); + + ul(); + li().classAttr(cAttr).b().text("Description:").end(); text(r.getRuleDesc()).end(); - li().text(r.getProblem()).end(); + + li().classAttr(cAttr).b().text("Message:").end(); + text(r.getMsg()).end(); + + li().classAttr(cAttr).b().text("xpath:").end(); + text(r.getXpath()).end(); + + li().classAttr(cAttr).b().text("Severity:").end(); + text(r.getType().toString()).end(); + end(); end(); i++; } diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java index a367d1d..6c83c7b 100644 --- a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java @@ -205,4 +205,9 @@ public class Result { + " |\\_ " + _ruleDesc + "\n" + " \\_ " + _prob; } + + public String getXpath() { + // TODO Auto-generated method stub + return null; + } } -- cgit v1.2.3 From 750bb02df87cb2731ee593b3206f1ac442fcd69d Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Mon, 24 Jun 2013 18:55:29 -0700 Subject: further UI refinements for the batch runner reports --- .../main/java/com/galois/fiveui/BatchRunner.java | 20 +++----- .../src/main/java/com/galois/fiveui/Reporter.java | 54 ++++++++++++++-------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java index 345f997..934620a 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java @@ -19,27 +19,23 @@ package com.galois.fiveui; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; +import com.galois.fiveui.drivers.Drivers; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Maps; import com.google.common.io.Files; -import com.galois.fiveui.Result; -import com.galois.fiveui.RuleSet; -import com.galois.fiveui.Utils; -import com.galois.fiveui.drivers.Drivers; import edu.uci.ics.crawler4j.util.IO; - -import org.apache.log4j.Logger; // System.out.* is old fashioned +// System.out.* is old fashioned /** @@ -54,10 +50,8 @@ public class BatchRunner { private JavascriptExecutor _exe; private String _root; // FiveUI root directory - private static final String JS_SRC_ROOT = "src/js/"; - private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchRunner"); - + private void registerDriver(WebDriver driver) { logger.debug("registering new webdriver..."); this._driver = driver; @@ -294,7 +288,7 @@ public class BatchRunner { logger.debug("building webdrivers ..."); ImmutableList r = ImmutableList.of( Drivers.buildFFDriver(ffProfile) - // , Drivers.buildChromeDriver() + //, Drivers.buildChromeDriver() ); logger.debug("built: " + r.toString()); return r; diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java index b1c60af..f0461d4 100644 --- a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java @@ -175,24 +175,11 @@ public class Reporter { ul(); int i = 0; for (Result r : scopedMap.get(url)) { - String cAttr = i % 2 == 0 ? "regRow" : "hlRow"; + String cAttr = i % 2 == 0 ? "hlRow" : "regRow"; // format an individual Result for this url: li().classAttr(cAttr).b().text(r.getRuleName()).end(); - - ul(); - li().classAttr(cAttr).b().text("Description:").end(); - text(r.getRuleDesc()).end(); - - li().classAttr(cAttr).b().text("Message:").end(); - text(r.getMsg()).end(); - - li().classAttr(cAttr).b().text("xpath:").end(); - text(r.getXpath()).end(); - - li().classAttr(cAttr).b().text("Severity:").end(); - text(r.getType().toString()).end(); - end(); + resultToHtml(this, r, cAttr); end(); i++; } @@ -202,10 +189,13 @@ public class Reporter { endAll(); done(); } + }; return byURLPage.getBuffer().toString(); } + + /** * Build the HTML markup for a report page sorted by rule name. * @@ -231,10 +221,11 @@ public class Reporter { ul(); int i = 0; for (Result r : scopedMap.get(rule)) { - li().classAttr(i % 2 == 0 ? "regRow" : "hlRow"); - text("Problem: " + r.getProblem()).br(); - text("URL: ").a().href(r.getURL()).text(r.getURL()) - .end().end(); + String cAttr = i % 2 == 0 ? "hlRow" : "regRow"; + + li().classAttr(cAttr).b().text(r.getURL()).end(); + resultToHtml(this, r, cAttr); + end(); i++; } end(); @@ -247,6 +238,31 @@ public class Reporter { return byRulePage.getBuffer().toString(); } + + private void resultToHtml(Html html, Result r, String cAttr) { + + html.ul(); + html.li().b().text("Description:").end(); + html.text(r.getRuleDesc()).end(); + + html.li().b().text("Message:").end(); + html.text(r.getMsg()).end(); + + html.li().b().text("xpath:").end(); + html.text(r.getXpath()).end(); + + html.li().b().text("Severity:").end(); + html.text(r.getType().toString()).end(); + + html.li().b().text("Browser:").end(); + html.text(r.getDriver().toString()).end(); + + html.li().b().text("Url:").end(); + html.a().href(r.getURL()).text(r.getURL()).end().end(); + + html.end(); + } + /** * Utility method to take all the reports and write them to standard file * names under a given directory. -- cgit v1.2.3 From 02b1aff60bad96af14ec73eab5a128c98f821f61 Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Tue, 2 Jul 2013 17:45:41 -0700 Subject: updated run description for a headless run to include firefox profile path --- exampleData/headlessRuns/headingsRun.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 exampleData/headlessRuns/headingsRun.json diff --git a/exampleData/headlessRuns/headingsRun.json b/exampleData/headlessRuns/headingsRun.json new file mode 100644 index 0000000..d6e5135 --- /dev/null +++ b/exampleData/headlessRuns/headingsRun.json @@ -0,0 +1,13 @@ +/* + * A very basic headless run example. This configuration runs two rule sets on + * the Whitehouse main webpage. + */ +{ + "rulePath" : "../ruleSets/", + "crawlType" : "2 5 1000 *localhost*", + "firefoxProfile": "../../profiles/firefox/", + "runs": [ + { "url": "http://localhost:8000/sites/headings.html", "ruleSet": "accessibility/accessibility.json" }, + { "url": "http://localhost:8000/sites/headings.html", "ruleSet": "basic/basicUIRules.json" } + ] +} -- cgit v1.2.3