我已经为我的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 了与服务器的连接?我遗漏了什么?