我已经为我的OpenLiberty与MicroProfile应用程序编写了一些集成测试.为了使测试工作,我必须首先执行libertyDev命令.因此,我认为使用Testcontainers是一个好主意,我将try 在其中创建一个OpenLiberty服务器容器,并使用适当的配置文件加载它.在这个范围内,我的测试如下.

package integration.gr.iag.dgtl.inventory

import gr.iag.dgtl.inventory.PropertyReader
import gr.iag.dgtl.inventory.TestItemProvider
import gr.iag.dgtl.inventory.dto.ErrorResponse
import jakarta.json.bind.Jsonb
import jakarta.json.bind.JsonbBuilder
import jakarta.ws.rs.client.Client
import jakarta.ws.rs.client.ClientBuilder
import jakarta.ws.rs.client.Entity
import jakarta.ws.rs.core.MediaType
import jakarta.ws.rs.core.Response
import org.slf4j.LoggerFactory
import org.testcontainers.containers.GenericContainer
import org.testcontainers.containers.output.Slf4jLogConsumer
import org.testcontainers.containers.wait.strategy.Wait
import org.testcontainers.spock.Testcontainers
import org.testcontainers.utility.DockerImageName
import org.testcontainers.utility.MountableFile
import spock.lang.Shared
import spock.lang.Specification

import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

@Testcontainers
class TrackingInventoryIntegrationSpec extends Specification {

    @Shared
    GenericContainer openLiberty = new GenericContainer(DockerImageName.parse("open-liberty:23.0.0.12-full-java17-openj9"))
            .withExposedPorts(9080)
            .withCopyFileToContainer(MountableFile.forHostPath("./src/main/liberty/config/tracking-inventory-0.0.1-SNAPSHOT.war"), "/opt/ol/wlp/usr/servers/defaultServer/apps/tracking-inventory-0.0.1-SNAPSHOT.war")
            .withCopyFileToContainer(MountableFile.forHostPath("./src/main/liberty/config/server.xml"), "/opt/ol/wlp/usr/servers/defaultServer/server.xml")
            .withCopyFileToContainer(MountableFile.forHostPath("./src/main/liberty/config/bootstrap.properties"), "/opt/ol/wlp/usr/servers/defaultServer/bootstrap.properties")
            .withCopyFileToContainer(MountableFile.forHostPath("./src/main/liberty/config/GeneratedSSLInclude.xml"), "/opt/ol/wlp/usr/servers/defaultServer/GeneratedSSLInclude.xml")
            .withCopyFileToContainer(MountableFile.forHostPath("./src/main/liberty/config/users.xml"), "/opt/ol/wlp/usr/servers/defaultServer/users.xml")
            .waitingFor(Wait.forHttp("/").forStatusCode(200))
            .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("openLiberty")))

    @Shared
    Jsonb jsonb

    def requestBody

    @Shared
    HttpClient client

    def appUrl

    def setup() {
        openLiberty.start()
        int actualPort = openLiberty.getMappedPort(9080)
        String host = openLiberty.getHost()
        appUrl = "http://$host:$actualPort"

        final String allLogs = openLiberty.getLogs()
        println("Container Logs: \n$allLogs")

        client = HttpClient.newHttpClient()
        jsonb = JsonbBuilder.create()
        requestBody = TestItemProvider.generateRandomItem()
    }

    def 'Successful create item and persist it into JSON, HTML and CSV'() {
        when: 'the call is succeeded'
        def response = doPost(jsonb.toJson(requestBody))

        then: 'empty response body means successful request'
        response.status == Response.Status.CREATED.statusCode
    }

    def 'Failed to create the item'() {
        given: 'an item with null name'
        def requestBody = TestItemProvider.createItemWithNullName()

        when: 'calling the application with this item'
        def response = doPost(jsonb.toJson(requestBody))

        then: 'a response with error message is returned'
        response.status != Response.Status.CREATED.statusCode
        response.readEntity(ErrorResponse.class).errors.size() > 0
    }

    def 'Successfully get an item'() {
        given: 'an item is already created'
        doPost(jsonb.toJson(requestBody))

        when: 'the call is made to the get api'
        def response = doGet()

        then: 'the response contains an OK status'
        response.status == Response.Status.OK.statusCode

        and: 'the response body contains the correct information'
        def returnedItemMap = response.readEntity(List.class)[0]

        returnedItemMap.name == requestBody.name
        returnedItemMap.serialNumber == requestBody.serialNumber
        returnedItemMap.value == requestBody.value
    }

    def 'Successfully delete an item'() {
        given: 'an item is already created'
        doPost(jsonb.toJson(requestBody))

        when: 'the call is made to the delete api'
        def response = doDelete(requestBody.serialNumber)

        then: 'the response contains an OK status'
        response.status == Response.Status.NO_CONTENT.statusCode
    }

    def doPost(Object requestPayload) {
        Client client = ClientBuilder.newClient()
        String targetUrl = "$appUrl/tracking-inventory/inventory"
        return client.target(targetUrl)
                .request(MediaType.APPLICATION_JSON)
                .post(Entity.json(requestPayload))
    }

    def doGet() {
        Client client = ClientBuilder.newClient()
        String targetUrl = "$appUrl/tracking-inventory/inventory"
        return client.target(targetUrl)
                .request(MediaType.APPLICATION_JSON)
                .get()
    }
}

