Skip to content

Commit

Permalink
Add MP4 support for Recorded video + Make FLV default format (testcon…
Browse files Browse the repository at this point in the history
  • Loading branch information
oussamabadr committed Dec 11, 2020
1 parent 7fb4f98 commit 8b78a9c
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@ToString
public class VncRecordingContainer extends GenericContainer<VncRecordingContainer> {

private static final String RECORDING_FILE_NAME = "/screen.flv";
private static final String ORIGINAL_RECORDING_FILE_NAME = "/screen.flv";

public static final String DEFAULT_VNC_PASSWORD = "secret";

Expand All @@ -36,6 +36,8 @@ public class VncRecordingContainer extends GenericContainer<VncRecordingContaine

private String vncPassword = DEFAULT_VNC_PASSWORD;

private VncRecordingFormat recordingFormat = VncRecordingFormat.FLV;

private int vncPort = 5900;

private int frameRate = 30;
Expand Down Expand Up @@ -72,6 +74,13 @@ public VncRecordingContainer withVncPort(int vncPort) {
return this;
}

public VncRecordingContainer withVideoExtension(VncRecordingFormat recordingFormat) {
if (recordingFormat != null) {
this.recordingFormat = recordingFormat;
}
return this;
}

public VncRecordingContainer withFrameRate(int frameRate) {
this.frameRate = frameRate;
return this;
Expand All @@ -84,7 +93,7 @@ protected void configure() {
setCommand(
"-c",
"echo '" + encodedPassword + "' | base64 -d > /vnc_password && " +
"flvrec.py -o " + RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort
"flvrec.py -o " + ORIGINAL_RECORDING_FILE_NAME + " -d -r " + frameRate + " -P /vnc_password " + targetNetworkAlias + " " + vncPort
);
}

Expand All @@ -97,18 +106,44 @@ public void saveRecordingToFile(File file) {

@SneakyThrows
public InputStream streamRecording() {
reencodeRecording();
String newRecordingFileName = recordingFormat.reencodeRecording(this, ORIGINAL_RECORDING_FILE_NAME);

TarArchiveInputStream archiveInputStream = new TarArchiveInputStream(
dockerClient.copyArchiveFromContainerCmd(getContainerId(), RECORDING_FILE_NAME).exec()
dockerClient.copyArchiveFromContainerCmd(getContainerId(), newRecordingFileName).exec()
);
archiveInputStream.getNextEntry();
return archiveInputStream;
}

private void reencodeRecording() throws IOException, InterruptedException {
String newFlvOutput = "/newScreen.flv";
execInContainer("ffmpeg" , "-i", RECORDING_FILE_NAME, "-vcodec", "libx264", newFlvOutput);
execInContainer("mv" , "-f", newFlvOutput, RECORDING_FILE_NAME);

public enum VncRecordingFormat {
FLV("flv") {
@Override
String reencodeRecording(VncRecordingContainer container, String source) throws IOException, InterruptedException {
String newFileOutput = "/newScreen.flv";
container.execInContainer("ffmpeg" , "-i", source, "-vcodec", "libx264", newFileOutput);
return newFileOutput;
}
},
MP4("mp4") {
@Override
String reencodeRecording(VncRecordingContainer container, String source) throws IOException, InterruptedException {
String newFileOutput = "/newScreen.mp4";
container.execInContainer("ffmpeg" , "-i", source, "-vcodec", "libx264", "-movflags", "faststart", newFileOutput);
return newFileOutput;
}
};

abstract String reencodeRecording(VncRecordingContainer container, String source) throws IOException, InterruptedException;

private final String filenameExtension;

VncRecordingFormat(String filenameExtension) {
this.filenameExtension = filenameExtension;
}

public String getExtension() {
return filenameExtension;
}
}
}
9 changes: 8 additions & 1 deletion docs/modules/webdriver_containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ just for failing tests.
[Record failing Tests](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordFailing
<!--/codeinclude-->

Note that the seconds parameter to `withRecordingMode` should be a directory where recordings can be saved.
Note that the second parameter of `withRecordingMode` should be a directory where recordings can be saved.

By default, the video will be recorded in [FLV](https://en.wikipedia.org/wiki/Flash_Video) format, but you can specify it explicitly or change it to [MP4](https://en.wikipedia.org/wiki/MPEG-4_Part_14) using `withRecordingMode` method with `VncRecordingFormat` option:

<!--codeinclude-->
[Video Format in MP4](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordAllMp4
[Video Format in FLV](../../modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java) inside_block:recordAllFlv
<!--/codeinclude-->

If you would like to customise the file name of the recording, or provide a different directory at runtime based on the description of the test and/or its success or failure, you may provide a custom recording file factory as follows:
<!--codeinclude-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.rnorth.ducttape.unreliables.Unreliables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat;
import org.testcontainers.containers.traits.LinkableContainer;
import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class BrowserWebDriverContainer<SELF extends BrowserWebDriverContainer<SE
@Nullable
private RemoteWebDriver driver;
private VncRecordingMode recordingMode = VncRecordingMode.RECORD_FAILING;
private VncRecordingFormat recordingFormat;
private RecordingFileFactory recordingFileFactory;
private File vncRecordingDirectory;

Expand Down Expand Up @@ -182,7 +184,8 @@ protected void configure() {

vncRecordingContainer = new VncRecordingContainer(this)
.withVncPassword(DEFAULT_PASSWORD)
.withVncPort(VNC_PORT);
.withVncPort(VNC_PORT)
.withVideoExtension(recordingFormat);
}

if (customImageName != null) {
Expand Down Expand Up @@ -334,7 +337,7 @@ private void retainRecordingIfNeeded(String prefix, boolean succeeded) {
}

if (shouldRecord) {
File recordingFile = recordingFileFactory.recordingFileForTest(vncRecordingDirectory, prefix, succeeded);
File recordingFile = recordingFileFactory.recordingFileForTest(vncRecordingDirectory, prefix, succeeded, vncRecordingContainer.getRecordingFormat());
LOGGER.info("Screen recordings for test {} will be stored at: {}", prefix, recordingFile);

vncRecordingContainer.saveRecordingToFile(recordingFile);
Expand All @@ -358,8 +361,13 @@ public SELF withLinkToContainer(LinkableContainer otherContainer, String alias)
}

public SELF withRecordingMode(VncRecordingMode recordingMode, File vncRecordingDirectory) {
return withRecordingMode(recordingMode, vncRecordingDirectory, null);
}

public SELF withRecordingMode(VncRecordingMode recordingMode, File vncRecordingDirectory, VncRecordingFormat recordingFormat) {
this.recordingMode = recordingMode;
this.vncRecordingDirectory = vncRecordingDirectory;
this.recordingFormat = recordingFormat;
return self();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@
import java.text.SimpleDateFormat;
import java.util.Date;

import static org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat;

public class DefaultRecordingFileFactory implements RecordingFileFactory {

private static final SimpleDateFormat filenameDateFormat = new SimpleDateFormat("YYYYMMdd-HHmmss");
private static final String PASSED = "PASSED";
private static final String FAILED = "FAILED";
private static final String FILENAME_FORMAT = "%s-%s-%s.flv";
private static final String FILENAME_FORMAT = "%s-%s-%s.%s";

@Override
public File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded) {
public File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded, VncRecordingFormat recordingFormat) {
final String resultMarker = succeeded ? PASSED : FAILED;
final String fileName = String.format(FILENAME_FORMAT,
resultMarker,
prefix,
filenameDateFormat.format(new Date())
filenameDateFormat.format(new Date()),
recordingFormat.getExtension()
);
return new File(vncRecordingDirectory, fileName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package org.testcontainers.containers;

import org.junit.runner.Description;
import org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat;

import java.io.File;

public interface RecordingFileFactory {

@Deprecated
default File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded) {
return recordingFileForTest(vncRecordingDirectory, description.getTestClass().getSimpleName() + "-" + description.getMethodName(), succeeded);
default File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded, VncRecordingFormat recordingFormat) {
return recordingFileForTest(vncRecordingDirectory, description.getTestClass().getSimpleName() + "-" + description.getMethodName(), succeeded, recordingFormat);
}

File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded);
File recordingFileForTest(File vncRecordingDirectory, String prefix, boolean succeeded, VncRecordingFormat recordingFormat);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat;

import java.io.File;
import java.nio.file.Files;
Expand Down Expand Up @@ -46,7 +47,7 @@ public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throw
File vncRecordingDirectory = Files.createTempDirectory("recording").toFile();
Description description = createTestDescription(getClass().getCanonicalName(), methodName, Test.class);

File recordingFile = factory.recordingFileForTest(vncRecordingDirectory, description, success);
File recordingFile = factory.recordingFileForTest(vncRecordingDirectory, description, success, VncRecordingFormat.FLV);

String expectedFilePrefix = format("%s-%s-%s", prefix, getClass().getSimpleName(), methodName);

Expand All @@ -57,4 +58,4 @@ public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throw

assertThat(expectedPossibleFileNames, hasItem(recordingFile));
}
}
}
Loading

0 comments on commit 8b78a9c

Please sign in to comment.