5

I am trying to integrate OperaDriver for Java (ver. 0.11) into my test suite. Here's the code snippet:

  DesiredCapabilities operaCapabilities = DesiredCapabilities.opera();
  operaCapabilities.setCapability("opera.host", "127.0.0.1");
  operaCapabilities.setCapability("opera.port", 7001);
  operaCapabilities.setCapability("opera.profile", "");

  webDriver = new OperaDriver(operaCapabilities);

The above code snippet fails to return a webdriver reference with a SocketTimeoutException Timeout waiting for launcher to connect on port 29392. I can see that the browser (opera ver. 11.62) is launched with speed dial tab loaded, and the launcher is also executing, but somehow OperaDriver seems to be unable to connect.

The exception I see is:

com.opera.core.systems.runner.OperaRunnerException: Timeout waiting for launcher to connect on port 29392
at com.opera.core.systems.runner.launcher.OperaLauncherRunner.<init>(OperaLauncherRunner.java:159)
at com.opera.core.systems.OperaDriver.<init>(OperaDriver.java:322)
at com.opera.core.systems.OperaDriver.<init>(OperaDriver.java:224)
at com.test.TestMain.main(TestMain.java:31)

Caused by: java.net.SocketTimeoutException: Accept timed out
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
    at java.net.ServerSocket.implAccept(ServerSocket.java:462)
    at java.net.ServerSocket.accept(ServerSocket.java:430)
    at com.opera.core.systems.runner.launcher.OperaLauncherRunner.<init>

(OperaLauncherRunner.java:140)
        ... 3 more

I have tried -1 for "opera.port" and also 7001, but the capability setting seems to be ignored, since it is attempting to connect with a random port each time. I have my firewalls temporarily turned off as well.

Ashwin Prabhu
  • 9,285
  • 5
  • 49
  • 82

1 Answers1

9

First, let's isolate the exception being hit here:

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);
    }
  }

We learn a few things from this code:

  1. private final int launcherPort =PortProber.findFreePort(); sets our launcherPort, and this variable is uniquely used to establish the connect.

    Indeed, your configuration of opera.port is completely ignored in this block. That seems less than desirable, and it may indeed be a bug or an unexpected regression.

  2. Once we establish the local port, a connection attempt is made immediately:

    // Setup listener server
    ServerSocket listenerServer = new ServerSocket(launcherPort); listenerServer.setSoTimeout((int) OperaIntervals.LAUNCHER_TIMEOUT.getValue());

    // Try to connect
    launcherProtocol = new OperaLauncherProtocol(listenerServer.accept());

So, we have a tightly coupled binding to the local server. The port is ignored in favor of a free one on your system, but simultaneously, it should always be able to use that port.

If your firewall is indeed not preventing the connection (as you've discussed), let's assume you desire Opera to be connected to programmatically, instead of manually opening the connection.

According to some documentation, opera.host carries the following caveat:

opera.host (String) The host Opera should connect to. Unless you're starting Opera manually you won't need this.

(Additional emphasis mine.)

Needless to say, the caveat concerns me. Likewise, despite its apparent inapplicability:

opera.port (Integer) The port to Opera should connect to. 0 = Random, -1 = Opera default (for use with Opera > 12).

(Additional emphasis mine.)

In short: try running your application as illustrated here:

DesiredCapabilities capabilities = new DesiredCapabilities.opera();
capabilities.setCapability("opera.binary", "/path/to/your/opera");
capabilities.setCapability("opera.log.level", "CONFIG");
WebDriver driver = new OperaDriver(capabilities);

If this doesn't work, something else is wrong, either with your project or with your current Opera binary, be it version-related or otherwise.

MrGomez
  • 23,788
  • 45
  • 72
  • 1
    Thanks Gomez. My findings match yours. I figured that the default port 7001 is not critical to connecting and any random port should suffice if things work normally. I tried in-memory editing of opera port back to 7001 just before it attempts connecting (after random port assignment) and saw the same results. I guess it must be 11.62 or operalauncher.exe (which I had to separately download) – Ashwin Prabhu Apr 11 '12 at 05:47
  • @AshwinPrabhu Cool. Do let me know if you need any more assistance tracking down the issue. I'll be happy to make myself available over Stack Overflow chat during the evening block, PST (7-12PM), should you want help with further troubleshooting. That should conform to workable morning hours for you. Good luck! – MrGomez Apr 11 '12 at 20:55
  • @Gomez. I logged a bug https://github.com/operasoftware/operadriver/issues/72 and gave up on Opera. Moved on to other important things. – Ashwin Prabhu Apr 17 '12 at 12:55
  • @AshwinPrabhu That'll do! Best of luck with the remainder of your work. :) – MrGomez Apr 17 '12 at 21:08
  • @Gomez Thanks. Since Opera desktop usage is languishing around 2-3%, this is not critical. – Ashwin Prabhu Apr 18 '12 at 08:05