Java tutorial
/* * (C) Copyright 2013 Java Test Automation Framework Contributors. * * 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 de.ppi.selenium.browser; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.arquillian.phantom.resolver.ResolvingPhantomJSDriverService; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; import org.openqa.selenium.Proxy; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.firefox.FirefoxBinary; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.firefox.FirefoxProfile; import org.openqa.selenium.htmlunit.HtmlUnitDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.phantomjs.PhantomJSDriver; import org.openqa.selenium.phantomjs.PhantomJSDriverService; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.safari.SafariDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gargoylesoftware.htmlunit.BrowserVersion; /** * SessionPool functionality used by SessionManager instances. Based on * https://github.com/FINRAOS/JTAF-ExtWebDriver * */ public class DefaultWebDriverFactory implements WebDriverFactory { /** The LOG-Instance. */ private static final Logger LOG = LoggerFactory.getLogger(DefaultWebDriverFactory.class); /** * Key which holds the reference to an property-file which could be read * from {@link ClientProperties}. */ public static final String CLIENT_PROPERTIES_KEY = "client"; private static final long MILLISECONDS_IN_DAY = 86400000; private static final Object lock = new Object(); private static final Log log = LogFactory.getLog(DefaultWebDriverFactory.class); private static boolean executedTaskKill = false; @Override public void cleanup(Map<String, String> options) throws Exception { ClientProperties properties = new ClientProperties(options.get(CLIENT_PROPERTIES_KEY)); // TODO Improvement Is this really needed? if (!executedTaskKill) { synchronized (lock) { if (properties.isKillTasksAtStartup()) { if (properties.getBrowser().equalsIgnoreCase("ie") || properties.getBrowser().equalsIgnoreCase("iexplore") || properties.getBrowser().equalsIgnoreCase("*iexplore")) { try { Runtime.getRuntime().exec("taskkill /F /IM IEDriverServer.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue IEDriverServer.exe tasks"); } try { Runtime.getRuntime().exec("taskkill /F /IM iexplore.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue Internet Explorer browsers"); } } else if (properties.getBrowser().equalsIgnoreCase("chrome")) { if (properties.getOS() == null || properties.getOS().equalsIgnoreCase("windows")) { try { Runtime.getRuntime().exec("taskkill /F /IM chromedriver.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chromedriver.exe processes"); } try { Runtime.getRuntime().exec("taskkill /F /IM chrome.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chrome browsers"); } } else if (properties.getOS().equalsIgnoreCase("linux")) { try { Runtime.getRuntime().exec("killall -9 chromedriver"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chromedriver.exe processes"); } try { Runtime.getRuntime().exec("killall -9 chrome"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chrome browsers"); } } else if (properties.getOS().equalsIgnoreCase("mac")) { try { Runtime.getRuntime().exec("killall -KILL chromedriver"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chromedriver tasks"); } try { Runtime.getRuntime().exec("killall -KILL chrome"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue chrome browsers"); } } else { log.warn("Taskkill failed to kill any rogue chromedriver or chrome tasks because the OS" + "provided is either incorrect or not supported"); } } else if (properties.getBrowser().equalsIgnoreCase("firefox") || properties.getBrowser().equalsIgnoreCase("*firefox")) { if (properties.getOS() == null || properties.getOS().equalsIgnoreCase("windows")) { // there is no taskkill for FirefoxDriver because // there is no "server" used for Firefox try { Runtime.getRuntime().exec("taskkill /F /IM firefox.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue firefox browsers"); } } else if (properties.getOS().equalsIgnoreCase("linux")) { try { Runtime.getRuntime().exec("killall -9 firefox"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue firefox browsers"); } } else if (properties.getOS().equalsIgnoreCase("mac")) { try { Runtime.getRuntime().exec("killall -KILL firefox"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue firefox browsers"); } } else { log.warn("Taskkill failed to kill any rogue firefox tasks because the OS" + "provided is either incorrect or not supported"); } } else if (properties.getBrowser().equalsIgnoreCase("phantomjs")) { if (properties.getOS() == null || properties.getOS().equalsIgnoreCase("windows")) { try { Runtime.getRuntime().exec("taskkill /F /IM phantomjs.exe /T"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue phantomjs browsers"); } } else if (properties.getOS().equalsIgnoreCase("linux")) { try { Runtime.getRuntime().exec("killall -9 phantomjs"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue phantomjs browsers"); } } else if (properties.getOS().equalsIgnoreCase("mac")) { try { Runtime.getRuntime().exec("killall -KILL phantomjs"); } catch (IOException e) { log.warn("Taskkill failed to kill any rogue phantomjs browsers"); } } else { log.warn("Taskkill failed to kill any rogue phantomjs tasks because the OS" + "provided is either incorrect or not supported"); } } } executedTaskKill = true; } } removeWebDriverTempOldFolders(properties); } @Override public DesiredCapabilities createCapabilities(Map<String, String> options) throws Exception { ClientProperties properties = new ClientProperties(options.get(CLIENT_PROPERTIES_KEY)); final String browser = properties.getBrowser(); if (properties.isUseGrid()) { DesiredCapabilities capabilities = null; if (properties.getGridUrl().length() == 0) { throw new Exception("You must provide 'grid.url' to use Selenium Grid in client property file"); } if (browser.length() == 0) { throw new Exception("You must provide 'browser' to use Selenium Grid in client property file"); } if (properties.getGridPlatform().length() == 0) { throw new Exception( "You must provide 'grid.platform' to use Selenium Grid in client property file"); } if (browser.equalsIgnoreCase("ie") || browser.equalsIgnoreCase("iexplore") || browser.equalsIgnoreCase("*iexplore")) { capabilities = DesiredCapabilities.internetExplorer(); } else if ((browser.equalsIgnoreCase("firefox") || browser.equalsIgnoreCase("*firefox"))) { capabilities = DesiredCapabilities.firefox(); } else if (browser.equalsIgnoreCase("chrome")) { capabilities = DesiredCapabilities.chrome(); } else if (browser.equalsIgnoreCase("safari")) { capabilities = DesiredCapabilities.safari(); } else if (browser.equalsIgnoreCase("opera")) { capabilities = DesiredCapabilities.operaBlink(); } else if (browser.equalsIgnoreCase("android")) { capabilities = DesiredCapabilities.android(); } else if (browser.equalsIgnoreCase("ipad")) { capabilities = DesiredCapabilities.ipad(); } else if (browser.equalsIgnoreCase("iphone")) { capabilities = DesiredCapabilities.iphone(); } else if (browser.equalsIgnoreCase("phantomjs")) { capabilities = DesiredCapabilities.phantomjs(); } else { log.fatal("Unsupported browser: " + browser + " Please refer to documentation for supported browsers."); } capabilities.setVersion(properties.getBrowserVersion()); String platform = properties.getGridPlatform(); if (platform != null && platform.length() > 0) { capabilities.setCapability("platform", platform); } else { // Default to Windows 7 capabilities.setCapability("platform", "Windows 7"); } // Set Proxy String proxyStr = properties.getProxy(); String proxyHttps = properties.getProxyHttps(); Proxy proxy = null; if (proxyStr != null && !proxyStr.equals("")) { proxy = new Proxy(); proxy.setHttpProxy(proxyStr); } if (proxyHttps != null && !proxyHttps.equals("")) { if (proxy == null) { proxy = new Proxy(); } proxy.setSslProxy(proxyHttps); } if (proxy != null) { capabilities.setCapability(CapabilityType.PROXY, proxy); } // preparing data for session name String computerName = null; try { computerName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { LOG.warn("error getting the computer-name", e); } capabilities.setCapability("name", "WebBrowser client=" + properties.getClient() + "; started from " + computerName); String gridProperties = properties.getGridProperties(); if (gridProperties != null && gridProperties.length() > 0) { String[] gridPropertiesSlpitted = gridProperties.split(" "); for (String gridPropertiesSlpittedCurrent : gridPropertiesSlpitted) { if (gridPropertiesSlpittedCurrent != null && gridPropertiesSlpittedCurrent.length() > 0) { String[] propertyNameAndValue = gridPropertiesSlpittedCurrent.split("="); if (propertyNameAndValue.length == 2) { capabilities.setCapability(propertyNameAndValue[0], propertyNameAndValue[1]); } } } } return capabilities; } else { log.debug("browser [" + browser + "]"); // Turning off all console logs using java.util.logging Handler[] h = java.util.logging.LogManager.getLogManager().getLogger("").getHandlers(); for (int i = 0; i < h.length; i++) { if (h[i] instanceof ConsoleHandler) { h[i].setLevel(Level.OFF); } } String proxyProperty = properties.getProxy(); DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); if (proxyProperty != null) { Proxy proxy = new Proxy(); proxy.setHttpProxy(proxyProperty).setFtpProxy(proxyProperty).setSslProxy(proxyProperty); desiredCapabilities = new DesiredCapabilities(); if (browser != null && browser.equalsIgnoreCase("chrome")) { // chrome way of proxy initialization desiredCapabilities.setCapability("chrome.switches", Arrays.asList("--proxy-server=http://" + proxy)); } else { // ff and ie way of proxy initialization desiredCapabilities.setCapability(CapabilityType.PROXY, proxy); } } if (properties.getDownloadFolder() != null && properties.getDownloadFolder().length() > 0) { // '0' means to download to the desktop, '1' means to download // to the default "Downloads" directory, '2' means to use the // directory you specify in "browser.download.dir" desiredCapabilities.setCapability("browser.download.folderList", Integer.valueOf(2)); desiredCapabilities.setCapability("browser.download.dir", System.getProperty("user.dir") + System.getProperty("file.separator") + properties.getDownloadFolder()); desiredCapabilities.setCapability("browser.helperApps.neverAsk.saveToDisk", "text/csv, application/octet-stream, application/pdf, application/vnd.fdf, application/x-msdos-program, application/x-unknown-application-octet-stream, application/vnd.ms-powerpoint, application/excel, application/vnd.ms-publisher, application/x-unknown-message-rfc822, application/vnd.ms-excel, application/msword, application/x-mspublisher, application/x-tar, application/zip, application/x-gzip,application/x-stuffit,application/vnd.ms-works, application/powerpoint, application/rtf, application/postscript, application/x-gtar, video/quicktime, video/x-msvideo, video/mpeg, audio/x-wav, audio/x-midi, audio/x-aiff"); desiredCapabilities.setCapability("browser.helperApps.alwaysAsk.force", false); desiredCapabilities.setCapability("browser.download.manager.showWhenStarting", false); } return desiredCapabilities; } } @Override public WebDriver createWebDriver(Map<String, String> options, DesiredCapabilities capabilities) throws IOException { ClientProperties properties = new ClientProperties(options.get(CLIENT_PROPERTIES_KEY)); WebDriver wd = null; DesiredCapabilities desiredCapabilities = new DesiredCapabilities(capabilities); String browser = properties.getBrowser(); if (properties.isUseGrid()) { RemoteWebDriver remoteWebDriver = new RemoteWebDriver(new URL(properties.getGridUrl()), capabilities); remoteWebDriver.setFileDetector(new LocalFileDetector()); wd = remoteWebDriver; } else { if (browser == null || browser.equals("")) { throw new RuntimeException( "Browser cannot be null. Please set 'browser' in client properties. Supported browser types: IE, Firefox, Chrome, Safari, HtmlUnit."); } else if (browser.equalsIgnoreCase("ie") || browser.equalsIgnoreCase("iexplore") || browser.equalsIgnoreCase("*iexplore")) { String webdriverIEDriver = properties.getWebDriverIEDriver(); if (webdriverIEDriver != null) { System.setProperty("webdriver.ie.driver", webdriverIEDriver); } String browserVersion = properties.getBrowserVersion(); if (browserVersion == null || browserVersion.equals("")) { throw new RuntimeException( "When using IE as the browser, please set 'browser.version' in client properties"); } else { if (browserVersion.startsWith("9")) { desiredCapabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true); desiredCapabilities.setCapability( InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); wd = new InternetExplorerDriver(desiredCapabilities); } else { wd = new InternetExplorerDriver(desiredCapabilities); } } } else if ((browser.equalsIgnoreCase("firefox") || browser.equalsIgnoreCase("*firefox"))) { final String ffProfileFolder = properties.getFirefoxProfileFolder(); final String ffProfileFile = properties.getFirefoxProfileFile(); final String path = properties.getFfBinaryPath(); final FirefoxProfile ffp; if (ffProfileFolder != null) { ffp = new FirefoxProfile(new File(ffProfileFolder)); } else { ffp = new FirefoxProfile(); } if (ffProfileFile != null) { addPreferences(ffp, ffProfileFile); } addPreferences(ffp, properties); List<String> ffExtensions = properties.getFirefoxExtensions(); if (ffExtensions != null && ffExtensions.size() > 0) { addExtensionsToFirefoxProfile(ffp, ffExtensions); } if (path != null) { FirefoxBinary fireFox = getFFBinary(path); wd = new FirefoxDriver(fireFox, ffp, desiredCapabilities); } else { wd = new FirefoxDriver(new FirefoxBinary(), ffp, desiredCapabilities); } } else if (browser.equalsIgnoreCase("chrome")) { final String webdriverChromeDriver = properties.getWebDriverChromeDriver(); if (webdriverChromeDriver != null) { System.setProperty("webdriver.chrome.driver", webdriverChromeDriver); } final ChromeOptions chromeOptions = new ChromeOptions(); final String chromeBinaryPath = properties.getChromeBinaryPath(); if (chromeBinaryPath != null) { chromeOptions.setBinary(chromeBinaryPath); } if (properties.getAcceptedLanguages() != null) { final Map<String, Object> prefs = new HashMap<String, Object>(); prefs.put("intl.accept_languages", properties.getAcceptedLanguages()); chromeOptions.setExperimentalOption("prefs", prefs); } desiredCapabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions); wd = new ChromeDriver(desiredCapabilities); } else if (browser.equalsIgnoreCase("safari")) { wd = new SafariDriver(desiredCapabilities); } else if (browser.equalsIgnoreCase("htmlunit")) { final BrowserVersion browserVersion = BrowserVersion.FIREFOX_45; if (properties.getAcceptedLanguages() != null) { browserVersion.setBrowserLanguage(properties.getAcceptedLanguages().split(",")[0]); } wd = new HtmlUnitDriver(browserVersion); ((HtmlUnitDriver) wd).setJavascriptEnabled(true); } else if (browser.equalsIgnoreCase("phantomjs")) { final String webdriverPhantomJSDriver = properties.getWebDriverPhantomJSDriver(); if (properties.getAcceptedLanguages() != null) { desiredCapabilities.setCapability("phantomjs.page.customHeaders.Accept-Language", properties.getAcceptedLanguages()); } if (webdriverPhantomJSDriver != null) { desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, webdriverPhantomJSDriver); wd = new PhantomJSDriver(desiredCapabilities); } else { wd = new PhantomJSDriver(ResolvingPhantomJSDriverService.createDefaultService(), desiredCapabilities); } } else { throw new IllegalArgumentException("Unsupported browser type: " + browser + ". Supported browser types: IE, Firefox, Chrome, Safari, HtmlUnit, phantomjs."); } // move browser windows to specific position. It's useful for // debugging... final int browserInitPositionX = properties.getBrowserInitPositionX(); final int browserInitPositionY = properties.getBrowserInitPositionY(); if (browserInitPositionX != 0 || browserInitPositionY != 0) { wd.manage().window().setSize(new Dimension(1280, 1024)); wd.manage().window().setPosition(new Point(browserInitPositionX, browserInitPositionY)); } wd.manage().timeouts().implicitlyWait(properties.getAppearWaitTime(), TimeUnit.MILLISECONDS); } return wd; } @Override public Map<String, String> createDefaultOptions() { HashMap<String, String> ret = new HashMap<String, String>(); // Add any default options needed here (like path to default properties) ret.put(CLIENT_PROPERTIES_KEY, "client.properties"); return ret; } /** * * @param ffp for use in setting the firefox profile for the tests to use * when running firefox */ private static void addPreferences(FirefoxProfile ffp, ClientProperties properties) { ffp.setPreference("capability.policy.default.HTMLDocument.readyState", "allAccess"); ffp.setPreference("capability.policy.default.HTMLDocument.compatMode", "allAccess"); ffp.setPreference("capability.policy.default.Document.compatMode", "allAccess"); ffp.setPreference("capability.policy.default.Location.href", "allAccess"); ffp.setPreference("capability.policy.default.Window.pageXOffset", "allAccess"); ffp.setPreference("capability.policy.default.Window.pageYOffset", "allAccess"); ffp.setPreference("capability.policy.default.Window.frameElement", "allAccess"); ffp.setPreference("capability.policy.default.Window.frameElement.get", "allAccess"); ffp.setPreference("capability.policy.default.Window.QueryInterface", "allAccess"); ffp.setPreference("capability.policy.default.Window.mozInnerScreenY", "allAccess"); ffp.setPreference("capability.policy.default.Window.mozInnerScreenX", "allAccess"); if (properties.getAcceptedLanguages() != null) { ffp.setPreference("intl.accept_languages", properties.getAcceptedLanguages()); } } /** * * @param ffp the firefox profile you are using * @param propertiesFile the properties you want to add to the profile */ private static void addPreferences(FirefoxProfile ffp, String propertiesFile) { Properties firefoxProfile = new Properties(); try { firefoxProfile.load(new FileInputStream(propertiesFile)); } catch (Throwable th) { throw new RuntimeException("Could not load firefox profile", th); } for (Object o : firefoxProfile.keySet()) { String key = (String) o; String getVal = null; if (key.endsWith(".type")) { getVal = key.substring(0, key.lastIndexOf(".")); } if (getVal != null) { String type = firefoxProfile.getProperty(key); String value = firefoxProfile.getProperty(getVal + ".value"); if (value.contains("${PROJECT_PATH}")) { String projectPath = (new File("")).getAbsolutePath(); value = projectPath + value.replaceAll("\\$\\{PROJECT_PATH\\}", ""); } if (type.equalsIgnoreCase("BOOLEAN")) { ffp.setPreference(getVal, Boolean.parseBoolean(value)); } else if (type.equalsIgnoreCase("STRING")) { ffp.setPreference(getVal, value); } else if (type.equalsIgnoreCase("INTEGER") || type.equalsIgnoreCase("INT")) { ffp.setPreference(getVal, Integer.parseInt(value)); } } } } /** * * @param ffp the firefox profile specified * @param extensions extensions desired to be added * @throws IOException */ private static void addExtensionsToFirefoxProfile(FirefoxProfile ffp, List<String> extensions) throws IOException { for (String s : extensions) { ffp.addExtension(new File(s)); } } /** * * @param filePath the binary path location of the firefox app (where it's * installed) * @return */ private static FirefoxBinary getFFBinary(String filePath) { File[] possibleLocations = { new File(filePath != null ? filePath : ""), new File("C:\\Program Files\\Mozilla Firefox\\firefox.exe"), new File("C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"), }; File ffbinary = null; for (File curr : possibleLocations) { if (curr.exists()) { ffbinary = curr; break; } } if (ffbinary == null) { throw new RuntimeException("Unable to find firefox binary, please ensure that firefox is installed " + "on your system. If it is then please determine the path to your firefox.exe and set it as " + "binaryPath=<FIREFOX PATH HERE>"); } else { return new FirefoxBinary(ffbinary); } } /** * This method cleans out folders where the WebDriver temp information is * stored. * * @param properties client properties specified */ private static void removeWebDriverTempOldFolders(ClientProperties properties) { String tempFolder = System.getProperty("java.io.tmpdir"); int numberOfDaysToKeepTempFolders = properties.getNumberOfDaysToKeepTempFolders(); if (numberOfDaysToKeepTempFolders < 0) { numberOfDaysToKeepTempFolders = 7; } List<String> tempFolderNameContainsList = new ArrayList<String>(); tempFolderNameContainsList.add("anonymous"); tempFolderNameContainsList.add("scoped_dir"); tempFolderNameContainsList.add("webdriver-ie"); // add parameters from config file String tempFolderNameContainsListFromProp = properties.getTempFolderNameContainsList(); if (tempFolderNameContainsListFromProp != null) { String[] tempFolderNameContainsListFromPropSpit = tempFolderNameContainsListFromProp.split(","); for (String name : tempFolderNameContainsListFromPropSpit) { tempFolderNameContainsList.add(name); } } removeFolders(tempFolder, tempFolderNameContainsList, numberOfDaysToKeepTempFolders); } /** * This method can be called to remove specific folders or set how long you * want to keep the temp information. * * @param folder which temp folder you want to remove * @param folderTemplates the templates of these temp folders * @param numberOfDaysToKeepTempFolders how long you want to keep the temp * information */ private final static void removeFolders(String folder, List<String> folderTemplates, int numberOfDaysToKeepTempFolders) { long dateToRemoveFiledAfter = (new Date()).getTime() - (numberOfDaysToKeepTempFolders * MILLISECONDS_IN_DAY); File tempFolder = new File(folder); for (File currentFile : tempFolder.listFiles()) { if (currentFile.isDirectory()) { for (String folderTemplate : folderTemplates) { if (currentFile.getName().contains(folderTemplate) && (currentFile.lastModified() < dateToRemoveFiledAfter)) { try { currentFile.delete(); FileUtils.deleteDirectory(currentFile); log.debug("Folder '" + currentFile.getName() + "' deleted..."); } catch (Exception e) { log.fatal("Error deleting folder '" + currentFile.getName() + "'"); } } } } } } }