Selenium Marionette driver UnreachableBrowserException при втором запуске

В настоящее время я играю с марионеткой Селена WebDriver. В моем приложении я хочу открыть несколько драйверов Marionette последовательно. В основном что-то вроде этого:

MarionetteDriver driver = new MarionetteDriver();
// do some stuff
driver.quit();

// a while later

driver = new MarionetteDriver();
// do some stuff
driver.quit();

Теперь я сталкиваюсь с проблемой, что только первый экземпляр марионетки может быть успешно запущен, и для каждой последующей попытки я получаю следующее исключение. Проблема происходит каждый раз, и используемый порт всегда меняется, поэтому, очевидно, нет порта конфликт.

Exception in thread "main" org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possible causes are invalid address of the remote server or browser start-up failure.
Build info: version: '2.48.2', revision: '41bccdd10cf2c0560f637404c2d96164b67d9d67', time: '2015-10-09 13:08:06'
System info: host: 'qqilihq.local', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.11.2', java.version: '1.7.0_71'
Driver info: driver.version: MarionetteDriver
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:641)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:247)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:232)
    at org.openqa.selenium.firefox.MarionetteDriver.run(MarionetteDriver.java:84)
    at org.openqa.selenium.firefox.MarionetteDriver.<init>(MarionetteDriver.java:73)
    at org.openqa.selenium.firefox.MarionetteDriver.<init>(MarionetteDriver.java:45)
    at MyMainClass.main(MyMainClass.java:131)
Caused by: org.openqa.selenium.WebDriverException: org.apache.http.conn.HttpHostConnectException: Connect to localhost:41886 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused
Build info: version: '2.48.2', revision: '41bccdd10cf2c0560f637404c2d96164b67d9d67', time: '2015-10-09 13:08:06'
System info: host: 'qqilihq.local', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.11.2', java.version: '1.7.0_71'
Driver info: driver.version: MarionetteDriver
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:91)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:620)
    ... 6 more
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to localhost:41886 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.openqa.selenium.remote.internal.ApacheHttpClient.fallBackExecute(ApacheHttpClient.java:143)
    at org.openqa.selenium.remote.internal.ApacheHttpClient.execute(ApacheHttpClient.java:89)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:142)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:82)
    ... 7 more
Caused by: java.net.ConnectException: Connection refused
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)
    at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:74)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.    java:134)
    ... 20 more

любой указатели с благодарностью!

4 ответов


копнув немного глубже, я пришел к следующим выводам, которые в конечном итоге решили мою проблему:

  1. марионеток респ. wires использует два порта (см. wires --help); a marionette-port и webdriver-port:

    Usage:
        ./wires [OPTIONS]
    
    WebDriver to marionette proxy.
    
    optional arguments:
      -h,--help             show this help message and exit
      -b,--binary BINARY    Path to the Firefox binary
      --webdriver-host WEBDRIVER_HOST
                            Host to run webdriver server on
      --webdriver-port WEBDRIVER_PORT
                            Port to run webdriver on
      --marionette-port MARIONETTE_PORT
                            Port to run marionette on
      --connect-existing    Connect to an existing firefox process
    

    при запуске нескольких MarionetteDrivers одновременно, оба порта должны отличаться от уже запущенного экземпляра, очевидно. Однако, при использовании конструктора по умолчанию new MarionetteDriver() на marionette-port остается постоянным (и не определяется на основе на каком-то свободном порту). Мы использовали некоторые обходные пути (см. ниже) для GeckoDriverService.Builder всегда выбирать два случайно выбранных доступных порта.

  2. текущий (версия 2.48.2) GeckoDriverService имеет пустую реализацию waitUntilAvailable() (который должен проверить, если WebDriver готово к работе). Спорадически это приводит к UnreachableBrowserException выложил выше.

чтобы обойти эти вопросы, мы сделали что-то вроде этого в конце:

// determine free ports for Marionette and WebDriver
final int marionettePort = PortProber.findFreePort();
final int webDriverPort = PortProber.findFreePort();
// override, as GeckoDriverService provides no direct way to set the Marionette port
GeckoDriverService.Builder builder = new GeckoDriverService.Builder() {
    @Override
    protected ImmutableList<String> createArgs() {
        Builder<String> argsBuilder = ImmutableList.builder();
        argsBuilder.addAll(super.createArgs());
        argsBuilder.add(String.format("--marionette-port=%d", marionettePort));
        return argsBuilder.build();
    }
};
builder.usingPort(webDriverPort);
builder.usingDriverExecutable(pathToDriver);
GeckoDriverService driverService = builder.build();
try {
    driverService.start();
} catch (IOException e) {
    throw new IllegalStateException("Could not start the GeckoDriverService", e);
}
try {
    // keep checking the WebDriver port via Socket until it's available;
    // as far as I could tell, there is nothing more "high level", e.g. REST API
    waitUntilReady(webDriverPort, TimeUnit.SECONDS.toMillis(30));
} catch (InterruptedException e) {
    // ignore
}
return new MarionetteDriver(driverService, capabilities);

вам нужно обработать двоичный файл, требуемый марионеткой. Вы можете сделать это вручную (загрузить двоичный файл самостоятельно и экспортировать соответствующую переменную), или вы можете сделать это автоматически, используя WebDriverManager. Просто добавьте следующую зависимость:

<dependency>
   <groupId>io.github.bonigarcia</groupId>
   <artifactId>webdrivermanager</artifactId>
    <version>1.6.0</version>
</dependency>

и затем, в вашем коде вызовите:

FirefoxDriverManager.getInstance().setup();

в основном UnreachableBrowserException происходит, когда Selenium не может найти требуемый exe драйвера. Поскольку вы не поставили настройку возможностей драйвера, я предполагаю, что следующие шаги решат вашу проблему.

согласно Mozilla MDN ссылке марионетка устанавливается как DesiredCapability

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
// Set Marionette on so the Grid will use this instead of normal FirefoxDriver
capabilities.setCapability("marionette", true);

WebDriver driver = new RemoteWebDriver(capabilities); 

кроме того, исполняемый файл марионетки добавляется в путь (в Windows):

добавление исполняемого файла в путь

селен попробует использовать исполняемый файл в пути. Вам нужно будет добавить его в путь, используя следующее.

наконец, еще один так вопрос где обрабатывается проблема UnreachableBrowserException.


У меня была аналогичная проблема, решенная путем создания переопределенного экземпляра MarionetteDriver с переопределенной реализацией builder. Принятый ответ-более элегантное решение. У меня было много времени, чтобы глубоко в первопричину

public static class CustomBuilder extends org.openqa.selenium.firefox.GeckoDriverService.Builder {

    @Override
    protected GeckoDriverService createDriverService(File exe, int port, ImmutableList<String> args, ImmutableMap<String, String> environment) {
        try {
            return new GeckoDriverService(exe, port, args, environment) {
                @Override
                protected void waitUntilAvailable() throws MalformedURLException {
                    logger.info("Waiting until avaliable");
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                    }
                    super.waitUntilAvailable();

                    logger.info("Finished waiting until avaliable");
                }
            };
        } catch (IOException e) {
            throw new WebDriverException(e);
        }
    }
}