From 88c95d18a81e4f107cc4e5967bfa45d1bf4882a1 Mon Sep 17 00:00:00 2001 From: Rogan Creswick Date: Fri, 7 Jun 2013 16:00:22 -0700 Subject: cleaned up some test files that broke during a merge --- Makefile | 15 +- batchtools/headless/.classpath | 31 - batchtools/headless/.gitignore | 2 - .../.settings/org.eclipse.core.resources.prefs | 5 - .../headless/.settings/org.eclipse.jdt.core.prefs | 5 - .../headless/.settings/org.eclipse.m2e.core.prefs | 4 - .../bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar | Bin 29292330 -> 0 bytes batchtools/headless/bin/runHeadless.sh | 8 - batchtools/headless/pom.xml | 121 --- batchtools/headless/programs.properties.example | 2 - .../main/java/com/galois/fiveui/BasicCrawler.java | 90 -- .../com/galois/fiveui/BasicCrawlerController.java | 150 --- .../main/java/com/galois/fiveui/BatchRunner.java | 312 ------ .../java/com/galois/fiveui/CrawlParameters.java | 84 -- .../main/java/com/galois/fiveui/HeadlessAtom.java | 95 -- .../com/galois/fiveui/HeadlessRunDescription.java | 177 --- .../java/com/galois/fiveui/HeadlessRunner.java | 181 ---- .../src/main/java/com/galois/fiveui/Reporter.java | 360 ------- .../java/com/galois/fiveui/BatchExecutorTest.java | 122 --- .../com/galois/fiveui/CrawlParametersTest.java | 107 -- .../src/test/java/com/galois/fiveui/CrawlTest.java | 136 --- .../test/java/com/galois/fiveui/HeadlessTest.java | 114 -- .../src/test/java/com/galois/fiveui/NanoHTTPD.java | 1122 -------------------- .../test/java/com/galois/fiveui/ReporterTest.java | 71 -- .../src/test/resources/crawlTest/four.html | 7 - .../headless/src/test/resources/crawlTest/one.html | 12 - .../src/test/resources/crawlTest/one_a.html | 6 - .../src/test/resources/crawlTest/one_b.html | 6 - .../src/test/resources/crawlTest/one_c.html | 6 - .../src/test/resources/crawlTest/one_d.html | 6 - .../src/test/resources/crawlTest/one_e.html | 6 - .../src/test/resources/crawlTest/three.html | 7 - .../headless/src/test/resources/crawlTest/two.html | 7 - .../src/test/resources/ruleSets/emptyRuleSet.json | 4 - .../runDescriptions/headlessRunTest0.json | 4 - .../runDescriptions/headlessRunTestCNN.json | 4 - .../runDescriptions/headlessRunTestGalois.json | 10 - .../resources/runDescriptions/headlessSample0.json | 4 - .../resources/runDescriptions/headlessSample1.json | 8 - .../resources/runDescriptions/headlessSample2.json | 13 - batchtools/headless/test.html | 0 batchtools/pom.xml | 36 - batchtools/rsTester/.buildpath | 10 - batchtools/rsTester/.classpath | 36 - batchtools/rsTester/.gitignore | 2 - .../org.ebayopensource.vjet.eclipse.core.prefs | 2 - .../rsTester/.settings/org.eclipse.jdt.core.prefs | 5 - .../rsTester/.settings/org.eclipse.m2e.core.prefs | 4 - .../rsTester/.settings/org.maven.ide.eclipse.prefs | 8 - batchtools/rsTester/pom.xml | 109 -- .../main/java/com/galois/fiveui/BatchRunner.java | 235 ---- .../java/com/galois/fiveui/RSTestDescription.java | 321 ------ .../src/main/java/com/galois/fiveui/ResType.java | 32 - .../src/main/java/com/galois/fiveui/Result.java | 174 --- .../src/main/java/com/galois/fiveui/Rule.java | 122 --- .../src/main/java/com/galois/fiveui/RuleSet.java | 154 --- .../main/java/com/galois/fiveui/RuleSetTester.java | 91 -- .../src/main/java/com/galois/fiveui/RuleTest.java | 76 -- .../src/main/java/com/galois/fiveui/Utils.java | 44 - .../src/main/resources/javascript/ruleEval.js | 74 -- .../resources/seleniumDrivers/linux64/chromedriver | Bin 16328112 -> 0 bytes .../com/galois/fiveui/BasicRuleSetParseTest.java | 115 -- .../fiveui/BasicRunDescriptionParseTest.java | 126 --- .../java/com/galois/fiveui/RunDescriptionTest.java | 118 -- .../src/test/resources/ruleSets/emptyCheck.js | 6 - .../src/test/resources/ruleSets/emptyRuleSet.json | 4 - .../resources/ruleSets/headingGuidelines-caps.js | 19 - .../ruleSets/headingGuidelines-noEmptyHdrs.js | 12 - .../test/resources/ruleSets/headingGuidelines.json | 6 - .../test/resources/ruleSets/simpleRuleSet1.json | 4 - .../runDescriptions/headingSample-1-fails.json | 13 - .../runDescriptions/headingSample-2-fails.json | 13 - .../resources/runDescriptions/headingSample.json | 13 - .../test/resources/runDescriptions/sample0.json | 4 - .../test/resources/runDescriptions/sample1.json | 4 - .../resources/runDescriptions/sample2-fails.json | 10 - .../test/resources/runDescriptions/sample2.json | 10 - .../test/resources/runDescriptions/sample3.json | 7 - .../test/resources/runDescriptions/sample4.json | 10 - .../test/resources/runDescriptions/sample5.json | 13 - batchtools/rsTester/test.html | 0 batchtools/webdrivers/.classpath | 36 - batchtools/webdrivers/.gitignore | 1 - .../.settings/org.eclipse.jdt.core.prefs | 5 - .../.settings/org.eclipse.m2e.core.prefs | 4 - batchtools/webdrivers/pom.xml | 43 - .../java/com/galois/fiveui/drivers/Drivers.java | 149 --- src/batchtools/headless/.classpath | 31 + src/batchtools/headless/.gitignore | 2 + .../.settings/org.eclipse.core.resources.prefs | 5 + .../headless/.settings/org.eclipse.jdt.core.prefs | 5 + .../headless/.settings/org.eclipse.m2e.core.prefs | 4 + src/batchtools/headless/bin/runHeadless.sh | 8 + src/batchtools/headless/pom.xml | 121 +++ .../headless/programs.properties.example | 2 + .../main/java/com/galois/fiveui/BasicCrawler.java | 90 ++ .../com/galois/fiveui/BasicCrawlerController.java | 150 +++ .../main/java/com/galois/fiveui/BatchRunner.java | 312 ++++++ .../java/com/galois/fiveui/CrawlParameters.java | 84 ++ .../main/java/com/galois/fiveui/HeadlessAtom.java | 95 ++ .../com/galois/fiveui/HeadlessRunDescription.java | 177 +++ .../java/com/galois/fiveui/HeadlessRunner.java | 181 ++++ .../src/main/java/com/galois/fiveui/Reporter.java | 360 +++++++ .../java/com/galois/fiveui/BatchExecutorTest.java | 122 +++ .../com/galois/fiveui/CrawlParametersTest.java | 107 ++ .../src/test/java/com/galois/fiveui/CrawlTest.java | 136 +++ .../test/java/com/galois/fiveui/HeadlessTest.java | 114 ++ .../src/test/java/com/galois/fiveui/NanoHTTPD.java | 1122 ++++++++++++++++++++ .../test/java/com/galois/fiveui/ReporterTest.java | 71 ++ .../src/test/resources/crawlTest/four.html | 7 + .../headless/src/test/resources/crawlTest/one.html | 12 + .../src/test/resources/crawlTest/one_a.html | 6 + .../src/test/resources/crawlTest/one_b.html | 6 + .../src/test/resources/crawlTest/one_c.html | 6 + .../src/test/resources/crawlTest/one_d.html | 6 + .../src/test/resources/crawlTest/one_e.html | 6 + .../src/test/resources/crawlTest/three.html | 7 + .../headless/src/test/resources/crawlTest/two.html | 7 + .../src/test/resources/ruleSets/emptyRuleSet.json | 4 + .../runDescriptions/headlessRunTest0.json | 4 + .../runDescriptions/headlessRunTestCNN.json | 4 + .../runDescriptions/headlessRunTestGalois.json | 10 + .../resources/runDescriptions/headlessSample0.json | 4 + .../resources/runDescriptions/headlessSample1.json | 4 + .../resources/runDescriptions/headlessSample2.json | 9 + src/batchtools/headless/test.html | 0 src/batchtools/pom.xml | 36 + src/batchtools/rsTester/.buildpath | 10 + src/batchtools/rsTester/.classpath | 36 + src/batchtools/rsTester/.gitignore | 2 + .../org.ebayopensource.vjet.eclipse.core.prefs | 2 + .../rsTester/.settings/org.eclipse.jdt.core.prefs | 5 + .../rsTester/.settings/org.eclipse.m2e.core.prefs | 4 + .../rsTester/.settings/org.maven.ide.eclipse.prefs | 8 + src/batchtools/rsTester/pom.xml | 109 ++ .../main/java/com/galois/fiveui/BatchRunner.java | 235 ++++ .../java/com/galois/fiveui/RSTestDescription.java | 321 ++++++ .../src/main/java/com/galois/fiveui/ResType.java | 32 + .../src/main/java/com/galois/fiveui/Result.java | 174 +++ .../src/main/java/com/galois/fiveui/Rule.java | 122 +++ .../src/main/java/com/galois/fiveui/RuleSet.java | 154 +++ .../main/java/com/galois/fiveui/RuleSetTester.java | 91 ++ .../src/main/java/com/galois/fiveui/RuleTest.java | 76 ++ .../src/main/java/com/galois/fiveui/Utils.java | 44 + .../src/main/resources/javascript/ruleEval.js | 74 ++ .../resources/seleniumDrivers/linux64/chromedriver | Bin 0 -> 16328112 bytes .../com/galois/fiveui/BasicRuleSetParseTest.java | 115 ++ .../fiveui/BasicRunDescriptionParseTest.java | 126 +++ .../java/com/galois/fiveui/RunDescriptionTest.java | 118 ++ .../src/test/resources/ruleSets/emptyCheck.js | 6 + .../src/test/resources/ruleSets/emptyRuleSet.json | 4 + .../resources/ruleSets/headingGuidelines-caps.js | 19 + .../ruleSets/headingGuidelines-noEmptyHdrs.js | 12 + .../test/resources/ruleSets/headingGuidelines.json | 6 + .../test/resources/ruleSets/simpleRuleSet1.json | 4 + .../runDescriptions/headingSample-1-fails.json | 13 + .../runDescriptions/headingSample-2-fails.json | 13 + .../resources/runDescriptions/headingSample.json | 13 + .../test/resources/runDescriptions/sample0.json | 4 + .../test/resources/runDescriptions/sample1.json | 4 + .../resources/runDescriptions/sample2-fails.json | 10 + .../test/resources/runDescriptions/sample2.json | 10 + .../test/resources/runDescriptions/sample3.json | 7 + .../test/resources/runDescriptions/sample4.json | 10 + .../test/resources/runDescriptions/sample5.json | 13 + src/batchtools/rsTester/test.html | 0 src/batchtools/webdrivers/.classpath | 36 + src/batchtools/webdrivers/.gitignore | 1 + .../.settings/org.eclipse.jdt.core.prefs | 5 + .../.settings/org.eclipse.m2e.core.prefs | 4 + src/batchtools/webdrivers/pom.xml | 43 + .../java/com/galois/fiveui/drivers/Drivers.java | 149 +++ 172 files changed, 5686 insertions(+), 5699 deletions(-) delete mode 100644 batchtools/headless/.classpath delete mode 100644 batchtools/headless/.gitignore delete mode 100644 batchtools/headless/.settings/org.eclipse.core.resources.prefs delete mode 100644 batchtools/headless/.settings/org.eclipse.jdt.core.prefs delete mode 100644 batchtools/headless/.settings/org.eclipse.m2e.core.prefs delete mode 100644 batchtools/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar delete mode 100755 batchtools/headless/bin/runHeadless.sh delete mode 100644 batchtools/headless/pom.xml delete mode 100644 batchtools/headless/programs.properties.example delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java delete mode 100644 batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java delete mode 100644 batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java delete mode 100644 batchtools/headless/src/test/resources/crawlTest/four.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one_a.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one_b.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one_c.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one_d.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/one_e.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/three.html delete mode 100644 batchtools/headless/src/test/resources/crawlTest/two.html delete mode 100644 batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json delete mode 100644 batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json delete mode 100644 batchtools/headless/test.html delete mode 100644 batchtools/pom.xml delete mode 100644 batchtools/rsTester/.buildpath delete mode 100644 batchtools/rsTester/.classpath delete mode 100644 batchtools/rsTester/.gitignore delete mode 100644 batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs delete mode 100644 batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs delete mode 100644 batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs delete mode 100644 batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs delete mode 100644 batchtools/rsTester/pom.xml delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java delete mode 100644 batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java delete mode 100644 batchtools/rsTester/src/main/resources/javascript/ruleEval.js delete mode 100755 batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver delete mode 100644 batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java delete mode 100644 batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java delete mode 100644 batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json delete mode 100644 batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample0.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample1.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample2.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample3.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample4.json delete mode 100644 batchtools/rsTester/src/test/resources/runDescriptions/sample5.json delete mode 100644 batchtools/rsTester/test.html delete mode 100644 batchtools/webdrivers/.classpath delete mode 100644 batchtools/webdrivers/.gitignore delete mode 100644 batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs delete mode 100644 batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs delete mode 100644 batchtools/webdrivers/pom.xml delete mode 100644 batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java create mode 100644 src/batchtools/headless/.classpath create mode 100644 src/batchtools/headless/.gitignore create mode 100644 src/batchtools/headless/.settings/org.eclipse.core.resources.prefs create mode 100644 src/batchtools/headless/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/batchtools/headless/.settings/org.eclipse.m2e.core.prefs create mode 100755 src/batchtools/headless/bin/runHeadless.sh create mode 100644 src/batchtools/headless/pom.xml create mode 100644 src/batchtools/headless/programs.properties.example create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java create mode 100644 src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java create mode 100644 src/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/four.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one_a.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one_b.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one_c.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one_d.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/one_e.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/three.html create mode 100644 src/batchtools/headless/src/test/resources/crawlTest/two.html create mode 100644 src/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json create mode 100644 src/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json create mode 100644 src/batchtools/headless/test.html create mode 100644 src/batchtools/pom.xml create mode 100644 src/batchtools/rsTester/.buildpath create mode 100644 src/batchtools/rsTester/.classpath create mode 100644 src/batchtools/rsTester/.gitignore create mode 100644 src/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs create mode 100644 src/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs create mode 100644 src/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs create mode 100644 src/batchtools/rsTester/pom.xml create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java create mode 100644 src/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java create mode 100644 src/batchtools/rsTester/src/main/resources/javascript/ruleEval.js create mode 100755 src/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver create mode 100644 src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java create mode 100644 src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java create mode 100644 src/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json create mode 100644 src/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json create mode 100644 src/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json create mode 100644 src/batchtools/rsTester/test.html create mode 100644 src/batchtools/webdrivers/.classpath create mode 100644 src/batchtools/webdrivers/.gitignore create mode 100644 src/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs create mode 100644 src/batchtools/webdrivers/pom.xml create mode 100644 src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java diff --git a/Makefile b/Makefile index f35a817..67ff74c 100644 --- a/Makefile +++ b/Makefile @@ -80,19 +80,14 @@ MVN_TEST_CMD := xvfb-run -a $(MVN_EXE) test define pkg .PHONY: pkg-$1 pkg-$1: - cd batchtools/$1 && xvfb-run -a $(MVN_EXE) install + cd src/$1 && xvfb-run -a $(MVN_EXE) package endef -$(eval $(call pkg,rsTester)) -$(eval $(call pkg,headless)) +$(eval $(call pkg,batchtools)) -TEST_RUNNER_DIR := testrunner -HEADLESS_DIR := batchtools/headless -RSTESTER_DIR := batchtools/rsTester +BATCHTOOLS_DIR := src/batchtools -test: fiveui.crx fiveui.xpi $(topdir)/profiles/chrome $(topdir)/profiles/firefox pkg-rsTester -# cd $(TEST_RUNNER_DIR) && $(MVN_TEST_CMD) - cd $(RSTESTER_DIR) && $(MVN_TEST_CMD) - cd $(HEADLESS_DIR) && $(MVN_TEST_CMD) +test: fiveui.crx fiveui.xpi $(topdir)/profiles/chrome $(topdir)/profiles/firefox + cd $(BATCHTOOLS_DIR) && $(MVN_TEST_CMD) endif diff --git a/batchtools/headless/.classpath b/batchtools/headless/.classpath deleted file mode 100644 index beba987..0000000 --- a/batchtools/headless/.classpath +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/batchtools/headless/.gitignore b/batchtools/headless/.gitignore deleted file mode 100644 index 24c4165..0000000 --- a/batchtools/headless/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -programs.properties diff --git a/batchtools/headless/.settings/org.eclipse.core.resources.prefs b/batchtools/headless/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index cdfe4f1..0000000 --- a/batchtools/headless/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,5 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/test/java=UTF-8 -encoding//src/test/resources=UTF-8 -encoding/=UTF-8 diff --git a/batchtools/headless/.settings/org.eclipse.jdt.core.prefs b/batchtools/headless/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index abec6ca..0000000 --- a/batchtools/headless/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/batchtools/headless/.settings/org.eclipse.m2e.core.prefs b/batchtools/headless/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/batchtools/headless/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/batchtools/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar b/batchtools/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar deleted file mode 100644 index 2c9219d..0000000 Binary files a/batchtools/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar and /dev/null differ diff --git a/batchtools/headless/bin/runHeadless.sh b/batchtools/headless/bin/runHeadless.sh deleted file mode 100755 index 4c4d863..0000000 --- a/batchtools/headless/bin/runHeadless.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -export FIVEUI_ROOT_PATH=$HOME/FiveUI -export FIREFOX_BIN_PATH=/Users/bjones/myapps/Firefox_17_esr.app/Contents/MacOS/firefox - -java -DFIVEUI_ROOT_PATH=$FIVEUI_ROOT_PATH \ - -DFIREFOX_BIN_PATH=$FIREFOX_BIN_PATH \ - -jar $FIVEUI_ROOT_PATH/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar \ - $* diff --git a/batchtools/headless/pom.xml b/batchtools/headless/pom.xml deleted file mode 100644 index da5b348..0000000 --- a/batchtools/headless/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - 4.0.0 - - com.galois.fiveui - HeadlessRunner - 0.0.1-SNAPSHOT - jar - - - - UTF-8 - - - - - onejar-maven-plugin.googlecode.com - http://onejar-maven-plugin.googlecode.com/svn/mavenrepo - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.11 - - programs.properties - - - - - maven-assembly-plugin - - - - com.galois.fiveui.HeadlessRunner - - - - jar-with-dependencies - - - - - org.dstovall - onejar-maven-plugin - 1.3.0 - - - - com.galois.fiveui.HeadlessRunner - - - one-jar - - - - - - - - - - org.seleniumhq.selenium - selenium-java - 2.26.0 - - - com.google.guava - guava - 13.0.1 - - - com.google.code.gson - gson - 2.2.2 - - - com.galois.fiveui - webdrivers - 0.0.1-SNAPSHOT - - - com.galois.fiveui - RuleSetTester - 1.0 - - - junit - junit - 4.9 - - - edu.uci.ics - crawler4j - 3.3 - - - org.apache.httpcomponents - httpclient - 4.2.1 - - - org.apache.httpcomponents - httpcore - 4.2.1 - - - commons-cli - commons-cli - 1.2 - - - com.googlecode.jatl - jatl - 0.2.2 - - - diff --git a/batchtools/headless/programs.properties.example b/batchtools/headless/programs.properties.example deleted file mode 100644 index 97bd0c6..0000000 --- a/batchtools/headless/programs.properties.example +++ /dev/null @@ -1,2 +0,0 @@ -FIREFOX_BIN_PATH=/home/creswick/myapps/firefox/firefox-17.0.2-x86_64/firefox -LOG_LEVEL=ERROR diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java b/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java deleted file mode 100644 index 7f64b1a..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.galois.fiveui; - -import edu.uci.ics.crawler4j.crawler.Page; -import edu.uci.ics.crawler4j.crawler.WebCrawler; -import edu.uci.ics.crawler4j.parser.HtmlParseData; -import edu.uci.ics.crawler4j.url.WebURL; - -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.log4j.Logger; - -import com.google.common.base.Function; - -/** - * @author bjones - */ -public class BasicCrawler extends WebCrawler { - - private static Logger logger = Logger.getLogger("com.galois.fiveui.BasicCrawler"); - private final static Pattern FILTERS = Pattern.compile( - ".*(\\.(css|js|bmp|gif|jpe?g" - + "|png|tiff?|mid|mp2|mp3|mp4" - + "|wav|avi|mov|mpeg|ram|m4v|pdf" - + "|rm|smil|wmv|swf|wma|zip|rar|gz))$"); - public static Function _predicate; - public static List _urls; - - /** - * Configure static properties of the class before a crawl. - * - * @param pred URLs will be crawled only if pred.apply(URL) is - * true - * @param urls reference to a list of strings which the crawler will - * append URLs to as it works - */ - public static void configure(Function pred, List urls) { - _predicate = pred; - _urls = urls; - } - - /** - * specify whether the given url should be crawled or not - */ - @Override - public boolean shouldVisit(WebURL url) { - String href = url.getURL(); - Boolean yesno = !FILTERS.matcher(href).matches() && _predicate.apply(href); - logger.debug("saying " + (yesno ? "yes" : "no") + " to " + href); - return yesno; - } - - /** - * This function is called when a page is fetched and ready to be processed - * by the program. - */ - @Override - public void visit(Page page) { - int docid = page.getWebURL().getDocid(); - String url = page.getWebURL().getURL(); - String domain = page.getWebURL().getDomain(); - String path = page.getWebURL().getPath(); - String subDomain = page.getWebURL().getSubDomain(); - String parentUrl = page.getWebURL().getParentUrl(); - - logger.debug(" - Docid: " + docid); - logger.debug(" - URL: " + url); - logger.debug(" - Domain: '" + domain + "'"); - logger.debug(" - Sub-domain: '" + subDomain + "'"); - logger.debug(" - Path: '" + path + "'"); - logger.debug(" - Parent page: " + parentUrl); - - if (page.getParseData() instanceof HtmlParseData) { - HtmlParseData htmlParseData = (HtmlParseData) page.getParseData(); - String text = htmlParseData.getText(); - String html = htmlParseData.getHtml(); - List links = htmlParseData.getOutgoingUrls(); - - logger.debug(" -- Text length: " + text.length()); - logger.debug(" -- Html length: " + html.length()); - logger.debug(" -- Number of outgoing links: " + links.size()); - } - logger.debug(" - ============="); - - // append to URLs list - if (null != _urls) { - _urls.add(url); - } - } -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java b/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java deleted file mode 100644 index 79338ec..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.galois.fiveui; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.base.Function; - -import edu.uci.ics.crawler4j.crawler.CrawlConfig; -import edu.uci.ics.crawler4j.crawler.CrawlController; -import edu.uci.ics.crawler4j.fetcher.PageFetcher; -import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig; -import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer; - -/** - * @author bjones - */ -public class BasicCrawlerController { - - private String seed; - private String tmpDir; - private int depth; - private int maxFetch; - private int politeness; - private int threads; - private Function predicate; - - /** - * Initialize a basic web crawler controller. - * - * @param seed URL to start the crawl - * @param domain string that all crawled page URLs must start with - * @param depth maximum depth to crawl - * @param maxFetch maximum number of pages to crawl - * @param politeness time in milliseconds to wait before making requests on same domain - * @param threads number of concurrent threads to use while crawling - * @param tmpDir temporary directory to store intermediate crawl data - * (must exist and be read/write before crawl starts) - */ - public BasicCrawlerController (String seed, final String domain, int depth, int maxFetch, - int politeness, int threads, String tmpDir) { - this.seed = seed; - this.predicate = new Function() { - public Boolean apply(String s) { - return s.startsWith(domain); - } - }; - this.depth = depth; - this.maxFetch = maxFetch; - this.politeness = politeness; - this.threads = threads; - this.tmpDir = tmpDir; - } - - /** - * Initialize a basic web crawler controller. - * - * @param seed URL to start the crawl - * @param pred a Function to be used as a predicate that all crawled URLs must pass - * @param depth maximum depth to crawl - * @param maxFetch maximum number of pages to crawl - * @param politeness time in milliseconds to wait before making requests on same domain - * @param threads number of concurrent threads to use while crawling - * @param tmpDir temporary directory to store intermediate crawl data - * (must exist and be read/write before crawl starts) - */ - public BasicCrawlerController (String seed, Function pred, int depth, int maxFetch, - int politeness, int threads, String tmpDir) { - this.seed = seed; - this.predicate = pred; - this.depth = depth; - this.maxFetch = maxFetch; - this.politeness = politeness; - this.threads = threads; - this.tmpDir = tmpDir; - } - - public List go() throws Exception { - - /* - * crawlStorageFolder is a folder where intermediate crawl data is - * stored. - */ - String crawlStorageFolder = this.tmpDir; - - /* - * numberOfCrawlers shows the number of concurrent threads that should - * be initiated for crawling. - */ - int numberOfCrawlers = this.threads; - - CrawlConfig config = new CrawlConfig(); - - config.setCrawlStorageFolder(crawlStorageFolder); - - /* - * Be polite: Make sure that we don't send more than 1 request per - * second (1000 milliseconds between requests). - */ - config.setPolitenessDelay(this.politeness); - - /* - * You can set the maximum crawl depth here. The default value is -1 for - * unlimited depth - */ - config.setMaxDepthOfCrawling(this.depth); - - /* - * You can set the maximum number of pages to crawl. The default value - * is -1 for unlimited number of pages - */ - config.setMaxPagesToFetch(this.maxFetch); - - /* - * Delete the temporary crawl storage after we're done. - */ - config.setResumableCrawling(false); - - /* - * Instantiate the controller for this crawl. - */ - PageFetcher pageFetcher = new PageFetcher(config); - RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); - //robotstxtConfig.setEnabled(false); // uncomment if you want to ignore robots.txt - RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher); - CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer); - - // add a seed URL - controller.addSeed(this.seed); - - /* - * Setup storage for data collection by the BasicCrawler class - */ - List store = new ArrayList(); - BasicCrawler.configure(this.predicate, store); - - /* - * Start the crawl. This is a blocking operation. - */ - try { - controller.start(BasicCrawler.class, numberOfCrawlers); - } finally { - controller.Shutdown(); - } - - /* - * Extract and return data collected by BasicCrawler - */ - return store; - } -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java b/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java deleted file mode 100644 index 9f3f301..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java +++ /dev/null @@ -1,312 +0,0 @@ -/** - * Module : BatchRunner.java Copyright : (c) 2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebDriver; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -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 - - -/** - * BatchRunner is initialized with a WebDriver object. It provides an interface - * for running {@code RuleSet}s and {@code RuleTest}s with the WebDriver. - * - * @author bjones - */ -public class BatchRunner { - - private WebDriver _driver; - private JavascriptExecutor _exe; - private String _root; // FiveUI root directory - - // Hard coded JS files, relative to the FiveUI root directory. - private static final String DATA_DIR = "contexts/data/"; - private static final String J_QUERY_JS = DATA_DIR - + "lib/jquery/jquery.js"; - private static final String PRELUDE_JS = DATA_DIR - + "fiveui/injected/prelude.js"; - private static final String MD5_JS = DATA_DIR - + "lib/jshash/md5.js"; - private static final String JQUERY_PLUGIN_JS = DATA_DIR - + "fiveui/injected/jquery-plugins.js"; - private static final String SEL_INJECTED_COMPUTE_JS = DATA_DIR + - "/fiveui/selenium/selenium-injected-compute.js"; - private static final String INJECTED_COMPUTE_JS = DATA_DIR + - "/fiveui/injected/fiveui-injected-compute.js"; - - private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchRunner"); - - private void registerDriver(WebDriver driver) { - logger.debug("registering new webdriver..."); - this._driver = driver; - this._exe = (JavascriptExecutor) driver; - this._root = Drivers.getRootPath(); - logger.debug("root path for webdriver is " + _root); - } - - public BatchRunner() { - logger.debug("initializing BatchRunner ..."); - } - - /** - * Run a headless run description, returning the raw results: 'PASS' if - * no inconsistencies were found, 'ERROR' for each inconsistency found, - * 'EXCEPTION' for each uncaught exception. - *

