Skip to content
This repository has been archived by the owner on Sep 21, 2021. It is now read-only.

Commit

Permalink
Merge pull request #53 from zalando/live-preview-features
Browse files Browse the repository at this point in the history
Live preview features
  • Loading branch information
diemol authored Jan 17, 2017
2 parents 06712e6 + aec8990 commit 58828ff
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 71 deletions.
29 changes: 24 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#== Ubuntu xenial is 16.04, i.e. FROM ubuntu:16.04
# Find latest images at https://hub.docker.com/r/library/ubuntu/
# Layer size: big: 127.2 MB
FROM ubuntu:xenial-20161010
FROM ubuntu:xenial-20161213
ENV UBUNTU_FLAVOR="xenial" \
UBUNTU_DATE="20161010"
UBUNTU_DATE="20161213"

#== Ubuntu flavors - common
RUN echo "deb http://archive.ubuntu.com/ubuntu ${UBUNTU_FLAVOR} main universe\n" > /etc/apt/sources.list \
&& echo "deb http://archive.ubuntu.com/ubuntu ${UBUNTU_FLAVOR}-updates main universe\n" >> /etc/apt/sources.list \
&& echo "deb http://archive.ubuntu.com/ubuntu ${UBUNTU_FLAVOR}-security main universe\n" >> /etc/apt/sources.list

MAINTAINER Team TIP <[email protected]>
# https://github.com/docker/docker/pull/25466#discussion-diff-74622923R677
LABEL maintainer "Team TIP <[email protected]>"

# No interactive frontend during docker build
ENV DEBIAN_FRONTEND=noninteractive \
Expand Down Expand Up @@ -209,12 +211,12 @@ RUN set -x \
&& docker-${DOCKER_VERSION} --version | grep "${DOCKER_VERSION}"

#-----------------------
# Docker 1.12.3 -- 15 MB
# Docker 1.12.6 -- 15 MB
#-----------------------
# https://github.com/docker-library/docker/blob/master/1.12/Dockerfile#L1
RUN set -x \
&& DOCKER_VERSION="1.12.3" \
DOCKER_SHA256="626601deb41d9706ac98da23f673af6c0d4631c4d194a677a9a1a07d7219fa0f" \
&& DOCKER_VERSION="1.12.6" \
DOCKER_SHA256="cadc6025c841e034506703a06cf54204e51d0cadfae4bae62628ac648d82efdd" \
&& curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz" \
-o docker.tgz \
&& echo "${DOCKER_SHA256} *docker.tgz" | sha256sum -c - \
Expand All @@ -223,6 +225,23 @@ RUN set -x \
&& rm -rf docker/ && rm docker.tgz \
&& docker-${DOCKER_VERSION} --version | grep "${DOCKER_VERSION}"

#-----------------
# Docker 1.13.0 --
#-----------------
# https://github.com/docker-library/docker/blob/master/1.13-rc/Dockerfile#L1
RUN set -x \
&& DOCKER_VERSION="1.13.0" \
&& DOCKER_VER_RC="-rc7" \
DOCKER_SHA256="beff8e0c5a235c0b9f374e4975401c793ceeca19332ffec965edb557ef7bfbc1" \
DOCKER_BUCKET="test.docker.com" \
&& curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}${DOCKER_VER_RC}.tgz" \
-o docker.tgz \
&& echo "${DOCKER_SHA256} *docker.tgz" | sha256sum -c - \
&& tar -xzvf docker.tgz \
&& mv docker/docker /usr/bin/docker-${DOCKER_VERSION} \
&& rm -rf docker/ && rm docker.tgz \
&& docker-${DOCKER_VERSION} --version | grep "${DOCKER_VERSION}"

# ------------------------#
# Sauce Connect Tunneling #
# ------------------------#
Expand Down
3 changes: 3 additions & 0 deletions docs/docker-compose-drone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ services:
- BROWSER_STACK_KEY
- TESTINGBOT_KEY
- TESTINGBOT_SECRET
# For OSX remember to include the docker version
# allowed values are: 1.11 or 1.12 or 1.13
# - DOCKER=1.11

