Permalink
Browse files

Continued refactoring to separate out different TestWatchers that ser…

…ve different purposes. Removed test for SauceREST (tested now adequately in sauce-rest). Forced mockito to avoid providing its own hamcrest version.
  • Loading branch information...
1 parent b608dae commit 7e650c4dfe452c5968265ba3aea115bca5e5964a @yurodivuie yurodivuie committed Mar 10, 2012
View
30 pom.xml
@@ -77,6 +77,15 @@
<url>scm:git:git@github.com:dynacron-group/${project.artifactId}.git</url>
</scm>
+ <!-- needed for sauce-rest -->
+ <repositories>
+ <repository>
+ <id>dynacrongroup-repository</id>
+ <url>https://repository-dynacrongroup.forge.cloudbees.com/release</url>
+ </repository>
+ </repositories>
+
+
<dependencyManagement>
<dependencies>
<dependency>
@@ -129,10 +138,19 @@
<dependency>
<groupId>com.dynacrongroup</groupId>
<artifactId>sauce-rest</artifactId>
- <version>0.0</version>
+ <version>0.1</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>commons-logging</artifactId>
+ <groupId>commons-logging</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>commons-codec</artifactId>
+ <groupId>commons-codec</groupId>
+ </exclusion>
+ </exclusions>
</dependency>
-
<!-- logging dependencies -->
<dependency>
<groupId>ch.qos.logback</groupId>
@@ -177,9 +195,15 @@
<!-- Test dependencies -->
<dependency>
<groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
+ <artifactId>mockito-core</artifactId>
<version>1.9.0</version>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ </exclusion>
+ </exclusions>
</dependency>
@@ -0,0 +1,50 @@
+package com.dynacrongroup.webtest;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * This TestWatcher reports on test progress in Sauce Labs using the JavascriptExecutor.
+ *
+ * User: yurodivuie
+ * Date: 3/9/12
+ * Time: 8:52 AM
+ *
+ *
+ */
+public class SauceLabsContextReporter extends TestWatcher {
+
+ WebDriver driver;
+
+ public SauceLabsContextReporter(WebDriver driver) {
+ this.driver = driver;
+ }
+
+ @Override
+ protected void starting(Description description) {
+ sendContextMessage(description.getMethodName() + " started.");
+ }
+
+ @Override
+ protected void failed(Throwable e, Description description) {
+ sendContextMessage(description.getMethodName() + " failed. " + e.getMessage());
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ sendContextMessage(description.getMethodName() + " passed.");
+ }
+
+ /**
+ * Sends a message to Sauce Labs that will be visible in the logs.
+ * @param message
+ */
+ void sendContextMessage(String message) {
+ if (driver != null && WebDriverUtilities.isExecutedRemotely(driver)) {
+ ((JavascriptExecutor) driver).executeScript("sauce:context=// " + message);
+ }
+ }
+
+}
@@ -35,7 +35,10 @@
* JUnit rule that handles reporting failures and managing WebDriver teardown
*/
@Rule
- public WebDriverWatcher webDriverWatcher;
+ public WebDriverManager webDriverManager;
+
+ @Rule
+ public SauceLabsContextReporter sauceReporter;
/**
* Tracks the jobId, if specified, for the job in Sauce Labs.
@@ -45,7 +48,7 @@
/**
* Stores job pass/fail data for a given parameterized run.
*/
- private static ThreadLocal<WebDriverWatcher> localWatcher = new ThreadLocal<WebDriverWatcher>();
+ private static ThreadLocal<WebDriverManager> storedManager = new ThreadLocal<WebDriverManager>();
/**
* The logger associated with this specific browser test execution
@@ -76,29 +79,32 @@ public WebDriverBase(String browser, String version) {
* Alternate parameterized constructor for supplying custom capabilities.
*/
public WebDriverBase(String browser, String version, Map<String, Object> customCapabilities) {
- this.targetWebBrowser = new TargetWebBrowser(browser, version);
+ targetWebBrowser = new TargetWebBrowser(browser, version);
browserTestLog = LoggerFactory.getLogger(this.getClass()
.getName() + "-" + this.targetWebBrowser.humanReadable());
- //webDriverWatcher tracks the driver lifecycle and reports on results to sauce labs.
- if (localWatcher.get() == null) {
+ //webDriverManager tracks the driver lifecycle
+ if (getStoredManager() == null) {
driver = WebDriverLauncher.getNewWebDriverInstance(
- this.getJobName(),
+ getJobName(),
browserTestLog,
targetWebBrowser,
customCapabilities);
+ setStoredManager(new WebDriverManager(this.getClass(), this.driver, this.browserTestLog));
setJobId(WebDriverUtilities.getJobIdFromDriver(driver));
browserTestLog.debug("WebDriver ready.");
if (getJobURL() != null) {
browserTestLog.info("View on SauceLabs at " + getJobURL());
}
- localWatcher.set(new WebDriverWatcher(this.getClass(), this.driver, this.browserTestLog));
}
- webDriverWatcher = localWatcher.get();
+ webDriverManager = getStoredManager();
+
+ //Sauce Labs reporter provides logging in Sauce Labs for test start/stop points.
+ sauceReporter = new SauceLabsContextReporter(webDriverManager.getDriver());
}
/**
@@ -119,12 +125,14 @@ public WebDriverBase(String browser, String version, Map<String, Object> customC
@Before
public void startWebDriver() {
if (driver == null) {
- driver = webDriverWatcher.getDriver();
+ driver = webDriverManager.getDriver();
}
if (timer == null) {
- timer = new Timing(targetWebBrowser, this.getClass()
- .getSimpleName() + "," + name.getMethodName());
+ String testName = String.format("%s,%s",
+ this.getClass().getSimpleName(),
+ name.getMethodName());
+ timer = new Timing(targetWebBrowser, testName);
}
timer.start();
@@ -144,9 +152,10 @@ public final TargetWebBrowser getTargetWebBrowser() {
*/
public final String getJobURL() {
String jobUrl = null;
+ String currentJobId = getJobId();
- if (getJobId() != null && !this.targetWebBrowser.isClassLoaded()) {
- jobUrl = WebDriverUtilities.constructSauceJobUrl(jobId.get());
+ if (currentJobId != null && targetWebBrowser.isRemote()) {
+ jobUrl = WebDriverUtilities.constructSauceJobUrl(currentJobId);
}
return jobUrl;
@@ -191,4 +200,12 @@ public Logger getLogger() {
private final void setJobId(String id) {
jobId.set(id);
}
+
+ private final void setStoredManager(WebDriverManager manager) {
+ storedManager.set(manager);
+ }
+
+ private final WebDriverManager getStoredManager() {
+ return storedManager.get();
+ }
}
@@ -13,31 +13,24 @@
public final static String WEBDRIVER_DRIVER = "WEBDRIVER_DRIVER";
public final static String SINGLE_SAUCE = "SINGLE_SAUCE";
public final static String DEFAULT_TARGETS = "DEFAULT_TARGETS";
-
- public List<String[]> pair(String key, String value) {
- List<String[]> results = new ArrayList<String[]>();
- results.add(new String[]{key, value});
- return results;
- }
+ public final static String STANDARD_TARGETS = "firefox:5,iexplore:7,iexplore:8,iexplore:9,chrome:*";
public List<String[]> getDriverTargets() {
List<String[]> targets;
String classDriver = ConfigurationValue.getConfigurationValue(
WEBDRIVER_DRIVER, null);
+ String single_sauce = ConfigurationValue.getConfigurationValue(
+ SINGLE_SAUCE, null);
+
if (classDriver != null) {
targets = pair("byclass", classDriver);
- }
- else {
- String single_sauce = ConfigurationValue.getConfigurationValue(
- SINGLE_SAUCE, null);
- if (single_sauce != null) {
- String[] items = splitTarget(single_sauce);
- targets = pair(items[0], items[1]);
- } else {
- targets = standardSauceLabsTargets();
- }
+ } else if (single_sauce != null) {
+ String[] items = splitTarget(single_sauce);
+ targets = pair(items[0], items[1]);
+ } else {
+ targets = standardSauceLabsTargets();
}
return targets;
}
@@ -50,9 +43,8 @@
*/
private List<String[]> standardSauceLabsTargets() {
List<String[]> result = new ArrayList<String[]>();
-
String[] defaultSauceLabsTargets = ConfigurationValue.getConfigurationValue(DEFAULT_TARGETS,
- "firefox:5,iexplore:7,iexplore:8,iexplore:9,chrome:*").split(",");
+ STANDARD_TARGETS).split(",");
for (String windowsBrowser : defaultSauceLabsTargets) {
result.add(splitTarget(windowsBrowser));
@@ -61,6 +53,12 @@
return result;
}
+ private List<String[]> pair(String key, String value) {
+ List<String[]> results = new ArrayList<String[]>();
+ results.add(new String[]{key, value});
+ return results;
+ }
+
/**
* Splits a target string into browser/version String pair, with version set
* to null if version is "*".
@@ -0,0 +1,104 @@
+package com.dynacrongroup.webtest;
+
+import com.dynacrongroup.webtest.sauce.SauceREST;
+import com.google.common.annotations.VisibleForTesting;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.openqa.selenium.WebDriver;
+import org.slf4j.Logger;
+
+import java.lang.reflect.Method;
+
+import static com.dynacrongroup.webtest.WebDriverUtilities.getJobIdFromDriver;
+
+/**
+ * User: yurodivuie
+ * Date: 3/9/12
+ * Time: 8:52 AM
+ *
+ * This TestWatcher extension manages the driver and reports pass/fail when the test completes.
+ */
+public class WebDriverManager extends TestWatcher {
+
+ private static final SauceREST sauceRest = new SauceREST(SauceLabsCredentials.getUser(), SauceLabsCredentials.getKey());
+
+ WebDriver driver;
+ Logger log;
+ Integer methodsRemaining;
+
+ // The job is assumed to have passed until proven otherwise.
+ Boolean jobPassed = true;
+
+ public WebDriverManager(Class testClass, WebDriver driver, Logger browserTestLog) {
+ this.methodsRemaining = countTestMethods(testClass);
+ this.driver = driver;
+ this.log = browserTestLog;
+ WebDriverLeakCheck.add(testClass, driver);
+ }
+
+ public WebDriver getDriver() {
+ return driver;
+ }
+
+ /**
+ * Record test failure for final report to Sauce Labs, if applicable.
+ *
+ * @param throwable not used.
+ * @param description not used.
+ */
+ @Override
+ protected void failed(Throwable throwable, Description description) {
+ jobPassed = false;
+ }
+
+ /**
+ * Cleans up drivers after tests and reports on results. Note that this is executed
+ * after the failed/succeeded methods, allowing the manager to send a final update for the job
+ * before destroying the driver.
+ */
+ @Override
+ protected void finished(Description description) {
+ methodsRemaining--;
+ log.trace("Methods remaining after test finished: [{}]", methodsRemaining);
+ WebDriverUtilities.reduceToOneWindow(driver);
+
+ // Test class is complete
+ if (methodsRemaining == 0 && driver != null) {
+ //If this job is running in Sauce Labs, send pass/fail information
+ reportFinalStatus(driver, jobPassed);
+ WebDriverLeakCheck.remove(driver);
+ driver = null;
+ }
+ }
+
+ static void reportFinalStatus(WebDriver driver, Boolean jobPassed) {
+ if (WebDriverUtilities.isExecutedRemotely(driver)) {
+ String jobId = getJobIdFromDriver(driver);
+ if (jobPassed) {
+ sauceRest.jobPassed(jobId);
+ }
+ else {
+ sauceRest.jobFailed(jobId);
+ }
+ }
+ }
+
+ /**
+ * This method counts the number of test methods. This counter is used to
+ * help shut down the browsers when the test is complete.
+ */
+ @VisibleForTesting
+ static int countTestMethods(
+ @SuppressWarnings("rawtypes") Class clazz) {
+ int count = 0;
+ for (Method m : clazz.getMethods()) {
+ if ((m.getAnnotation(Test.class) != null)
+ && (m.getAnnotation(Ignore.class) == null)) {
+ count++;
+ }
+ }
+ return count;
+ }
+}
Oops, something went wrong.

0 comments on commit 7e650c4

Please sign in to comment.