Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
3c07308
Implement MongoDbContainer
silaev Oct 7, 2019
a2c5c69
change oraclejdk8 with openjdk11, delete obsolete ITTest
silaev Oct 7, 2019
8ddd6b4
Small fixes
silaev Oct 7, 2019
1795235
Fix docs
silaev Oct 8, 2019
ee5e4fa
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Oct 9, 2019
e06749d
fix mongodb.md
silaev Oct 9, 2019
1a2b1dc
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Oct 11, 2019
8f68d71
Code review remarks adjusted
silaev Oct 14, 2019
58ab3f2
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Oct 14, 2019
957cd51
Small fix mongodb.md
silaev Oct 14, 2019
991a5f8
Small fix mongodb.md
silaev Oct 14, 2019
4d9f360
Merge branch 'master' into master
rnorth Jan 29, 2020
72d2b30
Merge branch 'master' into master
rnorth Feb 7, 2020
c0fe7ba
Merge branch 'master' into master
rnorth Feb 8, 2020
509a454
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Feb 26, 2020
d1d0367
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Mar 6, 2020
184d4e2
Fix container exit code check
silaev Mar 6, 2020
fc45144
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Mar 13, 2020
cfe5177
Adjust tests and build.gradle to follow Testcontainers module test co…
silaev Mar 13, 2020
a74d766
Add Javadoc explaining the use of LOCALHOST
silaev Mar 13, 2020
7620cb8
Refactor to use a default replica set configuration
silaev Mar 16, 2020
4ca7c7b
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Apr 17, 2020
aad0e76
Remove extra tests
silaev Apr 17, 2020
b92d690
Remove extra unit tests
silaev Apr 18, 2020
9a746df
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Apr 18, 2020
5c3182e
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Apr 20, 2020
5f3145b
Remove MockMaker
silaev Apr 24, 2020
2ea01ce
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Apr 24, 2020
8b727f0
Move initReplicaSet to containerIsStarted, set timeout delay to 100ms…
silaev Apr 24, 2020
e714b26
Make initReplicaSet private
silaev Apr 24, 2020
5b5531d
Fix docs
silaev Apr 24, 2020
d892006
Fix docs
silaev Apr 24, 2020
7adc9f8
Fix docs
silaev Apr 24, 2020
c136592
Make mongoDbContainer final in test
silaev Apr 24, 2020
a773cc5
Fix docs
silaev Apr 24, 2020
fb325d4
Fix docs, change MongoDb with MongoDB, remove logReplicaSetStatus
silaev Apr 24, 2020
649dae2
Reuse secondary constructor
silaev Apr 24, 2020
cd23ddb
Adjust heading
silaev Apr 24, 2020
47c39e7
Remove configureMongoDBContainer
silaev Apr 24, 2020
8e57d07
Merge branch 'master' into master
rnorth May 8, 2020
78ad147
Update docs/modules/databases/mongodb.md
rnorth May 8, 2020
7cdbad4
Merge branch 'master' into master
rnorth May 8, 2020
6ba608e
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Jul 8, 2020
e67bf4a
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Aug 25, 2020
83d6769
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Oct 11, 2020
38e7925
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Oct 14, 2020
15f61c6
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Dec 14, 2020
6db88f5
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Jan 29, 2021
abbfd1b
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Mar 7, 2021
7e2bdae
Merge branch 'master' of https://github.com/testcontainers/testcontai…
silaev Mar 9, 2021
f48f68c
Add loading and executing java script files feature. Throw a specific…
silaev Mar 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/mongodb/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ dependencies {
compile project(':testcontainers')

testCompile("org.mongodb:mongodb-driver-sync:4.0.2")
testCompile("org.assertj:assertj-core:3.19.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.testcontainers.utility.DockerImageName;

import java.io.IOException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Constructs a single node MongoDB replica set for testing transactions.
Expand All @@ -23,6 +25,7 @@ public class MongoDBContainer extends GenericContainer<MongoDBContainer> {
private static final int MONGODB_INTERNAL_PORT = 27017;
private static final int AWAIT_INIT_REPLICA_SET_ATTEMPTS = 60;
private static final String MONGODB_DATABASE_NAME_DEFAULT = "test";
private static final String DOCKER_ENTRYPOINT_INIT_DIR = "docker-entrypoint-initdb.d";

/**
* @deprecated use {@link MongoDBContainer(DockerImageName)} instead
Expand Down Expand Up @@ -64,9 +67,7 @@ public String getReplicaSetUrl() {
* @return a replica set url.
*/
public String getReplicaSetUrl(final String databaseName) {
if (!isRunning()) {
throw new IllegalStateException("MongoDBContainer should be started first");
}
checkIfRunning();
return String.format(
"mongodb://%s:%d/%s",
getContainerIpAddress(),
Expand All @@ -75,6 +76,34 @@ public String getReplicaSetUrl(final String databaseName) {
);
}

private void checkIfRunning() {
if (!isRunning()) {
throw new IllegalStateException("MongoDBContainer should be started first");
}
}

/**
* Loads and executes JavaScript files directly.
* Note that all the files are supposed to be delivered to a container via proper commands before starting.
* Should be used as an alternative to docker-entrypoint-initdb.d. This is because at docker-entrypoint-initdb.d
* stage, a replica set is not yet initialized and thus cannot accept operations.
*
* @param paths directory or file names as an array of strings.
* @see GenericContainer#withClasspathResourceMapping(String, String, BindMode) etc.
*/
@SneakyThrows(value = {IOException.class, InterruptedException.class})
public void loadAndExecuteJsFiles(final String... paths) {
checkIfRunning();
final String loadCommand =
Stream.of(paths).map(it -> "load(\"" + it + "\")").collect(Collectors.joining(";"));
final ExecResult execResult = execInContainer(buildMongoEvalCommand(loadCommand));
if (execResult.getExitCode() != CONTAINER_EXIT_CODE_OK) {
final String errorMessage = String.format("An error occurred: %s", execResult.getStdout());
log.error(errorMessage);
throw new LoadAndExecuteJsFilesException(errorMessage);
}
}

@Override
protected void containerIsStarted(InspectContainerResponse containerInfo) {
initReplicaSet();
Expand All @@ -92,6 +121,28 @@ private void checkMongoNodeExitCode(final Container.ExecResult execResult) {
}
}

@SneakyThrows(value = {IOException.class, InterruptedException.class})
private void checkDockerEntrypointDirIsEmpty() {
final ExecResult execResult = execInContainer(
"/bin/bash",
"-c",
String.format(
"if [ -n \"$(find \"%s\" -maxdepth 0 -type d -empty 2>/dev/null)\" ]; then exit 0; else exit -1; fi",
DOCKER_ENTRYPOINT_INIT_DIR
)
);
if (execResult.getExitCode() != CONTAINER_EXIT_CODE_OK) {
throw new DockerEntrypointInitDirIsNotEmptyException(
String.format(
"%s is supposed to be empty while running with the --replSet command-line option. " +
"Consider using loadAndExecuteJsFiles(...). Error: %s",
DOCKER_ENTRYPOINT_INIT_DIR,
execResult.getStdout()
)
);
}
}

private String buildMongoWaitCommand() {
return String.format(
"var attempt = 0; " +
Expand Down Expand Up @@ -122,6 +173,7 @@ private void checkMongoNodeExitCodeAfterWaiting(

@SneakyThrows(value = {IOException.class, InterruptedException.class})
private void initReplicaSet() {
checkDockerEntrypointDirIsEmpty();
log.debug("Initializing a single node node replica set...");
final ExecResult execResultInitRs = execInContainer(
buildMongoEvalCommand("rs.initiate();")
Expand All @@ -146,4 +198,16 @@ public static class ReplicaSetInitializationException extends RuntimeException {
super(errorMessage);
}
}

public static class DockerEntrypointInitDirIsNotEmptyException extends RuntimeException {
DockerEntrypointInitDirIsNotEmptyException(final String errorMessage) {
super(errorMessage);
}
}

public static class LoadAndExecuteJsFilesException extends RuntimeException {
LoadAndExecuteJsFilesException(final String errorMessage) {
super(errorMessage);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import org.junit.Test;
import org.testcontainers.utility.DockerImageName;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
Expand Down Expand Up @@ -95,4 +98,49 @@ public void shouldTestDatabaseName() {
assertThat(mongoDBContainer.getReplicaSetUrl(databaseName), endsWith(databaseName));
}
}

@Test
public void shouldTestLoadAndExecuteJsFiles() {
final String file1 = "mongo_init-1.js";
final String file2 = "mongo_init-2.js";
final String targetDir2 = "my-scripts-2/";
final String targetFile1 = "my-scripts-1/" + file1;
final String targetFile2 = targetDir2 + file2;
try (
final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))
.withClasspathResourceMapping(file1, targetFile1, BindMode.READ_ONLY)
.withClasspathResourceMapping(file2, targetFile2, BindMode.READ_ONLY)
) {
mongoDBContainer.start();
mongoDBContainer.loadAndExecuteJsFiles(targetFile1, targetDir2);
final String mongoRsUrl = mongoDBContainer.getReplicaSetUrl();
assertThat(mongoRsUrl, notNullValue());
try (
final MongoClient mongoSyncClient = MongoClients.create(mongoRsUrl)
) {
assertThat(
mongoSyncClient.getDatabase("test").getCollection("foo").countDocuments(),
is(3L)
);
assertThat(
mongoSyncClient.getDatabase("test").getCollection("bar").countDocuments(),
is(2L)
);
}
assertThatThrownBy(() -> mongoDBContainer.loadAndExecuteJsFiles("non-existed-file"))
.isExactlyInstanceOf(MongoDBContainer.LoadAndExecuteJsFilesException.class);
}
}

@Test
public void shouldNotStartBecauseOfDockerEntrypointInitDirectoryIsNotEmpty() {
try (
final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))
.withClasspathResourceMapping("mongo_init-1.js", "/docker-entrypoint-initdb.d/mongo_init-1.js", BindMode.READ_ONLY)
) {
assertThatThrownBy(mongoDBContainer::start)
.isExactlyInstanceOf(ContainerLaunchException.class)
.hasRootCauseExactlyInstanceOf(MongoDBContainer.DockerEntrypointInitDirIsNotEmptyException.class);
}
}
}
4 changes: 4 additions & 0 deletions modules/mongodb/src/test/resources/mongo_init-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
db.foo.insert({'id': 1});
db.foo.insert({'id': 2});
db.foo.insert({'id': 3});

3 changes: 3 additions & 0 deletions modules/mongodb/src/test/resources/mongo_init-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
db.bar.insert({'id': 1});
db.bar.insert({'id': 2});