com.google.caja.plugin.WebDriverHandle.java Source code

Java tutorial

Introduction

Here is the source code for com.google.caja.plugin.WebDriverHandle.java

Source

// Copyright (C) 2013 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.caja.plugin;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.Logs;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariDriver;

import com.google.caja.SomethingWidgyHappenedError;
import com.google.caja.util.TestFlag;
import com.google.gwt.thirdparty.guava.common.base.Charsets;

/**
 * Wrapper around a WebDriver instance.
 */

class WebDriverHandle {
    private RemoteWebDriver driver = null;
    private boolean canExecuteScript = true;
    private boolean reportedVersion = false;
    private String firstWindow = null;
    private int windowSeq = 0;
    private boolean windowOpened = false;

    // Don't keep more than this many failed test windows. (Otherwise
    // a broken tree can overload a machine with browser windows.)
    private static final int MAX_FAILS_KEPT = 9;
    private static int failsKept = 0;

    WebDriver begin() {
        if (driver == null) {
            driver = makeDriver();
            firstWindow = driver.getWindowHandle();
            reportVersion(driver);
            try {
                driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
            } catch (WebDriverException e) {
                Echo.echo("failed to set pageLoadTimeout: " + e);
                // harmless, ignore
            }
            try {
                driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);
            } catch (WebDriverException e) {
                Echo.echo("failed to setScriptTimeout: " + e);
                // harmless, ignore
            }
        }
        // Try to open a new window
        String name = "cajatest" + (windowSeq++);
        windowOpened = (Boolean) executeScript("return !!window.open('', '" + name + "');");
        if (windowOpened) {
            driver.switchTo().window(name);
        }
        return driver;
    }

    // Selenium 2.33 has trouble executing script on Firefox 23 and later
    private Object executeScript(String script) {
        if (canExecuteScript) {
            try {
                return driver.executeScript(script);
            } catch (WebDriverException e) {
                canExecuteScript = false;
                Echo.echo("executeScript failed: " + e);
            }
        }
        return null;
    }

    private void reportVersion(RemoteWebDriver driver) {
        if (reportedVersion) {
            return;
        }
        reportedVersion = true;
        Capabilities caps = driver.getCapabilities();
        String name = caps.getBrowserName();
        if (name == null) {
            name = "unknown";
        }
        String version = caps.getVersion();
        if (version == null) {
            version = "unknown";
        }
        // Firefox's version is something like "20.0", which doesn't tell
        // you the exact build, so we also try to report buildID.
        String build = (String) executeScript("return String(navigator.buildID || '')");
        if (build != null && !"".equals(build)) {
            version += " build " + build;
        }
        Echo.echo("webdriver: browser " + name + " version " + version);
    }

    void end(boolean passed) {
        // If a test fails, drop the driver handle without close or quit,
        // leaving the browser open, which is helpful for debugging.
        if (!passed && !TestFlag.BROWSER_CLOSE.truthy() && failsKept++ < MAX_FAILS_KEPT) {
            driver = null;
        } else {
            try {
                // If we're reusing the same browser, close the current window.
                if (windowOpened) {
                    driver.close();
                    driver.switchTo().window(firstWindow);
                } else {
                    driver.get("about:blank");
                }
            } catch (Exception e) {
                Echo.echo("window cleanup failed: " + e);
                closeDriver();
            }
        }
    }

    void release() {
        closeDriver();
    }

    private void closeDriver() {
        if (driver != null) {
            try {
                driver.quit();
            } finally {
                driver = null;
            }
        }
    }

    private static RemoteWebDriver makeDriver() {
        DesiredCapabilities dc = new DesiredCapabilities();

        String browserType = TestFlag.BROWSER.getString("firefox");

        if ("chrome".equals(browserType)) {
            // Chrome driver is odd in that the path to Chrome is specified
            // by a desiredCapability when you start a session. The other
            // browser drivers will read a java system property on start.
            // This applies to both remote Chrome and local Chrome.
            ChromeOptions chromeOpts = new ChromeOptions();
            String chromeBin = TestFlag.CHROME_BINARY.getString(null);
            if (chromeBin != null) {
                chromeOpts.setBinary(chromeBin);
            }
            String chromeArgs = TestFlag.CHROME_ARGS.getString(null);
            if (chromeArgs != null) {
                String[] args = chromeArgs.split(";");
                chromeOpts.addArguments(args);
            }
            dc.setCapability(ChromeOptions.CAPABILITY, chromeOpts);
        }

        String url = TestFlag.WEBDRIVER_URL.getString("");

        if (!"".equals(url)) {
            dc.setBrowserName(browserType);
            dc.setJavascriptEnabled(true);
            try {
                return new RemoteWebDriver(new URL(url), dc);
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        } else if ("chrome".equals(browserType)) {
            return new ChromeDriver(dc);
        } else if ("firefox".equals(browserType)) {
            return new FirefoxDriver();
        } else if ("safari".equals(browserType)) {
            // TODO(felix8a): local safari doesn't work yet
            return new SafariDriver();
        } else {
            throw new RuntimeException("No local driver for browser type '" + browserType + "'");
        }
    }

    public void captureResults(String name) {
        if (driver == null) {
            return;
        }

        String dir = TestFlag.CAPTURE_TO.getString("");
        if ("".equals(dir)) {
            return;
        }

        if (!dir.endsWith("/")) {
            dir = dir + "/";
        }
        mkdirs(dir);

        // Try to capture the final html
        try {
            String source = driver.getPageSource();
            if (source != null) {
                saveToFile(dir + name + ".capture.html", source);
            }
        } catch (WebDriverException e) {
            Echo.echo("capture html failed: " + e);
        }

        // Try to capture a screenshot
        if (driver instanceof TakesScreenshot) {
            TakesScreenshot ss = (TakesScreenshot) driver;
            try {
                byte[] bytes = ss.getScreenshotAs(OutputType.BYTES);
                saveToFile(dir + name + ".capture.png", bytes);
            } catch (WebDriverException e) {
                Echo.echo("capture screenshot failed: " + e);
            }
        }

        // Try to capture logs
        try {
            Logs logs = driver.manage().logs();
            if (logs != null) {
                if (logs.getAvailableLogTypes().contains(LogType.BROWSER)) {
                    LogEntries entries = logs.get(LogType.BROWSER);
                    if (entries != null) {
                        StringBuilder sb = new StringBuilder();
                        for (LogEntry e : entries) {
                            sb.append(e.toString() + "\n");
                        }
                        saveToFile(dir + name + ".capture.log", sb.toString());
                    }
                }
            }
        } catch (WebDriverException e) {
            Echo.echo("capture logs failed: " + e);
        }
    }

    private static void mkdirs(String dirName) {
        File dir = new File(dirName);
        if (!dir.isDirectory() && !dir.mkdirs()) {
            Echo.echo("couldn't mkdir " + dirName);
        }
    }

    private static void saveToFile(String fileName, String str) {
        saveToFile(fileName, str.getBytes(Charsets.UTF_8));
    }

    private static void saveToFile(String fileName, byte[] bytes) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(fileName);
            try {
                out.write(bytes);
            } finally {
                out.close();
            }
        } catch (IOException e) {
            throw new SomethingWidgyHappenedError(e);
        }
    }
}