在这里,我挂载了WAR和我的server.xml文件以及各种配置文件.我知道WAR文件被放在Build/libs文件夹中,我会try 在我的build.gradle文件中编写一个类似tests.dependsOn war的任务,以便在测试执行之前正确地生成它.

我的问题是,在运行第一个测试时,我会收到下一个错误:

org.testcontainers.containers.ContainerLaunchException: Container startup failed for image open-liberty:23.0.0.12-full-java17-openj9
    at app//org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:359)
    at app//org.testcontainers.containers.GenericContainer.start(GenericContainer.java:330)
    at org.testcontainers.spock.TestcontainersMethodInterceptor.startContainers_closure3(TestcontainersMethodInterceptor.groovy:83)
    at app//groovy.lang.Closure.call(Closure.java:433)
    at app//groovy.lang.Closure.call(Closure.java:422)
    at app//org.testcontainers.spock.TestcontainersMethodInterceptor.startContainers(TestcontainersMethodInterceptor.groovy:80)
    at app//org.testcontainers.spock.TestcontainersMethodInterceptor.interceptSetupSpecMethod(TestcontainersMethodInterceptor.groovy:25)
    at app//org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:36)
    at app//org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:101)
    at app//org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:156)
    at java.base@17.0.9/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
    at app//org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:88)
    at app//org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:344)
    ... 10 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
    at app//org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:563)
    at app//org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:354)
    at app//org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
    ... 11 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Timed out waiting for URL to be accessible (http://localhost:55240/ should return HTTP [200])
    at app//org.testcontainers.containers.wait.strategy.HttpWaitStrategy.waitUntilReady(HttpWaitStrategy.java:320)
    at app//org.testcontainers.containers.wait.strategy.AbstractWaitStrategy.waitUntilReady(AbstractWaitStrategy.java:52)
    at app//org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:909)
    at app//org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:500)
    ... 13 more
Caused by: org.rnorth.ducttape.TimeoutException: Timeout waiting for result with exception
    at app//org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:54)
    at app//org.testcontainers.containers.wait.strategy.HttpWaitStrategy.waitUntilReady(HttpWaitStrategy.java:252)
    ... 16 more
Caused by: java.lang.RuntimeException: java.net.SocketException: Unexpected end of file from server
    at org.testcontainers.containers.wait.strategy.HttpWaitStrategy.lambda$null$6(HttpWaitStrategy.java:312)
    at org.rnorth.ducttape.ratelimits.RateLimiter.doWhenReady(RateLimiter.java:27)
    at org.testcontainers.containers.wait.strategy.HttpWaitStrategy.lambda$waitUntilReady$7(HttpWaitStrategy.java:257)
    at org.rnorth.ducttape.unreliables.Unreliables.lambda$retryUntilSuccess$0(Unreliables.java:43)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:857)
Caused by: java.net.SocketException: Unexpected end of file from server
    at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:954)
    at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:761)
    at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:951)
    at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:761)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1688)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)
    at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:529)
    at org.testcontainers.containers.wait.strategy.HttpWaitStrategy.lambda$null$6(HttpWaitStrategy.java:276)
    ... 7 more

