如何通过测试容器启动 Informix?

Posted

技术标签:

【中文标题】如何通过测试容器启动 Informix?【英文标题】:How to launch Informix via testcontainers? 【发布时间】:2019-11-16 12:34:17 【问题描述】:

我对在我的项目中使用testcontainers 非常感兴趣。

但是,我很难将其设置为与 Informix 一起使用。

请注意,我可以使用 Docker-for-Mac 启动一个 informix 容器,它会构建并启动。

不确定它是否可以与测试容器一起使用。我希望它会。

这是我目前所拥有的

测试类

package com.example.demo;

import com.github.dockerjava.api.command.CreateContainerCmd;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.containers.wait.strategy.WaitAllStrategy;

import java.time.Duration;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests 

  private static GenericContainer informix;

  @BeforeClass
  public static void init() 
    informix = new GenericContainer("ibmcom/informix-innovator-c")
        .withExposedPorts(9088)
        .withEnv("LICENSE", "accept")
        .withPrivilegedMode(true)
        .withCreateContainerCmdModifier(command -> ((CreateContainerCmd)command).withTty(Boolean.TRUE))
        .waitingFor(new WaitAllStrategy().withStrategy(new LogMessageWaitStrategy().withRegEx(".*listener on port.*\n"))
            .withStrategy(new HostPortWaitStrategy())
            .withStartupTimeout(Duration.ofMinutes(2)));

    informix.start();
  

  @AfterClass
  public static void destroy()
    informix.close();
  

  @Test
  public void testDemo() 
    int foo = 1;
    assertEquals(foo, 1);
  


容器启动后永远挂起,永远不会进入测试

这是输出:

...
00:32:27  Updating Low Memory Manager to version 11 
00:32:27  Installing patch to Low Memory Manager code. version(11.01)
00:32:27  Installing patch to upgrade ph_task code. version(13.08)
00:32:27  SCHAPI: Started 2 dbWorker threads.
00:32:27  Checkpoint Completed:  duration was 0 seconds.
00:32:27  Sat Jul  6 - loguniq 3, logpos 0xa2e080, timestamp: 0x32abd Interval: 6

00:32:27  Maximum server connections 1 
00:32:27  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 1, Plog used 178, Llog used 4831

starting mongo listener on port 27017
starting rest listener on port 27018
starting mqtt listener on port 27883
17:34:05.472 [main] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536,false,com.github.dockerjava.core.exec.InspectContainerCmdExec@3fabf088
17:34:05.472 [main] DEBUG com.github.dockerjava.core.exec.InspectContainerCmdExec - GET: OkHttpWebTarget(okHttpClient=org.testcontainers.shaded.okhttp3.OkHttpClient@70925b45, baseUrl=http://docker.socket/, path=[/containers/b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536/json], queryParams=)
17:34:05.482 [main] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536,<null>,com.github.dockerjava.core.exec.KillContainerCmdExec@5cbf9e9f
17:34:06.186 [main] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536,false,com.github.dockerjava.core.exec.InspectContainerCmdExec@18e8473e
17:34:06.187 [main] DEBUG com.github.dockerjava.core.exec.InspectContainerCmdExec - GET: OkHttpWebTarget(okHttpClient=org.testcontainers.shaded.okhttp3.OkHttpClient@70925b45, baseUrl=http://docker.socket/, path=[/containers/b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536/json], queryParams=)
17:34:06.194 [main] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: b252c6f234c9d133d17f64f54344061e3689758089339abb7eda3f056adde536,true,true,com.github.dockerjava.core.exec.RemoveContainerCmdExec@6f6a7463
17:34:06.297 [main] DEBUG org.testcontainers.utility.ResourceReaper - Removed container and associated volume(s): ibmcom/informix-innovator-c:latest
17:34:06.298 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@624ea235 testClass = DemoApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@3932c79a testClass = DemoApplicationTests, locations = '', classes = 'class com.example.demo.DemoApplication', contextInitializerClasses = '[]', activeProfiles = '', propertySourceLocations = '', propertySourceProperties = 'org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3e2e18f2, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@703580bf, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@5c30a9b0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3c407114], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null].

org.testcontainers.containers.ContainerLaunchException: Container startup failed

    at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:217)
    at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:199)
    at com.example.demo.DemoApplicationTests.init(DemoApplicationTests.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
    at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:83)
    at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:210)
    ... 20 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
    at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:277)
    at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:212)
    at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:76)
    ... 21 more
Caused by: org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
    at org.rnorth.ducttape.timeouts.Timeouts.callFuture(Timeouts.java:70)
    at org.rnorth.ducttape.timeouts.Timeouts.doWithTimeout(Timeouts.java:60)
    at org.testcontainers.containers.wait.strategy.WaitAllStrategy.waitUntilReady(WaitAllStrategy.java:53)
    at org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:582)
    at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:259)
    ... 23 more