- * The run.getURL() is loaded using the WebDriver and the rule set returned - * by {@code run.getRule()} is run. - * - * @param run a headless run description object - */ - public ImmutableList runHeadless(HeadlessRunDescription run) { - String seedUrl; - Builder builder = ImmutableList.builder(); // for results - ImmutableList rawResults; - CrawlParameters params = new CrawlParameters(run.getCrawlType()); - int politeness = params.toString().equals("none") ? 1000 : params.politeness; - List urls; - Map>> urlCache; - //- URL, params, urls - urlCache = new HashMap>>(); - - for (HeadlessAtom a: run.getAtoms()) { - RuleSet rs = a.getRuleSet(); - seedUrl = a.getURL(); - logger.debug("setting seed URL for crawl: " + seedUrl); - urls = null; - - /************** - * Gather URLs - **************/ - - if (params.isNone()) { - urls = ImmutableList.of(seedUrl); - logger.debug("skipping webcrawl"); - } else if (urlCache.containsKey(seedUrl) && - urlCache.get(seedUrl).containsKey(params.toString())) { - logger.debug("retreiving urls list from cache"); - urls = urlCache.get(seedUrl).get(params.toString()); - } else { - File tmpPath = Files.createTempDir(); - logger.debug("tmp directory for crawl data: " + tmpPath.toString()); - logger.debug("starting webcrawl controller ..."); - BasicCrawlerController con = - new BasicCrawlerController(seedUrl, - params.matchFcn, - params.depth, params.maxFetch, - params.politeness, - 1, // TODO only one thread is currently supported - tmpPath.getAbsolutePath()); - try { - urls = con.go(); - logger.debug("adding urls list to cache"); - logger.debug("URLs: " + urls.toString()); - Map> entry = (Map>) new HashMap>(); - entry.put(params.toString(), urls); - urlCache.put(seedUrl, entry); - } catch (Exception e) { - String errStr = "failed to complete webcrawl of" + seedUrl + "\n"; - errStr += e.toString(); - builder.add(new Result(ResType.Exception, _driver, errStr, seedUrl, - rs.getName(), rs.getDescription(), "")); - logger.error(errStr); - continue; - } finally { - IO.deleteFolder(tmpPath); // does its own logging - } - } - - /*********************** - * Drive the browser(s) - ***********************/ - - for (WebDriver driver: getDrivers()) { - registerDriver(driver); - for (String url: urls) { - logger.info("loading " + url + " for ruleset run ..."); - loadURL(url); // set state of the WebDriver (blocking) - try { - logger.info("running ruleset \"" + rs.getName() + "\""); - rawResults = runRule(rs); // run the ruleset, collect results - builder.addAll(rawResults); - } catch (Exception e) { - String errStr = "exception during runRule: " + rs.getName() + "\n"; - errStr += e.toString(); - builder.add(new Result(ResType.Exception, _driver, errStr, url, - rs.getName(), rs.getDescription(), "")); - logger.error(errStr); - } - try { - logger.debug("being polite for " + politeness + " millis..."); - Thread.sleep(politeness); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - driver.quit(); - } - } - return builder.build(); - } - - /** - * Run a rule set on the currently loaded page. - *

- * This method uses the web driver instance to run a rule set on the currently - * loaded page. The webdriver injects javascript that - * includes all the dependencies (JQuery, etc..) as well as the function which - * executes the rule check. The method sleeps the thread for 1 second and - * queries the results, which are then parsed and returned as a list of - * Result objects. - * - * @param ruleSet the rule set to be run - * @return results of running the rule set - * @throws IOException - */ - private ImmutableList runRule(final RuleSet ruleSet) throws IOException { - String contentScript = wrapRule(ruleSet); - Builder builder = ImmutableList.builder(); - String state = "url=" + _driver.getCurrentUrl() + - ", ruleSet=\"" + ruleSet.getName() + "\""; - logger.debug("runRule: " + state); - - _exe.executeScript(contentScript); - - try { - Thread.sleep(1000); - } catch (InterruptedException e1) { - logger.error(e1.toString()); - } - - Object res = _exe.executeScript("return fiveui.selPort.query(type='ReportProblem')"); - - if (res.getClass() == String.class) { - // we received an error via the expected mechanisms: - logger.error("exception running rule: " + res); - builder.add(new Result(ResType.Exception, _driver, "", _driver.getCurrentUrl(), - ruleSet.getName(), ruleSet.getDescription(), "")); - return builder.build(); - } else { - try { - @SuppressWarnings({ "unchecked", "rawtypes" }) - List>> results = (List) res; - - if (0 == results.size()) { - builder.add(new Result(ResType.Pass, _driver, - "passed " + ruleSet.getRules().size() + " tests", - _driver.getCurrentUrl(), ruleSet.getName(), ruleSet.getDescription(), "")); - } - - for (Map> r : results) { - Map problem = r.get("payload"); - // TODO decide what to extract from problem object and what - // to do with it. - // - // Probably we should just pass along the Map - // and let the reporter deal with it. - String problemAsHTML = "Rule Name: " + problem.get("name") + " / " - + "Rule Desc: " + problem.get("descr") + " / " - + "XPath: " + problem.get("xpath"); - builder.add(new Result(ResType.Error, _driver, "", - _driver.getCurrentUrl(), - ruleSet.getName(), - ruleSet.getDescription(), - problemAsHTML)); - } - - } catch (ClassCastException e) { - // An unexpected error happened: - logger.error("unexpected object returned: " + e.toString()); - builder.add(new Result(ResType.Exception, _driver, - "Unexpected object returned: " + res + ", state: " + state, - _driver.getCurrentUrl(), - ruleSet.getName(), - ruleSet.getDescription(), - "")); - } - } - return builder.build(); - } - - /** - * Build up the complete content script needed to run the rule. - *

- * The string returned contains all the javascript dependencies required - * to run a rule set and the function that is injected into the page which - * executes the rule set. - * - * TODO DRY - * - * @param ruleSet a RuleSet object - * @throws IOException - */ - private String wrapRule(RuleSet ruleSet) throws IOException { - String injected = ""; - injected += Utils.readFile(_root + SEL_INJECTED_COMPUTE_JS); - injected += Utils.readFile(_root + J_QUERY_JS); - injected += Utils.readFile(_root + PRELUDE_JS); - injected += Utils.readFile(_root + MD5_JS); - injected += Utils.readFile(_root + JQUERY_PLUGIN_JS); - injected += Utils.readFile(_root + INJECTED_COMPUTE_JS); - - injected += "return fiveui.selPort.send('SetRules', " + ruleSet + ");"; - - return injected; - } - - /** - * Build a list of webdrivers with which to run each ruleset. - * - * @return list of initialized WebDriver objects - */ - private static ImmutableList getDrivers() { - logger.debug("building webdrivers ..."); - ImmutableList r = ImmutableList.of( - Drivers.buildFFDriver() - // , Drivers.buildChromeDriver() - ); - logger.debug("built: " + r.toString()); - return r; - } - - /** - * Sets the state of the WebDriver by loading a given URL. - * - * @param url URL to load - */ - private void loadURL(String url) { - _driver.get(url); - } -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java b/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java deleted file mode 100644 index a07d43a..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.galois.fiveui; - -import com.google.common.base.Function; -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import org.apache.log4j.Logger; - -public class CrawlParameters { - - private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlParameters"); - - public int depth; - public int maxFetch; - public int politeness; - public String match; - public Function matchFcn; - - private Boolean _doNotCrawl; - private String _str; - - /** - * Construct (parse) a crawl type object from a string description - * - * A valid description is a whitespace separated list as follows: - * " " - * where: - *

    - *
  1. (depth :: int) depth of the crawl
  2. - *
  3. (maxFetch :: int) maximum number of pages to crawl
  4. - *
  5. (politeness :: int) number of milliseconds between hits on same domain
  6. - *
  7. (match :: String) glob pattern to match URLs
  8. - *
- * or the string "none" which is, in spirit, equivalent to "0 1 1000 *", - * but in practice the webcrawl is skipped entirely in this case. - * - * @param desc a string description of the crawl type - * @throws Exception - */ - public CrawlParameters(String desc) { - String[] l = desc.split("\\s+"); - if (desc == "none" || l.length != 4) { - this._doNotCrawl = true; - this._str = desc; - logger.debug("setting doNotCrawl = True"); - return; - } else { - this.depth = Integer.parseInt(l[0]); - this.maxFetch = Integer.parseInt(l[1]); - this.politeness = Integer.parseInt(l[2]); - this.match = l[3]; - this._doNotCrawl = false; - this._str = desc; - this.matchFcn = compileMatchFcn(this.match); - logger.debug("setting depth: " + this.depth); - logger.debug("setting maxFetch: " + this.maxFetch); - logger.debug("setting politeness: " + this.politeness); - logger.debug("setting match: " + this.match); - } - } - - public static Function compileMatchFcn(String glob) { - String reg = glob.replaceAll("\\.", "\\.").replaceAll("\\*", ".*"); - final Pattern pat = Pattern.compile(reg); - return new Function() { - public Boolean apply(String input) { - Matcher m = pat.matcher(input); - return m.matches(); - } - }; - } - - public static CrawlParameters none() { - return new CrawlParameters("none"); - } - - public Boolean isNone() { - return this._doNotCrawl; - } - - public String toString() { - return _str; - } -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java b/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java deleted file mode 100644 index 01ffae0..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.IOException; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -/** - * A singular url to test with a RuleSet. - * - * @author bjones - */ -public class HeadlessAtom { - - private String _url; - private RuleSet _ruleSet; - - public HeadlessAtom(String url, RuleSet ruleSet) { - _url = url; - _ruleSet = ruleSet; - } - - public String getURL() { - return _url; - } - - public RuleSet getRuleSet() { - return _ruleSet; - } - - public String toString() { - Gson gson = new Gson(); - return gson.toJson(this); - } - - /** - * Construct a HeadlessAtom from a JsonObject - * - * @param obj JsonObject to convert from - * @param dir parent directory of the filenames referenced in the ruleSet field - * @return a HeadlessAtom POJO - * @throws IOException - * @throws JsonParseException - */ - public static HeadlessAtom fromJsonObject(JsonObject obj, String dir) throws IOException { - String url = obj.get("url").getAsString(); - String ruleSet = obj.get("ruleSet").getAsString(); - - if (url == null || ruleSet == null) { - throw new JsonParseException("could get either 'url' or 'ruleSet' properties"); - } - - String rsPath = dir + File.separator + ruleSet; - RuleSet parsed = RuleSet.parseFile(rsPath); - - return new HeadlessAtom(url, parsed); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((_url == null) ? 0 : _url.hashCode()); - result = prime * result + ((_ruleSet == null) ? 0 : _ruleSet.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - HeadlessAtom other = (HeadlessAtom) obj; - if (_url == null) { - if (other._url != null) - return false; - } else if (!_url.equals(other._url)) - return false; - if (_ruleSet == null) { - if (other._ruleSet != null) - return false; - } else if (!_ruleSet.equals(other._ruleSet)) - return false; - return true; - } - -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java b/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java deleted file mode 100644 index 92f2ef1..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * - */ -package com.galois.fiveui; - - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.Type; -import java.util.List; - -import org.apache.log4j.Logger; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -/** - * @author bjones - * - */ -public class HeadlessRunDescription { - - private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunDescription"); - private static String _crawlType; - private List _atoms; - - public HeadlessRunDescription (List atoms) { - _atoms = atoms; - } - - public List getAtoms() { - return _atoms; - } - - public int size() { - return _atoms.size(); - } - - /** - * Parse a JSON file into a HeadlessRunDescription - * - * @param runDescFileName The file to load. - * @return A populated HeadlessRunDescription object. - * @throws FileNotFoundException if runDescFile can't be found. - */ - 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); - } - - public static class Deserializer implements JsonDeserializer { - - private String _fn; // stores the filename on disk being parsed - private String _ctxDir; // stores the parent dir of _fn - - public Deserializer(String fn) { - _fn = fn; - _ctxDir = new File(_fn).getParent(); - if (null == _ctxDir) { - _ctxDir = "."; - } - } - - public static void reportError(JsonElement json) { - logger.error("HeadlessRunDescription.parse: ran into unexpected jsonElement type:"); - logger.error(" " + json.getAsString()); - } - - /** - * Gracefully lookup property 'prop' in JsonObject 'obj'. - * - * @param obj a JSON object - * @param prop a key string to lookup in the JSON object - * @return string property or null if the prop doesn't resolve - */ - public static String objGetString(JsonObject obj, String prop) { - try { - return obj.get(prop).getAsString(); - } catch (NullPointerException e) { - logger.error("HeadlessRunDescription.parse: failed to lookup JSON property: " + prop); - logger.error(e.toString()); - return null; - } - } - - public HeadlessRunDescription deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { - - String ruleSetDir; - JsonArray arr; - - if (json.isJsonObject()) { // check if the description is an extended one - JsonObject obj = json.getAsJsonObject(); - ruleSetDir = objGetString(obj, "rulePath"); - _crawlType = objGetString(obj, "crawlType"); - arr = obj.get("runs").getAsJsonArray(); - } else if (json.isJsonArray()) { - ruleSetDir = _ctxDir; - _crawlType = "none"; - arr = json.getAsJsonArray(); - } else { - reportError(json); - return new HeadlessRunDescription(null); - } - - Builder atoms = ImmutableList.builder(); - for (JsonElement jsonElement : arr) { - 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) { - reportError(jsonElement); - } - } - - return new HeadlessRunDescription(atoms.build()); - } - } - - public String getCrawlType() { - return _crawlType; - } - - public String toString() { - Gson gson = new Gson(); - return gson.toJson(this); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - for (HeadlessAtom a: _atoms) { - result = prime * result + a.hashCode(); - } - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - HeadlessRunDescription other = (HeadlessRunDescription) obj; - if (_atoms == null) { - if (other._atoms != null) - return false; - } else if (!_atoms.equals(other._atoms)) - return false; - - return true; - } -} diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java b/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java deleted file mode 100644 index aba0ad7..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Module : HeadlessRunner.java Copyright : (c) 2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.URISyntaxException; -import com.galois.fiveui.Result; -import com.google.common.collect.ImmutableList; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.log4j.BasicConfigurator; - -/** - * The main entry point for running headless rule set runs. - *

- * The {@link #main(String[])} method of this class sets up a WebDriver, loads - * a headless run description from disk, and executes the run which includes - * loading seed URL's, performing a webcrawl, and running rule sets on each of - * the crawled pages. - * - * @author bjones - * - */ -public class HeadlessRunner { - - private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunner"); - - /** - * @param args list of headless run description filenames - * @throws IOException - * @throws URISyntaxException - * @throws ParseException - */ - @SuppressWarnings("static-access") - public static void main(final String[] args) - throws IOException, URISyntaxException, ParseException { - - // Setup command line options - Options options = new Options(); - Option help = new Option( "h", "print this help message" ); - Option output = OptionBuilder.withArgName("outfile") - .hasArg() - .withDescription("write output to file") - .create("o"); - Option report = OptionBuilder.withArgName("report directory") - .hasArg() - .withDescription("write HTML reports to given directory") - .create("r"); - options.addOption(output); - options.addOption(report); - options.addOption("v", false, "verbose output"); - options.addOption("vv", false, "VERY verbose output"); - options.addOption(help); - - // Parse command line options - CommandLineParser parser = new GnuParser(); - CommandLine cmd = null; - try { - cmd = parser.parse( options, args); - } catch (ParseException e) { - System.err.println( "Command line option parsing failed. Reason: " + e.getMessage() ); - System.exit(1); - } - - // Display help if requested - if (cmd.hasOption("h")) { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("headless [ ...]", options); - System.exit(1); - } - - // Set logging levels - BasicConfigurator.configure(); - Logger fiveuiLogger = Logger.getLogger("com.galois.fiveui"); - Logger rootLogger = Logger.getRootLogger(); - if (cmd.hasOption("v")) { - fiveuiLogger.setLevel(Level.DEBUG); - rootLogger.setLevel(Level.ERROR); - } else if (cmd.hasOption("vv")) { - fiveuiLogger.setLevel(Level.DEBUG); - rootLogger.setLevel(Level.DEBUG); - } else { - fiveuiLogger.setLevel(Level.ERROR); - rootLogger.setLevel(Level.ERROR); - } - - // Setup output file if requested - PrintWriter outStream = null; - if (cmd.hasOption("o")) { - String outfile = cmd.getOptionValue("o"); - try { - outStream = new PrintWriter(new BufferedWriter(new FileWriter(outfile))); - } catch (IOException e) { - System.err.println("Could not open outfile for writing: " + cmd.getOptionValue("outfile")); - System.exit(1); - } - } else { - outStream = new PrintWriter(new BufferedWriter(new PrintWriter(System.out))); - } - - // Setup HTML reports directory before the major work happens in case we - // have to throw an exception. - PrintWriter summaryFile = null; - PrintWriter byURLFile = null; - PrintWriter byRuleFile = null; - if (cmd.hasOption("r")) { - String repDir = cmd.getOptionValue("r"); - try { - File file = new File(repDir); - if (!file.exists()) { - file.mkdir(); - logger.info("report directory created: " + repDir); - } else { - logger.info("report directory already exists!"); - } - summaryFile = new PrintWriter(new FileWriter(repDir + File.separator + "summary.html")); - byURLFile = new PrintWriter(new FileWriter(repDir + File.separator + "byURL.html")); - byRuleFile = new PrintWriter(new FileWriter(repDir + File.separator + "byRule.html")); - } catch (IOException e) { - System.err.println("could not open report directory / files for writing"); - System.exit(1); - } - } - - // Major work: process input files - ImmutableList results = null; - for (String in: cmd.getArgs()) { - HeadlessRunDescription descr = HeadlessRunDescription.parse(in); - logger.debug("invoking headless run..."); - BatchRunner runner = new BatchRunner(); - results = runner.runHeadless(descr); - logger.debug("runHeadless returned " + results.size() + " results"); - // write results to the output stream as we go - for (Result result : results) { - outStream.println(result.toString()); - } - outStream.flush(); - } - outStream.close(); - - // Write report files if requested - if (cmd.hasOption("r") && results != null) { - Reporter kermit = new Reporter(results); - summaryFile.write(kermit.getSummary()); - summaryFile.close(); - byURLFile.write(kermit.getByURL()); - byURLFile.close(); - byRuleFile.write(kermit.getByRule()); - byRuleFile.close(); - } - } -} - diff --git a/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java b/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java deleted file mode 100644 index 5c0b233..0000000 --- a/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java +++ /dev/null @@ -1,360 +0,0 @@ -/** - * Module : Reporter.java Copyright : (c) 2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - * - * @author Benjamin Jones - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.googlecode.jatl.Html; - -/** - * Reporter is responsible for turning a list of results from a FiveUI run and - * and generating various reports which summarize the results. The reports are - * 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"; - - /** - * 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(); - } - /** - * 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(); - 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(); - } - - /** - * 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 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(); - } - - /** 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(); - }}; - } - - /** - * 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; - } - - /** - * 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 - * @return a map representing the results sorted by rule name. - */ - private Map computeSummaryStats(List results) { - /** passFailMap semantics: Map */ - Map passFailMap = new HashMap(); - String url; - int pass, fail; - int[] passFailList; - Pattern numberPassedPattern = Pattern.compile("passed ([0-9]+) tests"); - 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; - } - - 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/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java b/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java deleted file mode 100644 index f7f593f..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Module : BatchExecutorTest.java - * Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : - * Stability : Provisional - * Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.BindException; - -import junit.framework.Assert; - -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import com.google.common.collect.ImmutableList; - - -/** - * @author bjones - * - */ -public class BatchExecutorTest { - - private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; - private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchExecutorTest"); - private static NanoHTTPD httpServer; - - @BeforeClass - public static void setupTests() { - BasicConfigurator.configure(); - logger.setLevel(Level.DEBUG); - Logger root = Logger.getRootLogger(); - root.setLevel(Level.ERROR); - // start up local web server for crawl tests - File dir = new File("."); - logger.info("Starting NanoHTTPD webserver in " + dir.getAbsolutePath() + " on port 8000 ..."); - try { - httpServer = new NanoHTTPD(8000, dir); - } catch (BindException e) { - logger.debug("assuming that local web server is already running"); - } catch (IOException e1) { - e1.printStackTrace(); - Assert.assertTrue("failed to start NanoHTTPD in current directory " + dir.getAbsolutePath(), false); - } - } - - @AfterClass - public static void teardown() { - LogManager.shutdown(); - httpServer.stop(); - } - - /** - * This unit test requires that a webserver be running locally on port 8000, - * what it serves does not matter. - * - * @throws IOException - * @throws FileNotFoundException - */ - @Test - public void headlessRunTest0() throws IOException { - String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTest0.json"; - testHeadlessRun(jsonFileName); - } - - /** - * This unit test requires Internet access to http://www.cnn.com - * - * @throws IOException - * @throws FileNotFoundException - */ - @Ignore - public void headlessRunTestCNN() throws IOException { - String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTestCNN.json"; - testHeadlessRun(jsonFileName); - } - - /** - * Helper method for headless run unit tests. - * - * @param fn filename of a .json file containing a headless run description - */ - private static void testHeadlessRun(String fn) { - boolean flag = true; - try { - HeadlessRunDescription descr = HeadlessRunDescription.parse(fn); - BatchRunner runner = new BatchRunner(); - ImmutableList results = runner.runHeadless(descr); - logger.info(results.toString()); - } catch (Exception e) { - logger.error("testHeadlessRun: exception caught while running a headless run description"); - logger.error(e.toString()); - flag = false; - } - Assert.assertTrue(flag); - } - -} diff --git a/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java b/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java deleted file mode 100644 index f5ffa35..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.galois.fiveui; - -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.galois.fiveui.CrawlParameters; - - -public class CrawlParametersTest { - - private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlParameters"); - - @BeforeClass - public static void before() { - //if (!Logger.getRootLogger().getAllAppenders().hasMoreElements()) - BasicConfigurator.configure(); - logger.info("running unit tests..."); - } - - @AfterClass - public static void after() { - LogManager.shutdown(); - } - - @Test - public void testConstructorFields() { - CrawlParameters c; - try { - c = new CrawlParameters("0 1 100 foo"); - } catch (Exception e) { - Assert.assertTrue("failed to parse crawl type string", false); - return; - } - Assert.assertArrayEquals(new int[]{0, 1, 100}, new int[]{c.depth, c.maxFetch, c.politeness}); - Assert.assertEquals("foo", c.match); - } - - @Test - public void testNone() { - CrawlParameters c = CrawlParameters.none(); - Assert.assertTrue(c.isNone()); - } - - @Test - public void testMatchFcn() { - CrawlParameters c; - try { - c = new CrawlParameters("0 1 100 foo"); - } catch (Exception e) { - Assert.assertTrue("failed to parse crawl type string", false); - return; - } - Assert.assertTrue("failed to match foo", c.matchFcn.apply("foo")); - Assert.assertFalse("failed to not match bar", c.matchFcn.apply("bar")); - } - - @Test - public void testMatchFcnGlob1() { - CrawlParameters c; - try { - c = new CrawlParameters("0 1 100 foo*"); - } catch (Exception e) { - Assert.assertTrue("failed to parse crawl type string", false); - return; - } - Assert.assertTrue("failed to match foo", c.matchFcn.apply("foo")); - Assert.assertFalse("failed to not match bar", c.matchFcn.apply("bar")); - Assert.assertTrue("failed to match foobar", c.matchFcn.apply("foobar")); - Assert.assertFalse("failed to not match barfoobar", c.matchFcn.apply("barfoobar")); - } - - @Test - public void testMatchFcnGlob2() { - CrawlParameters c; - try { - c = new CrawlParameters("0 1 100 http://foo.com/*.html"); - } catch (Exception e) { - Assert.assertTrue("failed to parse crawl type string", false); - return; - } - Assert.assertTrue("failed to match http://foo.com/index.html", c.matchFcn.apply("http://foo.com/index.html")); - Assert.assertTrue("failed to match http://foo.com/test/index.html", c.matchFcn.apply("http://foo.com/test/index.html")); - Assert.assertFalse("failed to not match http://bar.com/index.html", c.matchFcn.apply("http://bar.com/index.html")); - } - - @Test - public void testMatchFcnGlob3() { - CrawlParameters c; - try { - c = new CrawlParameters("0 1 100 *foo.com*"); - } catch (Exception e) { - Assert.assertTrue("failed to parse crawl type string", false); - return; - } - Assert.assertTrue("failed to match http://foo.com/index.html", c.matchFcn.apply("http://foo.com/index.html")); - Assert.assertTrue("failed to match http://foo.com/test/index.html", c.matchFcn.apply("http://foo.com/test/index.html")); - Assert.assertTrue("failed to match http://bar.foo.com", c.matchFcn.apply("http://bar.foo.com")); - Assert.assertFalse("failed to not match http://foobar.com", c.matchFcn.apply("http://foobar.com")); - } - -} - diff --git a/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java b/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java deleted file mode 100644 index 0f932c2..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.galois.fiveui; - -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.util.List; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import junit.framework.Assert; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.BasicConfigurator; - -import com.google.common.base.Function; -import com.google.common.io.Files; - -import edu.uci.ics.crawler4j.util.IO; - -public class CrawlTest { - - // TODO need a system independent way of getting the resources path - private static String resourceDir = "src/test/resources/crawlTest/"; - private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlTest"); - private static NanoHTTPD httpServer = null; - - @BeforeClass - public static void setupCrawlTests() { - // Set up a simple configuration that logs on the console. - BasicConfigurator.configure(); - logger.setLevel(Level.DEBUG); - Logger root = Logger.getRootLogger(); - root.setLevel(Level.ERROR); - - // start up local web server for crawl tests - - logger.info("Starting NanoHTTPD webserver in " + resourceDir + " on port 8080 ..."); - try { - httpServer = new NanoHTTPD(8080, new File(resourceDir)); - } catch (BindException e) { - logger.info("assuming that local web server is already running"); - } catch (IOException e1) { - e1.printStackTrace(); - Assert.assertTrue("failed to start NanoHTTPD in resource directory", false); - } - } - - @AfterClass - public static void teardown() { - LogManager.shutdown(); - httpServer.stop(); - } - - // Requires Internet access - // @Test - public void corpDotGaloisCrawlTest() { - File tmpPath = Files.createTempDir(); - BasicCrawlerController con = - new BasicCrawlerController("http://corp.galois.com", - "http://corp.galois.com", - 2, 5, 1000, 1, - tmpPath.getAbsolutePath()); - List urls = null; - try { - urls = con.go(); - System.out.println(urls.toString()); - } catch (Exception e) { - Assert.assertTrue("failed to complete webcrawl", false); - e.printStackTrace(); - } finally { - IO.deleteFolder(tmpPath); - } - - Assert.assertEquals((urls != null) && (urls.size() == 5), true); - } - - @Test - public void testLocalCrawlDepth3one() { - doLocalCrawlTest("http://localhost:8080/one.html", 3, 10, 9); - } - - @Test - public void testLocalCrawlDepth3two() { - doLocalCrawlTest("http://localhost:8080/two.html", 3, 10, 3); - } - - @Test - public void testLocalCrawlDepth0one() { - doLocalCrawlTest("http://localhost:8080/one.html", 0, 10, 1); - } - - @Test - public void testCrawlWithPredicate() { - CrawlParameters c = new CrawlParameters("5 5 100 *one.html"); - doLocalCrawlTest("http://localhost:8080/one.html", c.matchFcn, c.depth, c.maxFetch, 1); - } - - public void doLocalCrawlTest(String seed, int depth, int maxFetch, int oracle) { - Function pred = new Function() { - public Boolean apply(String s) { - return s.startsWith("http"); - } - }; - doLocalCrawlTest(seed, pred, depth, maxFetch, oracle); - } - - public void doLocalCrawlTest(String seed, Function pred, int depth, int maxFetch, int oracle) { - - logger.info("Starting localCrawlTest ..."); - logger.info(" seed " + seed + ", depth " + depth); - - File tmpPath = Files.createTempDir(); - BasicCrawlerController con = - new BasicCrawlerController(seed, pred, depth, maxFetch, 100, 1, - tmpPath.getAbsolutePath()); - List urls = null; - try { - logger.info("Starting webcrawl ..."); - urls = con.go(); - logger.info("RETURN -- " + urls.toString()); - } catch (Exception e) { - e.printStackTrace(); - Assert.assertTrue("failed to run webcrawler", false); - } finally { - IO.deleteFolder(tmpPath); - } - - // assert that we got oracle number of URLs - Assert.assertTrue("got " + urls.size() + " URLs, expected " + oracle, - (urls != null) && (urls.size() == oracle)); - } - -} diff --git a/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java b/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java deleted file mode 100644 index 804d9f6..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * - */ -package com.galois.fiveui; - -import java.io.IOException; - -import junit.framework.Assert; - -import org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.google.common.collect.ImmutableList; - -/** - * @author bjones - * - */ -public class HeadlessTest { - private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; - private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessTest"); - - @BeforeClass - public static void beforeClass() { - BasicConfigurator.configure(); - Logger root = Logger.getRootLogger(); - root.setLevel(Level.ERROR); - logger.setLevel(Level.DEBUG); - logger.debug("running headless tests..."); - } - /** - * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses - * 'src/test/resources/runDescriptions/headlessSample0.json'. - * - * @throws IOException - */ - @Test - public final void testDeserialize_headlessSample0() throws IOException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample0.json"; - String ruleSetLoc = - RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; - RuleSet ruleSetOracle = RuleSet.parseFile(ruleSetLoc); - HeadlessAtom headlessAtomOracle = - new HeadlessAtom("http://testhost", ruleSetOracle); - HeadlessRunDescription oracle = - new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); - - HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - - /** - * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses - * 'src/test/resources/runDescriptions/headlessSample1.json'. - * - * @throws IOException - */ - @Test - public final void testDeserialize_headlessSample1() throws IOException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample1.json"; - String ruleSetLoc = RUN_DESCRIPTION_DIR + - "../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json"; - RuleSet ruleSetOracle = RuleSet.parseFile(ruleSetLoc); - HeadlessAtom headlessAtomOracle = - new HeadlessAtom("http://testhost", ruleSetOracle); - HeadlessRunDescription oracle = - new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); - - HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - - /** - * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses - * 'src/test/resources/runDescriptions/headlessSample2.json'. - * - * @throws IOException - */ - @Test - public final void testDeserialize_headlessSample2() throws IOException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample2.json"; - // manually build first HeadlessAtom - String ruleSetLoc1 = - RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; - RuleSet ruleSetOracle1 = RuleSet.parseFile(ruleSetLoc1); - HeadlessAtom headlessAtomOracle1 = - new HeadlessAtom("http://testhost1", ruleSetOracle1); - // manually build second HeadlessAtom - String ruleSetLoc2 = RUN_DESCRIPTION_DIR + - "../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json"; - - RuleSet ruleSetOracle2 = RuleSet.parseFile(ruleSetLoc2); - HeadlessAtom headlessAtomOracle2 = - new HeadlessAtom("http://testhost2", ruleSetOracle2); - - HeadlessRunDescription oracle = - new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle1, - headlessAtomOracle2)); - - HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - - private void assertObjEqual(String msg, Object oracle, Object actual) { - Assert.assertTrue(msg + ";\n expected: "+oracle+"\n actual: "+actual, - oracle.equals(actual)); - } -} diff --git a/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java b/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java deleted file mode 100644 index 53434be..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java +++ /dev/null @@ -1,1122 +0,0 @@ -package com.galois.fiveui; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URLEncoder; -import java.util.Date; -import java.util.Enumeration; -import java.util.Vector; -import java.util.Hashtable; -import java.util.Locale; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.TimeZone; - -import java.io.ByteArrayOutputStream; -import java.io.FileOutputStream; - -/** - * A simple, tiny, nicely embeddable HTTP 1.0 (partially 1.1) server in Java - * - *

NanoHTTPD version 1.25, - * Copyright © 2001,2005-2012 Jarno Elonen (elonen@iki.fi, http://iki.fi/elonen/) - * and Copyright © 2010 Konstantinos Togias (info@ktogias.gr, http://ktogias.gr) - * - *

Features + limitations:

    - * - *
  • Only one Java file
  • - *
  • Java 1.1 compatible
  • - *
  • Released as open source, Modified BSD licence
  • - *
  • No fixed config files, logging, authorization etc. (Implement yourself if you need them.)
  • - *
  • Supports parameter parsing of GET and POST methods (+ rudimentary PUT support in 1.25)
  • - *
  • Supports both dynamic content and file serving
  • - *
  • Supports file upload (since version 1.2, 2010)
  • - *
  • Supports partial content (streaming)
  • - *
  • Supports ETags
  • - *
  • Never caches anything
  • - *
  • Doesn't limit bandwidth, request time or simultaneous connections
  • - *
  • Default code serves files and shows all HTTP parameters and headers
  • - *
  • File server supports directory listing, index.html and index.htm
  • - *
  • File server supports partial content (streaming)
  • - *
  • File server supports ETags
  • - *
  • File server does the 301 redirection trick for directories without '/'
  • - *
  • File server supports simple skipping for files (continue download)
  • - *
  • File server serves also very long files without memory overhead
  • - *
  • Contains a built-in list of most common mime types
  • - *
  • All header names are converted lowercase so they don't vary between browsers/clients
  • - * - *
- * - *

Ways to use:

    - * - *
  • Run as a standalone app, serves files and shows requests
  • - *
  • Subclass serve() and embed to your own program
  • - *
  • Call serveFile() from serve() with your own base directory
  • - * - *
- * - * See the end of the source file for distribution license - * (Modified BSD licence) - */ -public class NanoHTTPD -{ - // ================================================== - // API parts - // ================================================== - - /** - * Override this to customize the server.

- * - * (By default, this delegates to serveFile() and allows directory listing.) - * - * @param uri Percent-decoded URI without parameters, for example "/index.cgi" - * @param method "GET", "POST" etc. - * @param parms Parsed, percent decoded parameters from URI and, in case of POST, data. - * @param header Header entries, percent decoded - * @return HTTP response, see class Response for details - */ - public Response serve( String uri, String method, Properties header, Properties parms, Properties files ) - { - myOut.println( method + " '" + uri + "' " ); - - Enumeration e = header.propertyNames(); - while ( e.hasMoreElements()) - { - String value = (String)e.nextElement(); - myOut.println( " HDR: '" + value + "' = '" + - header.getProperty( value ) + "'" ); - } - e = parms.propertyNames(); - while ( e.hasMoreElements()) - { - String value = (String)e.nextElement(); - myOut.println( " PRM: '" + value + "' = '" + - parms.getProperty( value ) + "'" ); - } - e = files.propertyNames(); - while ( e.hasMoreElements()) - { - String value = (String)e.nextElement(); - myOut.println( " UPLOADED: '" + value + "' = '" + - files.getProperty( value ) + "'" ); - } - - return serveFile( uri, header, myRootDir, true ); - } - - /** - * HTTP response. - * Return one of these from serve(). - */ - public class Response - { - /** - * Default constructor: response = HTTP_OK, data = mime = 'null' - */ - public Response() - { - this.status = HTTP_OK; - } - - /** - * Basic constructor. - */ - public Response( String status, String mimeType, InputStream data ) - { - this.status = status; - this.mimeType = mimeType; - this.data = data; - } - - /** - * Convenience method that makes an InputStream out of - * given text. - */ - public Response( String status, String mimeType, String txt ) - { - this.status = status; - this.mimeType = mimeType; - try - { - this.data = new ByteArrayInputStream( txt.getBytes("UTF-8")); - } - catch ( java.io.UnsupportedEncodingException uee ) - { - uee.printStackTrace(); - } - } - - /** - * Adds given line to the header. - */ - public void addHeader( String name, String value ) - { - header.put( name, value ); - } - - /** - * HTTP status code after processing, e.g. "200 OK", HTTP_OK - */ - public String status; - - /** - * MIME type of content, e.g. "text/html" - */ - public String mimeType; - - /** - * Data of the response, may be null. - */ - public InputStream data; - - /** - * Headers for the HTTP response. Use addHeader() - * to add lines. - */ - public Properties header = new Properties(); - } - - /** - * Some HTTP response status codes - */ - public static final String - HTTP_OK = "200 OK", - HTTP_PARTIALCONTENT = "206 Partial Content", - HTTP_RANGE_NOT_SATISFIABLE = "416 Requested Range Not Satisfiable", - HTTP_REDIRECT = "301 Moved Permanently", - HTTP_NOTMODIFIED = "304 Not Modified", - HTTP_FORBIDDEN = "403 Forbidden", - HTTP_NOTFOUND = "404 Not Found", - HTTP_BADREQUEST = "400 Bad Request", - HTTP_INTERNALERROR = "500 Internal Server Error", - HTTP_NOTIMPLEMENTED = "501 Not Implemented"; - - /** - * Common mime types for dynamic content - */ - public static final String - MIME_PLAINTEXT = "text/plain", - MIME_HTML = "text/html", - MIME_DEFAULT_BINARY = "application/octet-stream", - MIME_XML = "text/xml"; - - // ================================================== - // Socket & server code - // ================================================== - - /** - * Starts a HTTP server to given port.

- * Throws an IOException if the socket is already in use - */ - public NanoHTTPD( int port, File wwwroot ) throws IOException - { - myTcpPort = port; - this.myRootDir = wwwroot; - myServerSocket = new ServerSocket( myTcpPort ); - myThread = new Thread( new Runnable() - { - public void run() - { - try - { - while( true ) - new HTTPSession( myServerSocket.accept()); - } - catch ( IOException ioe ) - {} - } - }); - myThread.setDaemon( true ); - myThread.start(); - } - - /** - * Stops the server. - */ - public void stop() - { - try - { - myServerSocket.close(); - myThread.join(); - } - catch ( IOException ioe ) {} - catch ( InterruptedException e ) {} - } - - - /** - * Starts as a standalone file server and waits for Enter. - */ - public static void main( String[] args ) - { - myOut.println( "NanoHTTPD 1.25 (C) 2001,2005-2011 Jarno Elonen and (C) 2010 Konstantinos Togias\n" + - "(Command line options: [-p port] [-d root-dir] [--licence])\n" ); - - // Defaults - int port = 80; - File wwwroot = new File(".").getAbsoluteFile(); - - // Show licence if requested - for ( int i=0; i= 0 && size > 0 ) - { - rlen = is.read(buf, 0, 512); - size -= rlen; - if (rlen > 0) - f.write(buf, 0, rlen); - } - - // Get the raw body as a byte [] - byte [] fbuf = f.toByteArray(); - - // Create a BufferedReader for easily reading it as string. - ByteArrayInputStream bin = new ByteArrayInputStream(fbuf); - BufferedReader in = new BufferedReader( new InputStreamReader(bin)); - - // If the method is POST, there may be parameters - // in data section, too, read it: - if ( method.equalsIgnoreCase( "POST" )) - { - String contentType = ""; - String contentTypeHeader = header.getProperty("content-type"); - StringTokenizer st = new StringTokenizer( contentTypeHeader , "; " ); - if ( st.hasMoreTokens()) { - contentType = st.nextToken(); - } - - if (contentType.equalsIgnoreCase("multipart/form-data")) - { - // Handle multipart/form-data - if ( !st.hasMoreTokens()) - sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html" ); - String boundaryExp = st.nextToken(); - st = new StringTokenizer( boundaryExp , "=" ); - if (st.countTokens() != 2) - sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary syntax error. Usage: GET /example/file.html" ); - st.nextToken(); - String boundary = st.nextToken(); - - decodeMultipartData(boundary, fbuf, in, parms, files); - } - else - { - // Handle application/x-www-form-urlencoded - String postLine = ""; - char pbuf[] = new char[512]; - int read = in.read(pbuf); - while ( read >= 0 && !postLine.endsWith("\r\n") ) - { - postLine += String.valueOf(pbuf, 0, read); - read = in.read(pbuf); - } - postLine = postLine.trim(); - decodeParms( postLine, parms ); - } - } - - if ( method.equalsIgnoreCase( "PUT" )) - files.put("content", saveTmpFile( fbuf, 0, f.size())); - - // Ok, now do the serve() - Response r = serve( uri, method, header, parms, files ); - if ( r == null ) - sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: Serve() returned a null response." ); - else - sendResponse( r.status, r.mimeType, r.header, r.data ); - - in.close(); - is.close(); - } - catch ( IOException ioe ) - { - try - { - sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); - } - catch ( Throwable t ) {} - } - catch ( InterruptedException ie ) - { - // Thrown by sendError, ignore and exit the thread. - } - } - - /** - * Decodes the sent headers and loads the data into - * java Properties' key - value pairs - **/ - private void decodeHeader(BufferedReader in, Properties pre, Properties parms, Properties header) - throws InterruptedException - { - try { - // Read the request line - String inLine = in.readLine(); - if (inLine == null) return; - StringTokenizer st = new StringTokenizer( inLine ); - if ( !st.hasMoreTokens()) - sendError( HTTP_BADREQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html" ); - - String method = st.nextToken(); - pre.put("method", method); - - if ( !st.hasMoreTokens()) - sendError( HTTP_BADREQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html" ); - - String uri = st.nextToken(); - - // Decode parameters from the URI - int qmi = uri.indexOf( '?' ); - if ( qmi >= 0 ) - { - decodeParms( uri.substring( qmi+1 ), parms ); - uri = decodePercent( uri.substring( 0, qmi )); - } - else uri = decodePercent(uri); - - // If there's another token, it's protocol version, - // followed by HTTP headers. Ignore version but parse headers. - // NOTE: this now forces header names lowercase since they are - // case insensitive and vary by client. - if ( st.hasMoreTokens()) - { - String line = in.readLine(); - while ( line != null && line.trim().length() > 0 ) - { - int p = line.indexOf( ':' ); - if ( p >= 0 ) - header.put( line.substring(0,p).trim().toLowerCase(), line.substring(p+1).trim()); - line = in.readLine(); - } - } - - pre.put("uri", uri); - } - catch ( IOException ioe ) - { - sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); - } - } - - /** - * Decodes the Multipart Body data and put it - * into java Properties' key - value pairs. - **/ - private void decodeMultipartData(String boundary, byte[] fbuf, BufferedReader in, Properties parms, Properties files) - throws InterruptedException - { - try - { - int[] bpositions = getBoundaryPositions(fbuf,boundary.getBytes()); - int boundarycount = 1; - String mpline = in.readLine(); - while ( mpline != null ) - { - if (mpline.indexOf(boundary) == -1) - sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html" ); - boundarycount++; - Properties item = new Properties(); - mpline = in.readLine(); - while (mpline != null && mpline.trim().length() > 0) - { - int p = mpline.indexOf( ':' ); - if (p != -1) - item.put( mpline.substring(0,p).trim().toLowerCase(), mpline.substring(p+1).trim()); - mpline = in.readLine(); - } - if (mpline != null) - { - String contentDisposition = item.getProperty("content-disposition"); - if (contentDisposition == null) - { - sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html" ); - } - StringTokenizer st = new StringTokenizer( contentDisposition , "; " ); - Properties disposition = new Properties(); - while ( st.hasMoreTokens()) - { - String token = st.nextToken(); - int p = token.indexOf( '=' ); - if (p!=-1) - disposition.put( token.substring(0,p).trim().toLowerCase(), token.substring(p+1).trim()); - } - String pname = disposition.getProperty("name"); - pname = pname.substring(1,pname.length()-1); - - String value = ""; - if (item.getProperty("content-type") == null) { - while (mpline != null && mpline.indexOf(boundary) == -1) - { - mpline = in.readLine(); - if ( mpline != null) - { - int d = mpline.indexOf(boundary); - if (d == -1) - value+=mpline; - else - value+=mpline.substring(0,d-2); - } - } - } - else - { - if (boundarycount> bpositions.length) - sendError( HTTP_INTERNALERROR, "Error processing request" ); - int offset = stripMultipartHeaders(fbuf, bpositions[boundarycount-2]); - String path = saveTmpFile(fbuf, offset, bpositions[boundarycount-1]-offset-4); - files.put(pname, path); - value = disposition.getProperty("filename"); - value = value.substring(1,value.length()-1); - do { - mpline = in.readLine(); - } while (mpline != null && mpline.indexOf(boundary) == -1); - } - parms.put(pname, value); - } - } - } - catch ( IOException ioe ) - { - sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); - } - } - - /** - * Find the byte positions where multipart boundaries start. - **/ - public int[] getBoundaryPositions(byte[] b, byte[] boundary) - { - int matchcount = 0; - int matchbyte = -1; - Vector matchbytes = new Vector(); - for (int i=0; i 0) - { - String tmpdir = System.getProperty("java.io.tmpdir"); - try { - File temp = File.createTempFile("NanoHTTPD", "", new File(tmpdir)); - OutputStream fstream = new FileOutputStream(temp); - fstream.write(b, offset, len); - fstream.close(); - path = temp.getAbsolutePath(); - } catch (Exception e) { // Catch exception if any - myErr.println("Error: " + e.getMessage()); - } - } - return path; - } - - - /** - * It returns the offset separating multipart file headers - * from the file's data. - **/ - private int stripMultipartHeaders(byte[] b, int offset) - { - int i = 0; - for (i=offset; i - * For example: "an+example%20string" -> "an example string" - */ - private String decodePercent( String str ) throws InterruptedException - { - try - { - StringBuffer sb = new StringBuffer(); - for( int i=0; i e = header.keys(); - while ( e.hasMoreElements()) - { - String key = (String)e.nextElement(); - String value = header.getProperty( key ); - pw.print( key + ": " + value + "\r\n"); - } - } - - pw.print("\r\n"); - pw.flush(); - - if ( data != null ) - { - int pending = data.available(); // This is to support partial sends, see serveFile() - byte[] buff = new byte[theBufferSize]; - while (pending>0) - { - int read = data.read( buff, 0, ( (pending>theBufferSize) ? theBufferSize : pending )); - if (read <= 0) break; - out.write( buff, 0, read ); - pending -= read; - } - } - out.flush(); - out.close(); - if ( data != null ) - data.close(); - } - catch( IOException ioe ) - { - // Couldn't write? No can do. - try { mySocket.close(); } catch( Throwable t ) {} - } - } - - private Socket mySocket; - } - - /** - * URL-encodes everything between "/"-characters. - * Encodes spaces as '%20' instead of '+'. - */ - @SuppressWarnings("deprecation") - private String encodeUri( String uri ) - { - String newUri = ""; - StringTokenizer st = new StringTokenizer( uri, "/ ", true ); - while ( st.hasMoreTokens()) - { - String tok = st.nextToken(); - if ( tok.equals( "/" )) - newUri += "/"; - else if ( tok.equals( " " )) - newUri += "%20"; - else - { - newUri += URLEncoder.encode( tok ); - // For Java 1.4 you'll want to use this instead: - // try { newUri += URLEncoder.encode( tok, "UTF-8" ); } catch ( java.io.UnsupportedEncodingException uee ) {} - } - } - return newUri; - } - - private int myTcpPort; - private final ServerSocket myServerSocket; - private Thread myThread; - private File myRootDir; - - // ================================================== - // File server code - // ================================================== - - /** - * Serves file from homeDir and its' subdirectories (only). - * Uses only URI, ignores all headers and HTTP parameters. - */ - public Response serveFile( String uri, Properties header, File homeDir, - boolean allowDirectoryListing ) - { - Response res = null; - - // Make sure we won't die of an exception later - if ( !homeDir.isDirectory()) - res = new Response( HTTP_INTERNALERROR, MIME_PLAINTEXT, - "INTERNAL ERRROR: serveFile(): given homeDir is not a directory." ); - - if ( res == null ) - { - // Remove URL arguments - uri = uri.trim().replace( File.separatorChar, '/' ); - if ( uri.indexOf( '?' ) >= 0 ) - uri = uri.substring(0, uri.indexOf( '?' )); - - // Prohibit getting out of current directory - if ( uri.startsWith( ".." ) || uri.endsWith( ".." ) || uri.indexOf( "../" ) >= 0 ) - res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, - "FORBIDDEN: Won't serve ../ for security reasons." ); - } - - File f = new File( homeDir, uri ); - if ( res == null && !f.exists()) - res = new Response( HTTP_NOTFOUND, MIME_PLAINTEXT, - "Error 404, file not found." ); - - // List the directory, if necessary - if ( res == null && f.isDirectory()) - { - // Browsers get confused without '/' after the - // directory, send a redirect. - if ( !uri.endsWith( "/" )) - { - uri += "/"; - res = new Response( HTTP_REDIRECT, MIME_HTML, - "Redirected: " + - uri + ""); - res.addHeader( "Location", uri ); - } - - if ( res == null ) - { - // First try index.html and index.htm - if ( new File( f, "index.html" ).exists()) - f = new File( homeDir, uri + "/index.html" ); - else if ( new File( f, "index.htm" ).exists()) - f = new File( homeDir, uri + "/index.htm" ); - // No index file, list the directory if it is readable - else if ( allowDirectoryListing && f.canRead() ) - { - String[] files = f.list(); - String msg = "

Directory " + uri + "


"; - - if ( uri.length() > 1 ) - { - String u = uri.substring( 0, uri.length()-1 ); - int slash = u.lastIndexOf( '/' ); - if ( slash >= 0 && slash < u.length()) - msg += "..
"; - } - - if (files!=null) - { - for ( int i=0; i" + - files[i] + ""; - - // Show file size - if ( curFile.isFile()) - { - long len = curFile.length(); - msg += "  ("; - if ( len < 1024 ) - msg += len + " bytes"; - else if ( len < 1024 * 1024 ) - msg += len/1024 + "." + (len%1024/10%100) + " KB"; - else - msg += len/(1024*1024) + "." + len%(1024*1024)/10%100 + " MB"; - - msg += ")"; - } - msg += "
"; - if ( dir ) msg += ""; - } - } - msg += ""; - res = new Response( HTTP_OK, MIME_HTML, msg ); - } - else - { - res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, - "FORBIDDEN: No directory listing." ); - } - } - } - - try - { - if ( res == null ) - { - // Get MIME type from file name extension, if possible - String mime = null; - int dot = f.getCanonicalPath().lastIndexOf( '.' ); - if ( dot >= 0 ) - mime = (String)theMimeTypes.get( f.getCanonicalPath().substring( dot + 1 ).toLowerCase()); - if ( mime == null ) - mime = MIME_DEFAULT_BINARY; - - // Calculate etag - String etag = Integer.toHexString((f.getAbsolutePath() + f.lastModified() + "" + f.length()).hashCode()); - - // Support (simple) skipping: - long startFrom = 0; - long endAt = -1; - String range = header.getProperty( "range" ); - if ( range != null ) - { - if ( range.startsWith( "bytes=" )) - { - range = range.substring( "bytes=".length()); - int minus = range.indexOf( '-' ); - try { - if ( minus > 0 ) - { - startFrom = Long.parseLong( range.substring( 0, minus )); - endAt = Long.parseLong( range.substring( minus+1 )); - } - } - catch ( NumberFormatException nfe ) {} - } - } - - // Change return code and add Content-Range header when skipping is requested - long fileLen = f.length(); - if (range != null && startFrom >= 0) - { - if ( startFrom >= fileLen) - { - res = new Response( HTTP_RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "" ); - res.addHeader( "Content-Range", "bytes 0-0/" + fileLen); - res.addHeader( "ETag", etag); - } - else - { - if ( endAt < 0 ) - endAt = fileLen-1; - long newLen = endAt - startFrom + 1; - if ( newLen < 0 ) newLen = 0; - - final long dataLen = newLen; - FileInputStream fis = new FileInputStream( f ) { - public int available() throws IOException { return (int)dataLen; } - }; - fis.skip( startFrom ); - - res = new Response( HTTP_PARTIALCONTENT, mime, fis ); - res.addHeader( "Content-Length", "" + dataLen); - res.addHeader( "Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen); - res.addHeader( "ETag", etag); - } - } - else - { - if (etag.equals(header.getProperty("if-none-match"))) - res = new Response( HTTP_NOTMODIFIED, mime, ""); - else - { - res = new Response( HTTP_OK, mime, new FileInputStream( f )); - res.addHeader( "Content-Length", "" + fileLen); - res.addHeader( "ETag", etag); - } - } - } - } - catch( IOException ioe ) - { - res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, "FORBIDDEN: Reading file failed." ); - } - - res.addHeader( "Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requestes - return res; - } - - /** - * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE - */ - private static Hashtable theMimeTypes = new Hashtable(); - static - { - StringTokenizer st = new StringTokenizer( - "css text/css "+ - "htm text/html "+ - "html text/html "+ - "xml text/xml "+ - "txt text/plain "+ - "asc text/plain "+ - "gif image/gif "+ - "jpg image/jpeg "+ - "jpeg image/jpeg "+ - "png image/png "+ - "mp3 audio/mpeg "+ - "m3u audio/mpeg-url " + - "mp4 video/mp4 " + - "ogv video/ogg " + - "flv video/x-flv " + - "mov video/quicktime " + - "swf application/x-shockwave-flash " + - "js application/javascript "+ - "pdf application/pdf "+ - "doc application/msword "+ - "ogg application/x-ogg "+ - "zip application/octet-stream "+ - "exe application/octet-stream "+ - "class application/octet-stream " ); - while ( st.hasMoreTokens()) - theMimeTypes.put( st.nextToken(), st.nextToken()); - } - - private static int theBufferSize = 16 * 1024; - - // Change these if you want to log to somewhere else than stdout - protected static PrintStream myOut = System.out; - protected static PrintStream myErr = System.err; - - /** - * GMT date formatter - */ - private static java.text.SimpleDateFormat gmtFrmt; - static - { - gmtFrmt = new java.text.SimpleDateFormat( "E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); - gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - /** - * The distribution licence - */ - private static final String LICENCE = - "Copyright (C) 2001,2005-2011 by Jarno Elonen \n"+ - "and Copyright (C) 2010 by Konstantinos Togias \n"+ - "\n"+ - "Redistribution and use in source and binary forms, with or without\n"+ - "modification, are permitted provided that the following conditions\n"+ - "are met:\n"+ - "\n"+ - "Redistributions of source code must retain the above copyright notice,\n"+ - "this list of conditions and the following disclaimer. Redistributions in\n"+ - "binary form must reproduce the above copyright notice, this list of\n"+ - "conditions and the following disclaimer in the documentation and/or other\n"+ - "materials provided with the distribution. The name of the author may not\n"+ - "be used to endorse or promote products derived from this software without\n"+ - "specific prior written permission. \n"+ - " \n"+ - "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"+ - "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"+ - "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"+ - "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"+ - "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"+ - "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"+ - "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"+ - "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"+ - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"+ - "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; -} - diff --git a/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java b/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java deleted file mode 100644 index 39a8e5c..0000000 --- a/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Module : Reporter.java Copyright : (c) 2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - * - * @author Benjamin Jones - */ -package com.galois.fiveui; - -import static org.junit.Assert.*; - -import java.io.File; -import java.io.IOException; -import org.junit.Test; -import org.openqa.selenium.WebDriver; - -import com.google.common.collect.ImmutableList; - -public class ReporterTest { - - @Test - public void testConstructor() { - ImmutableList r = ImmutableList.of( - new Result(ResType.Pass, (WebDriver) null, "OK", "http://nonexistant", "test rule 1", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 1", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://nonexistant", "test rule 2", "a desc or test rule 1", "problem!")); - Reporter kermit = new Reporter(r); - System.out.println("Summary page size: " + kermit.getSummary().length() + " bytes"); - System.out.println("Summary page size: " + kermit.getByURL().length() + " bytes"); - System.out.println("Summary page size: " + kermit.getByRule().length() + " bytes"); - assertTrue(kermit.getSummary().length() > 0 && - kermit.getByURL().length() > 0 && - kermit.getByRule().length() > 0); - } - - @Test - public void testSummaryPage() throws IOException { - //File tmpPath = Files.createTempDir(); - File tmpPath = new File("/tmp/"); - System.out.println("Writing test summary page to: " + tmpPath.toString() + File.separator); - ImmutableList r = ImmutableList.of( - new Result(ResType.Pass, (WebDriver) null, "OK", "http://nonexistant", "test rule 1", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 1", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 3", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 4", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 5", "a desc or test rule 1", "problem!"), - new Result(ResType.Pass, (WebDriver) null, "OK", "http://foo.com", "test rule 1", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://foo.com", "test rule 5", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://foo.com", "test rule 2", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), // multiple fails for same url+rule combo - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), - new Result(ResType.Error, (WebDriver) null, "ERROR", "http://nonexistant", "test rule 2", "a desc or test rule 1", "problem!")); - Reporter kermit = new Reporter(r); - kermit.writeReportsToDir(tmpPath.toString()); - assertTrue("made it!", true); - } -} diff --git a/batchtools/headless/src/test/resources/crawlTest/four.html b/batchtools/headless/src/test/resources/crawlTest/four.html deleted file mode 100644 index a25405b..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/four.html +++ /dev/null @@ -1,7 +0,0 @@ - - four - - END - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one.html b/batchtools/headless/src/test/resources/crawlTest/one.html deleted file mode 100644 index d5fae55..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one.html +++ /dev/null @@ -1,12 +0,0 @@ - - one - - two - one_a - one_b - one_c - one_d - one_e - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one_a.html b/batchtools/headless/src/test/resources/crawlTest/one_a.html deleted file mode 100644 index 3dd01ae..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one_a.html +++ /dev/null @@ -1,6 +0,0 @@ - - one_a - - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one_b.html b/batchtools/headless/src/test/resources/crawlTest/one_b.html deleted file mode 100644 index dbbf635..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one_b.html +++ /dev/null @@ -1,6 +0,0 @@ - - one_b - - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one_c.html b/batchtools/headless/src/test/resources/crawlTest/one_c.html deleted file mode 100644 index f1ef9bc..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one_c.html +++ /dev/null @@ -1,6 +0,0 @@ - - one_c - - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one_d.html b/batchtools/headless/src/test/resources/crawlTest/one_d.html deleted file mode 100644 index 2bfb0fd..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one_d.html +++ /dev/null @@ -1,6 +0,0 @@ - - one_d - - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/one_e.html b/batchtools/headless/src/test/resources/crawlTest/one_e.html deleted file mode 100644 index 3016b17..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/one_e.html +++ /dev/null @@ -1,6 +0,0 @@ - - one_e - - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/three.html b/batchtools/headless/src/test/resources/crawlTest/three.html deleted file mode 100644 index a6f1c32..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/three.html +++ /dev/null @@ -1,7 +0,0 @@ - - three - - four - - - diff --git a/batchtools/headless/src/test/resources/crawlTest/two.html b/batchtools/headless/src/test/resources/crawlTest/two.html deleted file mode 100644 index 9fe3c68..0000000 --- a/batchtools/headless/src/test/resources/crawlTest/two.html +++ /dev/null @@ -1,7 +0,0 @@ - - two - - three - - - diff --git a/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json b/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json deleted file mode 100644 index a01bc68..0000000 --- a/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "name": "emptyRuleSet" -, "description": "" -, "rules": [] -} diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json b/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json deleted file mode 100644 index e6c4c3b..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json +++ /dev/null @@ -1,4 +0,0 @@ -[{ - 'url': 'http://localhost:8000', - 'ruleSet': '../ruleSets/emptyRuleSet.json' -}] diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json b/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json deleted file mode 100644 index 07aaab8..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json +++ /dev/null @@ -1,4 +0,0 @@ -[{ - 'url': 'http://www.cnn.com', - 'ruleSet': '../ruleSets/headingGuidelines.json' -}] diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json b/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json deleted file mode 100644 index 5e1e5e6..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - 'rulePath' : '/Users/bjones/galois/FiveUI/exampleData/ruleSets', - 'crawlType' : 'none', - 'runs': [ - { 'url': 'http://corp.galois.com', 'ruleSet': 'colorRulesRF.json' }, - { 'url': 'http://corp.galois.com', 'ruleSet': 'fontRules.json' }, - { 'url': 'http://corp.galois.com', 'ruleSet': 'headingGuidelines.json' }, - { 'url': 'http://corp.galois.com', 'ruleSet': 'imageRules.json' } - ] -} diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json b/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json deleted file mode 100644 index 2b3a51a..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json +++ /dev/null @@ -1,4 +0,0 @@ -[{ - 'url': 'http://testhost', - 'ruleSet': '../ruleSets/emptyRuleSet.json' -}] diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json b/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json deleted file mode 100644 index 4b33419..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json +++ /dev/null @@ -1,8 +0,0 @@ -[{ - 'url': 'http://testhost', -<<<<<<< HEAD - 'ruleSet': '../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json' -======= - 'ruleSet': '../ruleSets/headingGuidelines.json' ->>>>>>> ea59a5c829886959b30b2abdfe0a8308993795fd -}] diff --git a/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json b/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json deleted file mode 100644 index 3c348f7..0000000 --- a/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json +++ /dev/null @@ -1,13 +0,0 @@ -[ -{ - 'url': 'http://testhost1', - 'ruleSet': '../ruleSets/emptyRuleSet.json' -}, -{ - 'url': 'http://testhost2', -<<<<<<< HEAD - 'ruleSet': '../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json' -======= - 'ruleSet': '../ruleSets/headingGuidelines.json' ->>>>>>> ea59a5c829886959b30b2abdfe0a8308993795fd -}] diff --git a/batchtools/headless/test.html b/batchtools/headless/test.html deleted file mode 100644 index e69de29..0000000 diff --git a/batchtools/pom.xml b/batchtools/pom.xml deleted file mode 100644 index 548cc0f..0000000 --- a/batchtools/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - 4.0.0 - com.galois.fiveui - BatchTools - 1.0 - pom - - - webdrivers - rsTester - headless - - - diff --git a/batchtools/rsTester/.buildpath b/batchtools/rsTester/.buildpath deleted file mode 100644 index 24e3b93..0000000 --- a/batchtools/rsTester/.buildpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/batchtools/rsTester/.classpath b/batchtools/rsTester/.classpath deleted file mode 100644 index 9fc2de7..0000000 --- a/batchtools/rsTester/.classpath +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/batchtools/rsTester/.gitignore b/batchtools/rsTester/.gitignore deleted file mode 100644 index 7e7291c..0000000 --- a/batchtools/rsTester/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -doc diff --git a/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs b/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs deleted file mode 100644 index 6e8a644..0000000 --- a/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -initialized_project_from_v4classpath=true diff --git a/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs b/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index abec6ca..0000000 --- a/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs b/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs b/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 0512605..0000000 --- a/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Tue Jan 10 18:30:41 PST 2012 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/batchtools/rsTester/pom.xml b/batchtools/rsTester/pom.xml deleted file mode 100644 index b3d637f..0000000 --- a/batchtools/rsTester/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - 4.0.0 - com.galois.fiveui - RuleSetTester - 1.0 - - - - onejar-maven-plugin.googlecode.com - http://onejar-maven-plugin.googlecode.com/svn/mavenrepo - - - - - - - - maven-assembly-plugin - - - - com.galois.fiveui.RuleSetTester - - - - jar-with-dependencies - - - - - org.dstovall - onejar-maven-plugin - 1.3.0 - - - - com.galois.fiveui.RuleSetTester - - - one-jar - - - - - - - - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.4.0-SNAPSHOT - - - - - - - org.seleniumhq.selenium - selenium-java - 2.25.0 - - - com.google.guava - guava - 10.0.1 - - - com.google.code.gson - gson - 2.1 - - - com.galois.fiveui - webdrivers - 0.0.1-SNAPSHOT - - - - - junit - junit - 4.11 - test - - - diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java deleted file mode 100644 index e065128..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Module : BatchRunner.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebDriver; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.Lists; - -/** - * BatchRunner is initialized with a WebDriver object. It provides an interface - * for running {@code RuleSet}s and {@code RuleTest}s with the WebDriver. - * - * @see #runTest - * @see #runRule - * @author creswick - */ -public class BatchRunner { - - private final WebDriver _driver; - private final JavascriptExecutor _exe; - - // Relative to the batch directory. - private static final String DATA_DIR = "../contexts/data/"; - private static final String J_QUERY_JS = DATA_DIR - + "lib/jquery/jquery-1.7.1.min.js"; - private static final String PRELUDE_JS = DATA_DIR - + "fiveui/injected/prelude.js"; - private static final String MD5_JS = DATA_DIR - + "lib/jshash/md5.js"; - private static final String JQUERY_PLUGIN_JS = DATA_DIR - + "fiveui/injected/jquery-plugins.js"; - private static final String SEL_INJECTED_COMPUTE_JS = DATA_DIR + - "/fiveui/selenium/selenium-injected-compute.js"; - - private static final String INJECTED_COMPUTE_JS = DATA_DIR + - "/fiveui/injected/fiveui-injected-compute.js"; - - /** - * BatchRunner constructor, stores the given WebDriver. - * - * @param driver the WebDriver object to run tests with - */ - public BatchRunner(WebDriver driver) { - _driver = driver; - _exe = (JavascriptExecutor) _driver; - } - - /** - * Run a collection of RuleTests and return the concatenated results. - * - * @param tests a list of RuleTest objects - * @return a list of Result objects - * @see #runTest - */ - public ImmutableList runTests(ImmutableList tests) { - Builder resBuilder = ImmutableList.builder(); - for (RuleTest test : tests) { - resBuilder.addAll(runTest(test)); - } - return resBuilder.build(); - } - - /** - * Run a RuleTest, returning the result (success, failure details, or - * indicator of exceptional conditions.) - *

- * The test URI is loaded using the WebDriver and the rule set contained in - * {@code test} is run. - *

- * For each result, look in the oracle collection for a corresponding ResType - * (exception, pass, error, ...). If one is found, remove it from the oracle - * and report that we got an expected result. If one is not found, report that - * we got an unexpected result. - *

- * Finally, for each ResType left over in the oracle, report that we missed - * an expected result. - *

- * Note: This method catches all exceptions generated during the rule run and - * reports them as "exception" ResType results in its return value. - * - * @param test a RuleTest to run - */ - public ImmutableList runTest(final RuleTest test) { - Rule rule = test.getRule(); - - ImmutableList rawResults; - Builder builder = ImmutableList.builder(); - try { - loadURL(test.getUri().toString()); // set state of the WebDriver - rawResults = runRule(rule); // run the ruleset, collect results - - List oracle = Lists.newArrayList(test.getOracle()); - for (Result result : rawResults) { - Result res; - if ( oracle.remove(result.getType()) ) { - res = Result.pass(_driver, - test.getRuleName() + ": Got expected result: "+result.getType()); - } else { - res = Result.error(_driver, - test.getRuleName() + ": Unexpected result: "+result); - } - builder.add(res); - } - for (ResType o : oracle) { - Result res = Result.error(_driver, - test.getRuleName() + ": missing expected result: "+o); - builder.add(res); - } - } catch (Exception e) { - String errStr = "Could not run rule: " + rule.getName() + "\n"; - errStr += e.toString(); - rawResults = ImmutableList.of( - Result.exception(_driver, "Could not run rule: "+errStr)); - - e.printStackTrace(); - } - - return builder.build(); - } - - /** - * Run a rule set on a page. - *

- * This method uses the web driver instance to run a rule set on the currently - * loaded page. The webdriver injects javascript that - * includes all the dependencies (JQuery, etc..) as well as the function which - * executes the rule check. The method sleeps the thread for 1 second and - * queries the results, which are then parsed and returned as a list of - * Result objects. - * - * @param rule the rule to be run - * @return results of running the rule set - * @throws IOException - */ - private ImmutableList runRule(final Rule rule) throws IOException { - String contentScript = wrapRule(rule); - Builder builder = ImmutableList.builder(); - - _exe.executeScript(contentScript); - - try { - Thread.sleep(1000); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - - Object res = _exe.executeScript("return fiveui.selPort.query(type='ReportProblem')"); - - if (res.getClass() == String.class) { - // we received an error via the expected mechanisms: - System.err.println("Exception running rule: " + res); - builder.add(Result.exception(_driver, (String) res)); - return builder.build(); - } else { - - try { - @SuppressWarnings({ "unchecked", "rawtypes" }) - List>> results = (List) res; - - if (0 == results.size()) { - builder.add(Result.pass(_driver, "passed")); - } - - for (Map> r : results) { - Map problem = r.get("payload"); - - builder.add(Result.error(_driver, problem.get("descr"))); - } - - } catch (ClassCastException e) { - // An unexpected error happened: - builder.add(Result.exception(_driver, "Unexpected object returned: " - + res)); - e.printStackTrace(); - } - } - return builder.build(); - } - - /** - * Build up the complete content script needed to run the rule. - *

- * The string returned contains all the javascript dependencies required - * to run a rule set and the function that is injected into the page which - * executes the rule set. - * - * @param rule a Rule object - * @throws IOException - */ - private String wrapRule(Rule rule) throws IOException { - String injected = ""; - injected += Utils.readFile(SEL_INJECTED_COMPUTE_JS); - injected += Utils.readFile(J_QUERY_JS); - injected += Utils.readFile(PRELUDE_JS); - injected += Utils.readFile(MD5_JS); - injected += Utils.readFile(JQUERY_PLUGIN_JS); - injected += Utils.readFile(INJECTED_COMPUTE_JS); - - injected += "return fiveui.selPort.send('SetRules', " + rule + ");"; - - return injected; - } - - /** - * Sets the state of the WebDriver by loading a given URL. - * - * @param url URL to load - */ - private void loadURL(String url) { - _driver.get(url); - } - -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java deleted file mode 100644 index 8341c6f..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.galois.fiveui; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.Type; -import java.net.URI; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.Lists; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -/** - * RSTestDescriptions represent a set of tests for a specific RuleSet. - * - * RSTestDescriptions are also JSON-serializiable (and deserializable). - * - * An example of the JSON is given below: - * - *

- * {@code
- * { 'ruleSet': '../../exampleData/ruleSets/headingGuidelines.json',
- *   'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html',
- *                'oracle': [ { 'ruleName': "Headings are capitalized"
- *                            , 'results': ['Error', 'Error']
- *                            },
- *                            { 'ruleName': "Disallow Empty Headers"
- *                            , 'results': ['Error']
- *                            }
- *                          ]
- *              }
- *            ]
- * }
- * }
- * 
- * - * {@code tests} is as list that may contain a number of urls and sets of - * expected Problems for the specified rule set and url combination. - * - * {@code ruleSet} is a string file path that is relative to the rule set - * description json file. - * - * @author creswick - * - */ -public class RSTestDescription { - - /** - * Parse a JSON file into a RSTestDescription - * - * @param runDescFileName The file to load. - * @return A populated RunDescription object. - * @throws FileNotFoundException if runDescFile can't be found. - */ - public static RSTestDescription parse(String runDescFileName) - throws FileNotFoundException { - - GsonBuilder gsonBuilder = new GsonBuilder(); - gsonBuilder.registerTypeAdapter(RSTestDescription.class, - new RSTestDescription.Deserializer(runDescFileName)); - Gson gson = gsonBuilder.create(); - - Reader in = new InputStreamReader(new FileInputStream(runDescFileName)); - - return gson.fromJson(in, RSTestDescription.class); - } - - public static class Deserializer implements JsonDeserializer { - - private final String _descFile; - - public Deserializer(String descFile) { - _descFile = descFile; - } - - public RSTestDescription deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { - - JsonObject obj = json.getAsJsonObject(); - - String ruleSet = obj.get("ruleSet").getAsString(); - JsonArray testArray = obj.get("tests").getAsJsonArray(); - - List tests = Lists.newArrayList(); - for (JsonElement jsonElement : testArray) { - tests.add((URIMap)context.deserialize(jsonElement, URIMap.class)); - } - - String descDir = new File(_descFile).getParent(); - if (null == descDir) { - descDir = "."; - } - - // This probably is not portable, because the ruleSet path separator - // may not match that of the file system. - // TODO if File.separator is not "/", then replace "\" with File.separator. - String rsPath = descDir + File.separator + ruleSet; - - RuleSet parsed; - try { - parsed = RuleSet.parseFile(rsPath); - } catch (IOException e) { - e.printStackTrace(); - throw new JsonParseException(e.getMessage()); - } - //RuleSet parsed = gson.fromJson(rsPath, RuleSet.class); - - return new RSTestDescription(rsPath, tests, parsed); - } - } - - /** - * The path to the selected rule set. - */ - private final String _ruleSetLoc; - - /** - * A list of urls and oracles that define tests for the specified RuleSet. - */ - private final List _tests; - - private final RuleSet _ruleSet; - - public RSTestDescription(String ruleSetLoc, List tests, RuleSet ruleSet) { - _ruleSetLoc = ruleSetLoc; - _tests = tests; - _ruleSet = ruleSet; - } - - public RuleSet getRuleSet() { - return _ruleSet; - } - - public String getRuleSetLoc() { - return _ruleSetLoc; - } - - /** - * Combines the URI in each test from the rule set test description with - * each rule that accompanies it. - *

- * The result is a list of RuleTest objects - * that each contain: a URI and rule set (to be run), a rule ID and list - * of results the we expect from the run. - * - * @return a list of RuleTest objects - * @throws IOException - */ - public ImmutableList getTests() throws IOException { - Builder builder = ImmutableList.builder(); - for (URIMap uriMap : _tests) { - for (RuleMap rMap : uriMap.getOracle()) { - builder.add( - new RuleTest(uriMap.getUrl(), getRuleSet(), rMap.getRuleName(), rMap.getResults())); - } - } - return builder.build(); - } - - public String toString() { - Gson gson = new Gson(); - return gson.toJson(this); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((_ruleSet == null) ? 0 : _ruleSet.hashCode()); - result = prime * result - + ((_ruleSetLoc == null) ? 0 : _ruleSetLoc.hashCode()); - result = prime * result + ((_tests == null) ? 0 : _tests.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RSTestDescription other = (RSTestDescription) obj; - if (_ruleSet == null) { - if (other._ruleSet != null) - return false; - } else if (!_ruleSet.equals(other._ruleSet)) - return false; - if (_ruleSetLoc == null) { - if (other._ruleSetLoc != null) - return false; - } else if (!_ruleSetLoc.equals(other._ruleSetLoc)) - return false; - if (_tests == null) { - if (other._tests != null) - return false; - } else if (!_tests.equals(other._tests)) - return false; - return true; - } - - public static class URIMap { - private URI url; - private List oracle; - - URIMap(){} - - public URIMap(URI url, List oracle) { - super(); - this.url = url; - this.oracle = oracle; - } - - public URI getUrl() { - return url; - } - - public List getOracle() { - return oracle; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((oracle == null) ? 0 : oracle.hashCode()); - result = prime * result + ((url == null) ? 0 : url.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - URIMap other = (URIMap) obj; - if (oracle == null) { - if (other.oracle != null) - return false; - } else if (!oracle.equals(other.oracle)) - return false; - if (url == null) { - if (other.url != null) - return false; - } else if (!url.equals(other.url)) - return false; - return true; - } - } - - public static class RuleMap { - private String ruleName; - private List results; - - public RuleMap(String ruleName, List results) { - super(); - this.ruleName = ruleName; - this.results = results; - } - - public String getRuleName() { - return ruleName; - } - - public List getResults() { - return results; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((results == null) ? 0 : results.hashCode()); - result = prime * result - + ((ruleName == null) ? 0 : ruleName.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RuleMap other = (RuleMap) obj; - if (results == null) { - if (other.results != null) - return false; - } else if (!results.equals(other.results)) - return false; - if (ruleName == null) { - if (other.ruleName != null) - return false; - } else if (!ruleName.equals(other.ruleName)) - return false; - return true; - } - } - -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java deleted file mode 100644 index ef14a60..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Module : ResType.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.galois.fiveui; - -/** -* Results are organized into categories as follows: -*

    -*
  1. exception: an uncaught exception occurred while running the rule set
  2. -*
  3. pass: the expected result was returned
  4. -*
  5. error: an unexpected result was returned
  6. -*
  7. warning: a warning was returned, currently this type is unused
  8. -*
-*/ -public enum ResType { - Pass, Error, Warning, Exception -} \ No newline at end of file diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java deleted file mode 100644 index 6543476..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Module : Result.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import org.openqa.selenium.WebDriver; - -/** - * A Result object encapsulates the result of running a rule set check on a URL - * with a WebDriver. Results are organized into four categories: - *
    - *
  1. exception: an uncaught exception occurred while running the rule set
  2. - *
  3. pass: the expected result was returned
  4. - *
  5. error: an unexpected result was returned
  6. - *
  7. warning: a warning was returned, currently this type is unused
  8. - *
- */ -public class Result { - - private ResType _type; - private String _msg; - private WebDriver _driver; - private String _url; - private String _ruleName; - private String _ruleDesc; - private String _prob; - - /** - * Construct a new result of one of the four types. - * - * @param type type of the result - * @param driver WebDriver that the result comes from - * @param msg any additional information from the rule runner - * @param url url - * @param ruleName rule name - * @param ruleDesc rule description - * @param prob problem description - */ - public Result(ResType type, WebDriver driver, String msg, String url, - String ruleName, String ruleDesc, String prob) { - super(); - _type = type; - _msg = msg; - _driver = driver; - _url = url; - _ruleName = ruleName; - _ruleDesc = ruleDesc; - _prob = prob; - } - - /** - * An information restricted version of the other public constructor. This - * constructor does not include URL, rule, or problem information. - */ - public Result(ResType type, WebDriver driver, String msg) { - super(); - _type = type; - _msg = msg; - _driver = driver; - _url = ""; - _ruleName = ""; - _ruleDesc = ""; - _prob = ""; - } - - /********************************************************************************** - * Factory methods: these provide easy construction of restricted Result - * types. - */ - - /** - * Result constructor, returns an "exception" type result. - * - * @param driver WebDriver the result came from - * @param res description of the result - * @return a Result object - */ - public static Result exception(WebDriver driver, String res) { - return new Result(ResType.Exception, driver, res); - } - - /** - * Result constructor, returns a "pass" type result. - * - * @param driver WebDriver the result came from - * @param res description of the result - * @return a Result object - */ - public static Result pass(WebDriver driver, String res) { - return new Result(ResType.Pass, driver, res); - } - - /** - * Result constructor, returns an "error" type result. - * - * @param driver WebDriver the result came from - * @param res description of the result - * @return a Result object - */ - public static Result error(WebDriver driver, String res) { - return new Result(ResType.Error, driver, res); - } - - /** - * Result constructor, returns a "warning" type result. - * - * @param driver WebDriver the result came from - * @param res description of the result - * @return a Result object - */ - public static Result warning(WebDriver driver, String res) { - return new Result(ResType.Warning, driver, res); - } - - /********************************************************************************** - * Extractor methods - */ - - public ResType getType() { - return _type; - } - - public String getMsg() { - return _msg; - } - - public WebDriver getDriver() { - return _driver; - } - - public String getURL() { - return _url; - } - - public String getRuleName() { - return _ruleName; - } - - public String getRuleDesc() { - return _ruleDesc; - } - - public String getProblem() { - return _prob; - } - - /** - * Stringify the result, returning the type, driver name, and - * full description. - */ - @Override - public String toString() { - return getType() + " - " + _driver.toString().split(":")[0] + ": " - + _msg + "\n" - + " |\\- " + _url + "\n" - + " |\\_ " + _ruleName + "\n" - + " |\\_ " + _ruleDesc + "\n" - + " \\_ " + _prob; - } -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java deleted file mode 100644 index 3f420cb..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Module : Rule.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.util.HashMap; - -import org.openqa.selenium.htmlunit.HtmlUnitDriver; - -import com.google.gson.Gson; - -public class Rule { - - /** - * Parse a string representation of a Rule into a Java POJO. - * - * @param str string representing a rule set - * @return a RuleSet object - */ - @SuppressWarnings("unchecked") - public static final Rule parse(String str) { - HtmlUnitDriver driver = new HtmlUnitDriver(true); - String name = ""; - String desc = ""; - String ruleStr = ""; - HashMap res = null; - String stmt = "exports = {};\n"+str + "; return exports;"; - try { - driver.get("http://localhost:8000/test.html"); - res = (HashMap) driver.executeScript(stmt); - name = (String) res.get("name"); - desc = (String) res.get("description"); - ruleStr = res.get("rule").toString(); - } finally { - driver.quit(); - } - - return new Rule(name, desc, ruleStr); - } - - private final String _name; - private final String _desc; - private final String _rule; - - public Rule(final String name, final String desc, final String rule) { - this._name = name; - this._desc = desc; - this._rule = rule; - } - - public String getName() { - return _name; - } - - public String getDescription() { - return _desc; - } - - public String getRule() { - return _rule; - } - - @Override - public String toString() { - Gson gson = new Gson(); - - return "exports.name = " + gson.toJson(getName()) + ";\n" + - "exports.description = " + gson.toJson(getDescription()) + ";\n" + - "exports.rule = " + gson.toJson(getRule()) + ";\n"; - } - - /** - * Equals and hashCode ignore the rule function text when performing comparisons. - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((_desc == null) ? 0 : _desc.hashCode()); - result = prime * result + ((_name == null) ? 0 : _name.hashCode()); - return result; - } - - /** - * Equals and hashCode ignore the rule function text when performing comparisons. - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Rule other = (Rule) obj; - if (_desc == null) { - if (other._desc != null) - return false; - } else if (!_desc.equals(other._desc)) - return false; - if (_name == null) { - if (other._name != null) - return false; - } else if (!_name.equals(other._name)) - return false; - return true; - } -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java deleted file mode 100644 index ed9bc99..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Module : RuleSet.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -import com.google.common.collect.ImmutableCollection; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; - -public class RuleSet { - - public static RuleSet parseFile(String rsFileName) throws JsonSyntaxException, IOException { - String descDir = new File(rsFileName).getParent(); - - Gson gson = new Gson(); - RuleSet rs = gson.fromJson(Utils.readFile(rsFileName), RuleSet.class); - - rs.setDirectory(descDir); - return rs; - } - - public void setDirectory(String descDir) { - this.descDir = descDir; - } - - private final String name; - private final String description; - private final List rules; - - private transient ImmutableMap _evaledRules = null; - - private transient String descDir = "."; - - public RuleSet(String name, String description, List ruleFiles) { - this.name = name; - this.description = description; - this.rules = ruleFiles; - } - - private void parseRules() { - ImmutableMap.Builder builder = ImmutableMap.builder(); - - // Parse all the rules from files: - for (String r : rules) { - String adjustedPath = descDir + File.separator + r; - try { - Rule evRule = Rule.parse( - Utils.readFile(adjustedPath)); - - builder.put(evRule.getName(), evRule); - } catch (IOException e) { - System.err.println("Could not load rule from file: "+adjustedPath); - System.err.println(" error: "+e); - } - } - - _evaledRules = builder.build(); - } - - /** - * Construct a new empty rule set. - * - * @return a new empty RuleSet object - */ - public static RuleSet empty() { - List rules = Lists.newArrayList(); - return new RuleSet("", "", ImmutableList.copyOf(rules)); - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public ImmutableCollection getRules() { - if (null == _evaledRules) { - parseRules(); - } - - return _evaledRules.values(); - } - - public Rule getRule(String ruleName) { - return _evaledRules.get(ruleName); - } - - @Override - public String toString() { - Gson gson = new Gson(); - return gson.toJson(this); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((description == null) ? 0 : description.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((rules == null) ? 0 : rules.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RuleSet other = (RuleSet) obj; - if (description == null) { - if (other.description != null) - return false; - } else if (!description.equals(other.description)) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (rules == null) { - if (other.rules != null) - return false; - } else if (!rules.equals(other.rules)) - return false; - return true; - } -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java deleted file mode 100644 index 3c85b22..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Module : BatchExecutor.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.IOException; -import java.net.URISyntaxException; - -import org.openqa.selenium.WebDriver; - -import com.galois.fiveui.drivers.Drivers; -import com.google.common.collect.ImmutableList; - -/** - * The main entry point for testing Rule Sets. - *

- * The {@link #main(String[])} method of this class sets up a WebDriver, loads - * a test run description from disk, and executes the test run which includes - * loading URL's and running rule sets on their content. - * - * @author creswick - * - */ -public class RuleSetTester { - - /** - * @param args - * @throws IOException - * @throws URISyntaxException - */ - public static void main(final String[] args) throws IOException, - URISyntaxException { - - if (0 == args.length) { - printHelp(); - System.exit(1); - } - - for (int i = 0; i < args.length; i++) { - String runDescFileName = args[i]; - RSTestDescription descr = RSTestDescription.parse(runDescFileName); - - for (WebDriver driver : getDrivers()) { - try { - ImmutableList results = invokeTest(descr, driver); - - for (Result result : results) { - System.out.println(result); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - driver.quit(); - } - } - } - } - - private static ImmutableList getDrivers() { - return ImmutableList.of( - Drivers.buildFFDriver() - // , Drivers.buildChromeDriver() - ); - } - - private static void printHelp() { - System.out.println( - "Usage: RuleSetTester []"); - } - - private static ImmutableList invokeTest(RSTestDescription descr, - WebDriver driver) throws IOException { - BatchRunner runner = new BatchRunner(driver); - - return runner.runTests(descr.getTests()); - } -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java deleted file mode 100644 index acf6743..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Module : RuleTest.java - * Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : - * Stability : Provisional - * Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.galois.fiveui; - -import java.net.URI; -import java.util.Collection; - -import com.google.common.collect.ImmutableMultiset; - -/** - * A RuleTest object encapsulates the following data: - *

    - *
  1. a URI on which to run rules, accessed using {@code getUri}
  2. - *
  3. a RuleSet object encapsulating the rule to run on the URI
  4. - *
  5. a rule ID, signifying we expect results for the corresponding rule - * (defined in the rule set) of the type(s) given in the oracle
  6. - *
  7. an oracle, the expected results of the test
  8. - *
- * - * @author creswick - * - */ -public class RuleTest { - - private final URI _uri; - private final RuleSet _ruleSet; - private final String _ruleName; - private final ImmutableMultiset _oracle; - - public RuleTest(URI uri, RuleSet ruleSet, String ruleName, Collection oracle) { - _uri = uri; - _ruleSet = ruleSet; - _ruleName = ruleName; - _oracle = ImmutableMultiset.copyOf(oracle); - } - - public Rule getRule() { - return _ruleSet.getRule(_ruleName); - } - - public URI getUri() { - return _uri; - } - - public RuleSet getRuelSet() { - return _ruleSet; - } - - public String getRuleName() { - return _ruleName; - } - - public ImmutableMultiset getOracle() { - return _oracle; - } - - -} diff --git a/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java b/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java deleted file mode 100644 index 429997f..0000000 --- a/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Module : Utils.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import com.google.common.io.CharStreams; - -/** - * Provides helper functions for reading files from disk. - * - * @author creswick - */ -public class Utils { - - public static String readFile(String fileName) throws IOException { - InputStream in = new FileInputStream(new File(fileName)); - return readStream(in); - } - - public static String readStream(final InputStream stream) - throws IOException { - return CharStreams.toString(new InputStreamReader(stream)); - } -} diff --git a/batchtools/rsTester/src/main/resources/javascript/ruleEval.js b/batchtools/rsTester/src/main/resources/javascript/ruleEval.js deleted file mode 100644 index 04e81ba..0000000 --- a/batchtools/rsTester/src/main/resources/javascript/ruleEval.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Module : ruleEval.js - * Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : - * Stability : Provisional - * Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* Evaluate a rule. - * - * @param {!string} ruleStr The string representation of the rule (as - * a JavaScript Object literal). - * @return {?Array} Empty if no problems were found or a string - * with an error if an exception occurred. - */ -var evaluate = function(ruleName, description, ruleStr) { - var theRule = null; - var results = []; - -// return [{ 'name': 'some rule', -// 'descr': 'some description', -// 'url': 'http:\/\/localhost:8000', -// 'severity': '1' -// }]; -//}; - - var report = function(name, node) { - var prob = { - 'name': name, - 'descr': description, - 'url': window.location.href, - 'severity': 1 - }; - - results.push(prob); - }; - - try { - eval('var theRule = '+ruleStr); - return theRule.toString(); - } catch (x) { -// console.log('could not load rule: '+ruleStr); -// console.log(x); - return "Error: "+x; - } - - var scope = { - name : ruleName, - description : description - }; - - if (theRule) { - try { - theRule.apply(scope); - } catch (x) { -// console.log('exception running rule: '+theRule.name); -// console.log(x); - return "Error: "+x; - } - } - return results; -}; diff --git a/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver b/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver deleted file mode 100755 index b0a0e4a..0000000 Binary files a/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver and /dev/null differ diff --git a/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java b/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java deleted file mode 100644 index 5db53f8..0000000 --- a/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - * Copyright (c) 2009-2013, - * - * Galois, Inc. (creswick) - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The names of the contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - */ -package com.galois.fiveui; - -import java.util.Collection; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import com.google.common.collect.Lists; - -/** - * @author creswick - * - */ -@RunWith(Parameterized.class) -public class BasicRuleSetParseTest { - - /** - * Set up the tests via the parameterized runner: - * - * @return - * @throws Throwable - */ - @Parameters(name = "{0} {1}") - public static Collection setup() throws Throwable { - List tests = Lists.newArrayList(); - - Object[][] rawTests = new Object[][] { - { "ruleSets/emptyRuleSet.json", true }, - { "ruleSets/simpleRuleSet1.json", true }, - { "ruleSets/headingGuidelines.json", true }, - }; - - for (Object[] descr : rawTests) { - tests.add(descr); - } - - return tests; - } - - /** - * The path (relative to test resources) to the file to test. - */ - private final String _filePath; - - private final boolean _parses; - - public BasicRuleSetParseTest(String path, boolean parses) { - this._filePath = path; - this._parses = parses; - } - - /** - * Try and parse the file, no oracle other than the expected success/fail. - * - * @throws Exception - */ - @Test - public void testParse() throws Exception{ - boolean actual = false; - String msg = ""; - try { - RuleSet desc = RuleSet.parseFile("src/test/resources/"+_filePath); - // if desc is not null, we assume the parse worked: - actual = (desc != null); - } catch (Exception e) { - // if an exception was thrown, then we assume the parse failed: - msg = e.getMessage(); - actual = false; - } finally { - // test to see if the parse result matched the expectation. - Assert.assertEquals("Parse did not complete as expected: "+msg, - _parses, actual); - } - } -} diff --git a/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java b/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java deleted file mode 100644 index 57cf772..0000000 --- a/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * - * Copyright (c) 2009-2013, - * - * Galois, Inc. (creswick) - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The names of the contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - */ -package com.galois.fiveui; - -import java.util.Collection; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import com.google.common.collect.Lists; - -/** - * @author creswick - * - */ -@RunWith(Parameterized.class) -public class BasicRunDescriptionParseTest { - - /** - * Set up the tests via the parameterized runner: - * - * @return - * @throws Throwable - */ - @Parameters(name = "{0} {1}") - public static Collection setup() throws Throwable { - List tests = Lists.newArrayList(); - - Object[][] rawTests = new Object[][] { - { "runDescriptions/sample0.json", true }, - { "runDescriptions/sample1.json", true }, - { "runDescriptions/sample2.json", true }, - - // This should test that tests must have run ids, - // but that can't be enforced with gson's standard deserializers. - // { "runDescriptions/sample2-fails.json", false }, - - { "runDescriptions/sample3.json", true }, - { "runDescriptions/sample4.json", true }, - { "runDescriptions/sample5.json", true }, - { "runDescriptions/headingSample.json", true }, - { "runDescriptions/headingSample-1-fails.json", true }, - { "runDescriptions/headingSample-2-fails.json", true }, - }; - - for (Object[] descr : rawTests) { - tests.add(descr); - } - - return tests; - } - - /** - * The path (relative to test resources) to the file to test. - */ - private final String _filePath; - - private final boolean _parses; - - public BasicRunDescriptionParseTest(String path, boolean parses) { - this._filePath = path; - this._parses = parses; - } - - /** - * Try and parse the file, no oracle other than the expected success/fail. - * - * @throws Exception - */ - @Test - public void testParse() throws Exception{ - boolean actual = false; - String msg = ""; - try { - RSTestDescription desc = RSTestDescription.parse("src/test/resources/"+_filePath); - // if desc is not null, we assume the parse worked: - actual = (desc != null); - } catch (Exception e) { - // if an exception was thrown, then we assume the parse failed: - msg = e.getMessage(); - actual = false; - } finally { - // test to see if the parse result matched the expectation. - Assert.assertEquals("Parse did not complete as expected: "+msg, - _parses, actual); - } - } -} diff --git a/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java b/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java deleted file mode 100644 index 0d5d4c4..0000000 --- a/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * RunDescriptionTest.java - * - * Copyright (c) 2012 Galois, Inc. - */ -package com.galois.fiveui; - -import java.io.FileNotFoundException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; - -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; - -/** - * @author creswick - * - */ -public class RunDescriptionTest { - - private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; - - /** - * Test method for {@link com.galois.fiveui.RSTestDescription}. - * @throws FileNotFoundException - */ - @Test - public final void testDeserialize_sample0() throws FileNotFoundException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "sample0.json"; - String ruleSetLoc = - RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; - - ImmutableList emptyRuleList = ImmutableList.of(); - RuleSet rsOracle = new RuleSet("emptyRuleSet", "", emptyRuleList); - - RSTestDescription oracle = - new RSTestDescription(ruleSetLoc, - new ArrayList(), rsOracle); - - - RSTestDescription actual = RSTestDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - - /** - * Test method for {@link com.galois.fiveui.RSTestDescription}. - * @throws FileNotFoundException - */ - @Test - public final void testDeserialize_sample1() throws FileNotFoundException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "sample1.json"; - String ruleSetLoc = - RUN_DESCRIPTION_DIR + "../ruleSets/simpleRuleSet1.json"; - - RuleSet rsOracle = - new RuleSet("simpleRuleSet1", "", ImmutableList.of("emptyCheck.js")); - rsOracle.setDirectory(RUN_DESCRIPTION_DIR + "../ruleSets/"); - - RSTestDescription oracle = - new RSTestDescription(ruleSetLoc, - new ArrayList(), rsOracle); - - - RSTestDescription actual = RSTestDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - - /** - * Test method for {@link com.galois.fiveui.RSTestDescription}. - * @throws FileNotFoundException - * @throws URISyntaxException - */ - @Test - public final void testDeserialize_headingGuidelines() throws FileNotFoundException, URISyntaxException { - - String jsonFileName = RUN_DESCRIPTION_DIR + "headingSample.json"; - String ruleSetLoc = - RUN_DESCRIPTION_DIR + "../ruleSets/headingGuidelines.json"; - - RuleSet rsOracle = new RuleSet( - "Heading Guidelines", - "Guidelines pertaining to the formatting and content of headings.", - ImmutableList.of("headingGuidelines-caps.js", - "headingGuidelines-noEmptyHdrs.js")); - rsOracle.setDirectory(RUN_DESCRIPTION_DIR + "../ruleSets/"); - rsOracle.getRules(); // force the rules to parse - - RSTestDescription.URIMap uriMapOracle = - new RSTestDescription.URIMap( - new URI("http://localhost:8000/exampleData/basic/headings.html"), - - Lists.newArrayList( - new RSTestDescription.RuleMap("Headings are capitalized", - Lists.newArrayList(ResType.Error, ResType.Error)), - new RSTestDescription.RuleMap("Disallow Empty Headers", - Lists.newArrayList(ResType.Error)))); - - - RSTestDescription oracle = - new RSTestDescription(ruleSetLoc, Lists.newArrayList(uriMapOracle), rsOracle); - - - RSTestDescription actual = RSTestDescription.parse(jsonFileName); - assertObjEqual("Object deserialized incorrectly.", oracle, actual); - } - private void assertObjEqual(String msg, Object oracle, Object actual) { - Assert.assertTrue(msg + "; expected: "+oracle+" actual: "+actual, - oracle.equals(actual)); - } - - -} diff --git a/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js b/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js deleted file mode 100644 index 6588e5b..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js +++ /dev/null @@ -1,6 +0,0 @@ -exports.name = 'Empty Rule'; - -exports.description = 'A rule with no body, used for testing.'; - -exports.rule = function() { }; - diff --git a/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json b/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json deleted file mode 100644 index a01bc68..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "name": "emptyRuleSet" -, "description": "" -, "rules": [] -} diff --git a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js b/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js deleted file mode 100644 index f6c1cb6..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js +++ /dev/null @@ -1,19 +0,0 @@ -exports.name = "Headings are capitalized"; - -exports.description = "Check to see if all headings use leading capital letters."; - -exports.rule = function() { - var badHeadings = - fiveui.query(':header').filter( - function(idx) { - var ch = $(this).text()[0]; - if (ch) { - return (ch == ch.toLowerCase() ); - } else { - return false; - } - }); - $(badHeadings).map(function(idx, elt){ - report('Heading does not start with a capitol letter.', elt); - }); -}; diff --git a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js b/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js deleted file mode 100644 index a70f71c..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js +++ /dev/null @@ -1,12 +0,0 @@ -exports.name = "Disallow Empty Headers"; - -exports.description = "Heading elements should contain text."; - -exports.rule = function() { - fiveui.query(':header').each( - function(ix, elt) { - if($(elt).text() == '') { - report('Heading does not contain text', elt); - } - }); - }; diff --git a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json b/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json deleted file mode 100644 index 330f389..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json +++ /dev/null @@ -1,6 +0,0 @@ -{ "name": "Heading Guidelines" -, "description": "Guidelines pertaining to the formatting and content of headings." -, "rules": [ "headingGuidelines-caps.js", - "headingGuidelines-noEmptyHdrs.js" - ] -} \ No newline at end of file diff --git a/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json b/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json deleted file mode 100644 index 71905cd..0000000 --- a/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "name": "simpleRuleSet1" -, "description": "" -, "rules": [ "emptyCheck.js" ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json b/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json deleted file mode 100644 index 23860b4..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - 'ruleSet': '../ruleSets/headingGuidelines.json', - 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', - 'oracle': [ { 'ruleName': "Headings are capitalized" - , 'results': ['Error'] /* actually errors twice */ - }, - { 'ruleName': "Disallow Empty Headers" - , 'results': ['Error'] - } - ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json b/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json deleted file mode 100644 index 8a1cb38..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - 'ruleSet': '../ruleSets/headingGuidelines.json', - 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', - 'oracle': [ { 'ruleName': "Headings are capitalized" - , 'results': ['Error', 'Error', 'Error'] /* actually only errors twice */ - }, - { 'ruleName': "Disallow Empty Headers" - , 'results': ['Error'] - } - ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json b/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json deleted file mode 100644 index 69deb49..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - 'ruleSet': '../ruleSets/headingGuidelines.json', - 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', - 'oracle': [ { 'ruleName': "Headings are capitalized" - , 'results': ['Error', 'Error'] - }, - { 'ruleName': "Disallow Empty Headers" - , 'results': ['Error'] - } - ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json deleted file mode 100644 index 0c2bbb7..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - 'ruleSet': '../ruleSets/emptyRuleSet.json', - 'tests': [] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json deleted file mode 100644 index 91f8f34..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json deleted file mode 100644 index a8ea9ec..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [ { 'url': 'http://localhost:8000/', - 'oracle': [ { 'ruleId': 42 - , 'results': ['Error', 'Error'] - } - ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json deleted file mode 100644 index acff2d7..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [ { 'url': 'http://localhost:8000/', - 'oracle': [ { 'ruleName': 'Empty Rule' - , 'results': [] - } - ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json deleted file mode 100644 index e4d1cea..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [ { 'url': 'http://localhost:8000/', - 'oracle': [ ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json deleted file mode 100644 index c4f46cd..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [ { 'url': 'http://localhost:8000/', - 'oracle': [ ] - }, - { 'url': 'http://localhost:8000/', - 'oracle': [ ] - } - ] -} diff --git a/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json b/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json deleted file mode 100644 index 11ca957..0000000 --- a/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - 'ruleSet': '../ruleSets/simpleRuleSet1.json', - 'tests': [ { 'url': 'http://localhost:8000/', - 'oracle': [ { 'ruleId': 42 - , 'results': ['Error'] - } - ] - }, - { 'url': 'http://localhost:8000/', - 'oracle': [ ] - } - ] -} diff --git a/batchtools/rsTester/test.html b/batchtools/rsTester/test.html deleted file mode 100644 index e69de29..0000000 diff --git a/batchtools/webdrivers/.classpath b/batchtools/webdrivers/.classpath deleted file mode 100644 index 75e85b7..0000000 --- a/batchtools/webdrivers/.classpath +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/batchtools/webdrivers/.gitignore b/batchtools/webdrivers/.gitignore deleted file mode 100644 index eb5a316..0000000 --- a/batchtools/webdrivers/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs b/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index abec6ca..0000000 --- a/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs b/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/batchtools/webdrivers/pom.xml b/batchtools/webdrivers/pom.xml deleted file mode 100644 index 4d8847f..0000000 --- a/batchtools/webdrivers/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - 4.0.0 - com.galois.fiveui - webdrivers - 0.0.1-SNAPSHOT - Web Drivers - Wrapper around Selenium Web Driver creation to handle configuration details that we wish to be uniform across all FiveUI applications. - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.5 - 1.5 - - - - - - - - junit - junit - 4.9 - test - - - - org.seleniumhq.selenium - selenium-java - 2.25.0 - - - - com.google.guava - guava - 10.0.1 - - - diff --git a/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java b/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java deleted file mode 100644 index d4bf40b..0000000 --- a/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Module : Drivers.java Copyright : (c) 2011-2012, Galois, Inc. - * - * Maintainer : Stability : Provisional Portability: Portable - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.galois.fiveui.drivers; - -import java.io.File; -import java.io.IOException; - -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.firefox.FirefoxBinary; -import org.openqa.selenium.firefox.FirefoxDriver; -import org.openqa.selenium.firefox.FirefoxProfile; - -/** - * @author creswick - * - */ -public class Drivers { - private static final String FIREFOX_BIN_PATH = "FIREFOX_BIN_PATH"; - private static final String CHROME_BIN_PATH = "CHROME_BIN_PATH"; - - private static final String CD_BINARY_NAME = "chromedriver"; - private static final String CD_BASE_PATH = mkPath("..", "tools", - "seleniumChromeDrivers"); - - private static final String FIVEUI_ROOT_PATH = "FIVEUI_ROOT_PATH"; - private static final String defaultFiveuiRootPath = "../../"; - private static final String firefoxProfilePath = "profiles/firefox"; - private static final String chromeProfilePath = "profiles/chrome"; - private static final String firefoxExtensionPath = "binaries/fiveui.xpi"; - private static final String chromeExtensionPath = "binaries/fiveui.crx"; - - /** - * Query the OS environment for the FiveUI root path, or return a default. - */ - public static String getRootPath() { - String rootPath = System.getProperty(FIVEUI_ROOT_PATH); - return (null != rootPath) ? rootPath + File.separator : defaultFiveuiRootPath; - } - - public static FirefoxDriver buildFFDriver() { - // Extracted into a method so we can set up profiles - - String rootPath = getRootPath(); - - File profileDir = new File(rootPath+firefoxProfilePath); - 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); - - FirefoxDriver driver; - if (null == ffBinaryPath) { - System.err - .println("WARNING: Running essentially random version of FireFox!"); - System.err.println(" set a path to firefox with -D" - + FIREFOX_BIN_PATH + "="); - driver = new FirefoxDriver(profile); - } else { - FirefoxBinary binary = new FirefoxBinary(new File(ffBinaryPath)); - driver = new FirefoxDriver(binary, profile); - } - - return driver; - } - - public static ChromeDriver buildChromeDriver() { - - String rootPath = getRootPath(); - - // set the chrome driver path: - String chromeDriverPth = - mkPath(CD_BASE_PATH, osNameArch(), CD_BINARY_NAME); - System.setProperty("webdriver.chrome.driver", chromeDriverPth); - - // setting the path to chrome also seems to cause issues: - ChromeOptions options = new ChromeOptions(); - 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) { - System.err - .println("WARNING: Running essentially random version of Chrome!"); - System.err.println(" set a path to Chrome with -D" - + CHROME_BIN_PATH + "="); - } else { - options.setBinary(new File(chromeBinaryPath)); - } - // For use with ChromeDriver: - return new ChromeDriver(options); - } - - private static String mkPath(String... components) { - StringBuilder path = new StringBuilder(); - int remaining = components.length; - for (String c : components) { - path.append(c); - remaining--; - if (remaining != 0) { - path.append(File.separator); - } - } - - return path.toString(); - } - - /** - * Determine the name of the directory that the chromedriver is in, based on - * os.name and os.arch. - * - * @return The name of the directory containing 'chromedriver' - */ - private static String osNameArch() { - String rawOsName = System.getProperty("os.name").toLowerCase(); - String osName = rawOsName.substring(0, 3); - boolean is64bit = System.getProperty("os.arch").indexOf("64") >= 0; - - if (osName.equals("lin")) { - osName += is64bit ? "64" : "32"; - } - return osName; - } - -} diff --git a/src/batchtools/headless/.classpath b/src/batchtools/headless/.classpath new file mode 100644 index 0000000..beba987 --- /dev/null +++ b/src/batchtools/headless/.classpath @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/batchtools/headless/.gitignore b/src/batchtools/headless/.gitignore new file mode 100644 index 0000000..24c4165 --- /dev/null +++ b/src/batchtools/headless/.gitignore @@ -0,0 +1,2 @@ +target +programs.properties diff --git a/src/batchtools/headless/.settings/org.eclipse.core.resources.prefs b/src/batchtools/headless/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..cdfe4f1 --- /dev/null +++ b/src/batchtools/headless/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/src/batchtools/headless/.settings/org.eclipse.jdt.core.prefs b/src/batchtools/headless/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..abec6ca --- /dev/null +++ b/src/batchtools/headless/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/src/batchtools/headless/.settings/org.eclipse.m2e.core.prefs b/src/batchtools/headless/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/src/batchtools/headless/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/src/batchtools/headless/bin/runHeadless.sh b/src/batchtools/headless/bin/runHeadless.sh new file mode 100755 index 0000000..4c4d863 --- /dev/null +++ b/src/batchtools/headless/bin/runHeadless.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +export FIVEUI_ROOT_PATH=$HOME/FiveUI +export FIREFOX_BIN_PATH=/Users/bjones/myapps/Firefox_17_esr.app/Contents/MacOS/firefox + +java -DFIVEUI_ROOT_PATH=$FIVEUI_ROOT_PATH \ + -DFIREFOX_BIN_PATH=$FIREFOX_BIN_PATH \ + -jar $FIVEUI_ROOT_PATH/headless/bin/HeadlessRunner-0.0.1-SNAPSHOT.one-jar.jar \ + $* diff --git a/src/batchtools/headless/pom.xml b/src/batchtools/headless/pom.xml new file mode 100644 index 0000000..da5b348 --- /dev/null +++ b/src/batchtools/headless/pom.xml @@ -0,0 +1,121 @@ + + 4.0.0 + + com.galois.fiveui + HeadlessRunner + 0.0.1-SNAPSHOT + jar + + + + UTF-8 + + + + + onejar-maven-plugin.googlecode.com + http://onejar-maven-plugin.googlecode.com/svn/mavenrepo + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.11 + + programs.properties + + + + + maven-assembly-plugin + + + + com.galois.fiveui.HeadlessRunner + + + + jar-with-dependencies + + + + + org.dstovall + onejar-maven-plugin + 1.3.0 + + + + com.galois.fiveui.HeadlessRunner + + + one-jar + + + + + + + + + + org.seleniumhq.selenium + selenium-java + 2.26.0 + + + com.google.guava + guava + 13.0.1 + + + com.google.code.gson + gson + 2.2.2 + + + com.galois.fiveui + webdrivers + 0.0.1-SNAPSHOT + + + com.galois.fiveui + RuleSetTester + 1.0 + + + junit + junit + 4.9 + + + edu.uci.ics + crawler4j + 3.3 + + + org.apache.httpcomponents + httpclient + 4.2.1 + + + org.apache.httpcomponents + httpcore + 4.2.1 + + + commons-cli + commons-cli + 1.2 + + + com.googlecode.jatl + jatl + 0.2.2 + + + diff --git a/src/batchtools/headless/programs.properties.example b/src/batchtools/headless/programs.properties.example new file mode 100644 index 0000000..97bd0c6 --- /dev/null +++ b/src/batchtools/headless/programs.properties.example @@ -0,0 +1,2 @@ +FIREFOX_BIN_PATH=/home/creswick/myapps/firefox/firefox-17.0.2-x86_64/firefox +LOG_LEVEL=ERROR diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java new file mode 100644 index 0000000..7f64b1a --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawler.java @@ -0,0 +1,90 @@ +package com.galois.fiveui; + +import edu.uci.ics.crawler4j.crawler.Page; +import edu.uci.ics.crawler4j.crawler.WebCrawler; +import edu.uci.ics.crawler4j.parser.HtmlParseData; +import edu.uci.ics.crawler4j.url.WebURL; + +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +import com.google.common.base.Function; + +/** + * @author bjones + */ +public class BasicCrawler extends WebCrawler { + + private static Logger logger = Logger.getLogger("com.galois.fiveui.BasicCrawler"); + private final static Pattern FILTERS = Pattern.compile( + ".*(\\.(css|js|bmp|gif|jpe?g" + + "|png|tiff?|mid|mp2|mp3|mp4" + + "|wav|avi|mov|mpeg|ram|m4v|pdf" + + "|rm|smil|wmv|swf|wma|zip|rar|gz))$"); + public static Function _predicate; + public static List _urls; + + /** + * Configure static properties of the class before a crawl. + * + * @param pred URLs will be crawled only if pred.apply(URL) is + * true + * @param urls reference to a list of strings which the crawler will + * append URLs to as it works + */ + public static void configure(Function pred, List urls) { + _predicate = pred; + _urls = urls; + } + + /** + * specify whether the given url should be crawled or not + */ + @Override + public boolean shouldVisit(WebURL url) { + String href = url.getURL(); + Boolean yesno = !FILTERS.matcher(href).matches() && _predicate.apply(href); + logger.debug("saying " + (yesno ? "yes" : "no") + " to " + href); + return yesno; + } + + /** + * This function is called when a page is fetched and ready to be processed + * by the program. + */ + @Override + public void visit(Page page) { + int docid = page.getWebURL().getDocid(); + String url = page.getWebURL().getURL(); + String domain = page.getWebURL().getDomain(); + String path = page.getWebURL().getPath(); + String subDomain = page.getWebURL().getSubDomain(); + String parentUrl = page.getWebURL().getParentUrl(); + + logger.debug(" - Docid: " + docid); + logger.debug(" - URL: " + url); + logger.debug(" - Domain: '" + domain + "'"); + logger.debug(" - Sub-domain: '" + subDomain + "'"); + logger.debug(" - Path: '" + path + "'"); + logger.debug(" - Parent page: " + parentUrl); + + if (page.getParseData() instanceof HtmlParseData) { + HtmlParseData htmlParseData = (HtmlParseData) page.getParseData(); + String text = htmlParseData.getText(); + String html = htmlParseData.getHtml(); + List links = htmlParseData.getOutgoingUrls(); + + logger.debug(" -- Text length: " + text.length()); + logger.debug(" -- Html length: " + html.length()); + logger.debug(" -- Number of outgoing links: " + links.size()); + } + logger.debug(" - ============="); + + // append to URLs list + if (null != _urls) { + _urls.add(url); + } + } +} diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java new file mode 100644 index 0000000..79338ec --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/BasicCrawlerController.java @@ -0,0 +1,150 @@ +package com.galois.fiveui; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Function; + +import edu.uci.ics.crawler4j.crawler.CrawlConfig; +import edu.uci.ics.crawler4j.crawler.CrawlController; +import edu.uci.ics.crawler4j.fetcher.PageFetcher; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer; + +/** + * @author bjones + */ +public class BasicCrawlerController { + + private String seed; + private String tmpDir; + private int depth; + private int maxFetch; + private int politeness; + private int threads; + private Function predicate; + + /** + * Initialize a basic web crawler controller. + * + * @param seed URL to start the crawl + * @param domain string that all crawled page URLs must start with + * @param depth maximum depth to crawl + * @param maxFetch maximum number of pages to crawl + * @param politeness time in milliseconds to wait before making requests on same domain + * @param threads number of concurrent threads to use while crawling + * @param tmpDir temporary directory to store intermediate crawl data + * (must exist and be read/write before crawl starts) + */ + public BasicCrawlerController (String seed, final String domain, int depth, int maxFetch, + int politeness, int threads, String tmpDir) { + this.seed = seed; + this.predicate = new Function() { + public Boolean apply(String s) { + return s.startsWith(domain); + } + }; + this.depth = depth; + this.maxFetch = maxFetch; + this.politeness = politeness; + this.threads = threads; + this.tmpDir = tmpDir; + } + + /** + * Initialize a basic web crawler controller. + * + * @param seed URL to start the crawl + * @param pred a Function to be used as a predicate that all crawled URLs must pass + * @param depth maximum depth to crawl + * @param maxFetch maximum number of pages to crawl + * @param politeness time in milliseconds to wait before making requests on same domain + * @param threads number of concurrent threads to use while crawling + * @param tmpDir temporary directory to store intermediate crawl data + * (must exist and be read/write before crawl starts) + */ + public BasicCrawlerController (String seed, Function pred, int depth, int maxFetch, + int politeness, int threads, String tmpDir) { + this.seed = seed; + this.predicate = pred; + this.depth = depth; + this.maxFetch = maxFetch; + this.politeness = politeness; + this.threads = threads; + this.tmpDir = tmpDir; + } + + public List go() throws Exception { + + /* + * crawlStorageFolder is a folder where intermediate crawl data is + * stored. + */ + String crawlStorageFolder = this.tmpDir; + + /* + * numberOfCrawlers shows the number of concurrent threads that should + * be initiated for crawling. + */ + int numberOfCrawlers = this.threads; + + CrawlConfig config = new CrawlConfig(); + + config.setCrawlStorageFolder(crawlStorageFolder); + + /* + * Be polite: Make sure that we don't send more than 1 request per + * second (1000 milliseconds between requests). + */ + config.setPolitenessDelay(this.politeness); + + /* + * You can set the maximum crawl depth here. The default value is -1 for + * unlimited depth + */ + config.setMaxDepthOfCrawling(this.depth); + + /* + * You can set the maximum number of pages to crawl. The default value + * is -1 for unlimited number of pages + */ + config.setMaxPagesToFetch(this.maxFetch); + + /* + * Delete the temporary crawl storage after we're done. + */ + config.setResumableCrawling(false); + + /* + * Instantiate the controller for this crawl. + */ + PageFetcher pageFetcher = new PageFetcher(config); + RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); + //robotstxtConfig.setEnabled(false); // uncomment if you want to ignore robots.txt + RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher); + CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer); + + // add a seed URL + controller.addSeed(this.seed); + + /* + * Setup storage for data collection by the BasicCrawler class + */ + List store = new ArrayList(); + BasicCrawler.configure(this.predicate, store); + + /* + * Start the crawl. This is a blocking operation. + */ + try { + controller.start(BasicCrawler.class, numberOfCrawlers); + } finally { + controller.Shutdown(); + } + + /* + * Extract and return data collected by BasicCrawler + */ + return store; + } +} 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 new file mode 100644 index 0000000..9f3f301 --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/BatchRunner.java @@ -0,0 +1,312 @@ +/** + * Module : BatchRunner.java Copyright : (c) 2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +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 + + +/** + * BatchRunner is initialized with a WebDriver object. It provides an interface + * for running {@code RuleSet}s and {@code RuleTest}s with the WebDriver. + * + * @author bjones + */ +public class BatchRunner { + + private WebDriver _driver; + private JavascriptExecutor _exe; + private String _root; // FiveUI root directory + + // Hard coded JS files, relative to the FiveUI root directory. + private static final String DATA_DIR = "contexts/data/"; + private static final String J_QUERY_JS = DATA_DIR + + "lib/jquery/jquery.js"; + private static final String PRELUDE_JS = DATA_DIR + + "fiveui/injected/prelude.js"; + private static final String MD5_JS = DATA_DIR + + "lib/jshash/md5.js"; + private static final String JQUERY_PLUGIN_JS = DATA_DIR + + "fiveui/injected/jquery-plugins.js"; + private static final String SEL_INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/selenium/selenium-injected-compute.js"; + private static final String INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/injected/fiveui-injected-compute.js"; + + private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchRunner"); + + private void registerDriver(WebDriver driver) { + logger.debug("registering new webdriver..."); + this._driver = driver; + this._exe = (JavascriptExecutor) driver; + this._root = Drivers.getRootPath(); + logger.debug("root path for webdriver is " + _root); + } + + public BatchRunner() { + logger.debug("initializing BatchRunner ..."); + } + + /** + * Run a headless run description, returning the raw results: 'PASS' if + * no inconsistencies were found, 'ERROR' for each inconsistency found, + * 'EXCEPTION' for each uncaught exception. + *

+ * The run.getURL() is loaded using the WebDriver and the rule set returned + * by {@code run.getRule()} is run. + * + * @param run a headless run description object + */ + public ImmutableList runHeadless(HeadlessRunDescription run) { + String seedUrl; + Builder builder = ImmutableList.builder(); // for results + ImmutableList rawResults; + CrawlParameters params = new CrawlParameters(run.getCrawlType()); + int politeness = params.toString().equals("none") ? 1000 : params.politeness; + List urls; + Map>> urlCache; + //- URL, params, urls + urlCache = new HashMap>>(); + + for (HeadlessAtom a: run.getAtoms()) { + RuleSet rs = a.getRuleSet(); + seedUrl = a.getURL(); + logger.debug("setting seed URL for crawl: " + seedUrl); + urls = null; + + /************** + * Gather URLs + **************/ + + if (params.isNone()) { + urls = ImmutableList.of(seedUrl); + logger.debug("skipping webcrawl"); + } else if (urlCache.containsKey(seedUrl) && + urlCache.get(seedUrl).containsKey(params.toString())) { + logger.debug("retreiving urls list from cache"); + urls = urlCache.get(seedUrl).get(params.toString()); + } else { + File tmpPath = Files.createTempDir(); + logger.debug("tmp directory for crawl data: " + tmpPath.toString()); + logger.debug("starting webcrawl controller ..."); + BasicCrawlerController con = + new BasicCrawlerController(seedUrl, + params.matchFcn, + params.depth, params.maxFetch, + params.politeness, + 1, // TODO only one thread is currently supported + tmpPath.getAbsolutePath()); + try { + urls = con.go(); + logger.debug("adding urls list to cache"); + logger.debug("URLs: " + urls.toString()); + Map> entry = (Map>) new HashMap>(); + entry.put(params.toString(), urls); + urlCache.put(seedUrl, entry); + } catch (Exception e) { + String errStr = "failed to complete webcrawl of" + seedUrl + "\n"; + errStr += e.toString(); + builder.add(new Result(ResType.Exception, _driver, errStr, seedUrl, + rs.getName(), rs.getDescription(), "")); + logger.error(errStr); + continue; + } finally { + IO.deleteFolder(tmpPath); // does its own logging + } + } + + /*********************** + * Drive the browser(s) + ***********************/ + + for (WebDriver driver: getDrivers()) { + registerDriver(driver); + for (String url: urls) { + logger.info("loading " + url + " for ruleset run ..."); + loadURL(url); // set state of the WebDriver (blocking) + try { + logger.info("running ruleset \"" + rs.getName() + "\""); + rawResults = runRule(rs); // run the ruleset, collect results + builder.addAll(rawResults); + } catch (Exception e) { + String errStr = "exception during runRule: " + rs.getName() + "\n"; + errStr += e.toString(); + builder.add(new Result(ResType.Exception, _driver, errStr, url, + rs.getName(), rs.getDescription(), "")); + logger.error(errStr); + } + try { + logger.debug("being polite for " + politeness + " millis..."); + Thread.sleep(politeness); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + driver.quit(); + } + } + return builder.build(); + } + + /** + * Run a rule set on the currently loaded page. + *

+ * This method uses the web driver instance to run a rule set on the currently + * loaded page. The webdriver injects javascript that + * includes all the dependencies (JQuery, etc..) as well as the function which + * executes the rule check. The method sleeps the thread for 1 second and + * queries the results, which are then parsed and returned as a list of + * Result objects. + * + * @param ruleSet the rule set to be run + * @return results of running the rule set + * @throws IOException + */ + private ImmutableList runRule(final RuleSet ruleSet) throws IOException { + String contentScript = wrapRule(ruleSet); + Builder builder = ImmutableList.builder(); + String state = "url=" + _driver.getCurrentUrl() + + ", ruleSet=\"" + ruleSet.getName() + "\""; + logger.debug("runRule: " + state); + + _exe.executeScript(contentScript); + + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + logger.error(e1.toString()); + } + + Object res = _exe.executeScript("return fiveui.selPort.query(type='ReportProblem')"); + + if (res.getClass() == String.class) { + // we received an error via the expected mechanisms: + logger.error("exception running rule: " + res); + builder.add(new Result(ResType.Exception, _driver, "", _driver.getCurrentUrl(), + ruleSet.getName(), ruleSet.getDescription(), "")); + return builder.build(); + } else { + try { + @SuppressWarnings({ "unchecked", "rawtypes" }) + List>> results = (List) res; + + if (0 == results.size()) { + builder.add(new Result(ResType.Pass, _driver, + "passed " + ruleSet.getRules().size() + " tests", + _driver.getCurrentUrl(), ruleSet.getName(), ruleSet.getDescription(), "")); + } + + for (Map> r : results) { + Map problem = r.get("payload"); + // TODO decide what to extract from problem object and what + // to do with it. + // + // Probably we should just pass along the Map + // and let the reporter deal with it. + String problemAsHTML = "Rule Name: " + problem.get("name") + " / " + + "Rule Desc: " + problem.get("descr") + " / " + + "XPath: " + problem.get("xpath"); + builder.add(new Result(ResType.Error, _driver, "", + _driver.getCurrentUrl(), + ruleSet.getName(), + ruleSet.getDescription(), + problemAsHTML)); + } + + } catch (ClassCastException e) { + // An unexpected error happened: + logger.error("unexpected object returned: " + e.toString()); + builder.add(new Result(ResType.Exception, _driver, + "Unexpected object returned: " + res + ", state: " + state, + _driver.getCurrentUrl(), + ruleSet.getName(), + ruleSet.getDescription(), + "")); + } + } + return builder.build(); + } + + /** + * Build up the complete content script needed to run the rule. + *

+ * The string returned contains all the javascript dependencies required + * to run a rule set and the function that is injected into the page which + * executes the rule set. + * + * TODO DRY + * + * @param ruleSet a RuleSet object + * @throws IOException + */ + private String wrapRule(RuleSet ruleSet) throws IOException { + String injected = ""; + injected += Utils.readFile(_root + SEL_INJECTED_COMPUTE_JS); + injected += Utils.readFile(_root + J_QUERY_JS); + injected += Utils.readFile(_root + PRELUDE_JS); + injected += Utils.readFile(_root + MD5_JS); + injected += Utils.readFile(_root + JQUERY_PLUGIN_JS); + injected += Utils.readFile(_root + INJECTED_COMPUTE_JS); + + injected += "return fiveui.selPort.send('SetRules', " + ruleSet + ");"; + + return injected; + } + + /** + * Build a list of webdrivers with which to run each ruleset. + * + * @return list of initialized WebDriver objects + */ + private static ImmutableList getDrivers() { + logger.debug("building webdrivers ..."); + ImmutableList r = ImmutableList.of( + Drivers.buildFFDriver() + // , Drivers.buildChromeDriver() + ); + logger.debug("built: " + r.toString()); + return r; + } + + /** + * Sets the state of the WebDriver by loading a given URL. + * + * @param url URL to load + */ + private void loadURL(String url) { + _driver.get(url); + } +} diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java new file mode 100644 index 0000000..a07d43a --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/CrawlParameters.java @@ -0,0 +1,84 @@ +package com.galois.fiveui; + +import com.google.common.base.Function; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import org.apache.log4j.Logger; + +public class CrawlParameters { + + private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlParameters"); + + public int depth; + public int maxFetch; + public int politeness; + public String match; + public Function matchFcn; + + private Boolean _doNotCrawl; + private String _str; + + /** + * Construct (parse) a crawl type object from a string description + * + * A valid description is a whitespace separated list as follows: + * " " + * where: + *

    + *
  1. (depth :: int) depth of the crawl
  2. + *
  3. (maxFetch :: int) maximum number of pages to crawl
  4. + *
  5. (politeness :: int) number of milliseconds between hits on same domain
  6. + *
  7. (match :: String) glob pattern to match URLs
  8. + *
+ * or the string "none" which is, in spirit, equivalent to "0 1 1000 *", + * but in practice the webcrawl is skipped entirely in this case. + * + * @param desc a string description of the crawl type + * @throws Exception + */ + public CrawlParameters(String desc) { + String[] l = desc.split("\\s+"); + if (desc == "none" || l.length != 4) { + this._doNotCrawl = true; + this._str = desc; + logger.debug("setting doNotCrawl = True"); + return; + } else { + this.depth = Integer.parseInt(l[0]); + this.maxFetch = Integer.parseInt(l[1]); + this.politeness = Integer.parseInt(l[2]); + this.match = l[3]; + this._doNotCrawl = false; + this._str = desc; + this.matchFcn = compileMatchFcn(this.match); + logger.debug("setting depth: " + this.depth); + logger.debug("setting maxFetch: " + this.maxFetch); + logger.debug("setting politeness: " + this.politeness); + logger.debug("setting match: " + this.match); + } + } + + public static Function compileMatchFcn(String glob) { + String reg = glob.replaceAll("\\.", "\\.").replaceAll("\\*", ".*"); + final Pattern pat = Pattern.compile(reg); + return new Function() { + public Boolean apply(String input) { + Matcher m = pat.matcher(input); + return m.matches(); + } + }; + } + + public static CrawlParameters none() { + return new CrawlParameters("none"); + } + + public Boolean isNone() { + return this._doNotCrawl; + } + + public String toString() { + return _str; + } +} diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java new file mode 100644 index 0000000..01ffae0 --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java @@ -0,0 +1,95 @@ +/** + * + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +/** + * A singular url to test with a RuleSet. + * + * @author bjones + */ +public class HeadlessAtom { + + private String _url; + private RuleSet _ruleSet; + + public HeadlessAtom(String url, RuleSet ruleSet) { + _url = url; + _ruleSet = ruleSet; + } + + public String getURL() { + return _url; + } + + public RuleSet getRuleSet() { + return _ruleSet; + } + + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + /** + * Construct a HeadlessAtom from a JsonObject + * + * @param obj JsonObject to convert from + * @param dir parent directory of the filenames referenced in the ruleSet field + * @return a HeadlessAtom POJO + * @throws IOException + * @throws JsonParseException + */ + public static HeadlessAtom fromJsonObject(JsonObject obj, String dir) throws IOException { + String url = obj.get("url").getAsString(); + String ruleSet = obj.get("ruleSet").getAsString(); + + if (url == null || ruleSet == null) { + throw new JsonParseException("could get either 'url' or 'ruleSet' properties"); + } + + String rsPath = dir + File.separator + ruleSet; + RuleSet parsed = RuleSet.parseFile(rsPath); + + return new HeadlessAtom(url, parsed); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((_url == null) ? 0 : _url.hashCode()); + result = prime * result + ((_ruleSet == null) ? 0 : _ruleSet.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + HeadlessAtom other = (HeadlessAtom) obj; + if (_url == null) { + if (other._url != null) + return false; + } else if (!_url.equals(other._url)) + return false; + if (_ruleSet == null) { + if (other._ruleSet != null) + return false; + } else if (!_ruleSet.equals(other._ruleSet)) + return false; + return true; + } + +} 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 new file mode 100644 index 0000000..92f2ef1 --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java @@ -0,0 +1,177 @@ +/** + * + */ +package com.galois.fiveui; + + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +/** + * @author bjones + * + */ +public class HeadlessRunDescription { + + private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunDescription"); + private static String _crawlType; + private List _atoms; + + public HeadlessRunDescription (List atoms) { + _atoms = atoms; + } + + public List getAtoms() { + return _atoms; + } + + public int size() { + return _atoms.size(); + } + + /** + * Parse a JSON file into a HeadlessRunDescription + * + * @param runDescFileName The file to load. + * @return A populated HeadlessRunDescription object. + * @throws FileNotFoundException if runDescFile can't be found. + */ + 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); + } + + public static class Deserializer implements JsonDeserializer { + + private String _fn; // stores the filename on disk being parsed + private String _ctxDir; // stores the parent dir of _fn + + public Deserializer(String fn) { + _fn = fn; + _ctxDir = new File(_fn).getParent(); + if (null == _ctxDir) { + _ctxDir = "."; + } + } + + public static void reportError(JsonElement json) { + logger.error("HeadlessRunDescription.parse: ran into unexpected jsonElement type:"); + logger.error(" " + json.getAsString()); + } + + /** + * Gracefully lookup property 'prop' in JsonObject 'obj'. + * + * @param obj a JSON object + * @param prop a key string to lookup in the JSON object + * @return string property or null if the prop doesn't resolve + */ + public static String objGetString(JsonObject obj, String prop) { + try { + return obj.get(prop).getAsString(); + } catch (NullPointerException e) { + logger.error("HeadlessRunDescription.parse: failed to lookup JSON property: " + prop); + logger.error(e.toString()); + return null; + } + } + + public HeadlessRunDescription deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + + String ruleSetDir; + JsonArray arr; + + if (json.isJsonObject()) { // check if the description is an extended one + JsonObject obj = json.getAsJsonObject(); + ruleSetDir = objGetString(obj, "rulePath"); + _crawlType = objGetString(obj, "crawlType"); + arr = obj.get("runs").getAsJsonArray(); + } else if (json.isJsonArray()) { + ruleSetDir = _ctxDir; + _crawlType = "none"; + arr = json.getAsJsonArray(); + } else { + reportError(json); + return new HeadlessRunDescription(null); + } + + Builder atoms = ImmutableList.builder(); + for (JsonElement jsonElement : arr) { + 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) { + reportError(jsonElement); + } + } + + return new HeadlessRunDescription(atoms.build()); + } + } + + public String getCrawlType() { + return _crawlType; + } + + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + for (HeadlessAtom a: _atoms) { + result = prime * result + a.hashCode(); + } + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + HeadlessRunDescription other = (HeadlessRunDescription) obj; + if (_atoms == null) { + if (other._atoms != null) + return false; + } else if (!_atoms.equals(other._atoms)) + return false; + + return true; + } +} diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java new file mode 100644 index 0000000..aba0ad7 --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java @@ -0,0 +1,181 @@ +/** + * Module : HeadlessRunner.java Copyright : (c) 2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URISyntaxException; +import com.galois.fiveui.Result; +import com.google.common.collect.ImmutableList; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.BasicConfigurator; + +/** + * The main entry point for running headless rule set runs. + *

+ * The {@link #main(String[])} method of this class sets up a WebDriver, loads + * a headless run description from disk, and executes the run which includes + * loading seed URL's, performing a webcrawl, and running rule sets on each of + * the crawled pages. + * + * @author bjones + * + */ +public class HeadlessRunner { + + private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessRunner"); + + /** + * @param args list of headless run description filenames + * @throws IOException + * @throws URISyntaxException + * @throws ParseException + */ + @SuppressWarnings("static-access") + public static void main(final String[] args) + throws IOException, URISyntaxException, ParseException { + + // Setup command line options + Options options = new Options(); + Option help = new Option( "h", "print this help message" ); + Option output = OptionBuilder.withArgName("outfile") + .hasArg() + .withDescription("write output to file") + .create("o"); + Option report = OptionBuilder.withArgName("report directory") + .hasArg() + .withDescription("write HTML reports to given directory") + .create("r"); + options.addOption(output); + options.addOption(report); + options.addOption("v", false, "verbose output"); + options.addOption("vv", false, "VERY verbose output"); + options.addOption(help); + + // Parse command line options + CommandLineParser parser = new GnuParser(); + CommandLine cmd = null; + try { + cmd = parser.parse( options, args); + } catch (ParseException e) { + System.err.println( "Command line option parsing failed. Reason: " + e.getMessage() ); + System.exit(1); + } + + // Display help if requested + if (cmd.hasOption("h")) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("headless [ ...]", options); + System.exit(1); + } + + // Set logging levels + BasicConfigurator.configure(); + Logger fiveuiLogger = Logger.getLogger("com.galois.fiveui"); + Logger rootLogger = Logger.getRootLogger(); + if (cmd.hasOption("v")) { + fiveuiLogger.setLevel(Level.DEBUG); + rootLogger.setLevel(Level.ERROR); + } else if (cmd.hasOption("vv")) { + fiveuiLogger.setLevel(Level.DEBUG); + rootLogger.setLevel(Level.DEBUG); + } else { + fiveuiLogger.setLevel(Level.ERROR); + rootLogger.setLevel(Level.ERROR); + } + + // Setup output file if requested + PrintWriter outStream = null; + if (cmd.hasOption("o")) { + String outfile = cmd.getOptionValue("o"); + try { + outStream = new PrintWriter(new BufferedWriter(new FileWriter(outfile))); + } catch (IOException e) { + System.err.println("Could not open outfile for writing: " + cmd.getOptionValue("outfile")); + System.exit(1); + } + } else { + outStream = new PrintWriter(new BufferedWriter(new PrintWriter(System.out))); + } + + // Setup HTML reports directory before the major work happens in case we + // have to throw an exception. + PrintWriter summaryFile = null; + PrintWriter byURLFile = null; + PrintWriter byRuleFile = null; + if (cmd.hasOption("r")) { + String repDir = cmd.getOptionValue("r"); + try { + File file = new File(repDir); + if (!file.exists()) { + file.mkdir(); + logger.info("report directory created: " + repDir); + } else { + logger.info("report directory already exists!"); + } + summaryFile = new PrintWriter(new FileWriter(repDir + File.separator + "summary.html")); + byURLFile = new PrintWriter(new FileWriter(repDir + File.separator + "byURL.html")); + byRuleFile = new PrintWriter(new FileWriter(repDir + File.separator + "byRule.html")); + } catch (IOException e) { + System.err.println("could not open report directory / files for writing"); + System.exit(1); + } + } + + // Major work: process input files + ImmutableList results = null; + for (String in: cmd.getArgs()) { + HeadlessRunDescription descr = HeadlessRunDescription.parse(in); + logger.debug("invoking headless run..."); + BatchRunner runner = new BatchRunner(); + results = runner.runHeadless(descr); + logger.debug("runHeadless returned " + results.size() + " results"); + // write results to the output stream as we go + for (Result result : results) { + outStream.println(result.toString()); + } + outStream.flush(); + } + outStream.close(); + + // Write report files if requested + if (cmd.hasOption("r") && results != null) { + Reporter kermit = new Reporter(results); + summaryFile.write(kermit.getSummary()); + summaryFile.close(); + byURLFile.write(kermit.getByURL()); + byURLFile.close(); + byRuleFile.write(kermit.getByRule()); + byRuleFile.close(); + } + } +} + 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 new file mode 100644 index 0000000..5c0b233 --- /dev/null +++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java @@ -0,0 +1,360 @@ +/** + * Module : Reporter.java Copyright : (c) 2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * @author Benjamin Jones + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.googlecode.jatl.Html; + +/** + * Reporter is responsible for turning a list of results from a FiveUI run and + * and generating various reports which summarize the results. The reports are + * 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"; + + /** + * 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(); + } + /** + * 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(); + 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(); + } + + /** + * 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 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(); + } + + /** 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(); + }}; + } + + /** + * 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; + } + + /** + * 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 + * @return a map representing the results sorted by rule name. + */ + private Map computeSummaryStats(List results) { + /** passFailMap semantics: Map */ + Map passFailMap = new HashMap(); + String url; + int pass, fail; + int[] passFailList; + Pattern numberPassedPattern = Pattern.compile("passed ([0-9]+) tests"); + 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; + } + + 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/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java new file mode 100644 index 0000000..f7f593f --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java @@ -0,0 +1,122 @@ +/** + * Module : BatchExecutorTest.java + * Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : + * Stability : Provisional + * Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.BindException; + +import junit.framework.Assert; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + + +/** + * @author bjones + * + */ +public class BatchExecutorTest { + + private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; + private static Logger logger = Logger.getLogger("com.galois.fiveui.BatchExecutorTest"); + private static NanoHTTPD httpServer; + + @BeforeClass + public static void setupTests() { + BasicConfigurator.configure(); + logger.setLevel(Level.DEBUG); + Logger root = Logger.getRootLogger(); + root.setLevel(Level.ERROR); + // start up local web server for crawl tests + File dir = new File("."); + logger.info("Starting NanoHTTPD webserver in " + dir.getAbsolutePath() + " on port 8000 ..."); + try { + httpServer = new NanoHTTPD(8000, dir); + } catch (BindException e) { + logger.debug("assuming that local web server is already running"); + } catch (IOException e1) { + e1.printStackTrace(); + Assert.assertTrue("failed to start NanoHTTPD in current directory " + dir.getAbsolutePath(), false); + } + } + + @AfterClass + public static void teardown() { + LogManager.shutdown(); + httpServer.stop(); + } + + /** + * This unit test requires that a webserver be running locally on port 8000, + * what it serves does not matter. + * + * @throws IOException + * @throws FileNotFoundException + */ + @Test + public void headlessRunTest0() throws IOException { + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTest0.json"; + testHeadlessRun(jsonFileName); + } + + /** + * This unit test requires Internet access to http://www.cnn.com + * + * @throws IOException + * @throws FileNotFoundException + */ + @Ignore + public void headlessRunTestCNN() throws IOException { + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTestCNN.json"; + testHeadlessRun(jsonFileName); + } + + /** + * Helper method for headless run unit tests. + * + * @param fn filename of a .json file containing a headless run description + */ + private static void testHeadlessRun(String fn) { + boolean flag = true; + try { + HeadlessRunDescription descr = HeadlessRunDescription.parse(fn); + BatchRunner runner = new BatchRunner(); + ImmutableList results = runner.runHeadless(descr); + logger.info(results.toString()); + } catch (Exception e) { + logger.error("testHeadlessRun: exception caught while running a headless run description"); + logger.error(e.toString()); + flag = false; + } + Assert.assertTrue(flag); + } + +} diff --git a/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java new file mode 100644 index 0000000..f5ffa35 --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlParametersTest.java @@ -0,0 +1,107 @@ +package com.galois.fiveui; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.galois.fiveui.CrawlParameters; + + +public class CrawlParametersTest { + + private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlParameters"); + + @BeforeClass + public static void before() { + //if (!Logger.getRootLogger().getAllAppenders().hasMoreElements()) + BasicConfigurator.configure(); + logger.info("running unit tests..."); + } + + @AfterClass + public static void after() { + LogManager.shutdown(); + } + + @Test + public void testConstructorFields() { + CrawlParameters c; + try { + c = new CrawlParameters("0 1 100 foo"); + } catch (Exception e) { + Assert.assertTrue("failed to parse crawl type string", false); + return; + } + Assert.assertArrayEquals(new int[]{0, 1, 100}, new int[]{c.depth, c.maxFetch, c.politeness}); + Assert.assertEquals("foo", c.match); + } + + @Test + public void testNone() { + CrawlParameters c = CrawlParameters.none(); + Assert.assertTrue(c.isNone()); + } + + @Test + public void testMatchFcn() { + CrawlParameters c; + try { + c = new CrawlParameters("0 1 100 foo"); + } catch (Exception e) { + Assert.assertTrue("failed to parse crawl type string", false); + return; + } + Assert.assertTrue("failed to match foo", c.matchFcn.apply("foo")); + Assert.assertFalse("failed to not match bar", c.matchFcn.apply("bar")); + } + + @Test + public void testMatchFcnGlob1() { + CrawlParameters c; + try { + c = new CrawlParameters("0 1 100 foo*"); + } catch (Exception e) { + Assert.assertTrue("failed to parse crawl type string", false); + return; + } + Assert.assertTrue("failed to match foo", c.matchFcn.apply("foo")); + Assert.assertFalse("failed to not match bar", c.matchFcn.apply("bar")); + Assert.assertTrue("failed to match foobar", c.matchFcn.apply("foobar")); + Assert.assertFalse("failed to not match barfoobar", c.matchFcn.apply("barfoobar")); + } + + @Test + public void testMatchFcnGlob2() { + CrawlParameters c; + try { + c = new CrawlParameters("0 1 100 http://foo.com/*.html"); + } catch (Exception e) { + Assert.assertTrue("failed to parse crawl type string", false); + return; + } + Assert.assertTrue("failed to match http://foo.com/index.html", c.matchFcn.apply("http://foo.com/index.html")); + Assert.assertTrue("failed to match http://foo.com/test/index.html", c.matchFcn.apply("http://foo.com/test/index.html")); + Assert.assertFalse("failed to not match http://bar.com/index.html", c.matchFcn.apply("http://bar.com/index.html")); + } + + @Test + public void testMatchFcnGlob3() { + CrawlParameters c; + try { + c = new CrawlParameters("0 1 100 *foo.com*"); + } catch (Exception e) { + Assert.assertTrue("failed to parse crawl type string", false); + return; + } + Assert.assertTrue("failed to match http://foo.com/index.html", c.matchFcn.apply("http://foo.com/index.html")); + Assert.assertTrue("failed to match http://foo.com/test/index.html", c.matchFcn.apply("http://foo.com/test/index.html")); + Assert.assertTrue("failed to match http://bar.foo.com", c.matchFcn.apply("http://bar.foo.com")); + Assert.assertFalse("failed to not match http://foobar.com", c.matchFcn.apply("http://foobar.com")); + } + +} + diff --git a/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java new file mode 100644 index 0000000..0f932c2 --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/CrawlTest.java @@ -0,0 +1,136 @@ +package com.galois.fiveui; + +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import junit.framework.Assert; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.BasicConfigurator; + +import com.google.common.base.Function; +import com.google.common.io.Files; + +import edu.uci.ics.crawler4j.util.IO; + +public class CrawlTest { + + // TODO need a system independent way of getting the resources path + private static String resourceDir = "src/test/resources/crawlTest/"; + private static Logger logger = Logger.getLogger("com.galois.fiveui.CrawlTest"); + private static NanoHTTPD httpServer = null; + + @BeforeClass + public static void setupCrawlTests() { + // Set up a simple configuration that logs on the console. + BasicConfigurator.configure(); + logger.setLevel(Level.DEBUG); + Logger root = Logger.getRootLogger(); + root.setLevel(Level.ERROR); + + // start up local web server for crawl tests + + logger.info("Starting NanoHTTPD webserver in " + resourceDir + " on port 8080 ..."); + try { + httpServer = new NanoHTTPD(8080, new File(resourceDir)); + } catch (BindException e) { + logger.info("assuming that local web server is already running"); + } catch (IOException e1) { + e1.printStackTrace(); + Assert.assertTrue("failed to start NanoHTTPD in resource directory", false); + } + } + + @AfterClass + public static void teardown() { + LogManager.shutdown(); + httpServer.stop(); + } + + // Requires Internet access + // @Test + public void corpDotGaloisCrawlTest() { + File tmpPath = Files.createTempDir(); + BasicCrawlerController con = + new BasicCrawlerController("http://corp.galois.com", + "http://corp.galois.com", + 2, 5, 1000, 1, + tmpPath.getAbsolutePath()); + List urls = null; + try { + urls = con.go(); + System.out.println(urls.toString()); + } catch (Exception e) { + Assert.assertTrue("failed to complete webcrawl", false); + e.printStackTrace(); + } finally { + IO.deleteFolder(tmpPath); + } + + Assert.assertEquals((urls != null) && (urls.size() == 5), true); + } + + @Test + public void testLocalCrawlDepth3one() { + doLocalCrawlTest("http://localhost:8080/one.html", 3, 10, 9); + } + + @Test + public void testLocalCrawlDepth3two() { + doLocalCrawlTest("http://localhost:8080/two.html", 3, 10, 3); + } + + @Test + public void testLocalCrawlDepth0one() { + doLocalCrawlTest("http://localhost:8080/one.html", 0, 10, 1); + } + + @Test + public void testCrawlWithPredicate() { + CrawlParameters c = new CrawlParameters("5 5 100 *one.html"); + doLocalCrawlTest("http://localhost:8080/one.html", c.matchFcn, c.depth, c.maxFetch, 1); + } + + public void doLocalCrawlTest(String seed, int depth, int maxFetch, int oracle) { + Function pred = new Function() { + public Boolean apply(String s) { + return s.startsWith("http"); + } + }; + doLocalCrawlTest(seed, pred, depth, maxFetch, oracle); + } + + public void doLocalCrawlTest(String seed, Function pred, int depth, int maxFetch, int oracle) { + + logger.info("Starting localCrawlTest ..."); + logger.info(" seed " + seed + ", depth " + depth); + + File tmpPath = Files.createTempDir(); + BasicCrawlerController con = + new BasicCrawlerController(seed, pred, depth, maxFetch, 100, 1, + tmpPath.getAbsolutePath()); + List urls = null; + try { + logger.info("Starting webcrawl ..."); + urls = con.go(); + logger.info("RETURN -- " + urls.toString()); + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue("failed to run webcrawler", false); + } finally { + IO.deleteFolder(tmpPath); + } + + // assert that we got oracle number of URLs + Assert.assertTrue("got " + urls.size() + " URLs, expected " + oracle, + (urls != null) && (urls.size() == oracle)); + } + +} diff --git a/src/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java new file mode 100644 index 0000000..804d9f6 --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/HeadlessTest.java @@ -0,0 +1,114 @@ +/** + * + */ +package com.galois.fiveui; + +import java.io.IOException; + +import junit.framework.Assert; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +/** + * @author bjones + * + */ +public class HeadlessTest { + private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; + private static Logger logger = Logger.getLogger("com.galois.fiveui.HeadlessTest"); + + @BeforeClass + public static void beforeClass() { + BasicConfigurator.configure(); + Logger root = Logger.getRootLogger(); + root.setLevel(Level.ERROR); + logger.setLevel(Level.DEBUG); + logger.debug("running headless tests..."); + } + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample0.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample0() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample0.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; + RuleSet ruleSetOracle = RuleSet.parseFile(ruleSetLoc); + HeadlessAtom headlessAtomOracle = + new HeadlessAtom("http://testhost", ruleSetOracle); + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample1.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample1() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample1.json"; + String ruleSetLoc = RUN_DESCRIPTION_DIR + + "../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json"; + RuleSet ruleSetOracle = RuleSet.parseFile(ruleSetLoc); + HeadlessAtom headlessAtomOracle = + new HeadlessAtom("http://testhost", ruleSetOracle); + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample2.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample2() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample2.json"; + // manually build first HeadlessAtom + String ruleSetLoc1 = + RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; + RuleSet ruleSetOracle1 = RuleSet.parseFile(ruleSetLoc1); + HeadlessAtom headlessAtomOracle1 = + new HeadlessAtom("http://testhost1", ruleSetOracle1); + // manually build second HeadlessAtom + String ruleSetLoc2 = RUN_DESCRIPTION_DIR + + "../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json"; + + RuleSet ruleSetOracle2 = RuleSet.parseFile(ruleSetLoc2); + HeadlessAtom headlessAtomOracle2 = + new HeadlessAtom("http://testhost2", ruleSetOracle2); + + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle1, + headlessAtomOracle2)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + private void assertObjEqual(String msg, Object oracle, Object actual) { + Assert.assertTrue(msg + ";\n expected: "+oracle+"\n actual: "+actual, + oracle.equals(actual)); + } +} diff --git a/src/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java new file mode 100644 index 0000000..53434be --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/NanoHTTPD.java @@ -0,0 +1,1122 @@ +package com.galois.fiveui; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URLEncoder; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.TimeZone; + +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; + +/** + * A simple, tiny, nicely embeddable HTTP 1.0 (partially 1.1) server in Java + * + *

NanoHTTPD version 1.25, + * Copyright © 2001,2005-2012 Jarno Elonen (elonen@iki.fi, http://iki.fi/elonen/) + * and Copyright © 2010 Konstantinos Togias (info@ktogias.gr, http://ktogias.gr) + * + *

Features + limitations:

    + * + *
  • Only one Java file
  • + *
  • Java 1.1 compatible
  • + *
  • Released as open source, Modified BSD licence
  • + *
  • No fixed config files, logging, authorization etc. (Implement yourself if you need them.)
  • + *
  • Supports parameter parsing of GET and POST methods (+ rudimentary PUT support in 1.25)
  • + *
  • Supports both dynamic content and file serving
  • + *
  • Supports file upload (since version 1.2, 2010)
  • + *
  • Supports partial content (streaming)
  • + *
  • Supports ETags
  • + *
  • Never caches anything
  • + *
  • Doesn't limit bandwidth, request time or simultaneous connections
  • + *
  • Default code serves files and shows all HTTP parameters and headers
  • + *
  • File server supports directory listing, index.html and index.htm
  • + *
  • File server supports partial content (streaming)
  • + *
  • File server supports ETags
  • + *
  • File server does the 301 redirection trick for directories without '/'
  • + *
  • File server supports simple skipping for files (continue download)
  • + *
  • File server serves also very long files without memory overhead
  • + *
  • Contains a built-in list of most common mime types
  • + *
  • All header names are converted lowercase so they don't vary between browsers/clients
  • + * + *
+ * + *

Ways to use:

    + * + *
  • Run as a standalone app, serves files and shows requests
  • + *
  • Subclass serve() and embed to your own program
  • + *
  • Call serveFile() from serve() with your own base directory
  • + * + *
+ * + * See the end of the source file for distribution license + * (Modified BSD licence) + */ +public class NanoHTTPD +{ + // ================================================== + // API parts + // ================================================== + + /** + * Override this to customize the server.

+ * + * (By default, this delegates to serveFile() and allows directory listing.) + * + * @param uri Percent-decoded URI without parameters, for example "/index.cgi" + * @param method "GET", "POST" etc. + * @param parms Parsed, percent decoded parameters from URI and, in case of POST, data. + * @param header Header entries, percent decoded + * @return HTTP response, see class Response for details + */ + public Response serve( String uri, String method, Properties header, Properties parms, Properties files ) + { + myOut.println( method + " '" + uri + "' " ); + + Enumeration e = header.propertyNames(); + while ( e.hasMoreElements()) + { + String value = (String)e.nextElement(); + myOut.println( " HDR: '" + value + "' = '" + + header.getProperty( value ) + "'" ); + } + e = parms.propertyNames(); + while ( e.hasMoreElements()) + { + String value = (String)e.nextElement(); + myOut.println( " PRM: '" + value + "' = '" + + parms.getProperty( value ) + "'" ); + } + e = files.propertyNames(); + while ( e.hasMoreElements()) + { + String value = (String)e.nextElement(); + myOut.println( " UPLOADED: '" + value + "' = '" + + files.getProperty( value ) + "'" ); + } + + return serveFile( uri, header, myRootDir, true ); + } + + /** + * HTTP response. + * Return one of these from serve(). + */ + public class Response + { + /** + * Default constructor: response = HTTP_OK, data = mime = 'null' + */ + public Response() + { + this.status = HTTP_OK; + } + + /** + * Basic constructor. + */ + public Response( String status, String mimeType, InputStream data ) + { + this.status = status; + this.mimeType = mimeType; + this.data = data; + } + + /** + * Convenience method that makes an InputStream out of + * given text. + */ + public Response( String status, String mimeType, String txt ) + { + this.status = status; + this.mimeType = mimeType; + try + { + this.data = new ByteArrayInputStream( txt.getBytes("UTF-8")); + } + catch ( java.io.UnsupportedEncodingException uee ) + { + uee.printStackTrace(); + } + } + + /** + * Adds given line to the header. + */ + public void addHeader( String name, String value ) + { + header.put( name, value ); + } + + /** + * HTTP status code after processing, e.g. "200 OK", HTTP_OK + */ + public String status; + + /** + * MIME type of content, e.g. "text/html" + */ + public String mimeType; + + /** + * Data of the response, may be null. + */ + public InputStream data; + + /** + * Headers for the HTTP response. Use addHeader() + * to add lines. + */ + public Properties header = new Properties(); + } + + /** + * Some HTTP response status codes + */ + public static final String + HTTP_OK = "200 OK", + HTTP_PARTIALCONTENT = "206 Partial Content", + HTTP_RANGE_NOT_SATISFIABLE = "416 Requested Range Not Satisfiable", + HTTP_REDIRECT = "301 Moved Permanently", + HTTP_NOTMODIFIED = "304 Not Modified", + HTTP_FORBIDDEN = "403 Forbidden", + HTTP_NOTFOUND = "404 Not Found", + HTTP_BADREQUEST = "400 Bad Request", + HTTP_INTERNALERROR = "500 Internal Server Error", + HTTP_NOTIMPLEMENTED = "501 Not Implemented"; + + /** + * Common mime types for dynamic content + */ + public static final String + MIME_PLAINTEXT = "text/plain", + MIME_HTML = "text/html", + MIME_DEFAULT_BINARY = "application/octet-stream", + MIME_XML = "text/xml"; + + // ================================================== + // Socket & server code + // ================================================== + + /** + * Starts a HTTP server to given port.

+ * Throws an IOException if the socket is already in use + */ + public NanoHTTPD( int port, File wwwroot ) throws IOException + { + myTcpPort = port; + this.myRootDir = wwwroot; + myServerSocket = new ServerSocket( myTcpPort ); + myThread = new Thread( new Runnable() + { + public void run() + { + try + { + while( true ) + new HTTPSession( myServerSocket.accept()); + } + catch ( IOException ioe ) + {} + } + }); + myThread.setDaemon( true ); + myThread.start(); + } + + /** + * Stops the server. + */ + public void stop() + { + try + { + myServerSocket.close(); + myThread.join(); + } + catch ( IOException ioe ) {} + catch ( InterruptedException e ) {} + } + + + /** + * Starts as a standalone file server and waits for Enter. + */ + public static void main( String[] args ) + { + myOut.println( "NanoHTTPD 1.25 (C) 2001,2005-2011 Jarno Elonen and (C) 2010 Konstantinos Togias\n" + + "(Command line options: [-p port] [-d root-dir] [--licence])\n" ); + + // Defaults + int port = 80; + File wwwroot = new File(".").getAbsoluteFile(); + + // Show licence if requested + for ( int i=0; i= 0 && size > 0 ) + { + rlen = is.read(buf, 0, 512); + size -= rlen; + if (rlen > 0) + f.write(buf, 0, rlen); + } + + // Get the raw body as a byte [] + byte [] fbuf = f.toByteArray(); + + // Create a BufferedReader for easily reading it as string. + ByteArrayInputStream bin = new ByteArrayInputStream(fbuf); + BufferedReader in = new BufferedReader( new InputStreamReader(bin)); + + // If the method is POST, there may be parameters + // in data section, too, read it: + if ( method.equalsIgnoreCase( "POST" )) + { + String contentType = ""; + String contentTypeHeader = header.getProperty("content-type"); + StringTokenizer st = new StringTokenizer( contentTypeHeader , "; " ); + if ( st.hasMoreTokens()) { + contentType = st.nextToken(); + } + + if (contentType.equalsIgnoreCase("multipart/form-data")) + { + // Handle multipart/form-data + if ( !st.hasMoreTokens()) + sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html" ); + String boundaryExp = st.nextToken(); + st = new StringTokenizer( boundaryExp , "=" ); + if (st.countTokens() != 2) + sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary syntax error. Usage: GET /example/file.html" ); + st.nextToken(); + String boundary = st.nextToken(); + + decodeMultipartData(boundary, fbuf, in, parms, files); + } + else + { + // Handle application/x-www-form-urlencoded + String postLine = ""; + char pbuf[] = new char[512]; + int read = in.read(pbuf); + while ( read >= 0 && !postLine.endsWith("\r\n") ) + { + postLine += String.valueOf(pbuf, 0, read); + read = in.read(pbuf); + } + postLine = postLine.trim(); + decodeParms( postLine, parms ); + } + } + + if ( method.equalsIgnoreCase( "PUT" )) + files.put("content", saveTmpFile( fbuf, 0, f.size())); + + // Ok, now do the serve() + Response r = serve( uri, method, header, parms, files ); + if ( r == null ) + sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: Serve() returned a null response." ); + else + sendResponse( r.status, r.mimeType, r.header, r.data ); + + in.close(); + is.close(); + } + catch ( IOException ioe ) + { + try + { + sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); + } + catch ( Throwable t ) {} + } + catch ( InterruptedException ie ) + { + // Thrown by sendError, ignore and exit the thread. + } + } + + /** + * Decodes the sent headers and loads the data into + * java Properties' key - value pairs + **/ + private void decodeHeader(BufferedReader in, Properties pre, Properties parms, Properties header) + throws InterruptedException + { + try { + // Read the request line + String inLine = in.readLine(); + if (inLine == null) return; + StringTokenizer st = new StringTokenizer( inLine ); + if ( !st.hasMoreTokens()) + sendError( HTTP_BADREQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html" ); + + String method = st.nextToken(); + pre.put("method", method); + + if ( !st.hasMoreTokens()) + sendError( HTTP_BADREQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html" ); + + String uri = st.nextToken(); + + // Decode parameters from the URI + int qmi = uri.indexOf( '?' ); + if ( qmi >= 0 ) + { + decodeParms( uri.substring( qmi+1 ), parms ); + uri = decodePercent( uri.substring( 0, qmi )); + } + else uri = decodePercent(uri); + + // If there's another token, it's protocol version, + // followed by HTTP headers. Ignore version but parse headers. + // NOTE: this now forces header names lowercase since they are + // case insensitive and vary by client. + if ( st.hasMoreTokens()) + { + String line = in.readLine(); + while ( line != null && line.trim().length() > 0 ) + { + int p = line.indexOf( ':' ); + if ( p >= 0 ) + header.put( line.substring(0,p).trim().toLowerCase(), line.substring(p+1).trim()); + line = in.readLine(); + } + } + + pre.put("uri", uri); + } + catch ( IOException ioe ) + { + sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); + } + } + + /** + * Decodes the Multipart Body data and put it + * into java Properties' key - value pairs. + **/ + private void decodeMultipartData(String boundary, byte[] fbuf, BufferedReader in, Properties parms, Properties files) + throws InterruptedException + { + try + { + int[] bpositions = getBoundaryPositions(fbuf,boundary.getBytes()); + int boundarycount = 1; + String mpline = in.readLine(); + while ( mpline != null ) + { + if (mpline.indexOf(boundary) == -1) + sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html" ); + boundarycount++; + Properties item = new Properties(); + mpline = in.readLine(); + while (mpline != null && mpline.trim().length() > 0) + { + int p = mpline.indexOf( ':' ); + if (p != -1) + item.put( mpline.substring(0,p).trim().toLowerCase(), mpline.substring(p+1).trim()); + mpline = in.readLine(); + } + if (mpline != null) + { + String contentDisposition = item.getProperty("content-disposition"); + if (contentDisposition == null) + { + sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html" ); + } + StringTokenizer st = new StringTokenizer( contentDisposition , "; " ); + Properties disposition = new Properties(); + while ( st.hasMoreTokens()) + { + String token = st.nextToken(); + int p = token.indexOf( '=' ); + if (p!=-1) + disposition.put( token.substring(0,p).trim().toLowerCase(), token.substring(p+1).trim()); + } + String pname = disposition.getProperty("name"); + pname = pname.substring(1,pname.length()-1); + + String value = ""; + if (item.getProperty("content-type") == null) { + while (mpline != null && mpline.indexOf(boundary) == -1) + { + mpline = in.readLine(); + if ( mpline != null) + { + int d = mpline.indexOf(boundary); + if (d == -1) + value+=mpline; + else + value+=mpline.substring(0,d-2); + } + } + } + else + { + if (boundarycount> bpositions.length) + sendError( HTTP_INTERNALERROR, "Error processing request" ); + int offset = stripMultipartHeaders(fbuf, bpositions[boundarycount-2]); + String path = saveTmpFile(fbuf, offset, bpositions[boundarycount-1]-offset-4); + files.put(pname, path); + value = disposition.getProperty("filename"); + value = value.substring(1,value.length()-1); + do { + mpline = in.readLine(); + } while (mpline != null && mpline.indexOf(boundary) == -1); + } + parms.put(pname, value); + } + } + } + catch ( IOException ioe ) + { + sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); + } + } + + /** + * Find the byte positions where multipart boundaries start. + **/ + public int[] getBoundaryPositions(byte[] b, byte[] boundary) + { + int matchcount = 0; + int matchbyte = -1; + Vector matchbytes = new Vector(); + for (int i=0; i 0) + { + String tmpdir = System.getProperty("java.io.tmpdir"); + try { + File temp = File.createTempFile("NanoHTTPD", "", new File(tmpdir)); + OutputStream fstream = new FileOutputStream(temp); + fstream.write(b, offset, len); + fstream.close(); + path = temp.getAbsolutePath(); + } catch (Exception e) { // Catch exception if any + myErr.println("Error: " + e.getMessage()); + } + } + return path; + } + + + /** + * It returns the offset separating multipart file headers + * from the file's data. + **/ + private int stripMultipartHeaders(byte[] b, int offset) + { + int i = 0; + for (i=offset; i + * For example: "an+example%20string" -> "an example string" + */ + private String decodePercent( String str ) throws InterruptedException + { + try + { + StringBuffer sb = new StringBuffer(); + for( int i=0; i e = header.keys(); + while ( e.hasMoreElements()) + { + String key = (String)e.nextElement(); + String value = header.getProperty( key ); + pw.print( key + ": " + value + "\r\n"); + } + } + + pw.print("\r\n"); + pw.flush(); + + if ( data != null ) + { + int pending = data.available(); // This is to support partial sends, see serveFile() + byte[] buff = new byte[theBufferSize]; + while (pending>0) + { + int read = data.read( buff, 0, ( (pending>theBufferSize) ? theBufferSize : pending )); + if (read <= 0) break; + out.write( buff, 0, read ); + pending -= read; + } + } + out.flush(); + out.close(); + if ( data != null ) + data.close(); + } + catch( IOException ioe ) + { + // Couldn't write? No can do. + try { mySocket.close(); } catch( Throwable t ) {} + } + } + + private Socket mySocket; + } + + /** + * URL-encodes everything between "/"-characters. + * Encodes spaces as '%20' instead of '+'. + */ + @SuppressWarnings("deprecation") + private String encodeUri( String uri ) + { + String newUri = ""; + StringTokenizer st = new StringTokenizer( uri, "/ ", true ); + while ( st.hasMoreTokens()) + { + String tok = st.nextToken(); + if ( tok.equals( "/" )) + newUri += "/"; + else if ( tok.equals( " " )) + newUri += "%20"; + else + { + newUri += URLEncoder.encode( tok ); + // For Java 1.4 you'll want to use this instead: + // try { newUri += URLEncoder.encode( tok, "UTF-8" ); } catch ( java.io.UnsupportedEncodingException uee ) {} + } + } + return newUri; + } + + private int myTcpPort; + private final ServerSocket myServerSocket; + private Thread myThread; + private File myRootDir; + + // ================================================== + // File server code + // ================================================== + + /** + * Serves file from homeDir and its' subdirectories (only). + * Uses only URI, ignores all headers and HTTP parameters. + */ + public Response serveFile( String uri, Properties header, File homeDir, + boolean allowDirectoryListing ) + { + Response res = null; + + // Make sure we won't die of an exception later + if ( !homeDir.isDirectory()) + res = new Response( HTTP_INTERNALERROR, MIME_PLAINTEXT, + "INTERNAL ERRROR: serveFile(): given homeDir is not a directory." ); + + if ( res == null ) + { + // Remove URL arguments + uri = uri.trim().replace( File.separatorChar, '/' ); + if ( uri.indexOf( '?' ) >= 0 ) + uri = uri.substring(0, uri.indexOf( '?' )); + + // Prohibit getting out of current directory + if ( uri.startsWith( ".." ) || uri.endsWith( ".." ) || uri.indexOf( "../" ) >= 0 ) + res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, + "FORBIDDEN: Won't serve ../ for security reasons." ); + } + + File f = new File( homeDir, uri ); + if ( res == null && !f.exists()) + res = new Response( HTTP_NOTFOUND, MIME_PLAINTEXT, + "Error 404, file not found." ); + + // List the directory, if necessary + if ( res == null && f.isDirectory()) + { + // Browsers get confused without '/' after the + // directory, send a redirect. + if ( !uri.endsWith( "/" )) + { + uri += "/"; + res = new Response( HTTP_REDIRECT, MIME_HTML, + "Redirected: " + + uri + ""); + res.addHeader( "Location", uri ); + } + + if ( res == null ) + { + // First try index.html and index.htm + if ( new File( f, "index.html" ).exists()) + f = new File( homeDir, uri + "/index.html" ); + else if ( new File( f, "index.htm" ).exists()) + f = new File( homeDir, uri + "/index.htm" ); + // No index file, list the directory if it is readable + else if ( allowDirectoryListing && f.canRead() ) + { + String[] files = f.list(); + String msg = "

Directory " + uri + "


"; + + if ( uri.length() > 1 ) + { + String u = uri.substring( 0, uri.length()-1 ); + int slash = u.lastIndexOf( '/' ); + if ( slash >= 0 && slash < u.length()) + msg += "..
"; + } + + if (files!=null) + { + for ( int i=0; i" + + files[i] + ""; + + // Show file size + if ( curFile.isFile()) + { + long len = curFile.length(); + msg += "  ("; + if ( len < 1024 ) + msg += len + " bytes"; + else if ( len < 1024 * 1024 ) + msg += len/1024 + "." + (len%1024/10%100) + " KB"; + else + msg += len/(1024*1024) + "." + len%(1024*1024)/10%100 + " MB"; + + msg += ")"; + } + msg += "
"; + if ( dir ) msg += ""; + } + } + msg += ""; + res = new Response( HTTP_OK, MIME_HTML, msg ); + } + else + { + res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, + "FORBIDDEN: No directory listing." ); + } + } + } + + try + { + if ( res == null ) + { + // Get MIME type from file name extension, if possible + String mime = null; + int dot = f.getCanonicalPath().lastIndexOf( '.' ); + if ( dot >= 0 ) + mime = (String)theMimeTypes.get( f.getCanonicalPath().substring( dot + 1 ).toLowerCase()); + if ( mime == null ) + mime = MIME_DEFAULT_BINARY; + + // Calculate etag + String etag = Integer.toHexString((f.getAbsolutePath() + f.lastModified() + "" + f.length()).hashCode()); + + // Support (simple) skipping: + long startFrom = 0; + long endAt = -1; + String range = header.getProperty( "range" ); + if ( range != null ) + { + if ( range.startsWith( "bytes=" )) + { + range = range.substring( "bytes=".length()); + int minus = range.indexOf( '-' ); + try { + if ( minus > 0 ) + { + startFrom = Long.parseLong( range.substring( 0, minus )); + endAt = Long.parseLong( range.substring( minus+1 )); + } + } + catch ( NumberFormatException nfe ) {} + } + } + + // Change return code and add Content-Range header when skipping is requested + long fileLen = f.length(); + if (range != null && startFrom >= 0) + { + if ( startFrom >= fileLen) + { + res = new Response( HTTP_RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "" ); + res.addHeader( "Content-Range", "bytes 0-0/" + fileLen); + res.addHeader( "ETag", etag); + } + else + { + if ( endAt < 0 ) + endAt = fileLen-1; + long newLen = endAt - startFrom + 1; + if ( newLen < 0 ) newLen = 0; + + final long dataLen = newLen; + FileInputStream fis = new FileInputStream( f ) { + public int available() throws IOException { return (int)dataLen; } + }; + fis.skip( startFrom ); + + res = new Response( HTTP_PARTIALCONTENT, mime, fis ); + res.addHeader( "Content-Length", "" + dataLen); + res.addHeader( "Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen); + res.addHeader( "ETag", etag); + } + } + else + { + if (etag.equals(header.getProperty("if-none-match"))) + res = new Response( HTTP_NOTMODIFIED, mime, ""); + else + { + res = new Response( HTTP_OK, mime, new FileInputStream( f )); + res.addHeader( "Content-Length", "" + fileLen); + res.addHeader( "ETag", etag); + } + } + } + } + catch( IOException ioe ) + { + res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, "FORBIDDEN: Reading file failed." ); + } + + res.addHeader( "Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requestes + return res; + } + + /** + * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE + */ + private static Hashtable theMimeTypes = new Hashtable(); + static + { + StringTokenizer st = new StringTokenizer( + "css text/css "+ + "htm text/html "+ + "html text/html "+ + "xml text/xml "+ + "txt text/plain "+ + "asc text/plain "+ + "gif image/gif "+ + "jpg image/jpeg "+ + "jpeg image/jpeg "+ + "png image/png "+ + "mp3 audio/mpeg "+ + "m3u audio/mpeg-url " + + "mp4 video/mp4 " + + "ogv video/ogg " + + "flv video/x-flv " + + "mov video/quicktime " + + "swf application/x-shockwave-flash " + + "js application/javascript "+ + "pdf application/pdf "+ + "doc application/msword "+ + "ogg application/x-ogg "+ + "zip application/octet-stream "+ + "exe application/octet-stream "+ + "class application/octet-stream " ); + while ( st.hasMoreTokens()) + theMimeTypes.put( st.nextToken(), st.nextToken()); + } + + private static int theBufferSize = 16 * 1024; + + // Change these if you want to log to somewhere else than stdout + protected static PrintStream myOut = System.out; + protected static PrintStream myErr = System.err; + + /** + * GMT date formatter + */ + private static java.text.SimpleDateFormat gmtFrmt; + static + { + gmtFrmt = new java.text.SimpleDateFormat( "E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + /** + * The distribution licence + */ + private static final String LICENCE = + "Copyright (C) 2001,2005-2011 by Jarno Elonen \n"+ + "and Copyright (C) 2010 by Konstantinos Togias \n"+ + "\n"+ + "Redistribution and use in source and binary forms, with or without\n"+ + "modification, are permitted provided that the following conditions\n"+ + "are met:\n"+ + "\n"+ + "Redistributions of source code must retain the above copyright notice,\n"+ + "this list of conditions and the following disclaimer. Redistributions in\n"+ + "binary form must reproduce the above copyright notice, this list of\n"+ + "conditions and the following disclaimer in the documentation and/or other\n"+ + "materials provided with the distribution. The name of the author may not\n"+ + "be used to endorse or promote products derived from this software without\n"+ + "specific prior written permission. \n"+ + " \n"+ + "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"+ + "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"+ + "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"+ + "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"+ + "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"+ + "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"+ + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"+ + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"+ + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"+ + "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; +} + diff --git a/src/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java b/src/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java new file mode 100644 index 0000000..39a8e5c --- /dev/null +++ b/src/batchtools/headless/src/test/java/com/galois/fiveui/ReporterTest.java @@ -0,0 +1,71 @@ +/** + * Module : Reporter.java Copyright : (c) 2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * @author Benjamin Jones + */ +package com.galois.fiveui; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import org.junit.Test; +import org.openqa.selenium.WebDriver; + +import com.google.common.collect.ImmutableList; + +public class ReporterTest { + + @Test + public void testConstructor() { + ImmutableList r = ImmutableList.of( + new Result(ResType.Pass, (WebDriver) null, "OK", "http://nonexistant", "test rule 1", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 1", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://nonexistant", "test rule 2", "a desc or test rule 1", "problem!")); + Reporter kermit = new Reporter(r); + System.out.println("Summary page size: " + kermit.getSummary().length() + " bytes"); + System.out.println("Summary page size: " + kermit.getByURL().length() + " bytes"); + System.out.println("Summary page size: " + kermit.getByRule().length() + " bytes"); + assertTrue(kermit.getSummary().length() > 0 && + kermit.getByURL().length() > 0 && + kermit.getByRule().length() > 0); + } + + @Test + public void testSummaryPage() throws IOException { + //File tmpPath = Files.createTempDir(); + File tmpPath = new File("/tmp/"); + System.out.println("Writing test summary page to: " + tmpPath.toString() + File.separator); + ImmutableList r = ImmutableList.of( + new Result(ResType.Pass, (WebDriver) null, "OK", "http://nonexistant", "test rule 1", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 1", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 3", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 4", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://intransigent", "test rule 5", "a desc or test rule 1", "problem!"), + new Result(ResType.Pass, (WebDriver) null, "OK", "http://foo.com", "test rule 1", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://foo.com", "test rule 5", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://foo.com", "test rule 2", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), // multiple fails for same url+rule combo + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://bar.com", "test rule 3", "a desc or test rule 1", "problem!"), + new Result(ResType.Error, (WebDriver) null, "ERROR", "http://nonexistant", "test rule 2", "a desc or test rule 1", "problem!")); + Reporter kermit = new Reporter(r); + kermit.writeReportsToDir(tmpPath.toString()); + assertTrue("made it!", true); + } +} diff --git a/src/batchtools/headless/src/test/resources/crawlTest/four.html b/src/batchtools/headless/src/test/resources/crawlTest/four.html new file mode 100644 index 0000000..a25405b --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/four.html @@ -0,0 +1,7 @@ + + four + + END + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one.html b/src/batchtools/headless/src/test/resources/crawlTest/one.html new file mode 100644 index 0000000..d5fae55 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one.html @@ -0,0 +1,12 @@ + + one + + two + one_a + one_b + one_c + one_d + one_e + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one_a.html b/src/batchtools/headless/src/test/resources/crawlTest/one_a.html new file mode 100644 index 0000000..3dd01ae --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one_a.html @@ -0,0 +1,6 @@ + + one_a + + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one_b.html b/src/batchtools/headless/src/test/resources/crawlTest/one_b.html new file mode 100644 index 0000000..dbbf635 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one_b.html @@ -0,0 +1,6 @@ + + one_b + + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one_c.html b/src/batchtools/headless/src/test/resources/crawlTest/one_c.html new file mode 100644 index 0000000..f1ef9bc --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one_c.html @@ -0,0 +1,6 @@ + + one_c + + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one_d.html b/src/batchtools/headless/src/test/resources/crawlTest/one_d.html new file mode 100644 index 0000000..2bfb0fd --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one_d.html @@ -0,0 +1,6 @@ + + one_d + + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/one_e.html b/src/batchtools/headless/src/test/resources/crawlTest/one_e.html new file mode 100644 index 0000000..3016b17 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/one_e.html @@ -0,0 +1,6 @@ + + one_e + + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/three.html b/src/batchtools/headless/src/test/resources/crawlTest/three.html new file mode 100644 index 0000000..a6f1c32 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/three.html @@ -0,0 +1,7 @@ + + three + + four + + + diff --git a/src/batchtools/headless/src/test/resources/crawlTest/two.html b/src/batchtools/headless/src/test/resources/crawlTest/two.html new file mode 100644 index 0000000..9fe3c68 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/crawlTest/two.html @@ -0,0 +1,7 @@ + + two + + three + + + diff --git a/src/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json b/src/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json new file mode 100644 index 0000000..a01bc68 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/ruleSets/emptyRuleSet.json @@ -0,0 +1,4 @@ +{ "name": "emptyRuleSet" +, "description": "" +, "rules": [] +} diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json new file mode 100644 index 0000000..e6c4c3b --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTest0.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://localhost:8000', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}] diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json new file mode 100644 index 0000000..07aaab8 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://www.cnn.com', + 'ruleSet': '../ruleSets/headingGuidelines.json' +}] diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json new file mode 100644 index 0000000..5e1e5e6 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json @@ -0,0 +1,10 @@ +{ + 'rulePath' : '/Users/bjones/galois/FiveUI/exampleData/ruleSets', + 'crawlType' : 'none', + 'runs': [ + { 'url': 'http://corp.galois.com', 'ruleSet': 'colorRulesRF.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'fontRules.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'headingGuidelines.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'imageRules.json' } + ] +} diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json new file mode 100644 index 0000000..2b3a51a --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample0.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://testhost', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}] diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json new file mode 100644 index 0000000..8e4d6c6 --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample1.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://testhost', + 'ruleSet': '../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json' +}] diff --git a/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json new file mode 100644 index 0000000..b5ea2ee --- /dev/null +++ b/src/batchtools/headless/src/test/resources/runDescriptions/headlessSample2.json @@ -0,0 +1,9 @@ +[ +{ + 'url': 'http://testhost1', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}, +{ + 'url': 'http://testhost2', + 'ruleSet': '../../../../../rsTester/src/test/resources/ruleSets/headingGuidelines.json' +}] diff --git a/src/batchtools/headless/test.html b/src/batchtools/headless/test.html new file mode 100644 index 0000000..e69de29 diff --git a/src/batchtools/pom.xml b/src/batchtools/pom.xml new file mode 100644 index 0000000..548cc0f --- /dev/null +++ b/src/batchtools/pom.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + 4.0.0 + com.galois.fiveui + BatchTools + 1.0 + pom + + + webdrivers + rsTester + headless + + + diff --git a/src/batchtools/rsTester/.buildpath b/src/batchtools/rsTester/.buildpath new file mode 100644 index 0000000..24e3b93 --- /dev/null +++ b/src/batchtools/rsTester/.buildpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/batchtools/rsTester/.classpath b/src/batchtools/rsTester/.classpath new file mode 100644 index 0000000..9fc2de7 --- /dev/null +++ b/src/batchtools/rsTester/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/batchtools/rsTester/.gitignore b/src/batchtools/rsTester/.gitignore new file mode 100644 index 0000000..7e7291c --- /dev/null +++ b/src/batchtools/rsTester/.gitignore @@ -0,0 +1,2 @@ +target +doc diff --git a/src/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs b/src/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs new file mode 100644 index 0000000..6e8a644 --- /dev/null +++ b/src/batchtools/rsTester/.settings/org.ebayopensource.vjet.eclipse.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +initialized_project_from_v4classpath=true diff --git a/src/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs b/src/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..abec6ca --- /dev/null +++ b/src/batchtools/rsTester/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/src/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs b/src/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/src/batchtools/rsTester/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/src/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs b/src/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..0512605 --- /dev/null +++ b/src/batchtools/rsTester/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,8 @@ +#Tue Jan 10 18:30:41 PST 2012 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/src/batchtools/rsTester/pom.xml b/src/batchtools/rsTester/pom.xml new file mode 100644 index 0000000..b3d637f --- /dev/null +++ b/src/batchtools/rsTester/pom.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + 4.0.0 + com.galois.fiveui + RuleSetTester + 1.0 + + + + onejar-maven-plugin.googlecode.com + http://onejar-maven-plugin.googlecode.com/svn/mavenrepo + + + + + + + + maven-assembly-plugin + + + + com.galois.fiveui.RuleSetTester + + + + jar-with-dependencies + + + + + org.dstovall + onejar-maven-plugin + 1.3.0 + + + + com.galois.fiveui.RuleSetTester + + + one-jar + + + + + + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 2.4.0-SNAPSHOT + + + + + + + org.seleniumhq.selenium + selenium-java + 2.25.0 + + + com.google.guava + guava + 10.0.1 + + + com.google.code.gson + gson + 2.1 + + + com.galois.fiveui + webdrivers + 0.0.1-SNAPSHOT + + + + + junit + junit + 4.11 + test + + + diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java new file mode 100644 index 0000000..e065128 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/BatchRunner.java @@ -0,0 +1,235 @@ +/** + * Module : BatchRunner.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Lists; + +/** + * BatchRunner is initialized with a WebDriver object. It provides an interface + * for running {@code RuleSet}s and {@code RuleTest}s with the WebDriver. + * + * @see #runTest + * @see #runRule + * @author creswick + */ +public class BatchRunner { + + private final WebDriver _driver; + private final JavascriptExecutor _exe; + + // Relative to the batch directory. + private static final String DATA_DIR = "../contexts/data/"; + private static final String J_QUERY_JS = DATA_DIR + + "lib/jquery/jquery-1.7.1.min.js"; + private static final String PRELUDE_JS = DATA_DIR + + "fiveui/injected/prelude.js"; + private static final String MD5_JS = DATA_DIR + + "lib/jshash/md5.js"; + private static final String JQUERY_PLUGIN_JS = DATA_DIR + + "fiveui/injected/jquery-plugins.js"; + private static final String SEL_INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/selenium/selenium-injected-compute.js"; + + private static final String INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/injected/fiveui-injected-compute.js"; + + /** + * BatchRunner constructor, stores the given WebDriver. + * + * @param driver the WebDriver object to run tests with + */ + public BatchRunner(WebDriver driver) { + _driver = driver; + _exe = (JavascriptExecutor) _driver; + } + + /** + * Run a collection of RuleTests and return the concatenated results. + * + * @param tests a list of RuleTest objects + * @return a list of Result objects + * @see #runTest + */ + public ImmutableList runTests(ImmutableList tests) { + Builder resBuilder = ImmutableList.builder(); + for (RuleTest test : tests) { + resBuilder.addAll(runTest(test)); + } + return resBuilder.build(); + } + + /** + * Run a RuleTest, returning the result (success, failure details, or + * indicator of exceptional conditions.) + *

+ * The test URI is loaded using the WebDriver and the rule set contained in + * {@code test} is run. + *

+ * For each result, look in the oracle collection for a corresponding ResType + * (exception, pass, error, ...). If one is found, remove it from the oracle + * and report that we got an expected result. If one is not found, report that + * we got an unexpected result. + *

+ * Finally, for each ResType left over in the oracle, report that we missed + * an expected result. + *

+ * Note: This method catches all exceptions generated during the rule run and + * reports them as "exception" ResType results in its return value. + * + * @param test a RuleTest to run + */ + public ImmutableList runTest(final RuleTest test) { + Rule rule = test.getRule(); + + ImmutableList rawResults; + Builder builder = ImmutableList.builder(); + try { + loadURL(test.getUri().toString()); // set state of the WebDriver + rawResults = runRule(rule); // run the ruleset, collect results + + List oracle = Lists.newArrayList(test.getOracle()); + for (Result result : rawResults) { + Result res; + if ( oracle.remove(result.getType()) ) { + res = Result.pass(_driver, + test.getRuleName() + ": Got expected result: "+result.getType()); + } else { + res = Result.error(_driver, + test.getRuleName() + ": Unexpected result: "+result); + } + builder.add(res); + } + for (ResType o : oracle) { + Result res = Result.error(_driver, + test.getRuleName() + ": missing expected result: "+o); + builder.add(res); + } + } catch (Exception e) { + String errStr = "Could not run rule: " + rule.getName() + "\n"; + errStr += e.toString(); + rawResults = ImmutableList.of( + Result.exception(_driver, "Could not run rule: "+errStr)); + + e.printStackTrace(); + } + + return builder.build(); + } + + /** + * Run a rule set on a page. + *

+ * This method uses the web driver instance to run a rule set on the currently + * loaded page. The webdriver injects javascript that + * includes all the dependencies (JQuery, etc..) as well as the function which + * executes the rule check. The method sleeps the thread for 1 second and + * queries the results, which are then parsed and returned as a list of + * Result objects. + * + * @param rule the rule to be run + * @return results of running the rule set + * @throws IOException + */ + private ImmutableList runRule(final Rule rule) throws IOException { + String contentScript = wrapRule(rule); + Builder builder = ImmutableList.builder(); + + _exe.executeScript(contentScript); + + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + + Object res = _exe.executeScript("return fiveui.selPort.query(type='ReportProblem')"); + + if (res.getClass() == String.class) { + // we received an error via the expected mechanisms: + System.err.println("Exception running rule: " + res); + builder.add(Result.exception(_driver, (String) res)); + return builder.build(); + } else { + + try { + @SuppressWarnings({ "unchecked", "rawtypes" }) + List>> results = (List) res; + + if (0 == results.size()) { + builder.add(Result.pass(_driver, "passed")); + } + + for (Map> r : results) { + Map problem = r.get("payload"); + + builder.add(Result.error(_driver, problem.get("descr"))); + } + + } catch (ClassCastException e) { + // An unexpected error happened: + builder.add(Result.exception(_driver, "Unexpected object returned: " + + res)); + e.printStackTrace(); + } + } + return builder.build(); + } + + /** + * Build up the complete content script needed to run the rule. + *

+ * The string returned contains all the javascript dependencies required + * to run a rule set and the function that is injected into the page which + * executes the rule set. + * + * @param rule a Rule object + * @throws IOException + */ + private String wrapRule(Rule rule) throws IOException { + String injected = ""; + injected += Utils.readFile(SEL_INJECTED_COMPUTE_JS); + injected += Utils.readFile(J_QUERY_JS); + injected += Utils.readFile(PRELUDE_JS); + injected += Utils.readFile(MD5_JS); + injected += Utils.readFile(JQUERY_PLUGIN_JS); + injected += Utils.readFile(INJECTED_COMPUTE_JS); + + injected += "return fiveui.selPort.send('SetRules', " + rule + ");"; + + return injected; + } + + /** + * Sets the state of the WebDriver by loading a given URL. + * + * @param url URL to load + */ + private void loadURL(String url) { + _driver.get(url); + } + +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java new file mode 100644 index 0000000..8341c6f --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RSTestDescription.java @@ -0,0 +1,321 @@ +package com.galois.fiveui; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.net.URI; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +/** + * RSTestDescriptions represent a set of tests for a specific RuleSet. + * + * RSTestDescriptions are also JSON-serializiable (and deserializable). + * + * An example of the JSON is given below: + * + *

+ * {@code
+ * { 'ruleSet': '../../exampleData/ruleSets/headingGuidelines.json',
+ *   'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html',
+ *                'oracle': [ { 'ruleName': "Headings are capitalized"
+ *                            , 'results': ['Error', 'Error']
+ *                            },
+ *                            { 'ruleName': "Disallow Empty Headers"
+ *                            , 'results': ['Error']
+ *                            }
+ *                          ]
+ *              }
+ *            ]
+ * }
+ * }
+ * 
+ * + * {@code tests} is as list that may contain a number of urls and sets of + * expected Problems for the specified rule set and url combination. + * + * {@code ruleSet} is a string file path that is relative to the rule set + * description json file. + * + * @author creswick + * + */ +public class RSTestDescription { + + /** + * Parse a JSON file into a RSTestDescription + * + * @param runDescFileName The file to load. + * @return A populated RunDescription object. + * @throws FileNotFoundException if runDescFile can't be found. + */ + public static RSTestDescription parse(String runDescFileName) + throws FileNotFoundException { + + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(RSTestDescription.class, + new RSTestDescription.Deserializer(runDescFileName)); + Gson gson = gsonBuilder.create(); + + Reader in = new InputStreamReader(new FileInputStream(runDescFileName)); + + return gson.fromJson(in, RSTestDescription.class); + } + + public static class Deserializer implements JsonDeserializer { + + private final String _descFile; + + public Deserializer(String descFile) { + _descFile = descFile; + } + + public RSTestDescription deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + + JsonObject obj = json.getAsJsonObject(); + + String ruleSet = obj.get("ruleSet").getAsString(); + JsonArray testArray = obj.get("tests").getAsJsonArray(); + + List tests = Lists.newArrayList(); + for (JsonElement jsonElement : testArray) { + tests.add((URIMap)context.deserialize(jsonElement, URIMap.class)); + } + + String descDir = new File(_descFile).getParent(); + if (null == descDir) { + descDir = "."; + } + + // This probably is not portable, because the ruleSet path separator + // may not match that of the file system. + // TODO if File.separator is not "/", then replace "\" with File.separator. + String rsPath = descDir + File.separator + ruleSet; + + RuleSet parsed; + try { + parsed = RuleSet.parseFile(rsPath); + } catch (IOException e) { + e.printStackTrace(); + throw new JsonParseException(e.getMessage()); + } + //RuleSet parsed = gson.fromJson(rsPath, RuleSet.class); + + return new RSTestDescription(rsPath, tests, parsed); + } + } + + /** + * The path to the selected rule set. + */ + private final String _ruleSetLoc; + + /** + * A list of urls and oracles that define tests for the specified RuleSet. + */ + private final List _tests; + + private final RuleSet _ruleSet; + + public RSTestDescription(String ruleSetLoc, List tests, RuleSet ruleSet) { + _ruleSetLoc = ruleSetLoc; + _tests = tests; + _ruleSet = ruleSet; + } + + public RuleSet getRuleSet() { + return _ruleSet; + } + + public String getRuleSetLoc() { + return _ruleSetLoc; + } + + /** + * Combines the URI in each test from the rule set test description with + * each rule that accompanies it. + *

+ * The result is a list of RuleTest objects + * that each contain: a URI and rule set (to be run), a rule ID and list + * of results the we expect from the run. + * + * @return a list of RuleTest objects + * @throws IOException + */ + public ImmutableList getTests() throws IOException { + Builder builder = ImmutableList.builder(); + for (URIMap uriMap : _tests) { + for (RuleMap rMap : uriMap.getOracle()) { + builder.add( + new RuleTest(uriMap.getUrl(), getRuleSet(), rMap.getRuleName(), rMap.getResults())); + } + } + return builder.build(); + } + + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((_ruleSet == null) ? 0 : _ruleSet.hashCode()); + result = prime * result + + ((_ruleSetLoc == null) ? 0 : _ruleSetLoc.hashCode()); + result = prime * result + ((_tests == null) ? 0 : _tests.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RSTestDescription other = (RSTestDescription) obj; + if (_ruleSet == null) { + if (other._ruleSet != null) + return false; + } else if (!_ruleSet.equals(other._ruleSet)) + return false; + if (_ruleSetLoc == null) { + if (other._ruleSetLoc != null) + return false; + } else if (!_ruleSetLoc.equals(other._ruleSetLoc)) + return false; + if (_tests == null) { + if (other._tests != null) + return false; + } else if (!_tests.equals(other._tests)) + return false; + return true; + } + + public static class URIMap { + private URI url; + private List oracle; + + URIMap(){} + + public URIMap(URI url, List oracle) { + super(); + this.url = url; + this.oracle = oracle; + } + + public URI getUrl() { + return url; + } + + public List getOracle() { + return oracle; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((oracle == null) ? 0 : oracle.hashCode()); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + URIMap other = (URIMap) obj; + if (oracle == null) { + if (other.oracle != null) + return false; + } else if (!oracle.equals(other.oracle)) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + return true; + } + } + + public static class RuleMap { + private String ruleName; + private List results; + + public RuleMap(String ruleName, List results) { + super(); + this.ruleName = ruleName; + this.results = results; + } + + public String getRuleName() { + return ruleName; + } + + public List getResults() { + return results; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((results == null) ? 0 : results.hashCode()); + result = prime * result + + ((ruleName == null) ? 0 : ruleName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RuleMap other = (RuleMap) obj; + if (results == null) { + if (other.results != null) + return false; + } else if (!results.equals(other.results)) + return false; + if (ruleName == null) { + if (other.ruleName != null) + return false; + } else if (!ruleName.equals(other.ruleName)) + return false; + return true; + } + } + +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java new file mode 100644 index 0000000..ef14a60 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/ResType.java @@ -0,0 +1,32 @@ +/** + * Module : ResType.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.galois.fiveui; + +/** +* Results are organized into categories as follows: +*

    +*
  1. exception: an uncaught exception occurred while running the rule set
  2. +*
  3. pass: the expected result was returned
  4. +*
  5. error: an unexpected result was returned
  6. +*
  7. warning: a warning was returned, currently this type is unused
  8. +*
+*/ +public enum ResType { + Pass, Error, Warning, Exception +} \ No newline at end of file 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 new file mode 100644 index 0000000..6543476 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Result.java @@ -0,0 +1,174 @@ +/** + * Module : Result.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import org.openqa.selenium.WebDriver; + +/** + * A Result object encapsulates the result of running a rule set check on a URL + * with a WebDriver. Results are organized into four categories: + *
    + *
  1. exception: an uncaught exception occurred while running the rule set
  2. + *
  3. pass: the expected result was returned
  4. + *
  5. error: an unexpected result was returned
  6. + *
  7. warning: a warning was returned, currently this type is unused
  8. + *
+ */ +public class Result { + + private ResType _type; + private String _msg; + private WebDriver _driver; + private String _url; + private String _ruleName; + private String _ruleDesc; + private String _prob; + + /** + * Construct a new result of one of the four types. + * + * @param type type of the result + * @param driver WebDriver that the result comes from + * @param msg any additional information from the rule runner + * @param url url + * @param ruleName rule name + * @param ruleDesc rule description + * @param prob problem description + */ + public Result(ResType type, WebDriver driver, String msg, String url, + String ruleName, String ruleDesc, String prob) { + super(); + _type = type; + _msg = msg; + _driver = driver; + _url = url; + _ruleName = ruleName; + _ruleDesc = ruleDesc; + _prob = prob; + } + + /** + * An information restricted version of the other public constructor. This + * constructor does not include URL, rule, or problem information. + */ + public Result(ResType type, WebDriver driver, String msg) { + super(); + _type = type; + _msg = msg; + _driver = driver; + _url = ""; + _ruleName = ""; + _ruleDesc = ""; + _prob = ""; + } + + /********************************************************************************** + * Factory methods: these provide easy construction of restricted Result + * types. + */ + + /** + * Result constructor, returns an "exception" type result. + * + * @param driver WebDriver the result came from + * @param res description of the result + * @return a Result object + */ + public static Result exception(WebDriver driver, String res) { + return new Result(ResType.Exception, driver, res); + } + + /** + * Result constructor, returns a "pass" type result. + * + * @param driver WebDriver the result came from + * @param res description of the result + * @return a Result object + */ + public static Result pass(WebDriver driver, String res) { + return new Result(ResType.Pass, driver, res); + } + + /** + * Result constructor, returns an "error" type result. + * + * @param driver WebDriver the result came from + * @param res description of the result + * @return a Result object + */ + public static Result error(WebDriver driver, String res) { + return new Result(ResType.Error, driver, res); + } + + /** + * Result constructor, returns a "warning" type result. + * + * @param driver WebDriver the result came from + * @param res description of the result + * @return a Result object + */ + public static Result warning(WebDriver driver, String res) { + return new Result(ResType.Warning, driver, res); + } + + /********************************************************************************** + * Extractor methods + */ + + public ResType getType() { + return _type; + } + + public String getMsg() { + return _msg; + } + + public WebDriver getDriver() { + return _driver; + } + + public String getURL() { + return _url; + } + + public String getRuleName() { + return _ruleName; + } + + public String getRuleDesc() { + return _ruleDesc; + } + + public String getProblem() { + return _prob; + } + + /** + * Stringify the result, returning the type, driver name, and + * full description. + */ + @Override + public String toString() { + return getType() + " - " + _driver.toString().split(":")[0] + ": " + + _msg + "\n" + + " |\\- " + _url + "\n" + + " |\\_ " + _ruleName + "\n" + + " |\\_ " + _ruleDesc + "\n" + + " \\_ " + _prob; + } +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java new file mode 100644 index 0000000..3f420cb --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Rule.java @@ -0,0 +1,122 @@ +/** + * Module : Rule.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.util.HashMap; + +import org.openqa.selenium.htmlunit.HtmlUnitDriver; + +import com.google.gson.Gson; + +public class Rule { + + /** + * Parse a string representation of a Rule into a Java POJO. + * + * @param str string representing a rule set + * @return a RuleSet object + */ + @SuppressWarnings("unchecked") + public static final Rule parse(String str) { + HtmlUnitDriver driver = new HtmlUnitDriver(true); + String name = ""; + String desc = ""; + String ruleStr = ""; + HashMap res = null; + String stmt = "exports = {};\n"+str + "; return exports;"; + try { + driver.get("http://localhost:8000/test.html"); + res = (HashMap) driver.executeScript(stmt); + name = (String) res.get("name"); + desc = (String) res.get("description"); + ruleStr = res.get("rule").toString(); + } finally { + driver.quit(); + } + + return new Rule(name, desc, ruleStr); + } + + private final String _name; + private final String _desc; + private final String _rule; + + public Rule(final String name, final String desc, final String rule) { + this._name = name; + this._desc = desc; + this._rule = rule; + } + + public String getName() { + return _name; + } + + public String getDescription() { + return _desc; + } + + public String getRule() { + return _rule; + } + + @Override + public String toString() { + Gson gson = new Gson(); + + return "exports.name = " + gson.toJson(getName()) + ";\n" + + "exports.description = " + gson.toJson(getDescription()) + ";\n" + + "exports.rule = " + gson.toJson(getRule()) + ";\n"; + } + + /** + * Equals and hashCode ignore the rule function text when performing comparisons. + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((_desc == null) ? 0 : _desc.hashCode()); + result = prime * result + ((_name == null) ? 0 : _name.hashCode()); + return result; + } + + /** + * Equals and hashCode ignore the rule function text when performing comparisons. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Rule other = (Rule) obj; + if (_desc == null) { + if (other._desc != null) + return false; + } else if (!_desc.equals(other._desc)) + return false; + if (_name == null) { + if (other._name != null) + return false; + } else if (!_name.equals(other._name)) + return false; + return true; + } +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java new file mode 100644 index 0000000..ed9bc99 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSet.java @@ -0,0 +1,154 @@ +/** + * Module : RuleSet.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class RuleSet { + + public static RuleSet parseFile(String rsFileName) throws JsonSyntaxException, IOException { + String descDir = new File(rsFileName).getParent(); + + Gson gson = new Gson(); + RuleSet rs = gson.fromJson(Utils.readFile(rsFileName), RuleSet.class); + + rs.setDirectory(descDir); + return rs; + } + + public void setDirectory(String descDir) { + this.descDir = descDir; + } + + private final String name; + private final String description; + private final List rules; + + private transient ImmutableMap _evaledRules = null; + + private transient String descDir = "."; + + public RuleSet(String name, String description, List ruleFiles) { + this.name = name; + this.description = description; + this.rules = ruleFiles; + } + + private void parseRules() { + ImmutableMap.Builder builder = ImmutableMap.builder(); + + // Parse all the rules from files: + for (String r : rules) { + String adjustedPath = descDir + File.separator + r; + try { + Rule evRule = Rule.parse( + Utils.readFile(adjustedPath)); + + builder.put(evRule.getName(), evRule); + } catch (IOException e) { + System.err.println("Could not load rule from file: "+adjustedPath); + System.err.println(" error: "+e); + } + } + + _evaledRules = builder.build(); + } + + /** + * Construct a new empty rule set. + * + * @return a new empty RuleSet object + */ + public static RuleSet empty() { + List rules = Lists.newArrayList(); + return new RuleSet("", "", ImmutableList.copyOf(rules)); + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public ImmutableCollection getRules() { + if (null == _evaledRules) { + parseRules(); + } + + return _evaledRules.values(); + } + + public Rule getRule(String ruleName) { + return _evaledRules.get(ruleName); + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((rules == null) ? 0 : rules.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RuleSet other = (RuleSet) obj; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (rules == null) { + if (other.rules != null) + return false; + } else if (!rules.equals(other.rules)) + return false; + return true; + } +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java new file mode 100644 index 0000000..3c85b22 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleSetTester.java @@ -0,0 +1,91 @@ +/** + * Module : BatchExecutor.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.openqa.selenium.WebDriver; + +import com.galois.fiveui.drivers.Drivers; +import com.google.common.collect.ImmutableList; + +/** + * The main entry point for testing Rule Sets. + *

+ * The {@link #main(String[])} method of this class sets up a WebDriver, loads + * a test run description from disk, and executes the test run which includes + * loading URL's and running rule sets on their content. + * + * @author creswick + * + */ +public class RuleSetTester { + + /** + * @param args + * @throws IOException + * @throws URISyntaxException + */ + public static void main(final String[] args) throws IOException, + URISyntaxException { + + if (0 == args.length) { + printHelp(); + System.exit(1); + } + + for (int i = 0; i < args.length; i++) { + String runDescFileName = args[i]; + RSTestDescription descr = RSTestDescription.parse(runDescFileName); + + for (WebDriver driver : getDrivers()) { + try { + ImmutableList results = invokeTest(descr, driver); + + for (Result result : results) { + System.out.println(result); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + driver.quit(); + } + } + } + } + + private static ImmutableList getDrivers() { + return ImmutableList.of( + Drivers.buildFFDriver() + // , Drivers.buildChromeDriver() + ); + } + + private static void printHelp() { + System.out.println( + "Usage: RuleSetTester []"); + } + + private static ImmutableList invokeTest(RSTestDescription descr, + WebDriver driver) throws IOException { + BatchRunner runner = new BatchRunner(driver); + + return runner.runTests(descr.getTests()); + } +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java new file mode 100644 index 0000000..acf6743 --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/RuleTest.java @@ -0,0 +1,76 @@ +/** + * Module : RuleTest.java + * Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : + * Stability : Provisional + * Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.galois.fiveui; + +import java.net.URI; +import java.util.Collection; + +import com.google.common.collect.ImmutableMultiset; + +/** + * A RuleTest object encapsulates the following data: + *

    + *
  1. a URI on which to run rules, accessed using {@code getUri}
  2. + *
  3. a RuleSet object encapsulating the rule to run on the URI
  4. + *
  5. a rule ID, signifying we expect results for the corresponding rule + * (defined in the rule set) of the type(s) given in the oracle
  6. + *
  7. an oracle, the expected results of the test
  8. + *
+ * + * @author creswick + * + */ +public class RuleTest { + + private final URI _uri; + private final RuleSet _ruleSet; + private final String _ruleName; + private final ImmutableMultiset _oracle; + + public RuleTest(URI uri, RuleSet ruleSet, String ruleName, Collection oracle) { + _uri = uri; + _ruleSet = ruleSet; + _ruleName = ruleName; + _oracle = ImmutableMultiset.copyOf(oracle); + } + + public Rule getRule() { + return _ruleSet.getRule(_ruleName); + } + + public URI getUri() { + return _uri; + } + + public RuleSet getRuelSet() { + return _ruleSet; + } + + public String getRuleName() { + return _ruleName; + } + + public ImmutableMultiset getOracle() { + return _oracle; + } + + +} diff --git a/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java new file mode 100644 index 0000000..429997f --- /dev/null +++ b/src/batchtools/rsTester/src/main/java/com/galois/fiveui/Utils.java @@ -0,0 +1,44 @@ +/** + * Module : Utils.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.google.common.io.CharStreams; + +/** + * Provides helper functions for reading files from disk. + * + * @author creswick + */ +public class Utils { + + public static String readFile(String fileName) throws IOException { + InputStream in = new FileInputStream(new File(fileName)); + return readStream(in); + } + + public static String readStream(final InputStream stream) + throws IOException { + return CharStreams.toString(new InputStreamReader(stream)); + } +} diff --git a/src/batchtools/rsTester/src/main/resources/javascript/ruleEval.js b/src/batchtools/rsTester/src/main/resources/javascript/ruleEval.js new file mode 100644 index 0000000..04e81ba --- /dev/null +++ b/src/batchtools/rsTester/src/main/resources/javascript/ruleEval.js @@ -0,0 +1,74 @@ +/** + * Module : ruleEval.js + * Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : + * Stability : Provisional + * Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Evaluate a rule. + * + * @param {!string} ruleStr The string representation of the rule (as + * a JavaScript Object literal). + * @return {?Array} Empty if no problems were found or a string + * with an error if an exception occurred. + */ +var evaluate = function(ruleName, description, ruleStr) { + var theRule = null; + var results = []; + +// return [{ 'name': 'some rule', +// 'descr': 'some description', +// 'url': 'http:\/\/localhost:8000', +// 'severity': '1' +// }]; +//}; + + var report = function(name, node) { + var prob = { + 'name': name, + 'descr': description, + 'url': window.location.href, + 'severity': 1 + }; + + results.push(prob); + }; + + try { + eval('var theRule = '+ruleStr); + return theRule.toString(); + } catch (x) { +// console.log('could not load rule: '+ruleStr); +// console.log(x); + return "Error: "+x; + } + + var scope = { + name : ruleName, + description : description + }; + + if (theRule) { + try { + theRule.apply(scope); + } catch (x) { +// console.log('exception running rule: '+theRule.name); +// console.log(x); + return "Error: "+x; + } + } + return results; +}; diff --git a/src/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver b/src/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver new file mode 100755 index 0000000..b0a0e4a Binary files /dev/null and b/src/batchtools/rsTester/src/main/resources/seleniumDrivers/linux64/chromedriver differ diff --git a/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java new file mode 100644 index 0000000..5db53f8 --- /dev/null +++ b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRuleSetParseTest.java @@ -0,0 +1,115 @@ +/** + * + * Copyright (c) 2009-2013, + * + * Galois, Inc. (creswick) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + */ +package com.galois.fiveui; + +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.collect.Lists; + +/** + * @author creswick + * + */ +@RunWith(Parameterized.class) +public class BasicRuleSetParseTest { + + /** + * Set up the tests via the parameterized runner: + * + * @return + * @throws Throwable + */ + @Parameters(name = "{0} {1}") + public static Collection setup() throws Throwable { + List tests = Lists.newArrayList(); + + Object[][] rawTests = new Object[][] { + { "ruleSets/emptyRuleSet.json", true }, + { "ruleSets/simpleRuleSet1.json", true }, + { "ruleSets/headingGuidelines.json", true }, + }; + + for (Object[] descr : rawTests) { + tests.add(descr); + } + + return tests; + } + + /** + * The path (relative to test resources) to the file to test. + */ + private final String _filePath; + + private final boolean _parses; + + public BasicRuleSetParseTest(String path, boolean parses) { + this._filePath = path; + this._parses = parses; + } + + /** + * Try and parse the file, no oracle other than the expected success/fail. + * + * @throws Exception + */ + @Test + public void testParse() throws Exception{ + boolean actual = false; + String msg = ""; + try { + RuleSet desc = RuleSet.parseFile("src/test/resources/"+_filePath); + // if desc is not null, we assume the parse worked: + actual = (desc != null); + } catch (Exception e) { + // if an exception was thrown, then we assume the parse failed: + msg = e.getMessage(); + actual = false; + } finally { + // test to see if the parse result matched the expectation. + Assert.assertEquals("Parse did not complete as expected: "+msg, + _parses, actual); + } + } +} diff --git a/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java new file mode 100644 index 0000000..57cf772 --- /dev/null +++ b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/BasicRunDescriptionParseTest.java @@ -0,0 +1,126 @@ +/** + * + * Copyright (c) 2009-2013, + * + * Galois, Inc. (creswick) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + */ +package com.galois.fiveui; + +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.collect.Lists; + +/** + * @author creswick + * + */ +@RunWith(Parameterized.class) +public class BasicRunDescriptionParseTest { + + /** + * Set up the tests via the parameterized runner: + * + * @return + * @throws Throwable + */ + @Parameters(name = "{0} {1}") + public static Collection setup() throws Throwable { + List tests = Lists.newArrayList(); + + Object[][] rawTests = new Object[][] { + { "runDescriptions/sample0.json", true }, + { "runDescriptions/sample1.json", true }, + { "runDescriptions/sample2.json", true }, + + // This should test that tests must have run ids, + // but that can't be enforced with gson's standard deserializers. + // { "runDescriptions/sample2-fails.json", false }, + + { "runDescriptions/sample3.json", true }, + { "runDescriptions/sample4.json", true }, + { "runDescriptions/sample5.json", true }, + { "runDescriptions/headingSample.json", true }, + { "runDescriptions/headingSample-1-fails.json", true }, + { "runDescriptions/headingSample-2-fails.json", true }, + }; + + for (Object[] descr : rawTests) { + tests.add(descr); + } + + return tests; + } + + /** + * The path (relative to test resources) to the file to test. + */ + private final String _filePath; + + private final boolean _parses; + + public BasicRunDescriptionParseTest(String path, boolean parses) { + this._filePath = path; + this._parses = parses; + } + + /** + * Try and parse the file, no oracle other than the expected success/fail. + * + * @throws Exception + */ + @Test + public void testParse() throws Exception{ + boolean actual = false; + String msg = ""; + try { + RSTestDescription desc = RSTestDescription.parse("src/test/resources/"+_filePath); + // if desc is not null, we assume the parse worked: + actual = (desc != null); + } catch (Exception e) { + // if an exception was thrown, then we assume the parse failed: + msg = e.getMessage(); + actual = false; + } finally { + // test to see if the parse result matched the expectation. + Assert.assertEquals("Parse did not complete as expected: "+msg, + _parses, actual); + } + } +} diff --git a/src/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java new file mode 100644 index 0000000..0d5d4c4 --- /dev/null +++ b/src/batchtools/rsTester/src/test/java/com/galois/fiveui/RunDescriptionTest.java @@ -0,0 +1,118 @@ +/** + * RunDescriptionTest.java + * + * Copyright (c) 2012 Galois, Inc. + */ +package com.galois.fiveui; + +import java.io.FileNotFoundException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; + +import org.junit.Assert; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * @author creswick + * + */ +public class RunDescriptionTest { + + private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; + + /** + * Test method for {@link com.galois.fiveui.RSTestDescription}. + * @throws FileNotFoundException + */ + @Test + public final void testDeserialize_sample0() throws FileNotFoundException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "sample0.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; + + ImmutableList emptyRuleList = ImmutableList.of(); + RuleSet rsOracle = new RuleSet("emptyRuleSet", "", emptyRuleList); + + RSTestDescription oracle = + new RSTestDescription(ruleSetLoc, + new ArrayList(), rsOracle); + + + RSTestDescription actual = RSTestDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.fiveui.RSTestDescription}. + * @throws FileNotFoundException + */ + @Test + public final void testDeserialize_sample1() throws FileNotFoundException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "sample1.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/simpleRuleSet1.json"; + + RuleSet rsOracle = + new RuleSet("simpleRuleSet1", "", ImmutableList.of("emptyCheck.js")); + rsOracle.setDirectory(RUN_DESCRIPTION_DIR + "../ruleSets/"); + + RSTestDescription oracle = + new RSTestDescription(ruleSetLoc, + new ArrayList(), rsOracle); + + + RSTestDescription actual = RSTestDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.fiveui.RSTestDescription}. + * @throws FileNotFoundException + * @throws URISyntaxException + */ + @Test + public final void testDeserialize_headingGuidelines() throws FileNotFoundException, URISyntaxException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headingSample.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/headingGuidelines.json"; + + RuleSet rsOracle = new RuleSet( + "Heading Guidelines", + "Guidelines pertaining to the formatting and content of headings.", + ImmutableList.of("headingGuidelines-caps.js", + "headingGuidelines-noEmptyHdrs.js")); + rsOracle.setDirectory(RUN_DESCRIPTION_DIR + "../ruleSets/"); + rsOracle.getRules(); // force the rules to parse + + RSTestDescription.URIMap uriMapOracle = + new RSTestDescription.URIMap( + new URI("http://localhost:8000/exampleData/basic/headings.html"), + + Lists.newArrayList( + new RSTestDescription.RuleMap("Headings are capitalized", + Lists.newArrayList(ResType.Error, ResType.Error)), + new RSTestDescription.RuleMap("Disallow Empty Headers", + Lists.newArrayList(ResType.Error)))); + + + RSTestDescription oracle = + new RSTestDescription(ruleSetLoc, Lists.newArrayList(uriMapOracle), rsOracle); + + + RSTestDescription actual = RSTestDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + private void assertObjEqual(String msg, Object oracle, Object actual) { + Assert.assertTrue(msg + "; expected: "+oracle+" actual: "+actual, + oracle.equals(actual)); + } + + +} diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js b/src/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js new file mode 100644 index 0000000..6588e5b --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/emptyCheck.js @@ -0,0 +1,6 @@ +exports.name = 'Empty Rule'; + +exports.description = 'A rule with no body, used for testing.'; + +exports.rule = function() { }; + diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json b/src/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json new file mode 100644 index 0000000..a01bc68 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/emptyRuleSet.json @@ -0,0 +1,4 @@ +{ "name": "emptyRuleSet" +, "description": "" +, "rules": [] +} diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js new file mode 100644 index 0000000..f6c1cb6 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-caps.js @@ -0,0 +1,19 @@ +exports.name = "Headings are capitalized"; + +exports.description = "Check to see if all headings use leading capital letters."; + +exports.rule = function() { + var badHeadings = + fiveui.query(':header').filter( + function(idx) { + var ch = $(this).text()[0]; + if (ch) { + return (ch == ch.toLowerCase() ); + } else { + return false; + } + }); + $(badHeadings).map(function(idx, elt){ + report('Heading does not start with a capitol letter.', elt); + }); +}; diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js new file mode 100644 index 0000000..a70f71c --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines-noEmptyHdrs.js @@ -0,0 +1,12 @@ +exports.name = "Disallow Empty Headers"; + +exports.description = "Heading elements should contain text."; + +exports.rule = function() { + fiveui.query(':header').each( + function(ix, elt) { + if($(elt).text() == '') { + report('Heading does not contain text', elt); + } + }); + }; diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json new file mode 100644 index 0000000..330f389 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/headingGuidelines.json @@ -0,0 +1,6 @@ +{ "name": "Heading Guidelines" +, "description": "Guidelines pertaining to the formatting and content of headings." +, "rules": [ "headingGuidelines-caps.js", + "headingGuidelines-noEmptyHdrs.js" + ] +} \ No newline at end of file diff --git a/src/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json b/src/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json new file mode 100644 index 0000000..71905cd --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/ruleSets/simpleRuleSet1.json @@ -0,0 +1,4 @@ +{ "name": "simpleRuleSet1" +, "description": "" +, "rules": [ "emptyCheck.js" ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json new file mode 100644 index 0000000..23860b4 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-1-fails.json @@ -0,0 +1,13 @@ +{ + 'ruleSet': '../ruleSets/headingGuidelines.json', + 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', + 'oracle': [ { 'ruleName': "Headings are capitalized" + , 'results': ['Error'] /* actually errors twice */ + }, + { 'ruleName': "Disallow Empty Headers" + , 'results': ['Error'] + } + ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json new file mode 100644 index 0000000..8a1cb38 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample-2-fails.json @@ -0,0 +1,13 @@ +{ + 'ruleSet': '../ruleSets/headingGuidelines.json', + 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', + 'oracle': [ { 'ruleName': "Headings are capitalized" + , 'results': ['Error', 'Error', 'Error'] /* actually only errors twice */ + }, + { 'ruleName': "Disallow Empty Headers" + , 'results': ['Error'] + } + ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json new file mode 100644 index 0000000..69deb49 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/headingSample.json @@ -0,0 +1,13 @@ +{ + 'ruleSet': '../ruleSets/headingGuidelines.json', + 'tests': [ { 'url': 'http://localhost:8000/exampleData/basic/headings.html', + 'oracle': [ { 'ruleName': "Headings are capitalized" + , 'results': ['Error', 'Error'] + }, + { 'ruleName': "Disallow Empty Headers" + , 'results': ['Error'] + } + ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json new file mode 100644 index 0000000..0c2bbb7 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample0.json @@ -0,0 +1,4 @@ +{ + 'ruleSet': '../ruleSets/emptyRuleSet.json', + 'tests': [] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json new file mode 100644 index 0000000..91f8f34 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample1.json @@ -0,0 +1,4 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json new file mode 100644 index 0000000..a8ea9ec --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2-fails.json @@ -0,0 +1,10 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [ { 'url': 'http://localhost:8000/', + 'oracle': [ { 'ruleId': 42 + , 'results': ['Error', 'Error'] + } + ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json new file mode 100644 index 0000000..acff2d7 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample2.json @@ -0,0 +1,10 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [ { 'url': 'http://localhost:8000/', + 'oracle': [ { 'ruleName': 'Empty Rule' + , 'results': [] + } + ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json new file mode 100644 index 0000000..e4d1cea --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample3.json @@ -0,0 +1,7 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [ { 'url': 'http://localhost:8000/', + 'oracle': [ ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json new file mode 100644 index 0000000..c4f46cd --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample4.json @@ -0,0 +1,10 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [ { 'url': 'http://localhost:8000/', + 'oracle': [ ] + }, + { 'url': 'http://localhost:8000/', + 'oracle': [ ] + } + ] +} diff --git a/src/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json new file mode 100644 index 0000000..11ca957 --- /dev/null +++ b/src/batchtools/rsTester/src/test/resources/runDescriptions/sample5.json @@ -0,0 +1,13 @@ +{ + 'ruleSet': '../ruleSets/simpleRuleSet1.json', + 'tests': [ { 'url': 'http://localhost:8000/', + 'oracle': [ { 'ruleId': 42 + , 'results': ['Error'] + } + ] + }, + { 'url': 'http://localhost:8000/', + 'oracle': [ ] + } + ] +} diff --git a/src/batchtools/rsTester/test.html b/src/batchtools/rsTester/test.html new file mode 100644 index 0000000..e69de29 diff --git a/src/batchtools/webdrivers/.classpath b/src/batchtools/webdrivers/.classpath new file mode 100644 index 0000000..75e85b7 --- /dev/null +++ b/src/batchtools/webdrivers/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/batchtools/webdrivers/.gitignore b/src/batchtools/webdrivers/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/src/batchtools/webdrivers/.gitignore @@ -0,0 +1 @@ +target diff --git a/src/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs b/src/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..abec6ca --- /dev/null +++ b/src/batchtools/webdrivers/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/src/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs b/src/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/src/batchtools/webdrivers/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/src/batchtools/webdrivers/pom.xml b/src/batchtools/webdrivers/pom.xml new file mode 100644 index 0000000..4d8847f --- /dev/null +++ b/src/batchtools/webdrivers/pom.xml @@ -0,0 +1,43 @@ + + 4.0.0 + com.galois.fiveui + webdrivers + 0.0.1-SNAPSHOT + Web Drivers + Wrapper around Selenium Web Driver creation to handle configuration details that we wish to be uniform across all FiveUI applications. + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.5 + 1.5 + + + + + + + + junit + junit + 4.9 + test + + + + org.seleniumhq.selenium + selenium-java + 2.25.0 + + + + com.google.guava + guava + 10.0.1 + + + 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 new file mode 100644 index 0000000..db73fec --- /dev/null +++ b/src/batchtools/webdrivers/src/main/java/com/galois/fiveui/drivers/Drivers.java @@ -0,0 +1,149 @@ +/** + * Module : Drivers.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.galois.fiveui.drivers; + +import java.io.File; +import java.io.IOException; + +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.firefox.FirefoxBinary; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxProfile; + +/** + * @author creswick + * + */ +public class Drivers { + private static final String FIREFOX_BIN_PATH = "FIREFOX_BIN_PATH"; + private static final String CHROME_BIN_PATH = "CHROME_BIN_PATH"; + + private static final String CD_BINARY_NAME = "chromedriver"; + private static final String CD_BASE_PATH = mkPath("..", "tools", + "seleniumChromeDrivers"); + + private static final String FIVEUI_ROOT_PATH = "FIVEUI_ROOT_PATH"; + private static final String defaultFiveuiRootPath = "../../../"; + private static final String firefoxProfilePath = "profiles/firefox"; + private static final String chromeProfilePath = "profiles/chrome"; + private static final String firefoxExtensionPath = "binaries/fiveui.xpi"; + private static final String chromeExtensionPath = "binaries/fiveui.crx"; + + /** + * Query the OS environment for the FiveUI root path, or return a default. + */ + public static String getRootPath() { + String rootPath = System.getProperty(FIVEUI_ROOT_PATH); + return (null != rootPath) ? rootPath + File.separator : defaultFiveuiRootPath; + } + + public static FirefoxDriver buildFFDriver() { + // Extracted into a method so we can set up profiles + + String rootPath = getRootPath(); + + File profileDir = new File(rootPath+firefoxProfilePath); + 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); + + FirefoxDriver driver; + if (null == ffBinaryPath) { + System.err + .println("WARNING: Running essentially random version of FireFox!"); + System.err.println(" set a path to firefox with -D" + + FIREFOX_BIN_PATH + "="); + driver = new FirefoxDriver(profile); + } else { + FirefoxBinary binary = new FirefoxBinary(new File(ffBinaryPath)); + driver = new FirefoxDriver(binary, profile); + } + + return driver; + } + + public static ChromeDriver buildChromeDriver() { + + String rootPath = getRootPath(); + + // set the chrome driver path: + String chromeDriverPth = + mkPath(CD_BASE_PATH, osNameArch(), CD_BINARY_NAME); + System.setProperty("webdriver.chrome.driver", chromeDriverPth); + + // setting the path to chrome also seems to cause issues: + ChromeOptions options = new ChromeOptions(); + 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) { + System.err + .println("WARNING: Running essentially random version of Chrome!"); + System.err.println(" set a path to Chrome with -D" + + CHROME_BIN_PATH + "="); + } else { + options.setBinary(new File(chromeBinaryPath)); + } + // For use with ChromeDriver: + return new ChromeDriver(options); + } + + private static String mkPath(String... components) { + StringBuilder path = new StringBuilder(); + int remaining = components.length; + for (String c : components) { + path.append(c); + remaining--; + if (remaining != 0) { + path.append(File.separator); + } + } + + return path.toString(); + } + + /** + * Determine the name of the directory that the chromedriver is in, based on + * os.name and os.arch. + * + * @return The name of the directory containing 'chromedriver' + */ + private static String osNameArch() { + String rawOsName = System.getProperty("os.name").toLowerCase(); + String osName = rawOsName.substring(0, 3); + boolean is64bit = System.getProperty("os.arch").indexOf("64") >= 0; + + if (osName.equals("lin")) { + osName += is64bit ? "64" : "32"; + } + return osName; + } + +} -- cgit v1.2.3