首先,让我们隔离这里遇到的异常:
private final int launcherPort = PortProber.findFreePort();
...
public OperaLauncherRunner(OperaSettings s) {
super(s);
// Locate the bundled launcher from OperaLaunchers project and copy it to its default location
// on users system if it's not there or outdated
bundledLauncher =
OperaLaunchers.class.getClassLoader().getResource("launchers/" + launcherNameForOS());
if (bundledLauncher == null) {
throw new OperaRunnerException("Not able to locate bundled launcher: " + bundledLauncher);
}
if (settings.getLauncher() == launcherDefaultLocation() &&
(!settings.getLauncher().exists() || isLauncherOutdated(settings.getLauncher()))) {
extractLauncher(bundledLauncher, settings.getLauncher());
}
makeLauncherExecutable(settings.getLauncher());
// Find an available Opera if present
if (settings.getBinary() == null) {
settings.setBinary(new File(OperaPaths.operaPath()));
}
// Create list of arguments for launcher binary
ImmutableList<String> arguments = buildArguments();
logger.config("launcher arguments: " + arguments);
try {
launcherRunner = new OperaLauncherBinary(settings.getLauncher().getPath(),
arguments.toArray(new String[]{}));
} catch (IOException e) {
throw new OperaRunnerException("Unable to start launcher: " + e.getMessage());
}
logger.fine("Waiting for launcher connection on port " + launcherPort);
try {
// Setup listener server
ServerSocket listenerServer = new ServerSocket(launcherPort);
listenerServer.setSoTimeout((int) OperaIntervals.LAUNCHER_TIMEOUT.getValue());
// Try to connect
launcherProtocol = new OperaLauncherProtocol(listenerServer.accept());
// We did it!
logger.fine("Connected with launcher on port " + launcherPort);
listenerServer.close();
// Do the handshake!
LauncherHandshakeRequest.Builder request = LauncherHandshakeRequest.newBuilder();
ResponseEncapsulation res = launcherProtocol.sendRequest(
MessageType.MSG_HELLO, request.build().toByteArray());
// Are we happy?
if (res.isSuccess()) {
logger.finer("Got launcher handshake: " + res.getResponse().toString());
} else {
throw new OperaRunnerException(
"Did not get launcher handshake: " + res.getResponse().toString());
}
} catch (SocketTimeoutException e) {
throw new OperaRunnerException("Timeout waiting for launcher to connect on port " +
launcherPort, e);
} catch (IOException e) {
throw new OperaRunnerException("Unable to listen to launcher port " + launcherPort, e);
}
}
我们从这段代码中学到了一些东西:
private final int launcherPort =
PortProber.findFreePort()
;
设置我们的launcherPort
,并且这个变量唯一地用于建立连接。
实际上,您的配置opera.port
在此块中被完全忽略。这似乎不太理想,它可能确实是一个错误或意外的回归。
一旦我们建立了本地端口,就会立即进行连接尝试:
// Setup listener server
ServerSocket listenerServer = new ServerSocket(launcherPort);
listenerServer.setSoTimeout((int) OperaIntervals.LAUNCHER_TIMEOUT.getValue());
// Try to connect
launcherProtocol = new OperaLauncherProtocol(listenerServer.accept());
所以,我们有一个与本地服务器紧密耦合的绑定。该端口被忽略,取而代之的是您系统上的空闲端口,但同时,它应该始终能够使用该端口。
如果您的防火墙确实没有阻止连接(正如您所讨论的),假设您希望 Opera 以编程方式连接,而不是手动打开连接。
根据一些文档,opera.host
带有以下警告:
opera.host (String) Opera 应该连接的主机。除非您手动启动 Opera,否则您将不需要它。
(另外强调我的。)
不用说,警告与我有关。同样,尽管它明显不适用:
opera.port (Integer) Opera 应该连接的端口。0 = 随机,-1 = Opera 默认值(用于 Opera > 12)。
(另外强调我的。)
简而言之:尝试运行您的应用程序,如下所示:
DesiredCapabilities capabilities = new DesiredCapabilities.opera();
capabilities.setCapability("opera.binary", "/path/to/your/opera");
capabilities.setCapability("opera.log.level", "CONFIG");
WebDriver driver = new OperaDriver(capabilities);
如果这不起作用,则说明您的项目或当前的 Opera 二进制文件有其他问题,无论是版本相关还是其他问题。