问题
I'm currently playing around with the Selenium Marionette WebDriver
. In my application, I want to open multiple Marionette drivers sequentially. Basically something like this:
MarionetteDriver driver = new MarionetteDriver();
// do some stuff
driver.quit();
// a while later
driver = new MarionetteDriver();
// do some stuff
driver.quit();
Now I'm facing the problem, that only the first Marionette instance can be successfully started and for each later attempt, I'm getting the following exception. The problem happens every time and the used port always changes, so there is obviously no port conflict.
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
Any pointers appreciated!
回答1:
After digging a little deeper, I came to the following findings which eventually solved my issue:
Marionette resp.
wires
uses two ports (seewires --help
); amarionette-port
and awebdriver-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
When running multiple
MarionetteDrivers
simultaneously, both ports have to be different from the already running instance obviously. However, when using the default constructornew MarionetteDriver()
themarionette-port
remains constant (and is not determined based on some free port). We used some workaround (see below) for theGeckoDriverService.Builder
to always pick two randomly-chosen available ports.The current (version 2.48.2)
GeckoDriverService
has an empty implementation ofwaitUntilAvailable()
(which should check, if theWebDriver
is ready to go). Sporadically, this lead to theUnreachableBrowserException
posted above.
To circumvent these issues, we did something like this at the end:
// 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);
回答2:
You need to handle the binary required by Marionette. You can do it by hand (download the binary on your own and export the proper variable), or you can do it automatically using WebDriverManager. Simply add the following dependency:
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>1.6.0</version>
</dependency>
And then, in your code call to:
FirefoxDriverManager.getInstance().setup();
回答3:
Mostly UnreachableBrowserException
happens when Selenium couldn't find the required exe of the driver. Since you haven't put driver capabilities setup, I am assuming the following steps will solve your issue.
As per Mozilla MDN link Marionette is set as a 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);
Also, Marionette executable is added to the path (In Windows):
Adding the executable to the PATH
Selenium will try use the executable in the path. You will need to add it to the path using the following.
Finally, another SO question where UnreachableBrowserException issue is handled.
回答4:
I had similar issue, solved by creating overridden instance of MarionetteDriver with overridden builder implementation. Accepted answer is more elegant solution though. Did have much time to deep into the root cause
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);
}
}
}
来源:https://stackoverflow.com/questions/34510794/selenium-marionette-driver-unreachablebrowserexception-upon-second-launch