diff --git a/build.gradle.kts b/build.gradle.kts index 885fada..7d0a552 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { } group = "com.testainers" -version = "0.1.0" +version = "0.1.1" java { sourceCompatibility = JavaVersion.VERSION_21 diff --git a/coverage.sh b/coverage.sh index ef0f861..9540964 100755 --- a/coverage.sh +++ b/coverage.sh @@ -2,7 +2,7 @@ set -e -./gradlew cleanTest test +./gradlew clean test /bin/cp -rf helpers/jacoco-report/* build/jacoco-report/. diff --git a/helpers/jacoco-report/jacoco-resources/prettify.css b/helpers/jacoco-report/jacoco-resources/prettify.css index 61abef8..e6dda2e 100644 --- a/helpers/jacoco-report/jacoco-resources/prettify.css +++ b/helpers/jacoco-report/jacoco-resources/prettify.css @@ -1,13 +1,46 @@ /* Pretty printing styles. Used with prettify.js. */ -.str { color: #ecc48d; } -.kwd { color: #f7768e; font-weight: bold; } -.com { color: #86c1b9; font-style: italic; } -.typ { color: #b8b8f3; font-weight: bold; } -.lit { color: #7b9df9; } -.pun { color: #f9a8d4; } -.pln { color: #d4d4d4; } -.tag { color: #008; font-weight: bold; } -.atn { color: #606; font-weight: bold; } -.atv { color: #080; } -.dec { color: #606; } +.str { + color: #80b3ff; /* Light blue for strings */ +} + +.kwd { + color: #ff80b3; /* Light pink for keywords */ + font-weight: bold; +} + +.com { + color: #b3d9ff; /* Light sky blue for comments */ +} + +.typ { + color: #c080ff; /* Light purple for types */ +} + +.lit { + color: #80ffd4; /* Light teal for literals */ +} + +.pun { + color: #ffd480; /* Light orange for punctuation */ +} + +.pln { + color: #e0e0e0; /* Light gray for plain text */ +} + +.tag { + color: #80ff80; /* Light green for tags */ +} + +.atn { + color: #ff80ff; /* Light magenta for attribute names */ +} + +.atv { + color: #80ffb3; /* Light green for attribute values */ +} + +.dec { + color: #ffb380; /* Light peach for decimal values */ +} diff --git a/helpers/jacoco-report/jacoco-resources/report.css b/helpers/jacoco-report/jacoco-resources/report.css index 4767e4d..17bdb8b 100644 --- a/helpers/jacoco-report/jacoco-resources/report.css +++ b/helpers/jacoco-report/jacoco-resources/report.css @@ -1,40 +1,45 @@ body, td { font-family: sans-serif; font-size: 10pt; - color: #ffffff; /* cor do texto */ - background-color: #222222; /* cor de fundo */ + color: #e0e0e0; + background-color: #1e1e1e; } h1 { font-weight: bold; font-size: 18pt; - color: #ffffff; /* cor do título */ + color: #ffffff; +} + +a { + color: #80b3ff; + text-decoration: none; +} + +a:hover, a:focus { + color: #ffcc80; + text-decoration: underline; } .breadcrumb { - border: #d6d3ce 1px solid; - padding: 2px 4px 2px 4px; - background-color: #333333; /* cor de fundo da breadcrumb */ - color: #ffffff; /* cor do texto da breadcrumb */ + border: #444 1px solid; + padding: 2px 4px; + background-color: #333; + color: #e0e0e0; +} + +.breadcrumb .info { + float: right; } .breadcrumb .info a { margin-left: 8px; - color: #ffffff; /* cor dos links da breadcrumb */ } -.el_report, -.el_group, -.el_bundle, -.el_package, -.el_class, -.el_source, -.el_method, -.el_session { +.el_report, .el_group, .el_bundle, .el_package, .el_class, .el_source, .el_method, .el_session { padding-left: 18px; background-position: left center; background-repeat: no-repeat; - color: #ffffff; /* cor do texto */ } .el_report { @@ -70,28 +75,32 @@ h1 { } pre.source { - border: #d6d3ce 1px solid; + border: #444 1px solid; font-family: monospace; - color: #ffffff; /* cor do texto */ - background-color: #333333; /* cor de fundo */ + background-color: #2e2e2e; + color: #c0c0c0; +} + +pre.source ol { + margin: 0; } pre.source li { - border-left: 1px solid #d6d3ce; - color: #a0a0a0; - padding-left: 0px; + border-left: 1px solid #444; + color: #888; + padding-left: 0; } pre.source span.fc { - background-color: #224422; /* cor de fundo dos spans .fc */ + background-color: #334d33; } pre.source span.nc { - background-color: #662222; /* cor de fundo dos spans .nc */ + background-color: #4d3333; } pre.source span.pc { - background-color: #666622; /* cor de fundo dos spans .pc */ + background-color: #4d4d33; } pre.source span.bfc { @@ -101,7 +110,7 @@ pre.source span.bfc { } pre.source span.bfc:hover { - background-color: #228822; /* cor de fundo hover dos spans .bfc */ + background-color: #267326; } pre.source span.bnc { @@ -111,7 +120,7 @@ pre.source span.bnc { } pre.source span.bnc:hover { - background-color: #882222; /* cor de fundo hover dos spans .bnc */ + background-color: #732626; } pre.source span.bpc { @@ -121,20 +130,7 @@ pre.source span.bpc { } pre.source span.bpc:hover { - background-color: #888822; /* cor de fundo hover dos spans .bpc */ -} - -/* Java Code */ - -pre.source.lang-java.linenums { - background-color: #2f3032; - color: #d4d4d4; - padding: 10px; - font-family: monospace; - font-size: 12px; - line-height: 1.4; - overflow-x: auto; - border-radius: 4px; + background-color: #737326; } pre.source.lang-java.linenums code { @@ -146,28 +142,26 @@ pre.source.lang-java.linenums code { table.coverage { empty-cells: show; border-collapse: collapse; - color: #ffffff; /* cor do texto */ } table.coverage thead { - background-color: #333333; /* cor de fundo do cabeçalho da tabela */ - color: #ffffff; /* cor do texto do cabeçalho da tabela */ + background-color: #444; + color: #e0e0e0; } table.coverage thead td { white-space: nowrap; - padding: 12px 18px; - border-bottom: 1px solid #555555; - font-weight: bold; + padding: 2px 14px 0 6px; + border-bottom: #666 1px solid; } table.coverage thead td.bar { - border-left: #cccccc 1px solid; + border-left: #555 1px solid; } table.coverage thead td.ctr1 { text-align: right; - border-left: #cccccc 1px solid; + border-left: #555 1px solid; } table.coverage thead td.ctr2 { @@ -192,64 +186,64 @@ table.coverage thead td.down { table.coverage tbody td { white-space: nowrap; - padding: 12px 18px; - border-bottom: 1px solid #555555; + padding: 2px 6px; + border-bottom: #444 1px solid; + color: #e0e0e0; } table.coverage tbody tr:hover { - background: #444444; /* cor de fundo hover das linhas da tabela */ + background: #333 !important; } table.coverage tbody td.bar { - border-left: #e8e8e8 1px solid; + border-left: #555 1px solid; } table.coverage tbody td.ctr1 { text-align: right; - padding-right: 18px; - border-left: #e8e8e8 1px solid; + padding-right: 14px; + border-left: #555 1px solid; } table.coverage tbody td.ctr2 { text-align: right; - padding-right: 18px; + padding-right: 14px; padding-left: 2px; } table.coverage tfoot td { white-space: nowrap; - padding: 12px 18px; + padding: 2px 6px; } table.coverage tfoot td.bar { - border-left: #e8e8e8 1px solid; + border-left: #555 1px solid; } table.coverage tfoot td.ctr1 { text-align: right; - padding-right: 18px; - border-left: #e8e8e8 1px solid; + padding-right: 14px; + border-left: #555 1px solid; } table.coverage tfoot td.ctr2 { text-align: right; - padding-right: 18px; + padding-right: 14px; padding-left: 2px; } .footer { margin-top: 20px; - border-top: #d6d3ce 1px solid; + border-top: #444 1px solid; padding-top: 2px; - color: #a0a0a0; - font-size: 1.5em; + font-size: 8pt; + color: #888; } .footer a { - color: #a0a0a0; + color: #80b3ff; } .right { - display: none; + float: right; } - diff --git a/src/main/kotlin/com/testainers/DelayResource.kt b/src/main/kotlin/com/testainers/DelayResource.kt index 7fcac50..724f2b4 100644 --- a/src/main/kotlin/com/testainers/DelayResource.kt +++ b/src/main/kotlin/com/testainers/DelayResource.kt @@ -73,18 +73,12 @@ class DelayResource( val responseBody = ResponseBody(request, uriInfo, body) var code = 200 - if (delay < 0 || delay > 10) { - code = 400 - responseBody.body = String.format("Invalid delay: %d", delay) + if (delay in 0..10) { + Thread.sleep(delay * 1000L) + responseBody.body = "Slept for $delay seconds." } else { - try { - Thread.sleep(delay * 1000L) - responseBody.body = - String.format("Slept for %d seconds.", delay) - } catch (e: InterruptedException) { - code = 500 - responseBody.body = String.format("Interrupted: %s", e.message) - } + code = 400 + responseBody.body = "Invalid delay: $delay" } return Response.status(code).entity(responseBody).build() diff --git a/src/main/kotlin/com/testainers/LengthResource.kt b/src/main/kotlin/com/testainers/LengthResource.kt index e410699..5387506 100644 --- a/src/main/kotlin/com/testainers/LengthResource.kt +++ b/src/main/kotlin/com/testainers/LengthResource.kt @@ -104,7 +104,7 @@ class LengthResource { Response .status(500) .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - .entity(String.format("Invalid size: %d", size)) + .entity("Invalid size: $size") .build() } else { if (MediaType.APPLICATION_OCTET_STREAM == accept) { diff --git a/src/main/kotlin/com/testainers/ResponseBody.kt b/src/main/kotlin/com/testainers/ResponseBody.kt index b6c01a4..f3e9d97 100644 --- a/src/main/kotlin/com/testainers/ResponseBody.kt +++ b/src/main/kotlin/com/testainers/ResponseBody.kt @@ -1,8 +1,5 @@ -@file:Suppress("unused", "MemberVisibilityCanBePrivate") - package com.testainers -import io.quarkus.runtime.annotations.RegisterForReflection import io.vertx.core.http.HttpServerRequest import jakarta.ws.rs.core.* import java.net.URI @@ -10,31 +7,24 @@ import java.net.URI /** * @author Eduardo Folly */ -@RegisterForReflection -class ResponseBody( - request: HttpServerRequest, - uriInfo: UriInfo, - body: Any?, +data class ResponseBody( + private val request: HttpServerRequest, + private val uriInfo: UriInfo, + var body: Any?, ) { - var uri: URI - var method: String = request.method().name() - var remoteAddress: String = request.remoteAddress().toString() - var remoteHost: String = request.remoteAddress().host() - var headers: MultivaluedMap = MultivaluedHashMap() - var pathParameters: MultivaluedMap - var queryParameters: MultivaluedMap - - var body: Any? - - init { - for ((key, value) in request.headers()) { - headers.add(key, value) - } - - this.uri = uriInfo.absolutePath - this.pathParameters = uriInfo.pathParameters - this.queryParameters = uriInfo.queryParameters - - this.body = body - } + val uri: URI get() = uriInfo.absolutePath + val method: String get() = request.method().name() + val remoteAddress: String get() = request.remoteAddress().toString() + val remoteHost: String get() = request.remoteAddress().host() + val pathParameters: MultivaluedMap + get() = uriInfo.pathParameters + val queryParameters: MultivaluedMap + get() = uriInfo.queryParameters + val headers: MultivaluedMap + get() = + request + .headers() + .fold(MultivaluedHashMap()) { acc, (key, value) -> + acc.apply { add(key, value) } + } } diff --git a/src/test/kotlin/com/testainers/BaseResourceTest.kt b/src/test/kotlin/com/testainers/BaseResourceTest.kt index 6bcbf2c..dcdd21b 100644 --- a/src/test/kotlin/com/testainers/BaseResourceTest.kt +++ b/src/test/kotlin/com/testainers/BaseResourceTest.kt @@ -14,15 +14,22 @@ import org.junit.jupiter.params.provider.Arguments */ abstract class BaseResourceTest { companion object { + @JvmStatic private val methods = - listOf(Method.GET, Method.POST, Method.PUT, Method.DELETE) + setOf( + Method.GET, + Method.POST, + Method.PUT, + Method.DELETE, + Method.PATCH, + ) @JvmStatic - fun notFoundStatus(): List = - argumentGenerator(listOf(null, "", " ", "a", "1.8")) + fun onlyMethods(): List = methods.map { Arguments.of(it) } @JvmStatic - fun onlyMethods(): List = methods.map { Arguments.of(it) } + fun notFoundStatus(): List = + argumentGenerator(listOf(null, "", " ", "a", "1.8")) @JvmStatic fun argumentGenerator(list: List): List { @@ -38,10 +45,6 @@ abstract class BaseResourceTest { } } -// @Deprecated("Not use") -// protected val methods = -// listOf(Method.GET, Method.POST, Method.PUT, Method.DELETE) - protected val config: RestAssuredConfig = RestAssured .config() diff --git a/src/test/kotlin/com/testainers/BasicAuthResourceTest.kt b/src/test/kotlin/com/testainers/BasicAuthResourceTest.kt index e917c9a..e06d727 100644 --- a/src/test/kotlin/com/testainers/BasicAuthResourceTest.kt +++ b/src/test/kotlin/com/testainers/BasicAuthResourceTest.kt @@ -12,16 +12,14 @@ import org.junit.jupiter.params.provider.MethodSource */ @QuarkusTest class BasicAuthResourceTest : BaseResourceTest() { - companion object : BaseResourceTest() { - const val USER = "test" - const val PASS = "test-pass0" - } + val user = "test" + val pass = "test-pass0" @ParameterizedTest @MethodSource("onlyMethods") fun noHeader(method: Method) { json(method) - .request(method, "/basic-auth/$USER/$PASS") + .request(method, "/basic-auth/$user/$pass") .then() .statusCode(401) .body( @@ -31,8 +29,8 @@ class BasicAuthResourceTest : BaseResourceTest() { method, mapOf( "body.auth" to equalTo(false), - "body.user" to equalTo(USER), - "body.pass" to equalTo(PASS), + "body.user" to equalTo(user), + "body.pass" to equalTo(pass), "body.message" to equalTo( "Authorization header not present.", @@ -47,7 +45,7 @@ class BasicAuthResourceTest : BaseResourceTest() { fun emptyHeader(method: Method) { json(method) .header(HttpHeaders.AUTHORIZATION, "") - .request(method, "/basic-auth/$USER/$PASS") + .request(method, "/basic-auth/$user/$pass") .then() .statusCode(401) .body( @@ -57,8 +55,8 @@ class BasicAuthResourceTest : BaseResourceTest() { method, mapOf( "body.auth" to equalTo(false), - "body.user" to equalTo(USER), - "body.pass" to equalTo(PASS), + "body.user" to equalTo(user), + "body.pass" to equalTo(pass), "body.message" to equalTo( "Authorization header not present.", @@ -74,8 +72,8 @@ class BasicAuthResourceTest : BaseResourceTest() { json(method) .auth() .preemptive() - .basic(USER, PASS) - .request(method, "/basic-auth/$USER/$PASS") + .basic(user, pass) + .request(method, "/basic-auth/$user/$pass") .then() .statusCode(200) .body( @@ -85,11 +83,36 @@ class BasicAuthResourceTest : BaseResourceTest() { method, mapOf( "body.auth" to equalTo(true), - "body.user" to equalTo(USER), - "body.pass" to equalTo(PASS), + "body.user" to equalTo(user), + "body.pass" to equalTo(pass), "body.message" to equalTo("Success."), ), ), ) } + + @ParameterizedTest + @MethodSource("onlyMethods") + fun fail(method: Method) { + json(method) + .auth() + .preemptive() + .basic(user + "A", pass + "A") + .request(method, "/basic-auth/$user/$pass") + .then() + .statusCode(403) + .body( + "body.body", + if (method == Method.GET) nullValue() else equalTo(body), + *bodyMatchers( + method, + mapOf( + "body.auth" to equalTo(false), + "body.user" to equalTo(user), + "body.pass" to equalTo(pass), + "body.message" to equalTo("Forbidden."), + ), + ), + ) + } }