Reputation: 53
I'm novice in Testcontainers, so i have a question. I have application on Spring/Hibernate. I have docker-image (h2testbase) with mysql-base (myTestDb) with data. I run that image in docker with -p 6161:3306. In test/resources directory I have file application.properties. It contains next
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:6161/myTestDb?allowPublicKeyRetrieval=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Europe/Moscow&&useSSL=false
jdbc.username=root
jdbc.cred=admin
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
I use mvn test - it's working. Now I want to run these test with Testcontainers. I added in pom.xml dependencies
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>1.9.1</version>
<scope>test</scope>
</dependency>
I extented class MySQLContainer
public class TestMySQL extends MySQLContainer {
public TestMySQL() {
super();
}
public TestMySQL(String dockerImageName) {
super(dockerImageName);
}
@Override
public String getDriverClassName() {
return "com.mysql.cj.jdbc.Driver";
}
}
cuz MySQLContainer using com.mysql.jdbc.Driver and it's deprecated. My test (for example)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
HibernateConfiguration.class,
SecurityConfiguration.class,
SecurityInitializer.class,
ViewConfiguration.class,
ViewInitializer.class})
@WebAppConfiguration
public class ControllerServiceJTest {
@ClassRule
public static TestMySQL container
= new TestMySQL("h2testbase");
@Autowired
ControllerService controllerService;
@Test
public void stationPagination() {
Map<String, Object> pag = controllerService.stationPagination(4);
Assert.assertTrue(((List<Station>)pag.get("stations")).size() == 8);
}
@Test
public void trainPagination() {
Map<String, Object> pag = controllerService.trainPagination(1);
Assert.assertTrue(((List<Train>)pag.get("trains")).size() == 20);
}
@Test
public void switchHelper() {
Assert.assertTrue(controllerService.stationSwitchHelper("BLUE").equals(URLs.REDIRECT_DASHSTATION + "/2"));
}
}
And there I'm hitting the wall. If I use mvn test, I see (through docker ps) that container is started. It started two or three times (and mapping go on random ports such 328xx), but then maven tells
org.testcontainers.containers.ContainerLaunchException: Container startup failed
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
Caused by: org.rnorth.ducttape.TimeoutException: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
Caused by: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
Caused by: java.util.concurrent.TimeoutException
What should I do now? How to tell to my testcontainer needed port (6161)? How to use parameters which in application.properties? I can't find code examples where used custom images with DB with data. Thank you in advance
Update Add full result for failed test.
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running ru.javasch.metro.junit.ControllerServiceJTest
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
SLF4J: Failed to load class "org.slf4j.impl.StaticMDCBinder".
SLF4J: Defaulting to no-operation MDCAdapter implementation.
SLF4J: See http://www.slf4j.org/codes.html#no_static_mdc_binder for further details.
?? Checking the system...
? Docker version should be at least 1.6.0
? Docker environment should have more than 2GB free disk space
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 97.189 s <<< FAILURE! - in ru.javasch.metro.junit.ControllerServiceJTest
[ERROR] ru.javasch.metro.junit.ControllerServiceJTest Time elapsed: 97.187 s <<< ERROR!
org.testcontainers.containers.ContainerLaunchException: Container startup failed
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
Caused by: org.rnorth.ducttape.TimeoutException: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
Caused by: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
Caused by: java.util.concurrent.TimeoutException
There some info. I tried tests with MySqlContainer from here (with my TestMySql). When I use clean mysql:5.5 image - all good. But when I try add some modifications in container (for example addFixedExposedPort) it's not start cuz port is already allocated. In case when I adding data from script - it's "Could not create container". If I'm trying give it my image (h2testbase), again "Could not create container".
Upvotes: 2
Views: 3152
Reputation: 1
I had the same problem. It seems that when extending a custom class from MySQLContainer the container starts multiple times. In my case three mysql container were started. When I use directly MySQLContainer class everything worked as expected. Only one mysql container is started.
Upvotes: 0
Reputation: 2167
It seems you have two problems here.
Docker is exposing mysql server on a random port, but you need a fixed port. To fix that you may set the fixed port using addFixedExposedPort
of GenericContainer
public class TestMySQL extends MySQLContainer {
public TestMySQL(String dockerImageName) {
super(dockerImageName);
addFixedExposedPort(6161, MYSQL_PORT);
}
@Override
public String getDriverClassName() {
return "com.mysql.cj.jdbc.Driver";
}
}
You probably don't have database test
, user test
with password test
as it's default credentials in MySQLContainer, that cause the ContainerLaunchException
you are getting. Use withDatabaseName
, withUsername
and withPassword
to configure DB and user properly.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
HibernateConfiguration.class,
SecurityConfiguration.class,
SecurityInitializer.class,
ViewConfiguration.class,
ViewInitializer.class})
@WebAppConfiguration
public class ControllerServiceJTest {
@ClassRule
public static TestMySQL container
= new TestMySQL("h2testbase")
.withDatabaseName("myTestDb")
.withUsername("root")
.withPassword("admin");
@Autowired
ControllerService controllerService;
@Test
public void stationPagination() {
Map<String, Object> pag = controllerService.stationPagination(4);
Assert.assertTrue(((List<Station>)pag.get("stations")).size() == 8);
}
@Test
public void trainPagination() {
Map<String, Object> pag = controllerService.trainPagination(1);
Assert.assertTrue(((List<Train>)pag.get("trains")).size() == 20);
}
@Test
public void switchHelper() {
Assert.assertTrue(controllerService.stationSwitchHelper("BLUE").equals(URLs.REDIRECT_DASHSTATION + "/2"));
}
}
UPDATE:
To turn on logging, add following dependency to pom.xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.1</version>
</dependency>
and create src/test/resources/logback.xml
with following content
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.testcontainers" level="DEBUG"/>
</configuration
Upvotes: 0