Partially externalize WebDriver tests

This change does a few things:

  1. Partially externalized WebDriver tests by using ChromeDriver
     as an implementation of WebDriver API in the external build.
  2. Refactored WebDriverRule.java to decouple the creation and
     using of WebDriver related stuff so we can have different
     implementations in internal and external builds.
  3. Refactored the usage of some internal libraries to have a
     central place to store all of them to make it easier to
     remove them in the external build.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=233661757
This commit is contained in:
shicong 2019-02-12 12:58:11 -08:00 committed by jianglai
parent 4097dae3b2
commit 76028ba1b4
75 changed files with 1743 additions and 28 deletions

View file

@ -28,6 +28,10 @@ cache:
- $HOME/.gradle/caches/ - $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/ - $HOME/.gradle/wrapper/
# Get Chrome binary for WebDriver tests
addons:
chrome: stable
env: env:
# Disable fancy status information (looks bad on travis and exceeds logfile # Disable fancy status information (looks bad on travis and exceeds logfile
# quota) # quota)

View file

@ -188,6 +188,7 @@ dependencies {
compile deps['org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core'] compile deps['org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core']
compile deps['org.apache.beam:beam-sdks-java-io-google-cloud-platform'] compile deps['org.apache.beam:beam-sdks-java-io-google-cloud-platform']
maybeRuntime deps['org.apache.commons:commons-compress'] maybeRuntime deps['org.apache.commons:commons-compress']
testCompile deps['org.apache.commons:commons-text']
maybeRuntime deps['org.apache.ftpserver:ftplet-api'] maybeRuntime deps['org.apache.ftpserver:ftplet-api']
testCompile deps['org.apache.ftpserver:ftplet-api'] testCompile deps['org.apache.ftpserver:ftplet-api']
maybeRuntime deps['org.apache.ftpserver:ftpserver-core'] maybeRuntime deps['org.apache.ftpserver:ftpserver-core']
@ -216,6 +217,10 @@ dependencies {
testCompile deps['org.mortbay.jetty:jetty'] testCompile deps['org.mortbay.jetty:jetty']
compile deps['org.mortbay.jetty:servlet-api'] compile deps['org.mortbay.jetty:servlet-api']
maybeRuntime deps['org.mortbay.jetty:jetty-util'] maybeRuntime deps['org.mortbay.jetty:jetty-util']
testCompile deps['org.seleniumhq.selenium:selenium-api']
testCompile deps['org.seleniumhq.selenium:selenium-chrome-driver']
testCompile deps['org.seleniumhq.selenium:selenium-java']
testCompile deps['org.seleniumhq.selenium:selenium-remote-driver']
maybeRuntime deps['org.slf4j:slf4j-api'] maybeRuntime deps['org.slf4j:slf4j-api']
maybeRuntime deps['org.tukaani:xz'] maybeRuntime deps['org.tukaani:xz']
maybeRuntime deps['org.xerial.snappy:snappy-java'] maybeRuntime deps['org.xerial.snappy:snappy-java']
@ -461,6 +466,11 @@ task stylesheetsToJavascript {
sourceFiles << (cssSourceDir + "/" + it.name) sourceFiles << (cssSourceDir + "/" + it.name)
} }
} }
// The css files have to be passed to the compiler in alphabetic order to
// avoid some flaky style issues
sourceFiles.sort()
cssCompile("${outputDir}/registrar_bin", false, sourceFiles) cssCompile("${outputDir}/registrar_bin", false, sourceFiles)
cssCompile("${outputDir}/registrar_dbg", true, sourceFiles) cssCompile("${outputDir}/registrar_dbg", true, sourceFiles)
} }
@ -485,13 +495,15 @@ task compileProdJS(type: JavaExec) {
// compilation options // compilation options
closureArgs << "--compilation_level=ADVANCED" closureArgs << "--compilation_level=ADVANCED"
closureArgs << "--entry_point=goog:registry.registrar.main" closureArgs << "--entry_point=goog:registry.registrar.main"
closureArgs << "--externs=${javaDir}/google/registry/ui/externs/json.js" closureArgs << "--generate_exports"
// manually include all the required js files // manually include all the required js files
closureArgs << "--js=${rootDir}/node_modules/google-closure-library/**.js" closureArgs << "--js=${rootDir}/node_modules/google-closure-library/**.js"
closureArgs << "--js=${rootDir}/node_modules/soyutils_usegoog.js" closureArgs << "--js=${rootDir}/node_modules/soyutils_usegoog.js"
closureArgs << "--js=${resourcesDir}/google/registry/ui/css/registrar_bin.css.js" closureArgs << "--js=${resourcesDir}/google/registry/ui/css/registrar_bin.css.js"
closureArgs << "--js=${javaDir}/google/registry/ui/js/**.js" closureArgs << "--js=${javaDir}/google/registry/ui/js/**.js"
// TODO(shicong) Verify the compiled JS file works in Alpha
closureArgs << "--js=${javaDir}/google/registry/ui/externs/json.js"
closureArgs << "--js=${generatedDir}/google/registry/ui/soy/**.js" closureArgs << "--js=${generatedDir}/google/registry/ui/soy/**.js"
args closureArgs args closureArgs
} }
@ -543,11 +555,42 @@ task outcastTest(type: Test) {
maxParallelForks 5 maxParallelForks 5
} }
import org.apache.tools.ant.taskdefs.condition.Os
import java.nio.file.Files
import java.nio.file.Paths
ext.getChromedriver = {
def chromedriverZipFileName
if (Os.isFamily(Os.FAMILY_UNIX)) {
chromedriverZipFileName = 'chromedriver_linux64.zip'
} else if (Os.isFamily(Os.FAMILY_MAC)) {
chromedriverZipFileName = 'chromedriver_mac64.zip'
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
chromedriverZipFileName = 'chromedriver_win32.zip'
} else {
throw new RuntimeException("Unsupported OS: ${OperatingSystem.getDisplayName()}")
}
def tempDir = Files.createTempDirectory("chromedriver-dir").toString()
ant.get(src: 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE', dest: tempDir)
def latestReleaseVersion = Paths.get(tempDir, 'LATEST_RELEASE').readLines().get(0)
ant.get(src: "https://chromedriver.storage.googleapis.com/${latestReleaseVersion}/${chromedriverZipFileName}", dest: tempDir)
ant.unzip(src: "${tempDir}/${chromedriverZipFileName}", dest: tempDir)
def chromedriverFile = new File(tempDir, 'chromedriver')
chromedriverFile.setExecutable(true)
return chromedriverFile.getCanonicalPath()
}
test { test {
// Common exclude pattern. See README in parent directory for explanation. // Common exclude pattern. See README in parent directory for explanation.
exclude "**/*TestCase.*", "**/*TestSuite.*" exclude "**/*TestCase.*", "**/*TestSuite.*"
exclude fragileTestPatterns exclude fragileTestPatterns
exclude outcastTestPatterns exclude outcastTestPatterns
if (rootProject.hasProperty("excludeWebDriverTests")) {
exclude "**/webdriver/*"
}
// Run every test class in its own process. // Run every test class in its own process.
// Uncomment to unblock build while troubleshooting inexplicable test errors. // Uncomment to unblock build while troubleshooting inexplicable test errors.
@ -556,6 +599,10 @@ test {
// Sets the maximum number of test executors that may exist at the same time. // Sets the maximum number of test executors that may exist at the same time.
maxParallelForks 5 maxParallelForks 5
// Set system property for Webdriver
systemProperty 'webdriver.chrome.driver', project.getChromedriver()
}.dependsOn(fragileTest, outcastTest) }.dependsOn(fragileTest, outcastTest)
task nomulus(type: Jar) { task nomulus(type: Jar) {

View file

@ -107,8 +107,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
commons-codec:commons-codec:1.10 commons-codec:commons-codec:1.10
commons-logging:commons-logging:1.2 commons-logging:commons-logging:1.2
@ -151,6 +152,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -160,6 +162,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -194,6 +199,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -106,6 +106,8 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okio:okio:1.14.0
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
commons-codec:commons-codec:1.10 commons-codec:commons-codec:1.10
commons-logging:commons-logging:1.2 commons-logging:commons-logging:1.2
@ -145,6 +147,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -154,6 +157,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -188,6 +194,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -112,6 +112,7 @@ ext {
'org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.1.0', 'org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.1.0',
'org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0', 'org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0',
'org.apache.commons:commons-compress:1.8.1', 'org.apache.commons:commons-compress:1.8.1',
'org.apache.commons:commons-text:1.6',
'org.apache.ftpserver:ftplet-api:1.0.6', 'org.apache.ftpserver:ftplet-api:1.0.6',
'org.apache.ftpserver:ftpserver-core:1.0.6', 'org.apache.ftpserver:ftpserver-core:1.0.6',
'org.apache.httpcomponents:httpclient:4.5.2', 'org.apache.httpcomponents:httpclient:4.5.2',
@ -138,6 +139,10 @@ ext {
'org.mortbay.jetty:jetty:6.1.26', 'org.mortbay.jetty:jetty:6.1.26',
'org.mortbay.jetty:jetty-util:6.1.26', 'org.mortbay.jetty:jetty-util:6.1.26',
'org.mortbay.jetty:servlet-api:2.5-20081211', 'org.mortbay.jetty:servlet-api:2.5-20081211',
'org.seleniumhq.selenium:selenium-api:3.141.59',
'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59',
'org.seleniumhq.selenium:selenium-java:3.141.59',
'org.seleniumhq.selenium:selenium-remote-driver:3.141.59',
'org.slf4j:slf4j-api:1.7.16', 'org.slf4j:slf4j-api:1.7.16',
'org.tukaani:xz:1.5', 'org.tukaani:xz:1.5',
'org.xerial.snappy:snappy-java:1.1.4-M3', 'org.xerial.snappy:snappy-java:1.1.4-M3',

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -107,6 +107,8 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -148,6 +150,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -157,6 +160,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -195,6 +201,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -107,6 +107,8 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -148,6 +150,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -157,6 +160,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -195,6 +201,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -108,8 +108,9 @@ com.googlecode.java-diff-utils:diffutils:1.3.0
com.googlecode.json-simple:json-simple:1.1.1 com.googlecode.json-simple:json-simple:1.1.1
com.ibm.icu:icu4j:57.1 com.ibm.icu:icu4j:57.1
com.jcraft:jsch:0.1.53 com.jcraft:jsch:0.1.53
com.squareup.okhttp3:okhttp:3.11.0
com.squareup.okhttp:okhttp:2.5.0 com.squareup.okhttp:okhttp:2.5.0
com.squareup.okio:okio:1.6.0 com.squareup.okio:okio:1.14.0
com.sun.istack:istack-commons-runtime:3.0.5 com.sun.istack:istack-commons-runtime:3.0.5
com.sun.xml.fastinfoset:FastInfoset:1.2.13 com.sun.xml.fastinfoset:FastInfoset:1.2.13
com.thoughtworks.paranamer:paranamer:2.7 com.thoughtworks.paranamer:paranamer:2.7
@ -154,6 +155,7 @@ javax.xml.bind:jaxb-api:2.3.0
jline:jline:1.0 jline:jline:1.0
joda-time:joda-time:2.9.2 joda-time:joda-time:2.9.2
junit:junit:4.12 junit:junit:4.12
net.bytebuddy:byte-buddy:1.8.15
org.apache.avro:avro:1.8.2 org.apache.avro:avro:1.8.2
org.apache.beam:beam-runners-direct-java:2.2.0 org.apache.beam:beam-runners-direct-java:2.2.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0 org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0
@ -163,6 +165,9 @@ org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.2.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0 org.apache.beam:beam-sdks-java-extensions-protobuf:2.2.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0 org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0
org.apache.commons:commons-compress:1.8.1 org.apache.commons:commons-compress:1.8.1
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6 org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6 org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.5 org.apache.httpcomponents:httpclient:4.5.5
@ -201,6 +206,16 @@ org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0 org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0 org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0 org.ow2.asm:asm:6.0
org.seleniumhq.selenium:selenium-api:3.141.59
org.seleniumhq.selenium:selenium-chrome-driver:3.141.59
org.seleniumhq.selenium:selenium-edge-driver:3.141.59
org.seleniumhq.selenium:selenium-firefox-driver:3.141.59
org.seleniumhq.selenium:selenium-ie-driver:3.141.59
org.seleniumhq.selenium:selenium-java:3.141.59
org.seleniumhq.selenium:selenium-opera-driver:3.141.59
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
org.seleniumhq.selenium:selenium-support:3.141.59
org.slf4j:slf4j-api:1.7.25 org.slf4j:slf4j-api:1.7.25
org.threeten:threetenbp:1.3.3 org.threeten:threetenbp:1.3.3
org.tukaani:xz:1.5 org.tukaani:xz:1.5

View file

@ -26,31 +26,27 @@ import google.registry.module.frontend.FrontendServlet;
import java.net.URL; import java.net.URL;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Optional;
import javax.servlet.Filter; import javax.servlet.Filter;
/** Lightweight HTTP server for testing the Nomulus Admin and Registrar consoles. */ /** Lightweight HTTP server for testing the Nomulus Admin and Registrar consoles. */
public final class RegistryTestServer { public final class RegistryTestServer {
// In most cases, the current working dir is ${projectRoot}/gradle/${subproject}
private static final String PROJECT_ROOT =
Optional.ofNullable(System.getProperty("test.projectRoot")).orElse("../../");
private static final String RESOURCES_DIR =
Optional.ofNullable(System.getProperty("test.resourcesDir")).orElse("build/resources/main");
public static final ImmutableMap<String, Path> RUNFILES = public static final ImmutableMap<String, Path> RUNFILES =
new ImmutableMap.Builder<String, Path>() new ImmutableMap.Builder<String, Path>()
.put( .put("/index.html", Paths.get(PROJECT_ROOT, "/java/google/registry/ui/html/index.html"))
"/index.html", .put("/error.html", Paths.get(PROJECT_ROOT, "/java/google/registry/ui/html/error.html"))
Paths.get( .put("/assets/js/*", Paths.get(RESOURCES_DIR, "/google/registry/ui"))
"../domain_registry/java/google/registry/ui/html/index.html")) .put("/assets/css/*", Paths.get(RESOURCES_DIR, "/google/registry/ui/css"))
.put( .put("/assets/sources/*", Paths.get(PROJECT_ROOT))
"/error.html", .put("/assets/*", Paths.get(PROJECT_ROOT, "/java/google/registry/ui/assets"))
Paths.get(
"../domain_registry/java/google/registry/ui/html/error.html"))
.put(
"/assets/js/*",
Paths.get("../domain_registry/java/google/registry/ui"))
.put(
"/assets/css/*",
Paths.get("../domain_registry/java/google/registry/ui/css"))
.put("/assets/sources/*", Paths.get(".."))
.put(
"/assets/*",
Paths.get("../domain_registry/java/google/registry/ui/assets"))
.build(); .build();
private static final ImmutableList<Route> ROUTES = private static final ImmutableList<Route> ROUTES =

View file

@ -0,0 +1,71 @@
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import java.io.IOException;
import java.io.UncheckedIOException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
/** Implementation of {@link WebDriverPlusScreenDiffer} that uses {@link ChromeDriver}. */
class ChromeWebDriverPlusScreenDiffer implements WebDriverPlusScreenDiffer {
private static final ChromeDriverService chromeDriverService = createChromeDriverService();
private final WebDriver webDriver;
public ChromeWebDriverPlusScreenDiffer() {
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setHeadless(true);
webDriver = new ChromeDriver(chromeDriverService, chromeOptions);
}
private static ChromeDriverService createChromeDriverService() {
ChromeDriverService chromeDriverService =
new ChromeDriverService.Builder().usingAnyFreePort().build();
try {
chromeDriverService.start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Runtime.getRuntime().addShutdownHook(new Thread(chromeDriverService::stop));
return chromeDriverService;
}
@Override
public WebDriver getWebDriver() {
return webDriver;
}
@Override
public void diffElement(String imageKey, WebElement element) {
// TODO(b/122650673): Add implementation for screenshots comparison. It is no-op
// right now to prevent the test failure.
}
@Override
public void diffPage(String imageKey) {
// TODO(b/122650673): Add implementation for screenshots comparison. It is no-op
// right now to prevent the test failure.
}
@Override
public void verifyAndQuit() {
// TODO(b/122650673): Add implementation for screenshots comparison. It is no-op
// right now to prevent the test failure.
}
}

View file

@ -0,0 +1,83 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static google.registry.server.Fixture.BASIC;
import static google.registry.server.Route.route;
import com.googlecode.objectify.ObjectifyFilter;
import google.registry.model.ofy.OfyFilter;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
/** Registrar Console Screenshot Differ tests. */
@RunWith(JUnit4.class)
public class OteSetupConsoleScreenshotTest {
@Rule
public final TestServerRule server =
new TestServerRule.Builder()
.setRunfiles(RegistryTestServer.RUNFILES)
.setRoutes(route("/registrar-ote-setup", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
.setFixtures(BASIC)
.setEmail("Marla.Singer@google.com")
.build();
@Rule public final WebDriverRule driver = new WebDriverRule();
@Test
public void get_owner_fails() throws Throwable {
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-ote-setup"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("unauthorized");
}
@Test
public void get_admin_succeeds() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-ote-setup"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("formEmpty");
driver.findElement(By.id("clientId")).sendKeys("acmereg");
driver.findElement(By.id("email")).sendKeys("acmereg@registry.example");
driver.findElement(By.id("password")).sendKeys("StRoNgPaSsWoRd");
driver.diffPage("formFilled");
driver.findElement(By.id("submit-button")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("oteResult");
}
@Test
public void get_admin_fails_badEmail() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-ote-setup"));
driver.waitForElement(By.tagName("h1"));
driver.findElement(By.id("clientId")).sendKeys("acmereg");
driver.findElement(By.id("email")).sendKeys("bad email");
driver.findElement(By.id("submit-button")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("oteResultFailed");
}
}

View file

@ -0,0 +1,373 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static google.registry.server.Fixture.BASIC;
import static google.registry.server.Route.route;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.ObjectifyFilter;
import google.registry.model.ofy.OfyFilter;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import google.registry.testing.CertificateSamples;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
/** Registrar Console Screenshot Differ tests. */
@RunWith(JUnit4.class)
public class RegistrarConsoleScreenshotTest {
@Rule
public final TestServerRule server =
new TestServerRule.Builder()
.setRunfiles(RegistryTestServer.RUNFILES)
.setRoutes(
route("/registrar", FrontendServlet.class),
route("/registrar-ote-status", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class),
route("/registrar-xhr", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
.setFixtures(BASIC)
.setEmail("Marla.Singer@google.com")
.build();
@Rule public final WebDriverRule driver = new WebDriverRule();
@Test
public void index_owner() throws Throwable {
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
/** Admins have an extra "admin" tab. */
@Test
public void index_adminAndOwner() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
/** Admins who aren't owners still have all the tabs. */
@Test
public void index_admin() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
// To make sure we're only ADMIN (and not also "OWNER"), we switch to the NewRegistrar we
// aren't in the contacts of
driver.get(server.getUrl("/registrar?clientId=NewRegistrar"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void contactUs() throws Throwable {
driver.get(server.getUrl("/registrar#contact-us"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void settingsContact() throws Throwable {
driver.get(server.getUrl("/registrar#contact-settings"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
/** Admins shouldn't have the "add" button */
@Test
public void settingsContact_asAdmin() throws Throwable {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#contact-settings"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void settingsContactItem() throws Throwable {
driver.get(server.getUrl("/registrar#contact-settings/johndoe@theregistrar.com"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
/** Admins shouldn't have the "edit" button */
@Test
public void settingsContactItem_asAdmin() throws Throwable {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#contact-settings/janedoe@theregistrar.com"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void settingsContactEdit() throws Throwable {
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#contact-settings/johndoe@theregistrar.com"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.diffPage("page");
}
@Test
public void settingsAdmin_whenAdmin() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1050, 2000));
// To make sure we're only ADMIN (and not also "OWNER"), we switch to the NewRegistrar we
// aren't in the contacts of
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#admin-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("edit");
}
/**
* Makes sure the user can't "manually" enter the admin-settings.
*
* <p>Users don't have the "admin setting" tab (see the {@link #index_owner()} test). However, we
* also want to make sure that if a user enter's the URL fragment manually they don't get the
* admin page.
*
* <p>Note that failure here is a UI issue only and not a security issue, since any "admin" change
* a user tries to do is validated on the backend and fails for non-admins.
*/
@Test
public void settingsAdmin_whenNotAdmin_showsHome() throws Throwable {
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#admin-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
}
@Test
public void getOteStatus_noButtonWhenReal() throws Exception {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar#admin-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("result");
}
@Test
public void getOteStatus_notCompleted() throws Exception {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar?clientId=oteunfinished-1#admin-settings"));
driver.findElement(By.id("btn-ote-status")).click();
driver.findElement(By.id("ote-results-table")).click();
// the 'hover' styling takes a bit to go away--sleep so we don't flake
Thread.sleep(250);
driver.diffPage("result");
}
@Test
public void getOteStatus_completed() throws Exception {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar?clientId=otefinished-1#admin-settings"));
driver.waitForElement(By.id("btn-ote-status"));
driver.diffPage("before_click");
driver.findElement(By.id("btn-ote-status")).click();
driver.findElement(By.id("ote-results-table")).click();
// the 'hover' styling takes a bit to go away--sleep so we don't flake
Thread.sleep(250);
driver.diffPage("result");
}
@Test
public void settingsSecurity() throws Throwable {
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#security-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("edit");
}
/** Admins shouldn't have the "edit" button */
@Test
public void settingsSecurity_asAdmin() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#security-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
}
@Test
public void settingsSecurityWithCerts() throws Throwable {
server.runInAppEngineEnvironment(
() -> {
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setClientCertificate(CertificateSamples.SAMPLE_CERT, START_OF_TIME)
.setFailoverClientCertificate(CertificateSamples.SAMPLE_CERT2, START_OF_TIME)
.build());
return null;
});
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#security-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("edit");
}
@Test
public void settingsSecurityWithHashOnly() throws Throwable {
server.runInAppEngineEnvironment(
() -> {
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH)
.build());
return null;
});
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#security-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("view");
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("edit");
}
@Test
public void settingsWhois() throws Throwable {
driver.get(server.getUrl("/registrar#whois-settings"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void settingsWhoisEdit() throws Throwable {
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#whois-settings"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void settingsWhoisEditError() throws Throwable {
driver.manage().window().setSize(new Dimension(1050, 2000));
driver.get(server.getUrl("/registrar#whois-settings"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.setFormFieldsById(ImmutableMap.of("faxNumber", "cat"));
driver.waitForElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
// EPP pages aren't being included in launch, so temporarily disable the following tests.
@Test
public void domainCreate() throws Throwable {
// TODO(b/17675279): Change labels to unicode.
driver.get(server.getUrl("/registrar#domain"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
@Ignore("TODO(b/26984251): Unflake nameserver ordering.")
public void domainView() throws Throwable {
driver.get(server.getUrl("/registrar#domain/love.xn--q9jyb4c"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
@Ignore("TODO(b/26984251): Unflake nameserver ordering.")
public void domainEdit() throws Throwable {
driver.get(server.getUrl("/registrar#domain/love.xn--q9jyb4c"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void contactCreate() throws Throwable {
driver.get(server.getUrl("/registrar#contact"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void contactView() throws Throwable {
driver.get(server.getUrl("/registrar#contact/google"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void contactEdit() throws Throwable {
driver.get(server.getUrl("/registrar#contact/google"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void hostCreate() throws Throwable {
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void hostView() throws Throwable {
driver.get(server.getUrl("/registrar#host/ns1.love.xn--q9jyb4c"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");
}
@Test
public void hostEdit() throws Throwable {
driver.get(server.getUrl("/registrar#host/ns1.love.xn--q9jyb4c"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
Thread.sleep(1000);
driver.diffPage("page");
}
@Test
public void indexPage_smallScrolledDown() throws Throwable {
driver.manage().window().setSize(new Dimension(400, 300));
driver.get(server.getUrl("/registrar"));
driver.waitForElement(By.tagName("h1"));
driver.executeScript("document.getElementById('reg-content-and-footer').scrollTop = 200");
Thread.sleep(500);
driver.diffPage("page");
}
}

View file

@ -0,0 +1,252 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.server.Fixture.BASIC;
import static google.registry.server.Route.route;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.ObjectifyFilter;
import google.registry.model.ofy.OfyFilter;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarContact;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import google.registry.testing.AppEngineRule;
import google.registry.ui.server.registrar.ConsoleUiAction;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
/** WebDriver tests for Registrar Console UI. */
@RunWith(JUnit4.class)
public class RegistrarConsoleWebTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore()
.withLocalModules()
.withTaskQueue()
.build();
@Rule
public final TestServerRule server =
new TestServerRule.Builder()
.setRunfiles(RegistryTestServer.RUNFILES)
.setRoutes(
route("/registrar-xhr", FrontendServlet.class),
route("/registrar", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
.setFixtures(BASIC)
.setEmail("Marla.Singer@google.com")
.build();
@Rule public final WebDriverRule driver = new WebDriverRule();
@Rule public final Timeout deathClock = new Timeout(60000);
/** Checks the identified element has the given text content. */
void assertEltText(String eltId, String eltValue) {
assertThat(driver.findElement(By.id(eltId)).getText()).isEqualTo(eltValue);
}
/** Checks that an element is visible. */
void assertEltVisible(String eltId) throws Throwable {
assertThat(driver.waitForElement(By.id(eltId)).isDisplayed()).isTrue();
}
/** Checks that an element is invisible. */
void assertEltInvisible(String eltId) throws Throwable {
assertThat(driver.waitForElement(By.id(eltId)).isDisplayed()).isFalse();
}
@Test
public void testEditButtonsVisibility_owner() throws Throwable {
driver.get(server.getUrl("/registrar#whois-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#security-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#contact-settings"));
assertEltInvisible("reg-app-btns-edit");
assertEltVisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#resources"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
}
@Test
public void testEditButtonsVisibility_adminAndOwner() throws Throwable {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar#whois-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#security-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#contact-settings"));
assertEltInvisible("reg-app-btns-edit");
assertEltVisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#admin-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar#resources"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
}
@Test
public void testEditButtonsVisibility_adminOnly() throws Throwable {
server.setIsAdmin(true);
// To make sure we're only ADMIN (and not also "OWNER"), we switch to the NewRegistrar we
// aren't in the contacts of
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#whois-settings"));
assertEltInvisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#security-settings"));
assertEltInvisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#contact-settings"));
assertEltInvisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#admin-settings"));
assertEltVisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#resources"));
assertEltInvisible("reg-app-btns-edit");
assertEltInvisible("reg-app-btn-add");
}
@Test
public void testWhoisSettingsEdit() throws Throwable {
driver.get(server.getUrl("/registrar#whois-settings"));
driver.waitForElement(By.id("reg-app-btn-edit")).click();
driver.setFormFieldsById(new ImmutableMap.Builder<String, String>()
.put("emailAddress", "test1@example.com")
.put("clientIdentifier", "ignored")
.put("whoisServer", "foo.bar.baz")
.put("url", "blah.blar")
.put("phoneNumber", "+1.2125650000")
.put("faxNumber", "+1.2125650001")
.put("localizedAddress.street[0]", "Bőulevard őf")
.put("localizedAddress.street[1]", "Brőken Dreams")
.put("localizedAddress.street[2]", "")
.put("localizedAddress.city", "New York")
.put("localizedAddress.state", "NY")
.put("localizedAddress.zip", "10011")
.put("localizedAddress.countryCode", "US")
.build());
driver.findElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000);
Registrar registrar = server.runInAppEngineEnvironment(() -> loadRegistrar("TheRegistrar"));
assertThat(registrar.getEmailAddress()).isEqualTo("test1@example.com");
assertThat(registrar.getClientId()).isEqualTo("TheRegistrar");
assertThat(registrar.getWhoisServer()).isEqualTo("foo.bar.baz");
assertThat(registrar.getUrl()).isEqualTo("blah.blar");
assertThat(registrar.getPhoneNumber()).isEqualTo("+1.2125650000");
assertThat(registrar.getFaxNumber()).isEqualTo("+1.2125650001");
RegistrarAddress address = registrar.getLocalizedAddress();
assertThat(address.getStreet()).containsExactly("Bőulevard őf", "Brőken Dreams");
assertThat(address.getCity()).isEqualTo("New York");
assertThat(address.getState()).isEqualTo("NY");
assertThat(address.getZip()).isEqualTo("10011");
assertThat(address.getCountryCode()).isEqualTo("US");
}
@Test
public void testContactSettingsView() throws Throwable {
driver.get(server.getUrl("/registrar#contact-settings"));
driver.waitForElement(By.id("reg-app-btn-add"));
ImmutableList<RegistrarContact> contacts =
server.runInAppEngineEnvironment(
() -> loadRegistrar("TheRegistrar").getContacts().asList());
assertEltText("contacts[0].name", contacts.get(0).getName());
assertEltText("contacts[0].emailAddress", contacts.get(0).getEmailAddress());
assertEltText("contacts[0].phoneNumber", contacts.get(0).getPhoneNumber());
}
@Test
public void testSecuritySettingsView() throws Throwable {
driver.get(server.getUrl("/registrar#security-settings"));
driver.waitForElement(By.id("reg-app-btn-edit"));
Registrar registrar = server.runInAppEngineEnvironment(() -> loadRegistrar("TheRegistrar"));
assertThat(driver.findElement(By.id("phonePasscode"))
.getAttribute("value"))
.isEqualTo(registrar.getPhonePasscode());
}
@Test
public void testHostCreate_hostIsAnSld_eppErrorShowsInButterBar() throws Throwable {
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.id("domain-host-addr-add-button")).click();
driver.setFormFieldsById(ImmutableMap.of(
"host:name", "empire.vampyre",
"host:addr[0].value", "1.2.3.4"));
driver.findElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000); // TODO(b/26129174): Change butterbar code to add/remove dynamically.
assertThat(getButterBarText())
.isEqualTo("Host names must be at least two levels below the registry suffix");
}
@Test
public void testHostCreate() throws Throwable {
server.runInAppEngineEnvironment(
() -> {
createTld("vampyre");
persistActiveDomain("empire.vampyre");
return null;
});
driver.get(server.getUrl("/registrar#host"));
driver.waitForElement(By.id("domain-host-addr-add-button")).click();
driver.setFormFieldsById(ImmutableMap.of(
"host:name", "the.empire.vampyre",
"host:addr[0].value", "1.2.3.4"));
driver.findElement(By.id("reg-app-btn-save")).click();
Thread.sleep(1000); // TODO(b/26129174): Change butterbar code to add/remove dynamically.
assertThat(getButterBarText()).isEqualTo("Saved.");
}
private String getButterBarText() {
return (String) driver.executeScript(
String.format("return document.querySelector('.%s').innerText", css("kd-butterbar-text")));
}
private static String css(String name) {
return ConsoleUiAction.CSS_RENAMING_MAP_SUPPLIER.get().get(name);
}
}

View file

@ -0,0 +1,108 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static google.registry.server.Fixture.BASIC;
import static google.registry.server.Route.route;
import com.googlecode.objectify.ObjectifyFilter;
import google.registry.model.ofy.OfyFilter;
import google.registry.module.frontend.FrontendServlet;
import google.registry.server.RegistryTestServer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
/** Registrar Console Screenshot Differ tests. */
@RunWith(JUnit4.class)
public class RegistrarCreateConsoleScreenshotTest {
@Rule
public final TestServerRule server =
new TestServerRule.Builder()
.setRunfiles(RegistryTestServer.RUNFILES)
.setRoutes(route("/registrar-create", FrontendServlet.class))
.setFilters(ObjectifyFilter.class, OfyFilter.class)
.setFixtures(BASIC)
.setEmail("Marla.Singer@google.com")
.build();
@Rule public final WebDriverRule driver = new WebDriverRule();
@Test
public void get_owner_fails() throws Throwable {
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-create"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("unauthorized");
}
@Test
public void get_admin_succeeds() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-create"));
driver.waitForElement(By.tagName("h1"));
driver.diffPage("formEmpty");
driver.findElement(By.id("clientId")).sendKeys("my-name");
driver.findElement(By.id("name")).sendKeys("registrar name");
driver
.findElement(By.id("billingAccount"))
.sendKeys(""
+ "USD=12345678-abcd-1234-5678-cba987654321\n"
+ "JPY=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee");
driver.findElement(By.id("driveId")).sendKeys("drive-id");
driver.findElement(By.id("ianaId")).sendKeys("15263");
driver.findElement(By.id("referralEmail")).sendKeys("email@icann.example");
driver.findElement(By.id("email")).sendKeys("my-name@registry.example");
driver.findElement(By.id("street1")).sendKeys("123 Street st.");
driver.findElement(By.id("city")).sendKeys("Citysville");
driver.findElement(By.id("countryCode")).sendKeys("fr");
driver.findElement(By.id("password")).sendKeys("StRoNgPaSsWoRd");
driver.findElement(By.id("passcode")).sendKeys("01234");
driver.diffPage("formFilled");
driver.findElement(By.id("submit-button")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("createResult");
}
@Test
public void get_admin_fails_badEmail() throws Throwable {
server.setIsAdmin(true);
driver.manage().window().setSize(new Dimension(1200, 2000));
driver.get(server.getUrl("/registrar-create"));
driver.waitForElement(By.tagName("h1"));
driver.findElement(By.id("clientId")).sendKeys("my-name");
driver.findElement(By.id("name")).sendKeys("registrar name");
driver
.findElement(By.id("billingAccount"))
.sendKeys(""
+ "USD=12345678-abcd-1234-5678-cba987654321\n"
+ "JPY=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee");
driver.findElement(By.id("driveId")).sendKeys("drive-id");
driver.findElement(By.id("ianaId")).sendKeys("15263");
driver.findElement(By.id("referralEmail")).sendKeys("email@icann.example");
driver.findElement(By.id("email")).sendKeys("bad email");
driver.findElement(By.id("street1")).sendKeys("123 Street st.");
driver.findElement(By.id("city")).sendKeys("Citysville");
driver.findElement(By.id("countryCode")).sendKeys("fr");
driver.findElement(By.id("submit-button")).click();
driver.waitForElement(By.tagName("h1"));
driver.diffPage("createResultFailed");
}
}

View file

@ -0,0 +1,247 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.testing.AppEngineRule.THE_REGISTRAR_GAE_USER_ID;
import static google.registry.util.NetworkUtils.pickUnusedPort;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.server.Fixture;
import google.registry.server.Route;
import google.registry.server.TestServer;
import google.registry.testing.AppEngineRule;
import google.registry.testing.UserInfo;
import java.net.URL;
import java.nio.file.Path;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingDeque;
import javax.servlet.Filter;
import org.junit.rules.ExternalResource;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* JUnit Rule that sets up and tears down {@link TestServer}.
*
* <p><b>Warning:</b> App Engine testing environments are thread local. This rule will spawn that
* testing environment in a separate thread from your unit tests. Therefore any modifications you
* need to make to that testing environment (e.g. Datastore interactions) must be done through the
* {@link #runInAppEngineEnvironment(Callable)} method.
*/
public final class TestServerRule extends ExternalResource {
private final ImmutableList<Fixture> fixtures;
private final AppEngineRule appEngineRule;
private final BlockingQueue<FutureTask<?>> jobs = new LinkedBlockingDeque<>();
private final TestServer testServer;
private Thread serverThread;
private TestServerRule(
ImmutableMap<String, Path> runfiles,
ImmutableList<Route> routes,
ImmutableList<Class<? extends Filter>> filters,
ImmutableList<Fixture> fixtures,
String email) {
this.fixtures = fixtures;
// We create an GAE-Admin user, and then use AuthenticatedRegistrarAccessor.bypassAdminCheck to
// choose whether the user is an admin or not.
this.appEngineRule = AppEngineRule.builder()
.withDatastore()
.withLocalModules()
.withUrlFetch()
.withTaskQueue()
.withUserService(UserInfo.createAdmin(email, THE_REGISTRAR_GAE_USER_ID))
.build();
this.testServer = new TestServer(
HostAndPort.fromParts("localhost", pickUnusedPort()),
runfiles,
routes,
filters);
}
@Override
protected void before() throws InterruptedException {
setIsAdmin(false);
serverThread = new Thread(new Server());
synchronized (testServer) {
serverThread.start();
testServer.wait();
}
}
@Override
protected void after() {
// Reset the global state AuthenticatedRegistrarAccessor.bypassAdminCheck
// to the default value so it doesn't interfere with other tests
AuthenticatedRegistrarAccessor.bypassAdminCheck = false;
serverThread.interrupt();
try {
serverThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
serverThread = null;
jobs.clear();
}
}
/**
* Set the current user's Admin status.
*
* <p>This is sort of a hack because we can't actually change the user itself, nor that user's GAE
* roles. Instead we created a GAE-admin user in the constructor and we "bypass the admin check"
* if we want that user to not be an admin.
*
* <p>A better implementation would be to replace the AuthenticatedRegistrarAccessor - that way we
* can fully control the Roles the user has without relying on the implementation. But right now
* we don't have the ability to change injected values like that :/
*/
public void setIsAdmin(boolean isAdmin) {
AuthenticatedRegistrarAccessor.bypassAdminCheck = !isAdmin;
}
/** @see TestServer#getUrl(String) */
public URL getUrl(String path) {
return testServer.getUrl(path);
}
/**
* Runs arbitrary code inside server event loop thread.
*
* <p>You should use this method when you want to do things like change Datastore, because the
* App Engine testing environment is thread-local.
*/
public <T> T runInAppEngineEnvironment(Callable<T> callback) throws Throwable {
FutureTask<T> job = new FutureTask<>(callback);
jobs.add(job);
testServer.ping();
return job.get();
}
private final class Server extends Statement implements Runnable {
@Override
public void run() {
try {
appEngineRule
.apply(this, Description.EMPTY)
.evaluate();
} catch (InterruptedException e) {
// This is what we expect to happen.
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void evaluate() throws InterruptedException {
for (Fixture fixture : fixtures) {
fixture.load();
}
testServer.start();
System.out.printf("TestServerRule is listening on: %s\n", testServer.getUrl("/"));
synchronized (testServer) {
testServer.notify();
}
try {
while (true) {
testServer.process();
flushJobs();
}
} finally {
testServer.stop();
}
}
private void flushJobs() {
while (true) {
FutureTask<?> job = jobs.poll();
if (job != null) {
job.run();
} else {
break;
}
}
}
}
/**
* Builder for {@link TestServerRule}.
*
* <p>This builder has three required fields: {@link #setRunfiles}, {@link #setRoutes}, and {@link
* #setFilters}.
*
*/
public static final class Builder {
private ImmutableMap<String, Path> runfiles;
private ImmutableList<Route> routes;
ImmutableList<Class<? extends Filter>> filters;
private ImmutableList<Fixture> fixtures = ImmutableList.of();
private String email;
/** Sets the directories containing the static files for {@link TestServer}. */
public Builder setRunfiles(ImmutableMap<String, Path> runfiles) {
this.runfiles = runfiles;
return this;
}
/** Sets the list of servlet {@link Route} objects for {@link TestServer}. */
public Builder setRoutes(Route... routes) {
checkArgument(routes.length > 0);
this.routes = ImmutableList.copyOf(routes);
return this;
}
/** Sets the list of servlet {@link Filter} objects for {@link TestServer}. */
@SafeVarargs
public final Builder setFilters(Class<? extends Filter>... filters) {
this.filters = ImmutableList.copyOf(filters);
return this;
}
/** Sets an ordered list of Datastore fixtures that should be loaded on startup. */
public Builder setFixtures(Fixture... fixtures) {
this.fixtures = ImmutableList.copyOf(fixtures);
return this;
}
/**
* Sets information about the logged in user.
*
* <p>This unfortunately cannot be changed by test methods.
*/
public Builder setEmail(String email) {
this.email = email;
return this;
}
/** Returns a new {@link TestServerRule} instance. */
public TestServerRule build() {
return new TestServerRule(
checkNotNull(this.runfiles),
checkNotNull(this.routes),
checkNotNull(this.filters),
checkNotNull(this.fixtures),
checkNotNull(this.email));
}
}
}

View file

@ -0,0 +1,58 @@
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
/**
* Interface to provide the implementation of {@link org.openqa.selenium.WebDriver} and APIs to
* compare screenshots for visual regression tests.
*/
interface WebDriverPlusScreenDiffer {
/** Gets the implementation of {@link org.openqa.selenium.WebDriver}. */
WebDriver getWebDriver();
/**
* Checks that the screenshot of the element matches the golden image by pixel comparison. {@link
* #verifyAndQuit()} needs to be invoked to actually trigger the comparison.
*
* <p>On mismatch, the test will continue until the end of the test (and then fail). This is so
* other screenshot matches can be executed in the same function - allowing you to approve /
* reject all at once.
*
* @param imageKey a unique name such that by prepending the calling class name and method name in
* the format of ClassName_MethodName_<imageKey> will uniquely identify golden image.
* @param element the element on the page to be compared
*/
void diffElement(String imageKey, WebElement element);
/**
* Checks that the screenshot matches the golden image by pixel comparison. {@link
* #verifyAndQuit()} needs to be invoked to actually trigger the comparison.
*
* <p>On mismatch, the test will continue until the end of the test (and then fail). This is so
* other screenshot matches can be executed in the same function - allowing you to approve /
* reject all at once.
*
* @param imageKey a unique name such that by prepending the calling class name and method name in
* the format of ClassName_MethodName_<imageKey> will uniquely identify golden image.
*/
void diffPage(String imageKey);
/** Asserts that all diffs up to this point have PASSED. */
void verifyAndQuit();
}

View file

@ -0,0 +1,288 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.webdriver;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.text.StringEscapeUtils.escapeEcmaScript;
import com.google.common.base.Preconditions;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import org.junit.rules.ExternalResource;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.HasInputDevices;
import org.openqa.selenium.interactions.Keyboard;
import org.openqa.selenium.interactions.Mouse;
import org.openqa.selenium.remote.DesiredCapabilities;
/** WebDriver delegate JUnit Rule that sends Sponge a screenshot on failure. */
public final class WebDriverRule extends ExternalResource
implements WebDriver, HasInputDevices, TakesScreenshot, JavascriptExecutor, HasCapabilities {
private static final int WAIT_FOR_ELEMENTS_POLLING_INTERVAL_MS = 10;
private static final int WAIT_FOR_ELEMENTS_BONUS_DELAY_MS = 150;
// The maximum difference between pixels that would be considered as "identical". Calculated as
// the sum of the absolute difference between the values of the RGB channels. So a 120,30,200
// reference pixel and a 122,31,193 result pixel have a difference of 10, and would be considered
// identical if MAX_COLOR_DIFF=10
private static final int MAX_COLOR_DIFF = 10;
// Percent of pixels that are allowed to be different (more than the MAX_COLOR_DIFF) between the
// images while still considering the test to have passed. Useful if there are a very small
// number of pixels that vary (usually on the corners of "rounded" buttons or similar)
private static final int MAX_PIXEL_DIFF = 0;
private WebDriver driver;
private WebDriverPlusScreenDiffer webDriverPlusScreenDiffer;
// Prefix to use for golden image files, will be set to ClassName_MethodName once the test
// starts. Will be added a user-given imageKey as a suffix, and of course a '.png' at the end.
private String imageNamePrefix = null;
@Override
public Statement apply(Statement base, Description description) {
if (imageNamePrefix == null) {
String className = description.getTestClass().getSimpleName();
String methodName = description.getMethodName();
String unsanitizedName = className + "_" + methodName;
// remove all of the special wildcard characters so they don't exist in filenames.
imageNamePrefix = unsanitizedName.replaceAll("[*?~\"\\[\\]]", "");
}
return super.apply(base, description);
}
@Override
protected void before() {
webDriverPlusScreenDiffer =
new ChromeWebDriverPlusScreenDiffer();
driver = webDriverPlusScreenDiffer.getWebDriver();
// non-zero timeout so findByElement will wait for the element to appear
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
}
@Override
protected void after() {
try {
driver.quit();
} finally {
driver = null;
}
webDriverPlusScreenDiffer.verifyAndQuit();
}
/** @see #get(String) */
public void get(URL url) {
driver.get(url.toString());
}
/** Waits indefinitely for an element to appear on the page, then returns it. */
public WebElement waitForElement(By by) throws InterruptedException {
while (true) {
List<WebElement> elements = findElements(by);
if (!elements.isEmpty()) {
Thread.sleep(WAIT_FOR_ELEMENTS_BONUS_DELAY_MS);
return elements.get(0);
}
Thread.sleep(WAIT_FOR_ELEMENTS_POLLING_INTERVAL_MS);
}
}
/** Waits for element matching {@code by} whose {@code attribute} satisfies {@code predicate}. */
public WebElement waitForAttribute(
By by, String attribute, Predicate</*@Nullable*/ ? super CharSequence> predicate)
throws InterruptedException {
while (true) {
for (WebElement element : findElements(by)) {
if (predicate.test(element.getAttribute(attribute))) {
Thread.sleep(WAIT_FOR_ELEMENTS_BONUS_DELAY_MS);
return element;
}
}
Thread.sleep(WAIT_FOR_ELEMENTS_POLLING_INTERVAL_MS);
}
}
/** Sets value of input fields, where {@code fields} key is the {@code id=""} attribute. */
public void setFormFieldsById(Map<String, String> fields) {
executeScript(
fields.entrySet().stream()
.map(
entry ->
String.format(
"document.getElementById('%s').value = '%s';",
escapeEcmaScript(entry.getKey()), escapeEcmaScript(entry.getValue())))
.collect(joining("\n")));
}
/**
* Checks that the screenshot of the element matches the golden image by pixel comparison.
*
* <p>On mismatch, the test will continue until the end of the test (and then fail). This is so
* other screenshot matches can be executed in the same function - allowing you to approve /
* reject all at once.
*
* @param imageKey a unique name such that by prepending the calling class name and method name in
* the format of ClassName_MethodName_<imageKey> will uniquely identify golden image.
* @param element the element on the page to be compared
*/
public void diffElement(String imageKey, WebElement element) {
webDriverPlusScreenDiffer.diffElement(getUniqueName(imageKey), element);
}
/**
* Checks that the screenshot of the element matches the golden image by pixel comparison.
*
* <p>On mismatch, the test will continue until the end of the test (and then fail). This is so
* other screenshot matches can be executed in the same function - allowing you to approve /
* reject all at once.
*
* @param imageKey a unique name such that by prepending the calling class name and method name in
* the format of ClassName_MethodName_<imageKey> will uniquely identify golden image.
* @param by {@link By} which locates the element on the page to be compared
*/
public void diffElement(String imageKey, By by) {
diffElement(imageKey, driver.findElement(by));
}
/**
* Checks that the screenshot matches the golden image by pixel comparison.
*
* <p>On mismatch, the test will continue until the end of the test (and then fail). This is so
* other screenshot matches can be executed in the same function - allowing you to approve /
* reject all at once.
*
* @param imageKey a unique name such that by prepending the calling class name and method name in
* the format of ClassName_MethodName_<imageKey> will uniquely identify golden image.
*/
public void diffPage(String imageKey) {
webDriverPlusScreenDiffer.diffPage(getUniqueName(imageKey));
}
@Override
public void get(String url) {
driver.get(url);
}
@Override
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
@Override
public String getTitle() {
return driver.getTitle();
}
@Override
public List<WebElement> findElements(By by) {
return driver.findElements(by);
}
@Override
public WebElement findElement(By by) {
return driver.findElement(by);
}
@Override
public String getPageSource() {
return driver.getPageSource();
}
@Override
public void close() {
driver.close();
}
@Override
public void quit() {
driver.quit();
}
@Override
public Set<String> getWindowHandles() {
return driver.getWindowHandles();
}
@Override
public String getWindowHandle() {
return driver.getWindowHandle();
}
@Override
public TargetLocator switchTo() {
return driver.switchTo();
}
@Override
public Navigation navigate() {
return driver.navigate();
}
@Override
public Options manage() {
return driver.manage();
}
@Override
public Keyboard getKeyboard() {
return ((HasInputDevices) driver).getKeyboard();
}
@Override
public Mouse getMouse() {
return ((HasInputDevices) driver).getMouse();
}
@Override
public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException {
return ((TakesScreenshot) driver).getScreenshotAs(target);
}
@Override
public Object executeScript(String script, Object... args) {
return ((JavascriptExecutor) driver).executeScript(script, args);
}
@Override
public Object executeAsyncScript(String script, Object... args) {
return ((JavascriptExecutor) driver).executeAsyncScript(script, args);
}
@Override
public Capabilities getCapabilities() {
return new DesiredCapabilities();
}
private String getUniqueName(String imageKey) {
Preconditions.checkNotNull(imageNamePrefix);
return imageNamePrefix + "_" + imageKey;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB