3

Update 2

By adding environment variables for setting up the container manually, the admin user gets created successfully.

When starting a SpringBootTest which uses a MongoDBContainer, the database in the container was not accessible - this is fixed now. I managed to get things going, but I need to understand how to setup proper authentication for the tests.

When starting a database via docker compose and the same settings, the tests run don't run into this issue.

I am using Spring Boot, Kotlin and Gradle for the general setup:

The entity

package com.tigerarcades.spring.administration

import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.core.mapping.MongoId

@Document(collection = "user")
data class User(
        @MongoId val id: String?,
        val email: String,
        val password: String
)

The repository

package com.tigerarcades.spring.administration

import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Repository

@Repository
interface UserRepository : MongoRepository<User, String> {
    fun findByEmail(email: String): User?
}

The test

package com.tigerarcades.spring.twittered

import com.tigerarcades.spring.administration.User
import com.tigerarcades.spring.administration.UserRepository
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.ApplicationContextInitializer
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.context.support.TestPropertySourceUtils.addInlinedPropertiesToEnvironment
import org.testcontainers.containers.MongoDBContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers


@Testcontainers
@SpringBootTest
@ExtendWith(SpringExtension::class)
@ContextConfiguration(
        initializers = [
            ApplicationTests.Companion.MongoInitializer::class
        ]
)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ApplicationTests {

    @Autowired
    lateinit var underTest: UserRepository

    @Test
    fun contextLoads() {
        print(underTest.save(User(null, "this.is.not@n.email", "n0p4ssw0rd")))
    }

    companion object {
        private const val username = "admin1"
        private const val password = "admin1"
        private const val database = "twitterStarter1"

        @Container
        @JvmField
        val mongoContainer: MongoDBContainer = MongoDBContainer("mongo:latest")
                .withEnv("MONGO_INITDB_DATABASE", database)
                .withEnv("MONGO_INITDB_ROOT_USERNAME", username)
                .withEnv("MONGO_INITDB_ROOT_PASSWORD", password)

        init {
            mongoContainer.start()
        }

        class MongoInitializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
            override fun initialize(context: ConfigurableApplicationContext) {
                val port = mongoContainer.firstMappedPort

                addInlinedPropertiesToEnvironment(
                        context,
                        "spring.data.mongodb.port=$port"
                )
            }
        }
    }
}

The message, that the user gets created:

Successfully added user: {
    "user" : "admin1",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}

It is now hanging because a single node replica was not initialized ...

2020-07-07T08:10:39.151+0000 I  CONTROL  [main] ***** SERVER RESTARTED *****
2020-07-07T08:10:39.154+0000 I  CONTROL  [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
2020-07-07T08:10:39.159+0000 W  ASIO     [main] No TransportLayer configured during NetworkInterface startup
killing process with pid: 28
2020-07-07T08:10:39.159+0000 I  CONTROL  [signalProcessingThread] got signal 15 (Terminated), will terminate after current cmd ends
2020-07-07T08:10:39.161+0000 I  NETWORK  [signalProcessingThread] shutdown: going to close listening sockets...
2020-07-07T08:10:39.162+0000 I  NETWORK  [listener] removing socket file: /tmp/mongodb-27017.sock
2020-07-07T08:10:39.163+0000 I  -        [signalProcessingThread] Stopping further Flow Control ticket acquisitions.
2020-07-07T08:10:39.163+0000 I  CONTROL  [signalProcessingThread] Shutting down free monitoring
2020-07-07T08:10:39.164+0000 I  FTDC     [signalProcessingThread] Shutting down full-time diagnostic data capture
2020-07-07T08:10:39.167+0000 I  STORAGE  [signalProcessingThread] Deregistering all the collections
2020-07-07T08:10:39.167+0000 I  STORAGE  [signalProcessingThread] Timestamp monitor shutting down
2020-07-07T08:10:39.168+0000 I  STORAGE  [signalProcessingThread] WiredTigerKVEngine shutting down
2020-07-07T08:10:39.170+0000 I  STORAGE  [signalProcessingThread] Shutting down session sweeper thread
2020-07-07T08:10:39.170+0000 I  STORAGE  [signalProcessingThread] Finished shutting down session sweeper thread
2020-07-07T08:10:39.170+0000 I  STORAGE  [signalProcessingThread] Shutting down journal flusher thread
2020-07-07T08:10:39.222+0000 I  STORAGE  [signalProcessingThread] Finished shutting down journal flusher thread
2020-07-07T08:10:39.222+0000 I  STORAGE  [signalProcessingThread] Shutting down checkpoint thread
2020-07-07T08:10:39.223+0000 I  STORAGE  [signalProcessingThread] Finished shutting down checkpoint thread
2020-07-07T08:10:39.275+0000 I  STORAGE  [signalProcessingThread] shutdown: removing fs lock...
2020-07-07T08:10:39.276+0000 I  CONTROL  [signalProcessingThread] now exiting
2020-07-07T08:10:39.276+0000 I  CONTROL  [signalProcessingThread] shutting down with code:0

java.lang.ExceptionInInitializerError
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:511)
    at org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:72)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:77)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:333)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:280)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:77)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:262)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:256)
    at java.base/java.util.Optional.orElseGet(Optional.java:369)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:255)
    at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$before$0(ClassBasedTestDescriptor.java:184)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:183)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:78)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:132)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.testcontainers.containers.ContainerLaunchException: Container startup failed
    at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:330)
    at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:311)
    at com.tigerarcades.spring.twittered.ApplicationTests.<clinit>(ApplicationTests.kt:52)
    ... 82 more
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
    at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:88)
    at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:323)
    ... 84 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
    at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:498)
    at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:325)
    at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
    ... 85 more
