Reputation: 273
Trying out testcontainers for integration testing. I am testing rest api endpoint. Here is the technology stack - quarkus, RESTEasy and mongodb-client
I am able to see MongoDB container is started successfully but getting exception. Exception: "com.mongodb.MongoSocketOpenException: Exception opening socket"
2020-04-26 15:13:18,330 INFO [org.tes.doc.DockerClientProviderStrategy] (main) Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2020-04-26 15:13:19,109 INFO [org.tes.doc.UnixSocketClientProviderStrategy] (main) Accessing docker with local Unix socket
2020-04-26 15:13:19,109 INFO [org.tes.doc.DockerClientProviderStrategy] (main) Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
2020-04-26 15:13:19,258 INFO [org.tes.DockerClientFactory] (main) Docker host IP address is localhost
2020-04-26 15:13:19,305 INFO [org.tes.DockerClientFactory] (main) Connected to docker:
Server Version: 19.03.8
API Version: 1.40
Operating System: Docker Desktop
Total Memory: 3940 MB
2020-04-26 15:13:19,524 INFO [org.tes.uti.RegistryAuthLocator] (main) Credential helper/store (docker-credential-desktop) does not have credentials for quay.io
2020-04-26 15:13:20,106 INFO [org.tes.DockerClientFactory] (main) Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2020-04-26 15:13:20,107 INFO [org.tes.DockerClientFactory] (main) Checking the system...
2020-04-26 15:13:20,107 INFO [org.tes.DockerClientFactory] (main) ✔︎ Docker server version should be at least 1.6.0
2020-04-26 15:13:20,230 INFO [org.tes.DockerClientFactory] (main) ✔︎ Docker environment should have more than 2GB free disk space
2020-04-26 15:13:20,291 INFO [🐳 .2]] (main) Creating container for image: mongo:4.2
2020-04-26 15:13:20,420 INFO [🐳 .2]] (main) Starting container with ID: d8d142bcdef8e2ebe9c09f171845deffcda503d47aa4893cd44e72d7067f0cdd
2020-04-26 15:13:20,756 INFO [🐳 .2]] (main) Container mongo:4.2 is starting: d8d142bcdef8e2ebe9c09f171845deffcda503d47aa4893cd44e72d7067f0cdd
2020-04-26 15:13:22,035 INFO [🐳 .2]] (main) Container mongo:4.2 started in PT3.721S
2020-04-26 15:13:24,390 INFO [org.mon.dri.cluster] (main) Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2020-04-26 15:13:24,453 INFO [org.mon.dri.cluster] (main) Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2020-04-26 15:13:24,453 INFO [org.mon.dri.cluster] (cluster-ClusterId{value='5ea5dd542fb66c613dc74629', description='null'}-127.0.0.1:27017) Exception in monitor thread while connecting to server 127.0.0.1:27017: com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.internal.connection.SocketChannelStream.open(SocketChannelStream.java:63)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:126)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:714)
at sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:122)
at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:64)
at com.mongodb.internal.connection.SocketChannelStream.initializeSocketChannel(SocketChannelStream.java:72)
at com.mongodb.internal.connection.SocketChannelStream.open(SocketChannelStream.java:60)
... 3 more
If I use docker run then my test case works properly.
docker run -p 27017:27017 --name mongodb mongo:4.2
using testcontainer as mentioned @ https://www.testcontainers.org/quickstart/junit_5_quickstart/
@Container
static GenericContainer mongodb = new GenericContainer<>("mongo:4.2").withExposedPorts(27017);
Upvotes: 10
Views: 7405
Reputation: 191
You can use in your tests the @QuarkusTestResource(MongoDBLifecycleManager.class)
.
And here we have the implementation of MongoDBLifecycleManager
:
public class MongoDBLifecycleManager implements QuarkusTestResourceLifecycleManager {
private MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:5.0.10"));
@Override
public Map<String, String> start() {
mongoDBContainer.start();
return Map.of(
"quarkus.mongodb.connection-string", mongoDBContainer.getConnectionString(),
"quarkus.mongodb.database", "testDB");
}
@Override
public void stop() {
mongoDBContainer.stop();
}
}
It is important to notice that your tests will ignore what you defined in the application.properties
as MongoDB connection parameters, and use what the method start
returns:
Map.of("quarkus.mongodb.connection-string", mongoDBContainer.getConnectionString(),
"quarkus.mongodb.database", "testDB");
You can have other MongoDB instances running in your local machine, with test containers you will run in a random port.
In your pom.xml
you will need some like:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mongodb</artifactId>
<scope>test</scope>
</dependency>
Upvotes: 0
Reputation: 64011
As of version 2.0.0.Alpha1
, Quarkus will automatically start MongoDB via testcontainers in dev and test mode if no Mongo configuration has been supplied.
See this for more information
Upvotes: 3
Reputation: 12149
Extending the @juan-rada answer with example (Quarkus + Mongo + Junit5)
import java.util.Map;
import org.apache.groovy.util.Maps;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
@Testcontainers
@QuarkusTestResource(FooIT.Initializer.class)
public class FooIT {
public static class Initializer implements QuarkusTestResourceLifecycleManager {
@Override
public Map<String, String> start() {
FooIT.mongoDBContainer.start();
// the way to dynamically expose allocated port
return Maps.of("quarkus.mongodb.connection-string", "mongodb://" + mongoDBContainer.getContainerIpAddress() + ":" + mongoDBContainer.getFirstMappedPort() + "/foo");
}
@Override
public void stop() {
FooIT.mongoDBContainer.stop();
}
}
@Container
public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:latest"));
@Test
public void testFoo() {
...
}
}
Upvotes: 1
Reputation: 3766
This solution works but Quakus provide a cleaner way of doing this check documentation. Just create a class implementing QuarkusTestResourceLifecycleManager
public static class Initializer implements QuarkusTestResourceLifecycleManager {
@Override
public Map<String, String> start() {
mongodb.start();
return Maps.of("quarkus.mongodb.connection-string", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getFirstMappedPort());
}
@Override
public void stop() {
mongodb.stop();
}
}
Then annotate your test with
@QuarkusTestResource(MyTestClass.Initializer.class)
Upvotes: 2
Reputation: 42936
I can't say for certain without seeing your test configuration, but I'm guessing that it works with docker run
and not Testcontainers because docker run
exposes a fixed port (always 27017) but Testcontainers will expose port 27017
as a random port (to avoid port conflicts on test machines).
To use Testcontainers with a Quarkus test, your tests must follow this flow:
Obtain randomized ports from Testcontainers after containers are started, then set any test configuration properties that depend on container ports. For example:
static GenericContainer mongodb = new GenericContainer<>("mongo:4.2").withExposedPorts(27017);
static {
mongodb.start();
System.setProperty("quarkus.mongodb.connection-string",
"mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getFirstMappedPort());
}
Upvotes: 4