# Feel free to add your services but remember
# to put them on the same network as Zalenium e.g.
Expand Down
2 changes: 1 addition & 1 deletion docs/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ services:
- TESTINGBOT_KEY
- TESTINGBOT_SECRET
# For OSX remember to include the docker version
# allowed values are: 1.11 or 1.12
# allowed values are: 1.11 or 1.12 or 1.13
# - DOCKER=1.11

# Feel free to add your services but remember
Expand Down
41 changes: 40 additions & 1 deletion docs/usage_examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
* [with TestingBot enabled](#with-testingbot-enabled)
* [with screen width and height, and time zone](#with-screen-width-and-height-and-time-zone)
* [Starting Zalenium with Docker Compose](#starting-zalenium-with-docker-compose)
* [Live preview](#live-preview)
* [Displaying the live preview](#displaying-the-live-preview)
* [Showing the test name on the live preview](#showing-the-test-name-on-the-live-preview)
* [Filtering tests by group name](#filtering-tests-by-group-name)


## Initial setup
Expand Down Expand Up @@ -75,4 +79,39 @@ Basic usage, without any of the integrated cloud testing platforms.

## Starting Zalenium with Docker Compose

You can see an example [here](./docker-compose.yaml)
You can see an example [here](./docker-compose.yaml)

## Live preview

### Displaying the live preview
* Just go to [http://localhost:4444/grid/admin/live](http://localhost:4444/grid/admin/live)
* You can also replace `localhost` for the IP/machine name where Zalenium is running.
* Auto-refresh, add `?refresh=numberOfSeconds` to refresh the view automatically. E.g.
[http://localhost:4444/grid/admin/live?refresh=20](http://localhost:4444/grid/admin/live?refresh=20) will refresh the
page every 20 seconds.

### Showing the test name on the live preview
Add a `name` capability with the test name to display it in the live preview. This helps to identify where your test
is running. Example code in Java for the capability:

```java
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX);
desiredCapabilities.setCapability(CapabilityType.PLATFORM, Platform.LINUX);
desiredCapabilities.setCapability("name", "myTestName");
```

### Filtering tests by group name
When more than one develper/tester is using the same instance of Zalenium, add a `group` capability to your tests. This
will let you filter the running tests in the live preview by passing `?group=myTestGroup` at the end of the url. E.g.

* Added capability

```java
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX);
desiredCapabilities.setCapability(CapabilityType.PLATFORM, Platform.LINUX);
desiredCapabilities.setCapability("group", "myTestGroup");
```

* Filter in live preview: [http://localhost:4444/grid/admin/live?group=myTestGroup](http://localhost:4444/grid/admin/live?group=myTestGroup)
2 changes: 1 addition & 1 deletion scripts/entry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set -e
if [ -f /usr/bin/docker ]; then
echo "Docker binary already present, will use that one."
else
# Grab the complete docker version `1.12.3` out of the partial one `1.12`
# Grab the complete docker version `1.12.5` out of the partial one `1.12`
export DOCKER_VERSION=$(ls /usr/bin/docker-${DOCKER}* | grep -Po '(?<=docker-)([a-z0-9\.]+)' | head -1)
# Link the docker binary to the selected docker version via e.g. `-e DOCKER=1.11`
sudo ln -s /usr/bin/docker-${DOCKER_VERSION} /usr/bin/docker
Expand Down
1 change: 1 addition & 0 deletions scripts/wait-saucelabs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ if [ "${SAUCE_TUNNEL}" = "true" ]; then
[ -z "${SAUCE_LOG_FILE}" ] && die "Required env var SAUCE_LOG_FILE"
while ! grep "${DONE_MSG}" ${SAUCE_LOG_FILE} >/dev/null; do
if grep "${GOODBYE_MSG}" ${SAUCE_LOG_FILE} >/dev/null; then
cat /home/seluser/logs/saucelabs-* 2>&1
die "Found GOODBYE_MSG '${GOODBYE_MSG}' in output so quitting."
fi
echo -n '.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class DockerSeleniumRemoteProxy extends DefaultRemoteProxy {
private static CommonProxyUtilities commonProxyUtilities = new CommonProxyUtilities();
private int amountOfExecutedTests;
private String testName;
private String testGroup;
private boolean stopSessionRequestReceived = false;
private DockerSeleniumNodePoller dockerSeleniumNodePollerThread = null;
private GoogleAnalyticsApi ga = new GoogleAnalyticsApi();
Expand Down Expand Up @@ -116,6 +117,7 @@ public TestSession getNewSession(Map<String, Object> requestedCapability) {
if (increaseCounter()) {
TestSession newSession = super.getNewSession(requestedCapability);
testName = requestedCapability.getOrDefault("name", "").toString();
testGroup = requestedCapability.getOrDefault("group", "").toString();
videoRecording(VideoRecordingAction.START_RECORDING);
return newSession;
}
Expand Down Expand Up @@ -202,6 +204,14 @@ void videoRecording(final VideoRecordingAction action) {
}
}

public String getTestName() {
return testName == null ? "" : testName;
}

public String getTestGroup() {
return testGroup == null ? "" : testGroup;
}

String getContainerId() throws DockerException, InterruptedException {
List<Container> containerList = dockerClient.listContainers(DockerClient.ListContainersParam.allContainers());
for (Container container : containerList) {
Expand All @@ -220,9 +230,9 @@ void processVideoAction(final VideoRecordingAction action, final String containe
final ExecCreation execCreation = dockerClient.execCreate(containerId, command,
DockerClient.ExecCreateParam.attachStdout(), DockerClient.ExecCreateParam.attachStderr());
final LogStream output = dockerClient.execStart(execCreation.id());
LOGGER.log(Level.INFO, String.format("%s %s", getNodeIpAndPort(), action.getRecordingAction()));
LOGGER.log(Level.INFO, () -> String.format("%s %s", getNodeIpAndPort(), action.getRecordingAction()));
try {
LOGGER.log(Level.INFO, String.format("%s %s", getNodeIpAndPort(), output.readFully()));
LOGGER.log(Level.INFO, () -> String.format("%s %s", getNodeIpAndPort(), output.readFully()));
} catch (RuntimeException e) {
LOGGER.log(Level.FINE, getNodeIpAndPort() + " " + e.toString(), e);
ga.trackException(e);
Expand All @@ -247,7 +257,7 @@ void copyVideos(final String containerId) throws IOException, DockerException, I
String fileExtension = entry.getName().substring(entry.getName().lastIndexOf('.'));
String fileName = String.format("%s_%s", entry.getName(), getCurrentDateAndTimeFormatted());
fileName = fileName.replace(fileExtension, "").concat(fileExtension);
fileName = testName.isEmpty() ? fileName : fileName.replace("vid_", testName + "_");
fileName = getTestName().isEmpty() ? fileName : fileName.replace("vid_", getTestName() + "_");
File curFile = new File(localPath, fileName);
File parent = curFile.getParentFile();
if (!parent.exists()) {
Expand All @@ -269,6 +279,11 @@ boolean isStopSessionRequestReceived() {
return stopSessionRequestReceived;
}

private String getCurrentDateAndTimeFormatted() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
return dateFormat.format(new Date());
}

public enum VideoRecordingAction {
START_RECORDING("start-video"), STOP_RECORDING("stop-video");

Expand All @@ -283,11 +298,6 @@ public String getRecordingAction() {
}
}

private String getCurrentDateAndTimeFormatted() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
return dateFormat.format(new Date());
}

/*
Class to poll continuously the node status regarding the amount of tests executed. If MAX_UNIQUE_TEST_SESSIONS
have been executed, then the node is removed from the grid (this should trigger the docker container to stop).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package de.zalando.tip.zalenium.servlet;

import com.google.gson.JsonObject;
import org.openqa.grid.common.exception.GridException;
import org.openqa.grid.internal.RemoteProxy;
import de.zalando.tip.zalenium.proxy.DockerSeleniumRemoteProxy;
import org.openqa.grid.internal.TestSession;
import org.openqa.grid.internal.TestSlot;
import org.openqa.grid.internal.utils.HtmlRenderer;
Expand All @@ -19,14 +18,43 @@ public class LiveNodeHtmlRenderer implements HtmlRenderer {

private static final Logger LOGGER = Logger.getLogger(LiveNodeHtmlRenderer.class.getName());

private RemoteProxy proxy;
private DockerSeleniumRemoteProxy proxy;
private String serverName;

public LiveNodeHtmlRenderer(RemoteProxy proxy, String serverName) {
@SuppressWarnings("WeakerAccess")
public LiveNodeHtmlRenderer(DockerSeleniumRemoteProxy proxy, String serverName) {
this.proxy = proxy;
this.serverName = serverName;
}

/**
* Platform for docker-selenium will be always Linux.
*
* @param proxy remote proxy
* @return Either the platform name, "Unknown", "mixed OS", or "not specified".
*/
@SuppressWarnings("WeakerAccess")
public static String getPlatform(DockerSeleniumRemoteProxy proxy) {

Platform res = getPlatform(proxy.getTestSlots().get(0));
if (res == null) {
return "not specified";
} else {
return res.toString();
}
}

private static Platform getPlatform(TestSlot slot) {
Object o = slot.getCapabilities().get(CapabilityType.PLATFORM);
if (o instanceof String) {
return Platform.valueOf((String) o);
} else if (o instanceof Platform) {
return (Platform) o;
} else {
return Platform.ANY;
}
}

@Override
public String renderSummary() {
StringBuilder builder = new StringBuilder();
Expand Down Expand Up @@ -60,10 +88,10 @@ private String getHtmlNodeVersion() {
String version = object.get("value").getAsJsonObject()
.get("build").getAsJsonObject()
.get("version").getAsString();
return " (version : "+version+ ")";
}catch (Exception e) {
return " (version : " + version + ")";
} catch (Exception e) {
LOGGER.log(Level.FINE, e.toString(), e);
return " unknown version, "+e.getMessage();
return " unknown version, " + e.getMessage();
}
}

Expand All @@ -85,7 +113,6 @@ private String tabConfig() {
return builder.toString();
}


// content of the browsers tab
private String tabBrowsers() {
StringBuilder builder = new StringBuilder();
Expand All @@ -95,6 +122,13 @@ private String tabBrowsers() {

for (TestSlot slot : proxy.getTestSlots()) {
wdLines.add(slot);
// Display test name when it exists in the capabilities
if (!proxy.getTestName().isEmpty()) {
builder.append("<p>Test name: ").append(proxy.getTestName()).append("</p>");
}
if (!proxy.getTestGroup().isEmpty()) {
builder.append("<p>Test group: ").append(proxy.getTestGroup()).append("</p>");
}
}

if (!wdLines.getLinesType().isEmpty()) {
Expand Down Expand Up @@ -174,48 +208,4 @@ private String nodeTabs() {
return nodeTabs;
}


/**
* return the platform for the proxy. It should be the same for all slots of the proxy, so checking that.
* @param proxy remote proxy
* @return Either the platform name, "Unknown", "mixed OS", or "not specified".
*/
public static String getPlatform(RemoteProxy proxy) {
Platform res;
if (proxy.getTestSlots().isEmpty()) {
return "Unknown";
} else {
res = getPlatform(proxy.getTestSlots().get(0));
}

for (TestSlot slot : proxy.getTestSlots()) {
Platform tmp = getPlatform(slot);
if (tmp != res) {
return "mixed OS";
} else {
res = tmp;
}
}
if (res == null) {
return "not specified";
} else {
return res.toString();
}
}

private static Platform getPlatform(TestSlot slot) {
Object o = slot.getCapabilities().get(CapabilityType.PLATFORM);
if (o == null) {
return Platform.ANY;
} else {
if (o instanceof String) {
return Platform.valueOf((String) o);
} else if (o instanceof Platform) {
return (Platform) o;
} else {
throw new GridException("Cannot cast " + o + " to org.openqa.selenium.Platform");
}
}
}

}
Loading

0 comments on commit 58828ff

Please sign in to comment.