diff --git a/charts/zalenium/values.yaml b/charts/zalenium/values.yaml index e9ebce3149..6f0771eb78 100644 --- a/charts/zalenium/values.yaml +++ b/charts/zalenium/values.yaml @@ -5,7 +5,7 @@ hub: ## The tag for the image ## ref: https://hub.docker.com/r/dosel/zalenium/tags - tag: "3" + tag: "latest" ## Specify a imagePullPolicy ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images @@ -250,4 +250,4 @@ nodeSelector: hostAliases: [] # - ip: "127.0.0.1" # hostnames: -# - "cosbench.local" \ No newline at end of file +# - "cosbench.local" diff --git a/docs/_posts/2000-01-08-usage.md b/docs/_posts/2000-01-08-usage.md index 41be671f86..a01f14b4a4 100644 --- a/docs/_posts/2000-01-08-usage.md +++ b/docs/_posts/2000-01-08-usage.md @@ -331,6 +331,42 @@ Thanks [adrichem](https://github.com/adrichem) for implementing this feature! Mo +#### Change video recording status while in session +
+ Click for details. + +
+ It is possible to enable or disable video recording while the test is running regardless of what is setup when the session starts. + This is done by sending a cookie with the name zaleniumVideo with a value of true (to enable recording) + or false (to disable recording). Disabling recording while it is originally enable will result in a new video file. This can be useful + when you have multiple tests in one session and want to split up each test in its own file. This feature is only available with elgalu/selenium. + Here is an example in Java: + +{% highlight java %} + Cookie cookie = new Cookie("zaleniumVideo", "true"); + webDriver.manage().addCookie(cookie); +{% endhighlight %} + +
+ +
+ +#### Change test file name while in session +
+ Click for details. + +
+ A video file name can be changed in session by sending a cookie with the name zaleniumTestName with any value. + This can be useful when coupling with zaleniumVideo to give each split video a custom name. Here is an example in Java: + +{% highlight java %} + Cookie cookie = new Cookie("zaleniumTestName", "anyName"); + webDriver.manage().addCookie(cookie); +{% endhighlight %} + +
+ +
*** diff --git a/run_integration_tests.sh b/run_integration_tests.sh index f112ac8388..e9e3e17b58 100755 --- a/run_integration_tests.sh +++ b/run_integration_tests.sh @@ -15,7 +15,7 @@ else if [ "${INTEGRATION_TO_TEST}" = sauceLabs ]; then if [ -n "${SAUCE_USERNAME}" ]; then env "PATH=$PATH" mvn clean - mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -DintegrationToTest=${INTEGRATION_TO_TEST} + mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dgroups=normal -DintegrationToTest=${INTEGRATION_TO_TEST} # Check for generated videos ls -la ${VIDEOS_FOLDER}/saucelabs*.mp4 || (echo "No Sauce Labs videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) @@ -24,7 +24,7 @@ else if [ "${INTEGRATION_TO_TEST}" = browserStack ]; then if [ -n "${BROWSER_STACK_USER}" ]; then env "PATH=$PATH" mvn clean - mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -DintegrationToTest=${INTEGRATION_TO_TEST} + mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dgroups=normal -DintegrationToTest=${INTEGRATION_TO_TEST} # Check for generated videos ls -la ${VIDEOS_FOLDER}/browserstack*.mp4 || (echo "No BrowserStack videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) @@ -33,7 +33,7 @@ else if [ "${INTEGRATION_TO_TEST}" = testingBot ]; then if [ -n "${TESTINGBOT_KEY}" ]; then env "PATH=$PATH" mvn clean - mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -DintegrationToTest=${INTEGRATION_TO_TEST} + mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dgroups=normal -DintegrationToTest=${INTEGRATION_TO_TEST} # Check for generated videos ls -la ${VIDEOS_FOLDER}/testingbot*.mp4 || (echo "No TestingBot videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) @@ -42,7 +42,7 @@ else if [ "${INTEGRATION_TO_TEST}" = crossBrowserTesting ]; then if [ -n "${CBT_USERNAME}" ]; then env "PATH=$PATH" mvn clean - mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -DintegrationToTest=${INTEGRATION_TO_TEST} + mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dgroups=normal -DintegrationToTest=${INTEGRATION_TO_TEST} # Check for generated videos ls -la ${VIDEOS_FOLDER}/crossbrowsertesting*.mp4 || (echo "No CBT videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) @@ -51,7 +51,7 @@ else if [ "${INTEGRATION_TO_TEST}" = lambdaTest ]; then if [ -n "${LT_USERNAME}" ]; then env "PATH=$PATH" mvn clean - mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -DintegrationToTest=${INTEGRATION_TO_TEST} + mvn clean verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dgroups=normal -DintegrationToTest=${INTEGRATION_TO_TEST} # Check for generated videos ls -la ${VIDEOS_FOLDER}/lambdatest*.mp4 || (echo "No LambdaTest videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) @@ -64,7 +64,7 @@ else mkdir -p "${VIDEOS_FOLDER}" chmod +x target/zalenium_in_docker_compose.sh target/zalenium_in_docker_compose.sh start - mvn verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dskip.failsafe.setup=true -DintegrationToTest=sauceLabs + mvn verify -Pintegration-test -DthreadCountProperty=2 -Dskip.surefire.tests=true -Dskip.failsafe.setup=true -Dgroups=normal -DintegrationToTest=sauceLabs # Check for generated videos ls -la ${VIDEOS_FOLDER}/saucelabs*.mp4 || (echo "No Sauce Labs videos were downloaded." && exit 2) ls -la ${VIDEOS_FOLDER}/zalenium*.mp4 || (echo "No Zalenium videos were generated." && exit 2) diff --git a/src/main/java/de/zalando/ep/zalenium/dashboard/TestInformation.java b/src/main/java/de/zalando/ep/zalenium/dashboard/TestInformation.java index c8ccc8f0e1..10a9e86942 100644 --- a/src/main/java/de/zalando/ep/zalenium/dashboard/TestInformation.java +++ b/src/main/java/de/zalando/ep/zalenium/dashboard/TestInformation.java @@ -34,6 +34,7 @@ public class TestInformation { private String platform; private String platformVersion; private String fileName; + private int fileCount = 0; private String fileExtension; private String videoUrl; private List logUrls; @@ -113,6 +114,10 @@ public String getFileName() { return fileName; } + public int getFileCount() { + return fileCount; + } + public List getLogUrls() { return logUrls; } @@ -244,6 +249,12 @@ public String getBrowserAndPlatform() { public JsonObject getMetadata() { return this.metadata;} public void setMetadata(JsonObject metadata) { this.metadata = metadata;} + public void setTestName(String name) { this.testName = name;} + + public void setFileCount(int fileCount) { + this.fileCount = fileCount; + } + public boolean equals(Object obj) { if (obj == null) return false; if (obj == this) return true; diff --git a/src/main/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxy.java b/src/main/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxy.java index b5b461a745..711367b7f1 100644 --- a/src/main/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxy.java +++ b/src/main/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxy.java @@ -106,6 +106,7 @@ public class DockerSeleniumRemoteProxy extends DefaultRemoteProxy { private long cleanupStartedTime = 0; private AtomicBoolean timedOut = new AtomicBoolean(false); private long timeRegistered = System.currentTimeMillis(); + private boolean stopRecordingByCookie = false; public DockerSeleniumRemoteProxy(RegistrationRequest request, GridRegistry registry) { super(request, registry); @@ -326,6 +327,27 @@ public void beforeCommand(TestSession session, HttpServletRequest request, HttpS processContainerAction(DockerSeleniumContainerAction.SEND_NOTIFICATION, messageCommand, getContainerId()); } + if ("zaleniumVideo".equalsIgnoreCase(cookieName)) { + boolean recordVideo = Boolean.parseBoolean(cookie.get("value").getAsString()); + if (recordVideo && !isVideoRecordingEnabled()) { + setVideoRecordingEnabledSession(true); + testInformation.setVideoRecorded(true); + stopRecordingByCookie = false; + videoRecording(DockerSeleniumContainerAction.START_RECORDING); + } else if (!recordVideo && isVideoRecordingEnabled()){ + stopRecordingByCookie = true; + videoRecording(DockerSeleniumContainerAction.STOP_RECORDING); + setVideoRecordingEnabledSession(false); + testInformation.setVideoRecorded(false); + } + } + if ("zaleniumTestName".equalsIgnoreCase(cookieName)) { + String newTestName = cookie.get("value").getAsString(); + if (!newTestName.isEmpty()) { + testName = newTestName; + testInformation.setTestName(testName); + } + } else if(CommonProxyUtilities.metadataCookieName.equalsIgnoreCase(cookieName)) { JsonParser jsonParser = new JsonParser(); JsonObject metadata = jsonParser.parse(cookie.get("value").getAsString()).getAsJsonObject(); @@ -634,6 +656,9 @@ void processContainerAction(final DockerSeleniumContainerAction action, final St if (keepVideoAndLogs()) { if (DockerSeleniumContainerAction.STOP_RECORDING == action) { copyVideos(containerId); + if (stopRecordingByCookie) { + DashboardCollection.updateDashboard(testInformation); + } } if (DockerSeleniumContainerAction.TRANSFER_LOGS == action) { copyLogs(containerId); @@ -660,9 +685,18 @@ void copyVideos(final String containerId) { if (!Files.exists(videoFile.getParent())) { Files.createDirectories(videoFile.getParent()); } + + //For multiple recording in one session, add '_{count}' to the test name + if (Files.exists(videoFile)) { + testInformation.setTestName(testName + "_" + testInformation.getFileCount()); + testInformation.buildVideoFileName(); + videoFile = Paths.get(String.format("%s/%s", testInformation.getVideoFolderPath(), + testInformation.getFileName())); + } Files.copy(entry.get(), videoFile, StandardCopyOption.REPLACE_EXISTING); CommonProxyUtilities.setFilePermissions(videoFile); videoWasCopied = true; + testInformation.setFileCount(testInformation.getFileCount() + 1); LOGGER.debug("Video file copied to: {}/{}", testInformation.getVideoFolderPath(), testInformation.getFileName()); } } catch (IOException e) { @@ -765,22 +799,25 @@ private void unsetCleaningMarker() { private void cleanupNode(boolean willShutdown) { // This basically means that the node is cleaning up and will receive a new request soon // willShutdown == true => there won't be a next session - this.setCleaningMarker(!willShutdown); + if (!isCleaningUp()) { + this.setCleaningMarker(!willShutdown); - try { - if (testInformation != null) { - processContainerAction(DockerSeleniumContainerAction.SEND_NOTIFICATION, + try { + if (testInformation != null) { + processContainerAction(DockerSeleniumContainerAction.SEND_NOTIFICATION, testInformation.getTestStatus().getTestNotificationMessage(), getContainerId()); - } - videoRecording(DockerSeleniumContainerAction.STOP_RECORDING); - processContainerAction(DockerSeleniumContainerAction.TRANSFER_LOGS, getContainerId()); - processContainerAction(DockerSeleniumContainerAction.CLEANUP_CONTAINER, getContainerId()); + } + videoRecording(DockerSeleniumContainerAction.STOP_RECORDING); + processContainerAction(DockerSeleniumContainerAction.TRANSFER_LOGS, getContainerId()); + processContainerAction(DockerSeleniumContainerAction.CLEANUP_CONTAINER, + getContainerId()); - if (testInformation != null && keepVideoAndLogs()) { - DashboardCollection.updateDashboard(testInformation); + if (testInformation != null && keepVideoAndLogs()) { + DashboardCollection.updateDashboard(testInformation); + } + } finally { + this.unsetCleaningMarker(); } - } finally { - this.unsetCleaningMarker(); } } diff --git a/src/test/java/de/zalando/ep/zalenium/it/ParallelIT.java b/src/test/java/de/zalando/ep/zalenium/it/ParallelIT.java index cb7b38b94a..752abcd317 100644 --- a/src/test/java/de/zalando/ep/zalenium/it/ParallelIT.java +++ b/src/test/java/de/zalando/ep/zalenium/it/ParallelIT.java @@ -1,5 +1,7 @@ package de.zalando.ep.zalenium.it; +import org.openqa.selenium.By; +import org.openqa.selenium.Cookie; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.net.NetworkUtils; @@ -17,7 +19,9 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.util.concurrent.TimeUnit; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.containsString; @@ -148,7 +152,8 @@ private WebDriver getWebDriver() { return webDriver.get(); } - @Test(dataProvider = "browsersAndPlatformsForLivePreview") + @SuppressWarnings("groupsTestNG") + @Test(dataProvider = "browsersAndPlatformsForLivePreview", groups = "normal") public void checkIframeLinksForLivePreviewWithMachineIp(DesiredCapabilities desiredCapabilities) { NetworkUtils networkUtils = new NetworkUtils(); @@ -165,8 +170,8 @@ public void checkIframeLinksForLivePreviewWithMachineIp(DesiredCapabilities desi assertThat(pageSource, containsString("view_only=false")); } - - @Test(dataProvider = "browsersAndPlatforms") + @SuppressWarnings("groupsTestNG") + @Test(dataProvider = "browsersAndPlatforms", groups = "normal") public void loadGooglePageAndCheckTitle(DesiredCapabilities desiredCapabilities) { // Go to the homepage @@ -187,4 +192,47 @@ public void loadTheInternetPageAndCheckTitle(DesiredCapabilities desiredCapabili assertThat(getWebDriver().getTitle(), containsString("Internet")); } + @SuppressWarnings("groupsTestNG") + @Test(dataProvider = "browsersAndPlatformsForLivePreview", groups = {"minikube"}) + public void splitVideoRecordingOfOneSessionIntoMultipleFiles(DesiredCapabilities desiredCapabilities) { + + // Go to first page + getWebDriver().manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); + getWebDriver().get("https://the-internet.herokuapp.com/"); + + // Set test name + String testName = desiredCapabilities.getBrowserName() + "_splitVideoTest"; + Cookie nameCookie = new Cookie("zaleniumTestName", testName); + getWebDriver().manage().addCookie(nameCookie); + + // Stop the video + Cookie stopCookie = new Cookie("zaleniumVideo", "false"); + getWebDriver().manage().addCookie(stopCookie); + + // Start the video + Cookie startCookie = new Cookie("zaleniumVideo", "true"); + getWebDriver().manage().addCookie(startCookie); + + getWebDriver().get("https://www.google.com"); + + // Stop the video + getWebDriver().manage().addCookie(stopCookie); + + // Start the video + getWebDriver().manage().addCookie(startCookie); + + getWebDriver().get("https://www.apple.com"); + + // Stop the video + getWebDriver().manage().addCookie(stopCookie); + + // Go to the dashboard + getWebDriver().get(String.format("http://%s:%s/dashboard", ZALENIUM_HOST, ZALENIUM_PORT)); + + assertThat(getWebDriver().findElements(By.xpath("//small[text()='" + testName + "']")).size(), is(1)); + assertThat(getWebDriver().findElements(By.xpath("//small[text()='" + testName + "_1']")).size(), is(1)); + assertThat(getWebDriver().findElements(By.xpath("//small[text()='" + testName + "_2']")).size(), is(1)); + + } + } diff --git a/src/test/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxyTest.java b/src/test/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxyTest.java index 80b6cdac8f..a3e10f53f9 100644 --- a/src/test/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxyTest.java +++ b/src/test/java/de/zalando/ep/zalenium/proxy/DockerSeleniumRemoteProxyTest.java @@ -557,6 +557,76 @@ public void videoRecordingIsDisabledViaCapability() { Assert.assertFalse(proxy.isVideoRecordingEnabled()); } + @Test + public void videoRecordingStopAndStartViaCookie() { + Map requestedCapability = getCapabilitySupportedByDockerSelenium(); + requestedCapability.put("recordVideo", true); + + DockerSeleniumRemoteProxy spyProxy = spy(proxy); + + // Start pulling thread + spyProxy.startPolling(); + + // Get a test session + TestSession newSession = spyProxy.getNewSession(requestedCapability); + Assert.assertNotNull(newSession); + + // Set cookie. Start with turning video recording off + WebDriverRequest request = mock(WebDriverRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + when(request.getMethod()).thenReturn("POST"); + when(request.getRequestType()).thenReturn(RequestType.REGULAR); + when(request.getPathInfo()).thenReturn("/cookie"); + when(request.getBody()).thenReturn("{\"cookie\": {\"name\": \"zaleniumVideo\", \"value\": false}}"); + spyProxy.beforeCommand(newSession, request, response); + + // Assert video recording is stopped + String containerId = spyProxy.getContainerId(); + verify(spyProxy, times(1)) + .videoRecording(DockerSeleniumRemoteProxy.DockerSeleniumContainerAction.STOP_RECORDING); + verify(spyProxy, times(1)) + .processContainerAction(DockerSeleniumRemoteProxy.DockerSeleniumContainerAction.STOP_RECORDING, containerId); + verify(spyProxy, times(1)) + .copyVideos(containerId); + + // Turn the recording back on + when(request.getBody()).thenReturn("{\"cookie\": {\"name\": \"zaleniumVideo\", \"value\": true}}"); + spyProxy.beforeCommand(newSession, request, response); + + // Assert video recording is stopped + verify(spyProxy, times(1)) + .videoRecording(DockerSeleniumRemoteProxy.DockerSeleniumContainerAction.START_RECORDING); + verify(spyProxy, times(1)) + .processContainerAction(DockerSeleniumRemoteProxy.DockerSeleniumContainerAction.START_RECORDING, containerId); + } + + @Test + public void setTestNameViaCookie() { + String testName = "Test"; + + Map requestedCapability = getCapabilitySupportedByDockerSelenium(); + + DockerSeleniumRemoteProxy spyProxy = spy(proxy); + + // Start pulling thread + spyProxy.startPolling(); + + // Get a test session + TestSession newSession = spyProxy.getNewSession(requestedCapability); + Assert.assertNotNull(newSession); + + // Set cookie. Start with turning video recording off + WebDriverRequest request = mock(WebDriverRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + when(request.getMethod()).thenReturn("POST"); + when(request.getRequestType()).thenReturn(RequestType.REGULAR); + when(request.getPathInfo()).thenReturn("/cookie"); + when(request.getBody()).thenReturn("{\"cookie\": {\"name\": \"zaleniumTestName\", \"value\": \"" + testName + "\"}}"); + spyProxy.beforeCommand(newSession, request, response); + + Assert.assertEquals(spyProxy.getTestName(), testName); + } + private Map getCapabilitySupportedByDockerSelenium() { Map requestedCapability = new HashMap<>(); requestedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.CHROME);