eja
eja

Reputation: 5329

Mongo driver with @Testcontainers, throws exceptions after tests run successfully

I'm setting up integration tests in a sample spring boot kotlin project, using testcontainers:mongodb.

I've set up a MongoDBContaine, and everything works as expected - the app connects to the mongodb and tests with repositories (e.g. save, delete) work perfectly fine, but I've noticed that after the tests ran (successfully) mongodb.driver throws an exception in the end - would seem like the container isn't being gracefully closed/stopped - is that possible?

Example of how I start the container

companion object {
        @Container
        var mongoDBContainer = MongoDBContainer("mongo:4.4.2")

        @JvmStatic
        @DynamicPropertySource
        fun setProperties(registry: DynamicPropertyRegistry) {
            registry.add("spring.data.mongodb.uri") { mongoDBContainer.replicaSetUrl }
        }
    }

Test method

@Test fun someTest() {
   autowiredRepository.save(document)
   ...
   ...
}

As for the running class, I'm simply using the @Testcontainers annotation on top of it with @SpringBootTest, nothing else.

The exception I'm getting in the end is

com.mongodb.MongoSocketReadException: Prematurely reached end of stream
    at com.mongodb.internal.connection.SocketStream.read(SocketStream.java:112) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.SocketStream.read(SocketStream.java:131) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:647) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receiveMessageWithAdditionalTimeout(InternalStreamConnection.java:512) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:355) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receive(InternalStreamConnection.java:315) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:215) ~[mongodb-driver-core-4.2.3.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:144) ~[mongodb-driver-core-4.2.3.jar:na]
    at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]

Upvotes: 21

Views: 5021

Answers (4)

Osmund Francis
Osmund Francis

Reputation: 821

I was getting the exception when trying to run an integration test with test containers in a different way (it may not be the best way). What I found was that even though I closed my Mongo Client objects, they were still being used somehow. What worked for me was getting the application context for the application instance I was running, and ensuring that was closed as well.

@Tag("container")
public class ExampleITest {

  private MongoDBContainer container;
  private String connectionString;

  @BeforeEach
  void setUp() {
    container = new MongoDBContainer(DockerImageName.parse("mongo:7.0.0"));
    container.start();
    connectionString = container.getConnectionString();
  }

  @AfterEach
  void tearDown() {
    container.stop();
  }

  @Test
  void withNewOutboundTest() {
    final var args = new ArrayList<String>();
    args.add(programArgument("MONGO_DB_CONNECTION_STRING", connectionString));

    final var application = new SpringApplication(Application.class);
    final var context = application.run(args.toArray(new String[0]));
    
    // Close the context when you are done with it.
    context.close();
  }

  public String programArgument(String name, String value) {
    return String.format("--%s=%s", name, value);
  }
}

Upvotes: 0

michaldo
michaldo

Reputation: 4639

Question is a bit old and answers looks outdated. I would like propose alternative solution.

Nowadays (3.4.1) annotation @Testcontainers seems be not necessary. If you create application with Spring Initializr, choosing Mongo and Testcontainer, you will get sample code with working test using Testcontainer without @Testcontainers annotation and without exception at the end

Upvotes: 0

Igor Leal
Igor Leal

Reputation: 148

I was facing the same issue and solved it by removing the annotation @Container from my container and starting it manually as a Singleton. The reason is that @Container was starting multiple containers. The first one was being successfully used by the tests and the other ones were throwing the com.mongodb.MongoSocketReadException: Prematurely reached end of stream exception.

Replacing this:


    @Testcontainers  
    @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)  
    class UserRepositoryTest {  
    
        @Container  
        static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:5.0.10");  
    
        @DynamicPropertySource  
        static void setProperties(DynamicPropertyRegistry registry) {  
            registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);  
        }
    }

with this


    @Testcontainers  
    @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)  
    class UserRepositoryTest {  
    
        static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:5.0.13");
    
        static {
            mongoDBContainer.start();
        }
    
        @DynamicPropertySource  
        static void setProperties(DynamicPropertyRegistry registry) {  
            registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);  
        }
    }

Upvotes: 13

Franck Anso
Franck Anso

Reputation: 1458

Did you try to exclude the default mongoEmbedded which is provided by spring?

I don't know in Kotlin but in Java it's something like that:

@Testcontainers  
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)  
class UserRepositoryTest {  

    @Container  
    static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:5.0.10");  

    @DynamicPropertySource  
    static void setProperties(DynamicPropertyRegistry registry) {  
        registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);  
    }
}

Upvotes: 0

Related Questions