From b08541e4feef9a916ff6bdd795c4e8b409d84b2d Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Tue, 28 Nov 2017 04:44:57 +1100 Subject: [PATCH 1/7] Add RecordingFileFactory with default implementation By default this returns a file in the given vlc recording directory named '---.flv', where RESULT is either 'PASSED' or 'FAILED'. A custom factory can be provided to BrowserWebDriverContainer#withRecordingFileFactory. The factory is only applicable if the BrowserWebDriverContainer#recordingMode enables the retention of recordings. Fixes #500. --- .../containers/BrowserWebDriverContainer.java | 18 +++--- .../DefaultRecordingFileFactory.java | 24 ++++++++ .../containers/RecordingFileFactory.java | 9 +++ .../DefaultRecordingFileFactoryTest.java | 57 +++++++++++++++++++ ...ChromeRecordingWebDriverContainerTest.java | 4 +- 5 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java create mode 100644 modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java create mode 100644 modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 443ddde9591..1d46494fa91 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -17,11 +17,9 @@ 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 static java.time.temporal.ChronoUnit.SECONDS; @@ -47,12 +45,12 @@ public class BrowserWebDriverContainer currentVncRecordings = new ArrayList<>(); private static final Logger LOGGER = LoggerFactory.getLogger(BrowserWebDriverContainer.class); - private static final SimpleDateFormat filenameDateFormat = new SimpleDateFormat("YYYYMMdd-HHmmss"); /** */ @@ -60,6 +58,7 @@ public BrowserWebDriverContainer() { this.waitStrategy = new LogMessageWaitStrategy() .withRegEx(".*(RemoteWebDriver instances should connect to|Selenium Server is up and running).*\n") .withStartupTimeout(Duration.of(15, SECONDS)); + this.withRecordingFileFactory(new DefaultRecordingFileFactory()); } /** @@ -187,7 +186,7 @@ protected void failed(Throwable e, Description description) { switch (recordingMode) { case RECORD_FAILING: case RECORD_ALL: - stopAndRetainRecording(description); + stopAndRetainRecording(description, false); break; } currentVncRecordings.clear(); @@ -198,7 +197,7 @@ protected void succeeded(Description description) { switch (recordingMode) { case RECORD_ALL: - stopAndRetainRecording(description); + stopAndRetainRecording(description, true); break; } currentVncRecordings.clear(); @@ -212,9 +211,8 @@ protected void finished(Description description) { this.stop(); } - private void stopAndRetainRecording(Description description) { - File recordingFile = new File(vncRecordingDirectory, "recording-" + filenameDateFormat.format(new Date()) + ".flv"); - + private void stopAndRetainRecording(Description description, boolean succeeded) { + File recordingFile = recordingFileFactory.recordingFileForTest(vncRecordingDirectory, description, succeeded); LOGGER.info("Screen recordings for test {} will be stored at: {}", description.getDisplayName(), recordingFile); for (VncRecordingSidekickContainer container : currentVncRecordings) { @@ -244,6 +242,10 @@ public SELF withRecordingMode(VncRecordingMode recordingMode, File vncRecordingD return self(); } + public SELF withRecordingFileFactory(RecordingFileFactory recordingFileFactory) { + this.recordingFileFactory = recordingFileFactory; + return self(); + } public enum VncRecordingMode { SKIP, RECORD_ALL, RECORD_FAILING diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java new file mode 100644 index 00000000000..48cadd11229 --- /dev/null +++ b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java @@ -0,0 +1,24 @@ +package org.testcontainers.containers; + +import org.junit.runner.Description; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DefaultRecordingFileFactory implements RecordingFileFactory { + + private static final SimpleDateFormat filenameDateFormat = new SimpleDateFormat("YYYYMMdd-HHmmss"); + + @Override + public File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded) { + final String prefix = succeeded ? "PASSED" : "FAILED"; + final String fileName = String.format("%s-%s-%s-%s.flv", + prefix, + description.getTestClass().getSimpleName(), + description.getMethodName(), + filenameDateFormat.format(new Date()) + ); + return new File(vncRecordingDirectory, fileName); + } +} diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java b/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java new file mode 100644 index 00000000000..cbd91562301 --- /dev/null +++ b/modules/selenium/src/main/java/org/testcontainers/containers/RecordingFileFactory.java @@ -0,0 +1,9 @@ +package org.testcontainers.containers; + +import org.junit.runner.Description; + +import java.io.File; + +public interface RecordingFileFactory { + File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded); +} diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java new file mode 100644 index 00000000000..2e34273041c --- /dev/null +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -0,0 +1,57 @@ +package org.testcontainers.containers; + +import lombok.Value; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.text.SimpleDateFormat; +import java.util.*; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.runner.Description.createTestDescription; + +@RunWith(Parameterized.class) +@Value +public class DefaultRecordingFileFactoryTest { + + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("YYYYMMdd-HHmmss"); + + + @Parameterized.Parameters + public static Collection data() { + Random random = new Random(); + return new ArrayList() {{ + add(new Object[]{format("testMethodName%d", random.nextInt()), "FAILED", FALSE}); + add(new Object[]{format("testMethodName%d", random.nextInt()), "PASSED", TRUE}); + }}; + } + + private final DefaultRecordingFileFactory factory = new DefaultRecordingFileFactory(); + private final String methodName; + private final String prefix; + private final boolean success; + + @Test + public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throws Exception { + File vncRecordingDirectory = Files.createTempDirectory("recording").toFile(); + Description description = createTestDescription(getClass().getCanonicalName(), methodName, Test.class); + + File recordingFile = factory.recordingFileForTest(vncRecordingDirectory, description, success); + + File expectedFile = new File(vncRecordingDirectory, format("%s-%s-%s-%s.flv", + prefix, + getClass().getSimpleName(), + methodName, + DATE_FORMAT.format(new Date())) + ); + assertEquals(expectedFile, recordingFile); + } +} \ No newline at end of file diff --git a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java index 5698b083339..6eba1ae478d 100644 --- a/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/junit/ChromeRecordingWebDriverContainerTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.DefaultRecordingFileFactory; import java.io.File; @@ -17,7 +18,8 @@ public class ChromeRecordingWebDriverContainerTest extends BaseWebDriverContaine @Rule public BrowserWebDriverContainer chromeThatRecordsAllTests = new BrowserWebDriverContainer() .withDesiredCapabilities(DesiredCapabilities.chrome()) - .withRecordingMode(RECORD_ALL, new File("./target/")); + .withRecordingMode(RECORD_ALL, new File("./target/")) + .withRecordingFileFactory(new DefaultRecordingFileFactory()); @Rule public BrowserWebDriverContainer chromeThatRecordsFailingTests = new BrowserWebDriverContainer() From 30dcbb7d45fc87c57d6de49d3c2104881e64fd27 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Tue, 28 Nov 2017 09:22:35 +1100 Subject: [PATCH 2/7] Fix Codacy failures/warnings Fixes #500 --- .../DefaultRecordingFileFactoryTest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java index 2e34273041c..049bfb58803 100644 --- a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -7,10 +7,12 @@ import org.junit.runners.Parameterized; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Random; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; @@ -24,21 +26,20 @@ public class DefaultRecordingFileFactoryTest { private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("YYYYMMdd-HHmmss"); + private final DefaultRecordingFileFactory factory = new DefaultRecordingFileFactory(); + private final String methodName; + private final String prefix; + private final boolean success; @Parameterized.Parameters public static Collection data() { Random random = new Random(); - return new ArrayList() {{ - add(new Object[]{format("testMethodName%d", random.nextInt()), "FAILED", FALSE}); - add(new Object[]{format("testMethodName%d", random.nextInt()), "PASSED", TRUE}); - }}; + Collection args = new ArrayList<>(); + args.add(new Object[]{format("testMethodName%d", random.nextInt()), "FAILED", FALSE}); + args.add(new Object[]{format("testMethodName%d", random.nextInt()), "PASSED", TRUE}); + return args; } - private final DefaultRecordingFileFactory factory = new DefaultRecordingFileFactory(); - private final String methodName; - private final String prefix; - private final boolean success; - @Test public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throws Exception { File vncRecordingDirectory = Files.createTempDirectory("recording").toFile(); From 079852419a283e79eb8c74cfda3b32d24ba22bf9 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Wed, 6 Dec 2017 13:20:58 +1100 Subject: [PATCH 3/7] Code review requested changes Fixes #500. --- .../containers/BrowserWebDriverContainer.java | 8 +++----- .../containers/DefaultRecordingFileFactory.java | 7 +++++-- .../containers/DefaultRecordingFileFactoryTest.java | 6 ++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java index 1d46494fa91..81c84786f6d 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/BrowserWebDriverContainer.java @@ -182,11 +182,10 @@ public RemoteWebDriver getWebDriver() { @Override protected void failed(Throwable e, Description description) { - switch (recordingMode) { case RECORD_FAILING: case RECORD_ALL: - stopAndRetainRecording(description, false); + stopAndRetainRecordingForDescriptionAndSuccessState(description, false); break; } currentVncRecordings.clear(); @@ -194,10 +193,9 @@ protected void failed(Throwable e, Description description) { @Override protected void succeeded(Description description) { - switch (recordingMode) { case RECORD_ALL: - stopAndRetainRecording(description, true); + stopAndRetainRecordingForDescriptionAndSuccessState(description, true); break; } currentVncRecordings.clear(); @@ -211,7 +209,7 @@ protected void finished(Description description) { this.stop(); } - private void stopAndRetainRecording(Description description, boolean succeeded) { + private void stopAndRetainRecordingForDescriptionAndSuccessState(Description description, boolean succeeded) { File recordingFile = recordingFileFactory.recordingFileForTest(vncRecordingDirectory, description, succeeded); LOGGER.info("Screen recordings for test {} will be stored at: {}", description.getDisplayName(), recordingFile); diff --git a/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java index 48cadd11229..b68b03d46a9 100644 --- a/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java +++ b/modules/selenium/src/main/java/org/testcontainers/containers/DefaultRecordingFileFactory.java @@ -9,11 +9,14 @@ 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-%s.flv"; @Override public File recordingFileForTest(File vncRecordingDirectory, Description description, boolean succeeded) { - final String prefix = succeeded ? "PASSED" : "FAILED"; - final String fileName = String.format("%s-%s-%s-%s.flv", + final String prefix = succeeded ? PASSED : FAILED; + final String fileName = String.format(FILENAME_FORMAT, prefix, description.getTestClass().getSimpleName(), description.getMethodName(), diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java index 049bfb58803..83baa3f8c0b 100644 --- a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; -import java.util.Random; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; @@ -33,10 +32,9 @@ public class DefaultRecordingFileFactoryTest { @Parameterized.Parameters public static Collection data() { - Random random = new Random(); Collection args = new ArrayList<>(); - args.add(new Object[]{format("testMethodName%d", random.nextInt()), "FAILED", FALSE}); - args.add(new Object[]{format("testMethodName%d", random.nextInt()), "PASSED", TRUE}); + args.add(new Object[]{"testMethod1", "FAILED", FALSE}); + args.add(new Object[]{"testMethod2", "PASSED", TRUE}); return args; } From 446295173d33646f177ec13b18647e9c431e8e22 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Sat, 9 Dec 2017 16:28:19 +1100 Subject: [PATCH 4/7] Avoiding nano-second risk of test failures due to datetime format differences. Fixes #500. --- .../DefaultRecordingFileFactoryTest.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java index 83baa3f8c0b..ef3bd50772e 100644 --- a/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java +++ b/modules/selenium/src/test/java/org/testcontainers/containers/DefaultRecordingFileFactoryTest.java @@ -8,22 +8,25 @@ import java.io.File; import java.nio.file.Files; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.Date; +import java.util.List; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static java.lang.String.format; -import static org.junit.Assert.assertEquals; +import static java.time.LocalDateTime.now; +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.junit.Assert.assertThat; import static org.junit.runner.Description.createTestDescription; @RunWith(Parameterized.class) @Value public class DefaultRecordingFileFactoryTest { - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("YYYYMMdd-HHmmss"); + private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("YYYYMMdd-HHmmss"); private final DefaultRecordingFileFactory factory = new DefaultRecordingFileFactory(); private final String methodName; @@ -45,12 +48,13 @@ public void recordingFileThatShouldDescribeTheTestResultAtThePresentTime() throw File recordingFile = factory.recordingFileForTest(vncRecordingDirectory, description, success); - File expectedFile = new File(vncRecordingDirectory, format("%s-%s-%s-%s.flv", - prefix, - getClass().getSimpleName(), - methodName, - DATE_FORMAT.format(new Date())) + String expectedFilePrefix = format("%s-%s-%s", prefix, getClass().getSimpleName(), methodName); + + List expectedPossibleFileNames = Arrays.asList( + new File(vncRecordingDirectory, format("%s-%s.flv", expectedFilePrefix, now().format(DATETIME_FORMATTER))), + new File(vncRecordingDirectory, format("%s-%s.flv", expectedFilePrefix, now().minusSeconds(1L).format(DATETIME_FORMATTER))) ); - assertEquals(expectedFile, recordingFile); + + assertThat(expectedPossibleFileNames, hasItem(recordingFile)); } } \ No newline at end of file From b42082f07e69424817230cacbf88579585d3bcf1 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Sat, 9 Dec 2017 16:36:31 +1100 Subject: [PATCH 5/7] Add changelog for custom file name factory Fixes #500. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b6a253ec8..795c7fb1ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Use Visible Assertions 2.1.0 for pre-flight test output (eliminating Jansi/JNR-POSIX dependencies for lower likelihood of conflict. JNA is now used internally by Visible Assertions instead). - Mark all links functionality as deprecated. This is pending removal in a later release. Please see [\#465](https://github.com/testcontainers/testcontainers-java/issues/465). {@link Network} features should be used instead. - Added support for copying files to/from running containers ([\#378](https://github.com/testcontainers/testcontainers-java/issues/378)) +- Added support for customising the recording file name ([\#500](https://github.com/testcontainers/testcontainers-java/issues/500)) ## [1.4.3] - 2017-10-14 ### Fixed From bb28bed58145c0b52983d9ceab6ec3128d3c1af0 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Sat, 9 Dec 2017 16:53:20 +1100 Subject: [PATCH 6/7] Add docs for BrowserWebDriverContainer#withRecordingFileFactory Fixes #500. --- docs/usage/webdriver_containers.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/usage/webdriver_containers.md b/docs/usage/webdriver_containers.md index 621324c7ee1..5ab2f7b3909 100644 --- a/docs/usage/webdriver_containers.md +++ b/docs/usage/webdriver_containers.md @@ -80,6 +80,15 @@ new BrowserWebDriverContainer() ``` Note that the seconds parameter to `withRecordingMode` should be a directory where recordings can be saved. +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: +```java +new BrowserWebDriverContainer() + //... + .withRecordingFileFactory(new CustomRecordingFileFactory()) +``` + +Note the factory must implement org.testcontainers.containers.RecordingFileFactory. + ## More examples A few different examples are shown in [ChromeWebDriverContainerTest.java](https://github.com/testcontainers/testcontainers-java/blob/master/modules/selenium/src/test/java/org/testcontainers/junit/ChromeWebDriverContainerTest.java). \ No newline at end of file From e0140486140356e5c1ded8631a4b9e622fba8672 Mon Sep 17 00:00:00 2001 From: Lachlan Deck Date: Sat, 9 Dec 2017 16:58:48 +1100 Subject: [PATCH 7/7] Update docs for BrowserWebDriverContainer#withRecordingFileFactory Fixes #500. --- docs/usage/webdriver_containers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/webdriver_containers.md b/docs/usage/webdriver_containers.md index 5ab2f7b3909..246b1943373 100644 --- a/docs/usage/webdriver_containers.md +++ b/docs/usage/webdriver_containers.md @@ -87,7 +87,7 @@ new BrowserWebDriverContainer() .withRecordingFileFactory(new CustomRecordingFileFactory()) ``` -Note the factory must implement org.testcontainers.containers.RecordingFileFactory. +Note the factory must implement `org.testcontainers.containers.RecordingFileFactory`. ## More examples