Skip to content

Commit

Permalink
Resolve #326, making browser container startup timeout configurable.
Browse files Browse the repository at this point in the history
Reduces default browser container startup timeout to 15s, down from an
unnecessarily high 120s.

This also replaces inheritance-based `waitUntilContainerStarted` with
composition-based `WaitStrategy`. The new `LogMessageWaitStrategy` allows
us to wait based upon the Selenium container log output, rather than the
 relatively expensive process of repeatedly trying to create and connect
 a `RemoteWebDriver` instance.
  • Loading branch information
rnorth committed Apr 15, 2017
1 parent 764f9f8 commit 234215b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -867,8 +867,9 @@ public ExecResult execInContainer(Charset outputCharset, String... command)
*
* @param attempts number of attempts
*/
public void withStartupAttempts(int attempts) {
public SELF withStartupAttempts(int attempts) {
this.startupAttempts = attempts;
return self();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package org.testcontainers.containers;

import com.google.common.util.concurrent.Uninterruptibles;
import com.github.dockerjava.api.command.InspectContainerResponse;
import org.jetbrains.annotations.Nullable;
import org.junit.runner.Description;
import org.openqa.selenium.remote.BrowserType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.rnorth.ducttape.unreliables.Unreliables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.traits.LinkableContainer;
import org.testcontainers.containers.traits.VncService;
import org.testcontainers.containers.wait.LogMessageWaitStrategy;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.google.common.base.Preconditions.checkState;
import static java.time.temporal.ChronoUnit.SECONDS;

/**
* A chrome/firefox/custom container based on SeleniumHQ's standalone container sets.
Expand Down Expand Up @@ -55,14 +55,17 @@ public class BrowserWebDriverContainer<SELF extends BrowserWebDriverContainer<SE
/**
*/
public BrowserWebDriverContainer() {

this.waitStrategy = new LogMessageWaitStrategy()
.withRegEx(".*RemoteWebDriver instances should connect to.*\n")
.withStartupTimeout(Duration.of(15, SECONDS));
}

/**
* Constructor taking a specific webdriver container name and tag
* @param dockerImageName
*/
public BrowserWebDriverContainer(String dockerImageName) {
this();
super.setDockerImageName(dockerImageName);
this.customImageNameIsSet = true;
}
Expand Down Expand Up @@ -143,26 +146,18 @@ public int getPort() {
}

@Override
protected void waitUntilContainerStarted() {
// Repeatedly try and open a webdriver session

AtomicInteger backoff = new AtomicInteger(1000);

driver = Unreliables.retryUntilSuccess(120, TimeUnit.SECONDS, () -> {
Uninterruptibles.sleepUninterruptibly(backoff.getAndUpdate(current -> (int)(current * 1.5)), TimeUnit.MILLISECONDS);
RemoteWebDriver driver = new RemoteWebDriver(getSeleniumAddress(), desiredCapabilities);
driver.getCurrentUrl();

logger().info("Obtained a connection to container ({})", BrowserWebDriverContainer.this.getSeleniumAddress());
return driver;
});

protected void containerIsStarted(InspectContainerResponse containerInfo) {
if (recordingMode != VncRecordingMode.SKIP) {
LOGGER.debug("Starting VNC recording");
VncRecordingSidekickContainer recordingSidekickContainer = new VncRecordingSidekickContainer<>(this);

// Use multiple startup attempts due to race condition between Selenium being available and VNC being available
VncRecordingSidekickContainer recordingSidekickContainer = new VncRecordingSidekickContainer<>(this)
.withStartupAttempts(3);

recordingSidekickContainer.start();
currentVncRecordings.add(recordingSidekickContainer);
}
this.driver = new RemoteWebDriver(getSeleniumAddress(), desiredCapabilities);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.testcontainers.junit;

import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testcontainers.containers.BrowserWebDriverContainer;

import java.io.IOException;
import java.time.Duration;

import static java.time.temporal.ChronoUnit.SECONDS;

/**
*
*/
public class CustomWaitTimeoutWebDriverContainerTest extends BaseWebDriverContainerTest {

@Rule
public BrowserWebDriverContainer chromeWithCustomTimeout = new BrowserWebDriverContainer<>()
.withDesiredCapabilities(DesiredCapabilities.chrome())
.withStartupTimeout(Duration.of(30, SECONDS));

@Test
public void simpleTest() throws IOException {
doSimpleWebdriverTest(chromeWithCustomTimeout);
}
}

0 comments on commit 234215b

Please sign in to comment.