Caused by: org.testcontainers.containers.MongoDBContainer$ReplicaSetInitializationException: A single node replica set was not initialized in a set timeout: 60 attempts
    at org.testcontainers.containers.MongoDBContainer.checkMongoNodeExitCodeAfterWaiting(MongoDBContainer.java:90)
    at org.testcontainers.containers.MongoDBContainer.initReplicaSet(MongoDBContainer.java:112)
    at org.testcontainers.containers.MongoDBContainer.containerIsStarted(MongoDBContainer.java:51)
    at org.testcontainers.containers.GenericContainer.containerIsStarted(GenericContainer.java:657)
    at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:477)
    ... 87 more

ApplicationTests > initializationError FAILED
    java.lang.ExceptionInInitializerError at NativeConstructorAccessorImpl.java:-2
        Caused by: org.testcontainers.containers.ContainerLaunchException at ApplicationTests.kt:52
            Caused by: org.rnorth.ducttape.RetryCountExceededException at ApplicationTests.kt:52
                Caused by: org.testcontainers.containers.ContainerLaunchException at ApplicationTests.kt:52
                    Caused by: org.testcontainers.containers.MongoDBContainer$ReplicaSetInitializationException at ApplicationTests.kt:52
1 test completed, 1 failed
> Task :test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///Users/florian/Playgrounds/github.com/tigerarcades/spring-kt-twitter-starter/build/reports/tests/test/index.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 5s
9 actionable tasks: 3 executed, 6 up-to-date
Florian Salihovic
  • 3,921
  • 2
  • 19
  • 26
  • Can you please share the `application.properties` or `application.yml` file ? – kaushik Jul 06 '20 at 09:41
  • @kaushik added the `application.properties` – Florian Salihovic Jul 06 '20 at 09:51
  • Are you able to connect to the mongodb using command (I am not well versed in mongodb) `mongo "mongodb://localhost:27017"` – kaushik Jul 06 '20 at 09:57
  • No, that was not possible. But your question was actually leading me to the sweet spot. Testcontainers appear to run with randomised ports. This helped to run into an authentication issue which should be proof, that the container is now accessible. – Florian Salihovic Jul 06 '20 at 10:57
  • Get everything working with mongo shell before involving the java client. – D. SM Jul 06 '20 at 16:42
  • do you have the same `application.properties` also in `src/test/resources`? It seems that you somewhere configure to use a `admin` user which is not present on the _raw_ MongoDb container – rieckpil Jul 07 '20 at 05:08
  • @rieck good idea, but it did not solve the issue. The user needed to be created, which I now managed to do. – Florian Salihovic Jul 07 '20 at 08:17
  • In general, this should not be required. The following is the least setup you need: https://stackoverflow.com/questions/62588809/mongo-in-testcontainers/62588891#62588891 – rieckpil Jul 07 '20 at 12:30

0 Answers0