Skip to content

Commit

Permalink
Fix bugs and factoring; upgrade HtmlUnitDriver (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbabcoc authored Sep 23, 2021
1 parent f00148a commit f68f242
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 50 deletions.
7 changes: 4 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,15 @@ nexusStaging {
repositories {
mavenLocal()
mavenCentral()
maven { url 'https://repo1.maven.org/maven2' }
maven { url 'https://repo.maven.apache.org/maven2' }
maven { url "${projectDir}/repo" }
}

dependencies {
compile 'com.nordstrom.tools:java-utils:2.0.3'
compile 'com.nordstrom.tools:settings:2.3.9'
compile 'com.nordstrom.tools:junit-foundation:15.3.2'
compile 'com.nordstrom.tools:java-utils:2.1.0'
compile 'com.nordstrom.tools:settings:2.3.10'
compile 'com.nordstrom.tools:junit-foundation:15.3.4'
compile('com.github.sbabcoc:logback-testng:1.3.4') {
exclude group: 'org.testng', module: 'testng'
}
Expand Down
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
<revision>@projectVersion@</revision>
<timestamp>@projectTimestamp@</timestamp>
<selenium-api>@seleniumApi@</selenium-api>
<java-utils.version>2.0.3</java-utils.version>
<java-utils.version>2.1.0</java-utils.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
<source-plugin.version>3.2.1</source-plugin.version>
<javadoc-plugin.version>3.3.0</javadoc-plugin.version>
<settings.version>2.3.9</settings.version>
<junit-foundation.version>15.3.2</junit-foundation.version>
<settings.version>2.3.10</settings.version>
<junit-foundation.version>15.3.4</junit-foundation.version>
<logback-testng.version>1.3.4</logback-testng.version>
<sonar.language>java</sonar.language>
<jacoco.version>0.8.7</jacoco.version>
Expand Down Expand Up @@ -138,7 +138,7 @@
</activation>
<properties>
<release.version>7</release.version>
<testng-foundation.version>3.0.5-j7</testng-foundation.version>
<testng-foundation.version>3.0.6-j7</testng-foundation.version>
<selenium.version>2.53.1</selenium.version>
<commons-io.version>2.6</commons-io.version>
<jsoup.version>1.13.1</jsoup.version>
Expand Down Expand Up @@ -290,11 +290,11 @@
</activation>
<properties>
<release.version>8</release.version>
<testng-foundation.version>3.0.5-j8</testng-foundation.version>
<testng-foundation.version>3.0.6-j8</testng-foundation.version>
<selenium.version>3.141.59</selenium.version>
<guava.version>30.1.1-jre</guava.version>
<jsoup.version>1.14.2</jsoup.version>
<htmlunit.version>2.52.0</htmlunit.version>
<htmlunit.version>2.53.0</htmlunit.version>
<jcommander.version>1.78</jcommander.version>
<mockito.version>3.1.0</mockito.version>
<!-- managed to resolve identified threat -->
Expand Down
2 changes: 1 addition & 1 deletion selenium2Deps.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tasks.withType(JavaCompile) {

dependencies {
selenium2Compile configurations.compile
selenium2Compile 'com.nordstrom.tools:testng-foundation:3.0.5-j7'
selenium2Compile 'com.nordstrom.tools:testng-foundation:3.0.6-j7'
selenium2Compile 'commons-io:commons-io:2.4'
selenium2Compile('org.seleniumhq.selenium:selenium-server:2.53.1') {
exclude group: 'org.seleniumhq.selenium', module: 'selenium-java'
Expand Down
4 changes: 2 additions & 2 deletions selenium3Deps.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tasks.withType(JavaCompile) {

dependencies {
selenium3Compile configurations.compile
selenium3Compile 'com.nordstrom.tools:testng-foundation:3.0.5-j8'
selenium3Compile 'com.nordstrom.tools:testng-foundation:3.0.6-j8'
selenium3Compile('com.google.guava:guava:30.1.1-jre') { force = true }
selenium3Compile('com.beust:jcommander:1.78') { force = true }
selenium3Compile 'commons-io:commons-io:2.6'
Expand All @@ -23,7 +23,7 @@ dependencies {
exclude group: 'net.sourceforge.htmlunit', module: 'htmlunit'
}
selenium3Compile 'org.jsoup:jsoup:1.14.2'
selenium3Compile 'org.seleniumhq.selenium:htmlunit-driver:2.52.0'
selenium3Compile 'org.seleniumhq.selenium:htmlunit-driver:2.53.0'
selenium3Compile('com.squareup.okhttp3:okhttp:4.9.1') { force = true }
selenium3Compile('com.squareup.okio:okio:2.10.0') { force = true }
selenium3Compile('org.eclipse.jetty.websocket:websocket-client:9.4.43.v20210629') { force = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public HtmlUnitPlugin() {
* <pre>&lt;dependency&gt;
* &lt;groupId&gt;org.seleniumhq.selenium&lt;/groupId&gt;
* &lt;artifactId&gt;htmlunit-driver&lt;/artifactId&gt;
* &lt;version&gt;2.52.0&lt;/version&gt;
* &lt;version&gt;2.53.0&lt;/version&gt;
*&lt;/dependency&gt;</pre>
*/
private static final String[] DEPENDENCY_CONTEXTS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,10 @@ public static void beforeInvocation(final Object obj, final Method method) {

// if getting a driver
if (getDriver) {
SeleniumConfig config = SeleniumConfig.getConfig();

// if driver not yet acquired
if (!optDriver.isPresent()) {
long prior = System.currentTimeMillis();

long timeOutInSeconds = config.getLong(SeleniumSettings.HOST_TIMEOUT.key());
DriverSessionWait wait = new DriverSessionWait(instance, timeOutInSeconds);
wait.ignoring(WebDriverException.class);
WebDriver driver = wait.until(driverIsAcquired(method));

setDriverTimeouts(driver, config);
instance.setDriver(driver);
WebDriver driver = injectDriver(instance, method);
optDriver = Optional.of(driver);
if (instance.isTest(method)) {
long after = System.currentTimeMillis();
Expand All @@ -120,6 +111,7 @@ public static void beforeInvocation(final Object obj, final Method method) {

// if initial page spec'd
if (initialPage != null) {
SeleniumConfig config = SeleniumConfig.getConfig();
Page page = Page.openInitialPage(initialPage, optDriver.get(), config.getTargetUri());
instance.setInitialPage(instance.prepInitialPage(page));
instance.activatePlatform(instance.getDriver());
Expand Down Expand Up @@ -159,6 +151,25 @@ public static void onFinish() {
}
}

/**
* Inject new driver session into the indicated test context.
*
* @param instance test class instance
* @param method test method <br>
* <b>NOTE</b>: May be {@code null} if the test class isn't a {@link DriverProvider}.
* @return new driver session
*/
public static WebDriver injectDriver(TestBase instance, final Method method) {
SeleniumConfig config = SeleniumConfig.getConfig();
long timeOutInSeconds = config.getLong(SeleniumSettings.HOST_TIMEOUT.key());
DriverSessionWait wait = new DriverSessionWait(instance, timeOutInSeconds);
wait.ignoring(WebDriverException.class);
WebDriver driver = wait.until(driverIsAcquired(method));
setDriverTimeouts(driver, config);
instance.setDriver(driver);
return driver;
}

/**
* Set configured timeout intervals in the specified driver.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static SeleniumGrid launch(SeleniumConfig config, final Path hubConfigPat
* @param config {@link SeleniumConfig} object
* @return list of driver plugin instances
*/
private static List<DriverPlugin> getDriverPlugins(SeleniumConfig config) {
static List<DriverPlugin> getDriverPlugins(SeleniumConfig config) {
List<DriverPlugin> driverPlugins;

// get grid plugins setting
Expand Down Expand Up @@ -259,19 +259,14 @@ public static LocalGridServer start(final String launcherClassName, final String
}
}

// get assembled classpath string
String classPath = JarUtils.getClasspath(dependencyContexts);
// split on Java agent list separator
String[] pathBits = classPath.split("\n");
// if agent(s) specified
if (pathBits.length > 1) {
// extract classpath
classPath = pathBits[0];
// for each specified agent...
for (String agentPath : pathBits[1].split("\t")) {
// ... specify a 'javaagent' argument
argsList.add(0, "-javaagent:" + agentPath);
}
// get dependency context paths
List<String> contextPaths = JarUtils.getContextPaths(dependencyContexts);
// extract classpath specification
String classPath = contextPaths.remove(0);
// for each specified Java agent...
for (String agentSpec : contextPaths) {
// ... specify a 'javaagent' argument
argsList.add(0, agentSpec);
}

// specify Java class path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
Expand All @@ -33,6 +32,7 @@
import com.nordstrom.automation.selenium.DriverPlugin;
import com.nordstrom.automation.selenium.SeleniumConfig;
import com.nordstrom.automation.selenium.core.LocalSeleniumGrid.LocalGridServer;
import com.nordstrom.automation.selenium.plugins.PluginUtils;
import com.nordstrom.common.base.UncheckedThrow;

/**
Expand Down Expand Up @@ -93,7 +93,7 @@ public SeleniumGrid(SeleniumConfig config, URL hubUrl) throws IOException {
nodeServers.put(nodeEndpoint, new GridServer(nodeUrl, GridRole.NODE));
addNodePersonalities(config, hubServer.getUrl(), nodeEndpoint);
}
addPluginPersonalities();
addPluginPersonalities(config);
}

/**
Expand All @@ -116,7 +116,7 @@ public SeleniumGrid(SeleniumConfig config, GridServer hubServer, GridServer... n
this.nodeServers.put(nodeEndpoint, nodeServer);
addNodePersonalities(config, hubServer.getUrl(), nodeEndpoint);
}
addPluginPersonalities();
addPluginPersonalities(config);
}

/**
Expand Down Expand Up @@ -145,20 +145,22 @@ private void addNodePersonalities(SeleniumConfig config, URL hubUrl, String node
capsList = (List<Map>) conf.get("capabilities");
}
for (Map<String, Object> capsItem : capsList) {
String personalityName = (String) capsItem.get("automationName");
if (personalityName == null) {
personalityName = (String) capsItem.get("browserName");
String browserName = (String) capsItem.get("automationName");
if (browserName == null) {
browserName = (String) capsItem.get("browserName");
}
personalities.put(personalityName, config.toJson(capsItem));
personalities.putAll(PluginUtils.getPersonalitiesForBrowser(browserName));
}
}
}

/**
* Add supported personalities from configured driver plug-ins.
*
* @param config {@link SeleniumConfig} object
*/
private void addPluginPersonalities() {
for (DriverPlugin driverPlugin : ServiceLoader.load(DriverPlugin.class)) {
private void addPluginPersonalities(SeleniumConfig config) {
for (DriverPlugin driverPlugin : LocalSeleniumGrid.getDriverPlugins(config)) {
if (personalities.containsKey(driverPlugin.getBrowserName())) {
personalities.putAll(driverPlugin.getPersonalities());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,12 @@ public boolean isBoxChecked() {
return findElement(Using.CHECK).isSelected();
}

public static void setHubAsTarget() {
public static URI setHubAsTarget() {
URI targetUri = null;
SeleniumConfig config = SeleniumConfig.getConfig();
URL hubUrl = config.getSeleniumGrid().getHubServer().getUrl();
try {
URI targetUri = new URIBuilder()
targetUri = new URIBuilder()
.setScheme(hubUrl.getProtocol())
.setHost(hubUrl.getHost())
.setPort(hubUrl.getPort())
Expand All @@ -226,6 +227,7 @@ public static void setHubAsTarget() {
} catch (URISyntaxException e) {
// nothing to do here
}
return targetUri;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,8 @@ public static String getPageUrl(final PageUrl pageUrl, final URI targetUri) {
if ("file".equals(scheme)) {
result = Thread.currentThread().getContextClassLoader().getResource(path).toString();
} else {
Objects.requireNonNull(targetUri, "[targetUri] must be non-null");

String userInfo = pageUrl.userInfo();
String host = pageUrl.host();
String port = pageUrl.port();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private static synchronized InstanceCreator getCreator(final WrapsContext contex
.subclass(refClass)
.name(refClass.getPackage().getName() + ".Robust" + refClass.getSimpleName());

for (DriverPlugin driverPlugin : ServiceLoader.load(DriverPlugin.class)) {
for (DriverPlugin driverPlugin : ServiceLoader.loadInstalled(DriverPlugin.class)) {
Implementation ctorImpl = driverPlugin.getWebElementCtor(driver, refClass);
if (ctorImpl != null) {
builder = builder.defineConstructor(Visibility.PUBLIC).intercept(ctorImpl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ private FirefoxCaps() {
private static final String CAPABILITIES =
"{\"browserName\":\"firefox\",\"maxInstances\":5,\"seleniumProtocol\":\"WebDriver\"}";

private static final String BASELINE = "{\"browserName\":\"firefox\"}";
private static final String BASELINE =
"{\"browserName\":\"firefox\"," +
"\"marionette\":true}";

private static final String HEADLESS =
"{\"browserName\":\"firefox\"," +
"\"marionette\":true," +
"\"moz:firefoxOptions\":{\"args\":[\"-headless\"]}," +
"\"personality\":\"firefox.headless\"" +
"}";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.nordstrom.automation.selenium.plugins;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Map;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import com.nordstrom.automation.selenium.DriverPlugin;

/**
* This static utility class contains support methods for <b>Local Selenium Grid</b> plug-ins.
*/
public class PluginUtils {

private static final String PLUGIN_PACKAGE_NAME = PluginUtils.class.getPackage().getName();
private static final Logger LOGGER = LoggerFactory.getLogger(PluginUtils.class);

private PluginUtils() {
throw new AssertionError("PluginUtils is a static constants class that cannot be instantiated");
}

/**
* Get "personalities" from the plug-in that supports the specified browser.
* <p>
* <b>NOTE</b>: This method uses the {@link ClassLoader} of the current thread to search for candidate classes,
* and only plug-in classes in the <i>com.nordstrom.automation.selenium.plugins</i> package are
* considered.
*
* @param browserName browser name
* @return map: "personality" &rarr; desired capabilities (JSON); empty if plug-in for browser not found
*/
public static Map<String, String> getPersonalitiesForBrowser(String browserName) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassPath classPath = ClassPath.from(classLoader);
for (ClassInfo classInfo : classPath.getTopLevelClasses(PLUGIN_PACKAGE_NAME)) {
DriverPlugin driverPlugin = pluginForName(classInfo.getName());
if ((driverPlugin != null) && (driverPlugin.getBrowserName().equals(browserName))) {
return driverPlugin.getPersonalities();
}
}
} catch (IOException e) {
throw new IllegalArgumentException("Failed building class path model", e);
}
LOGGER.warn("No plugin for browser '{}' found in package: {}", browserName, PLUGIN_PACKAGE_NAME);
return Collections.emptyMap();
}

/**
* Create an instance of the specified plug-in class.
*
* @param candidateName candidate class name
* @return {@link DriverPlugin} object; {@code null} if instantiation attempt fails
*/
private static DriverPlugin pluginForName(String candidateName) {
try {
Class<?> clazz = Class.forName(candidateName);
if (DriverPlugin.class.isAssignableFrom(clazz)) {
return (DriverPlugin) ConstructorUtils.invokeConstructor(clazz);
}
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
InvocationTargetException | InstantiationException e) {
// nothing to do here
}
return null;
}

}

0 comments on commit f68f242

Please sign in to comment.