Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support mongodb/mongodb-community-server and mongodb/mongodb-enterprise-server #8386

Merged
merged 1 commit into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/**
* Testcontainers implementation for MongoDB.
* <p>
* Supported image: {@code mongo}
* Supported images: {@code mongo}, {@code mongodb/mongodb-community-server}, {@code mongodb/mongodb-enterprise-server}
* <p>
* Exposed ports: 27017
*/
Expand All @@ -22,6 +22,14 @@ public class MongoDBContainer extends GenericContainer<MongoDBContainer> {

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mongo");

private static final DockerImageName COMMUNITY_SERVER_IMAGE = DockerImageName.parse(
"mongodb/mongodb-community-server"
);

private static final DockerImageName ENTERPRISE_SERVER_IMAGE = DockerImageName.parse(
"mongodb/mongodb-enterprise-server"
);

private static final String DEFAULT_TAG = "4.0.10";

private static final int CONTAINER_EXIT_CODE_OK = 0;
Expand All @@ -48,7 +56,7 @@ public MongoDBContainer(@NonNull final String dockerImageName) {

public MongoDBContainer(final DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, COMMUNITY_SERVER_IMAGE, ENTERPRISE_SERVER_IMAGE);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.testcontainers.containers;

import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.TransactionBody;
import org.bson.Document;

import static org.assertj.core.api.Assertions.assertThat;

public class AbstractMongo {

protected void executeTx(MongoDBContainer mongoDBContainer) {
final MongoClient mongoSyncClientBase = MongoClients.create(mongoDBContainer.getConnectionString());
final MongoClient mongoSyncClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl());
mongoSyncClient
.getDatabase("mydb1")
.getCollection("foo")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("abc", 0));
mongoSyncClient
.getDatabase("mydb2")
.getCollection("bar")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("xyz", 0));
mongoSyncClientBase
.getDatabase("mydb3")
.getCollection("baz")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("def", 0));

final ClientSession clientSession = mongoSyncClient.startSession();
final TransactionOptions txnOptions = TransactionOptions
.builder()
.readPreference(ReadPreference.primary())
.readConcern(ReadConcern.LOCAL)
.writeConcern(WriteConcern.MAJORITY)
.build();

final String trxResult = "Inserted into collections in different databases";

TransactionBody<String> txnBody = () -> {
final MongoCollection<Document> coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo");
final MongoCollection<Document> coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar");

coll1.insertOne(clientSession, new Document("abc", 1));
coll2.insertOne(clientSession, new Document("xyz", 999));
return trxResult;
};

try {
final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions);
assertThat(trxResultActual).isEqualTo(trxResult);
} catch (RuntimeException re) {
throw new IllegalStateException(re.getMessage(), re);
} finally {
clientSession.close();
mongoSyncClient.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.testcontainers.containers;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.Document;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(Parameterized.class)
public class CompatibleImageTest extends AbstractMongo {

private final String image;

public CompatibleImageTest(String image) {
this.image = image;
}

@Parameterized.Parameters(name = "{0}")
public static String[] image() {
return new String[] {
"mongo:7",
"mongodb/mongodb-community-server:7.0.2-ubi8",
"mongodb/mongodb-enterprise-server:7.0.0-ubi8",
};
}

@Test
public void shouldExecuteTransactions() {
try (
// creatingMongoDBContainer {
final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10")
// }
) {
// startingMongoDBContainer {
mongoDBContainer.start();
// }
executeTx(mongoDBContainer);
}
}

@Test
public void shouldSupportSharding() {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(this.image).withSharding()) {
mongoDBContainer.start();
final MongoClient mongoClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl());

mongoClient.getDatabase("mydb1").getCollection("foo").insertOne(new Document("abc", 0));

Document shards = mongoClient.getDatabase("config").getCollection("shards").find().first();
assertThat(shards).isNotNull();
assertThat(shards).isNotEmpty();
assertThat(isReplicaSet(mongoClient)).isFalse();
}
}

private boolean isReplicaSet(MongoClient mongoClient) {
return runIsMaster(mongoClient).get("setName") != null;
}

private Document runIsMaster(MongoClient mongoClient) {
return mongoClient.getDatabase("admin").runCommand(new Document("ismaster", 1));
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
package org.testcontainers.containers;

import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.TransactionBody;
import org.bson.Document;
import org.junit.Test;
import org.testcontainers.utility.DockerImageName;

import static org.assertj.core.api.Assertions.assertThat;

public class MongoDBContainerTest {
public class MongoDBContainerTest extends AbstractMongo {

/**
* Taken from <a href="https://docs.mongodb.com/manual/core/transactions/">https://docs.mongodb.com</a>
Expand All @@ -24,7 +13,7 @@ public class MongoDBContainerTest {
public void shouldExecuteTransactions() {
try (
// creatingMongoDBContainer {
final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))
final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10")
// }
) {
// startingMongoDBContainer {
Expand All @@ -34,91 +23,19 @@ public void shouldExecuteTransactions() {
}
}

private void executeTx(MongoDBContainer mongoDBContainer) {
final MongoClient mongoSyncClientBase = MongoClients.create(mongoDBContainer.getConnectionString());
final MongoClient mongoSyncClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl());
mongoSyncClient
.getDatabase("mydb1")
.getCollection("foo")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("abc", 0));
mongoSyncClient
.getDatabase("mydb2")
.getCollection("bar")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("xyz", 0));
mongoSyncClientBase
.getDatabase("mydb3")
.getCollection("baz")
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(new Document("def", 0));

final ClientSession clientSession = mongoSyncClient.startSession();
final TransactionOptions txnOptions = TransactionOptions
.builder()
.readPreference(ReadPreference.primary())
.readConcern(ReadConcern.LOCAL)
.writeConcern(WriteConcern.MAJORITY)
.build();

final String trxResult = "Inserted into collections in different databases";

TransactionBody<String> txnBody = () -> {
final MongoCollection<Document> coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo");
final MongoCollection<Document> coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar");

coll1.insertOne(clientSession, new Document("abc", 1));
coll2.insertOne(clientSession, new Document("xyz", 999));
return trxResult;
};

try {
final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions);
assertThat(trxResultActual).isEqualTo(trxResult);
} catch (RuntimeException re) {
throw new IllegalStateException(re.getMessage(), re);
} finally {
clientSession.close();
mongoSyncClient.close();
}
}

@Test
public void supportsMongoDB_4_4() {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4"))) {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4")) {
mongoDBContainer.start();
}
}

@Test
public void shouldTestDatabaseName() {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))) {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10")) {
mongoDBContainer.start();
final String databaseName = "my-db";
assertThat(mongoDBContainer.getReplicaSetUrl(databaseName)).endsWith(databaseName);
}
}

@Test
public void shouldSupportSharding() {
try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6").withSharding()) {
mongoDBContainer.start();
final MongoClient mongoClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl());

mongoClient.getDatabase("mydb1").getCollection("foo").insertOne(new Document("abc", 0));

Document shards = mongoClient.getDatabase("config").getCollection("shards").find().first();
assertThat(shards).isNotNull();
assertThat(shards).isNotEmpty();
assertThat(isReplicaSet(mongoClient)).isFalse();
}
}

private boolean isReplicaSet(MongoClient mongoClient) {
return runIsMaster(mongoClient).get("setName") != null;
}

private Document runIsMaster(MongoClient mongoClient) {
return mongoClient.getDatabase("admin").runCommand(new Document("ismaster", 1));
}
}