Search code examples
mongodbdockerspring-data-jpatestcontainers

MongoDB and Spring TestContainers


I've been trying to troubleshoot a Netty connection exception when my Spring application is attempting to connect to a MongoDb TestContainer. If needed I can push the project to github (it's a sample project from udemy, the teacher of the course is using maven, but I prefer gradle so I inadvertently got myself in hot water), but here are the relevant test classes that are being used below. Before getting into the classes, I will mention that with a docker-compose.yaml, I'm able to have my application connect to the defined mongo service with no issue, but for some reason with the test container setup, I'm not able to. I have ensured to include the port mapping for the "spring.data.mongodb.uri".

The build.gradle:

    plugins {
    java
    id("org.springframework.boot") version "3.4.1"
    id("io.spring.dependency-management") version "1.1.7"
}

group = "com.omri"
version = "0.0.1-SNAPSHOT"

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    compileOnly("org.projectlombok:lombok")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("io.projectreactor:reactor-test")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    testImplementation("org.testcontainers:testcontainers:1.20.4")
    testImplementation("org.testcontainers:junit-jupiter")
}

dependencyManagement {
    imports {
        mavenBom("org.testcontainers:testcontainers-bom:1.20.4")
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

The test base class where the mongodb container is defined and started:

public abstract class BaseTest {

private static final int MONGO_PORT = 27017;
private static final String INIT_JS = "/docker-entrypoint-initdb.d/init.js";
private static final String MONGO_URI_FORMAT = "mongodb://job_user:job_password@%s:%s/job";

@Container
protected static final GenericContainer<?> mongo = new GenericContainer<>(DockerImageName.parse("mongo"))
        .withExposedPorts(MONGO_PORT)
        .withClasspathResourceMapping("data/job-init.js", INIT_JS, BindMode.READ_ONLY)
        .waitingFor(Wait.forListeningPort());

@DynamicPropertySource
static void mongoProperties(DynamicPropertyRegistry registry) {
    mongo.start();
    registry.add("spring.data.mongodb.uri", () -> String.format(MONGO_URI_FORMAT, mongo.getHost(), mongo.getFirstMappedPort()));
}
}

The test class itself (not much here currently):

    @SpringBootTest
@AutoConfigureWebTestClient
class JobServiceIT extends BaseTest {

    @Autowired
    private WebTestClient webClient;

    @Autowired
    private Environment env;

    @Test
    public void allJobsTest() {
        System.out.println(env.getProperty("spring.data.mongodb.uri"));
        /*webClient.get().uri("/jobs/all").exchange()
                .expectStatus()
                .is2xxSuccessful()
                .expectBody().jsonPath("$").isNotEmpty();*/
    }

    }

This is the exception that I am seeing:

com.mongodb.MongoSocketWriteException: Exception sending message
    at com.mongodb.internal.connection.InternalStreamConnection.throwTranslatedWriteException(InternalStreamConnection.java:790) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:675) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.trySendMessage(InternalStreamConnection.java:507) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendCommandMessage(InternalStreamConnection.java:482) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceiveInternal(InternalStreamConnection.java:440) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.lambda$sendAndReceive$0(InternalStreamConnection.java:375) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:378) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:100) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:49) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:144) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.startHandshake(InternalStreamConnectionInitializer.java:79) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:235) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitor.lookupServerDescription(DefaultServerMonitor.java:219) ~[mongodb-driver-core-5.2.1.jar:na]
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitor.run(DefaultServerMonitor.java:176) ~[mongodb-driver-core-5.2.1.jar:na]
Caused by: io.netty.channel.StacklessClosedChannelException: null
    at io.netty.channel.AbstractChannel$AbstractUnsafe.write(Object, ChannelPromise)(Unknown Source) ~[netty-transport-4.1.116.Final.jar:4.1.116.Final]```

Solution

  • The exception was a red herring. I misspelled the "job/all" GET request as "jobs/all".

    If anyone found this post with a similar error, I found this thread to be useful: https://github.com/testcontainers/testcontainers-java/issues/4695