I'm using Testcontainers to test my REST services, by default testcontainers jdbc mmodules (I'm using Mariadb) create a single schema but I need two; so I've created a customized image
FROM mariadb:10
ADD ./docker-entrypoint-initdb.d /docker-entrypoint-initdb.d
in ./docker-entrypoint-initdb.d
a sql script initializes schemas and user grants
create database if not exists my_app_events;
create database if not exists my_app_db;
create user if not exists 'test'@'%' identified by 'test';
grant all on my_app_db.* to 'test'@'%';
grant all on my_app_events.* to 'test'@'%';
the test class looks like:
@SpringBootTest
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = MyTest.DatabaseTestInitializer.class)
public class MyTest {
@Test
public void testSomething(){
// ...
}
public static class DatabaseTestInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private MariaDBContainer mariaDBContainer;
@Override
public void initialize(final ConfigurableApplicationContext configurableApplicationContext) {
mariaDBContainer = new MariaDBContainer(
DockerImageName.parse("registry.gitlab.com/myproject/empty-database")
.asCompatibleSubstituteFor("mariadb")
);
mariaDBContainer.start();
// This is solution for 1.x.x Spring Boot framework
// Article for migration from 1.x.x to 2.x.x Spring Boot https://stackoverflow.com/questions/54718995/appropriate-usage-of-testpropertyvalues-in-spring-boot-tests
EnvironmentTestUtils.addEnvironment(configurableApplicationContext.getEnvironment(),
"spring.datasource.url=" + mariaDBContainer.getJdbcUrl(),
"spring.datasource.username=" + mariaDBContainer.getUsername(),
"spring.datasource.password=" + mariaDBContainer.getPassword()
);
}
}
}
docker ps
shows the running container and it's logs seems ok but the tests do not execute due to:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.22.RELEASE)
2023-02-25 12:55:22.805 INFO 41908 --- [ main] o.t.utility.ImageNameSubstitutor : Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2023-02-25 12:55:22.834 INFO 41908 --- [ main] o.t.d.DockerClientProviderStrategy : Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2023-02-25 12:55:23.238 INFO 41908 --- [ main] o.t.d.DockerClientProviderStrategy : Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
2023-02-25 12:55:23.239 INFO 41908 --- [ main] org.testcontainers.DockerClientFactory : Docker host IP address is localhost
2023-02-25 12:55:23.251 INFO 41908 --- [ main] org.testcontainers.DockerClientFactory : Connected to docker:
Server Version: 23.0.1
API Version: 1.42
Operating System: Ubuntu 22.04.2 LTS
Total Memory: 31729 MB
2023-02-25 12:55:23.310 INFO 41908 --- [ main] 🐳 [testcontainers/ryuk:0.3.4] : Creating container for image: testcontainers/ryuk:0.3.4
2023-02-25 12:55:23.429 INFO 41908 --- [ main] 🐳 [testcontainers/ryuk:0.3.4] : Container testcontainers/ryuk:0.3.4 is starting: e1fb00ceb884f930b4395f6a4ae52e3d782cd18b3e5095d64e879cc3c6a546ab
2023-02-25 12:55:23.770 INFO 41908 --- [ main] 🐳 [testcontainers/ryuk:0.3.4] : Container testcontainers/ryuk:0.3.4 started in PT0.511S
2023-02-25 12:55:23.775 INFO 41908 --- [ main] o.t.utility.RyukResourceReaper : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2023-02-25 12:55:23.775 INFO 41908 --- [ main] org.testcontainers.DockerClientFactory : Checking the system...
2023-02-25 12:55:23.775 INFO 41908 --- [ main] org.testcontainers.DockerClientFactory : ✔︎ Docker server version should be at least 1.6.0
2023-02-25 12:55:23.788 INFO 41908 --- [ main] .g.com/garanteasy/empty-database:latest] : Creating container for image: registry.gitlab.com/garanteasy/empty-database:latest
2023-02-25 12:55:23.871 INFO 41908 --- [ main] .g.com/garanteasy/empty-database:latest] : Container registry.gitlab.com/garanteasy/empty-database:latest is starting: 064f7bcb915621d2cd7d891f2c2920462bd7197854aad5f6f46ff1e4b827d691
2023-02-25 12:55:24.122 INFO 41908 --- [ main] .g.com/garanteasy/empty-database:latest] : Waiting for database connection to become available at jdbc:mariadb://localhost:32806/test using query 'SELECT 1'
2023-02-25 12:55:28.922 INFO 41908 --- [ main] .g.com/garanteasy/empty-database:latest] : Container is started (JDBC URL: jdbc:mariadb://localhost:32806/test)
2023-02-25 12:55:28.923 INFO 41908 --- [ main] .g.com/garanteasy/empty-database:latest] : Container registry.gitlab.com/garanteasy/empty-database:latest started in PT5.146S
2023-02-25 12:55:28.926 INFO 41908 --- [ main] c.g.cms_api.BrandCmsResourceTest : Starting BrandCmsResourceTest on lrkwz-XPS-15-7590 with PID 41908 (started by lrkwz in /home/lrkwz/garanteasy/api-development-environment/garanteasy-cms-api)
2023-02-25 12:55:28.926 DEBUG 41908 --- [ main] c.g.cms_api.BrandCmsResourceTest : Running with Spring Boot v1.5.22.RELEASE, Spring v4.3.25.RELEASE
2023-02-25 12:55:28.926 INFO 41908 --- [ main] c.g.cms_api.BrandCmsResourceTest : No active profile set, falling back to default profiles: default
2023-02-25 12:55:28.943 INFO 41908 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3fce8fd9: startup date [Sat Feb 25 12:55:28 CET 2023]; root of context hierarchy
2023-02-25 12:55:29.697 INFO 41908 --- [ main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2023-02-25 12:55:30.212 INFO 41908 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2023-02-25 12:55:30.224 INFO 41908 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2023-02-25 12:55:30.286 INFO 41908 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final}
2023-02-25 12:55:30.287 INFO 41908 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2023-02-25 12:55:30.288 INFO 41908 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2023-02-25 12:55:30.320 INFO 41908 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2023-02-25 12:55:30.415 DEBUG 41908 --- [ main] o.a.tomcat.jdbc.pool.PooledConnection : Instantiating driver using class: org.testcontainers.jdbc.ContainerDatabaseDriver [url=jdbc:mariadb://localhost:32806/test]
2023-02-25 12:55:30.416 DEBUG 41908 --- [ main] o.a.tomcat.jdbc.pool.ClassLoaderUtil : Attempting to load class[org.testcontainers.jdbc.ContainerDatabaseDriver] from sun.misc.Launcher$AppClassLoader@18b4aac2
2023-02-25 12:55:30.417 DEBUG 41908 --- [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create a new JDBC connection.
java.sql.SQLException: Driver:org.testcontainers.jdbc.ContainerDatabaseDriver@65036e8d returned null for URL:jdbc:mariadb://localhost:32806/test
at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:338)
at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:212)
at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:736)
I've also tried to stop the execution on a breakpoint and manually connect mysql -u test -ptest -h localhost -P <RANDOMPORT> my_app_db
(you can read the random port in many ways: i.e. using docker ps
) has success.
What's wrong in the context initialization?
I guess you forget to configure the spring.datasource.driver-class-name
. So try below to see if it can fix the problem :
EnvironmentTestUtils.addEnvironment(configurableApplicationContext.getEnvironment(),
"spring.datasource.url=" + mariaDBContainer.getJdbcUrl(),
"spring.datasource.username=" + mariaDBContainer.getUsername(),
"spring.datasource.password=" + mariaDBContainer.getPassword(),
"spring.datasource.driver-class-name=org.mariadb.jdbc.Driver");