我正在玩Selenium Marionette WebDriver
.在我的应用程序中,我想顺序打开多个Marionette驱动程序.基本上是这样的:
MarionetteDriver driver = new MarionetteDriver(); // do some stuff driver.quit(); // a while later driver = new MarionetteDriver(); // do some stuff driver.quit();
现在我面临的问题是,只有第一个Marionette实例可以成功启动,并且对于每个后来的尝试,我都会遇到以下异常.问题每次都会发生,并且使用的端口总是在变化,因此显然没有端口冲突.
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.(MarionetteDriver.java:73) at org.openqa.selenium.firefox.MarionetteDriver. (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
任何指针赞赏!
在深入挖掘之后,我得出了以下结论,最终解决了我的问题:
木偶和 wires
使用两个端口(见wires --help
); a marionette-port
和a 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.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 ImmutableListcreateArgs() { Builder 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);