容器日志(log)如下:

WARNING: Unknown module: jdk.management.agent specified to --add-exports
WARNING: Unknown module: jdk.attach specified to --add-exports
Launching defaultServer (Open Liberty 23.0.0.12/wlp-1.0.84.cl231220231127-1901) on Eclipse OpenJ9 VM, version 17.0.10+7 (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml
[AUDIT   ] CWWKG0028A: Processing included configuration resource: /opt/ol/wlp/usr/servers/defaultServer/users.xml
[AUDIT   ] CWWKG0028A: Processing included configuration resource: /opt/ol/wlp/usr/servers/defaultServer/GeneratedSSLInclude.xml
[AUDIT   ] CWWKG0102I: Found conflicting settings for defaultKeyStore instance of keyStore configuration.
  Property password has conflicting values:
    Secure value is set in file:/opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml.
    Secure value is set in file:/opt/ol/wlp/usr/servers/defaultServer/GeneratedSSLInclude.xml.
  Property password will be set to the value defined in file:/opt/ol/wlp/usr/servers/defaultServer/GeneratedSSLInclude.xml.

[AUDIT   ] CWWKG0102I: Found conflicting settings for defaultHttpEndpoint instance of httpEndpoint configuration.
  Property host has conflicting values:
    Value * is set in file:/opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml.
    Value localhost is set in file:/opt/ol/wlp/usr/servers/defaultServer/server.xml.
  Property host will be set to localhost.

[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT   ] CWWKS4104A: LTPA keys created in 0.206 seconds. LTPA key file: /opt/ol/wlp/output/defaultServer/resources/security/ltpa.keys
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/jwt/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/openapi/platform/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/openapi/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/IBMJMXConnectorREST/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/metrics/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/health/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/openapi/ui/
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/ibm/api/
[AUDIT   ] CWPKI0803A: SSL certificate created in 1.513 seconds. SSL key file: /opt/ol/wlp/output/defaultServer/resources/security/key.p12
[AUDIT   ] CWWKI0001I: The CORBA name server is now available at corbaloc:iiop:localhost:2809/NameService.
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/
[AUDIT   ] CWWKZ0001I: Application tracking-inventory-0.0.1-SNAPSHOT started in 2.275 seconds.
[AUDIT   ] CWWKF1037I: The server added the [appAuthentication-2.0, appAuthorization-2.0, appClientSupport-2.0, appSecurity-4.0, batch-2.0, beanValidation-3.0, cdi-3.0, concurrent-2.0, connectors-2.0, connectorsInboundSecurity-2.0, enterpriseBeans-4.0, enterpriseBeansHome-4.0, enterpriseBeansLite-4.0, enterpriseBeansPersistentTimer-4.0, enterpriseBeansRemote-4.0, expressionLanguage-4.0, faces-3.0, jakartaee-9.1, json-1.0, jsonb-2.0, jsonp-2.0, jwt-1.0, localConnector-1.0, mail-2.0, managedBeans-2.0, mdb-4.0, messaging-3.0, messagingClient-3.0, messagingSecurity-3.0, messagingServer-3.0, microProfile-5.0, monitor-1.0, mpConfig-3.0, mpFaultTolerance-4.0, mpHealth-4.0, mpJwt-2.0, mpMetrics-4.0, mpOpenAPI-3.0, mpOpenTracing-3.0, mpRestClient-3.0, pages-3.0, persistence-3.0, persistenceContainer-3.0, restConnector-2.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, transportSecurity-1.0, webProfile-9.1, websocket-2.0, xmlBinding-3.0, xmlWS-3.0] features to the existing feature set.
[AUDIT   ] CWWKF0012I: The server installed the following features: [appAuthentication-2.0, appAuthorization-2.0, appClientSupport-2.0, appSecurity-4.0, batch-2.0, beanValidation-3.0, cdi-3.0, concurrent-2.0, connectors-2.0, connectorsInboundSecurity-2.0, distributedMap-1.0, enterpriseBeans-4.0, enterpriseBeansHome-4.0, enterpriseBeansLite-4.0, enterpriseBeansPersistentTimer-4.0, enterpriseBeansRemote-4.0, expressionLanguage-4.0, faces-3.0, jakartaee-9.1, jdbc-4.2, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, jwt-1.0, localConnector-1.0, mail-2.0, managedBeans-2.0, mdb-4.0, messaging-3.0, messagingClient-3.0, messagingSecurity-3.0, messagingServer-3.0, microProfile-5.0, monitor-1.0, mpConfig-3.0, mpFaultTolerance-4.0, mpHealth-4.0, mpJwt-2.0, mpMetrics-4.0, mpOpenAPI-3.0, mpOpenTracing-3.0, mpRestClient-3.0, pages-3.0, persistence-3.0, persistenceContainer-3.0, restConnector-2.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0, webProfile-9.1, websocket-2.0, xmlBinding-3.0, xmlWS-3.0].
[AUDIT   ] CWWKF0013I: The server removed the following features: [appClientSupport-1.0, appSecurity-2.0, appSecurity-3.0, batch-1.0, beanValidation-2.0, cdi-2.0, concurrent-1.0, ejb-3.2, ejbHome-3.2, ejbLite-3.2, ejbPersistentTimer-3.2, ejbRemote-3.2, el-3.0, j2eeManagement-1.1, jacc-1.5, jaspic-1.1, javaMail-1.6, javaee-8.0, jaxb-2.2, jaxrs-2.1, jaxrsClient-2.1, jaxws-2.2, jca-1.7, jcaInboundSecurity-1.0, jms-2.0, jpa-2.2, jpaContainer-2.2, jsf-2.3, jsonb-1.0, jsonp-1.1, jsp-2.3, managedBeans-1.0, mdb-3.2, servlet-4.0, wasJmsClient-2.0, wasJmsSecurity-1.0, wasJmsServer-1.0, webProfile-8.0, websocket-1.1].
[AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 6.601 seconds.

我try 使用docker run --rm -p 9080:9080 open-liberty:23.0.0.12-full-java17-openj9命令在测试之外运行映像,然后判断http://localhost:9080,它按预期工作.为什么我失go 了与服务器的连接?我遗漏了什么?

推荐答案

我设法解决了这个问题,方法是将server.xml文件中的<httpEndpoint>元素配置为host="*",具体地说是将host参数配置为host="*".在此之前,我将其设置为host="localhost",这将通信限制到我的容器.我提供了server.xml以供将来参考:

<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>jakartaee-9.1</feature>
        <feature>microProfile-5.0</feature>
        <feature>localConnector-1.0</feature>
    </featureManager>

    <include location="users.xml" optional="true"/>

    <!-- SSL Config -->
    <ssl id="defaultSSLConfig" trustDefaultCerts="true"/>
    <include location="GeneratedSSLInclude.xml"/>

    <!-- App Config -->
    <httpEndpoint
            host="*"
            httpPort="${default.http.port}"
            httpsPort="${default.https.port}"
            id="defaultHttpEndpoint"/>
    <applicationManager autoExpand="true"/>
    <webApplication
            location="tracking-inventory-0.0.1-SNAPSHOT.war"
            context-root="/">
    </webApplication>
</server>

Java相关问答推荐

如何审查Java dtos中的自定义注释字段?

SQlite for Android无法使用json_group_array/json_object

无法传递消费者<;>;实例

缩小画布比例后更改滚动窗格的内部大小

Kubernetes的Java客户端检索状态.处于终止状态的Pod的阶段';正在运行';

试着做一个2x2的魔方求解算法,我如何找到解路径(DFS)?

GSON期间的Java类型擦除

每次FXMLLoader调用ApplationConext.getBean(类)时创建@Component的新实例

如何从日期中截取时间并将其传递给组件?

如何将Pane的图像快照保存为BMP?

Spring动态反序列化JSON可以是列表,也可以只是一个对象

如何生成指定范围内的11位序列号?

组合连接以从两个表返回数据

为了安全起见,有必要复制一份 list 吗?

在Java中使用StorageReference将数据从Firebase存储添加到数组列表

如何在Spring Boot Auth服务器上正确配置CORS?

简化每个元素本身都是 map 列表的列表

using case default on switch语句返回;预览特征切换中的模式匹配仅在源级别20及以上的情况下可用;

使用DynamoDB增强客户端时未更新属性

单例模式中热切初始化和惰性初始化的区别