Caused by: java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
    at org.rnorth.ducttape.timeouts.Timeouts.callFuture(Timeouts.java:65)
    ... 27 more


Disconnected from the target VM, address: '127.0.0.1:51062', transport: 'socket'

Test ignored.

Process finished with exit code 255

如果我注释掉这一行

// .withCreateContainerCmdModifier(command -> ((CreateContainerCmd)command).withTty(Boolean.TRUE))

然后它开始,但随后被这些消息无休止地卡在一个循环中,然后最终以同样的方式超时

6:09:07.489 [ducttape-1] DEBUG com.github.dockerjava.core.exec.InspectExecCmdExec - GET: OkHttpWebTarget(okHttpClient=org.testcontainers.shaded.okhttp3.OkHttpClient@1a2e2935, baseUrl=http://docker.socket/, path=[/exec/ab3ed2f2d3fa129b21c787a7bcce603a267fea48268ab7c861657005919ee546/json], queryParams=)
16:09:08.494 [ducttape-1] DEBUG org.testcontainers.containers.ExecInContainerPattern - /elastic_raman: Running "exec" command: /bin/sh -c cat /proc/net/tcp,6 | awk 'print $2' | grep -i :2380
16:09:08.495 [ducttape-1] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: 3a30ec6ec83dff4b2f330b9c9d71b907dbfd7596a0bd9cc54d1b4f7eb2164f3e,<null>,true,true,<null>,<null>,<null>,/bin/sh,-c,cat /proc/net/tcp,6 | awk 'print $2' | grep -i :2380,com.github.dockerjava.core.exec.ExecCreateCmdExec@74c5bfba
16:09:08.582 [ducttape-1] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: b82e102d716c5530e5aa8c9699f8f5a5e0d6aa6cc4aa69c44b8553f79de4101f,com.github.dockerjava.core.exec.InspectExecCmdExec@90283ab
16:09:08.582 [ducttape-1] DEBUG com.github.dockerjava.core.exec.InspectExecCmdExec - GET: OkHttpWebTarget(okHttpClient=org.testcontainers.shaded.okhttp3.OkHttpClient@1a2e2935, baseUrl=http://docker.socket/, path=[/exec/b82e102d716c5530e5aa8c9699f8f5a5e0d6aa6cc4aa69c44b8553f79de4101f/json], queryParams=)

【问题讨论】:

尝试添加.withLogConsumer(new Slf4jLogConsumer(LOGGER)) 仍然挂起... 这不是修复,而是用于调试。它打印什么? 这里是输出:gist.github.com/diyseguy/d6278bd18e2f33d96d4ea1fcbb6a68e0 @bsideup 感谢您的任何建议... 【参考方案1】:

Informix 的 docker 映像中存在错误配置。在 docker 容器中启动的服务器只会监听主机名,而不是 localhost。 Testcontainers 使用 'localhost' 作为网络接口来连接到您的容器。因此,当您使用 .withExposedPorts(9088) 时,该端口实际上并未暴露在 TestContainers 可以连接的网络接口上。

这就是为什么即使您等待日志消息,您也很可能仍然遇到问题,您也在端口上等待并且它永远不可用。

好消息是,现在可以通过拉取最新的 Informix docker 映像来解决此问题

ibmcom/informix-developer-database:latest 获取最新的 14.10 docker 镜像

下面是我运行的代码,用于验证新图像是否能更好地与 TestContainers 配合使用。

public class DockerTest 
    GenericContainer<?>container  = new GenericContainer<>("ibmcom/informix-developer-database:latest")
        .withExposedPorts(9088, 9089, 27017, 27018, 27883).withEnv("LICENSE", "accept");
@Test
public void testIfxContainer() throws Exception 
    container.start();
    System.out.println("Informix started");
    //test the connection
    try(Connection c = DriverManager.getConnection("jdbc:informix-sqli:localhost:"  + container.getFirstMappedPort() + "/sysmaster:user=informix;password=your-password")) 
      try(Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT FIRST 10 tabname from systables");) 
        while(rs.next()) 
          System.out.println(r.getString(1));
        
      
    
  

【讨论】:

以上是关于如何通过测试容器启动 Informix?的主要内容,如果未能解决你的问题,请参考以下文章

Informix 日期查询 GROUP BY Month

informix数据库锁表处理方法

无法通过php连接到informix数据库

如何删除在线表informix Db中的大量行

如何使用特定的 docker 镜像启动测试容器?

如何在 Informix 中创建 BTS 索引