From b4df9b642847cb2246bd5c67272197c160398947 Mon Sep 17 00:00:00 2001 From: Sergio del Amo Date: Mon, 19 Dec 2022 15:48:25 +0100 Subject: [PATCH] test: use HTTP Server TCK for function-aws-api-proxy Delete Test in this commit are moved to the TCK https://github.com/micronaut-projects/micronaut-core/pull/8499 --- ...aut.build.internal.http-test-module.gradle | 25 ++ .../aws/proxy/BodyArgumentsSpec.groovy | 54 --- .../function/aws/proxy/BodySpec.groovy | 74 ---- .../function/aws/proxy/ConsumesSpec.groovy | 59 --- .../function/aws/proxy/CookiesSpec.groovy | 87 ----- .../aws/proxy/DeleteWithoutBodySpec.groovy | 52 --- .../aws/proxy/ErrorHandlerSpec.groovy | 297 +-------------- .../function/aws/proxy/FiltersSpec.groovy | 131 ------- .../function/aws/proxy/FluxSpec.groovy | 48 --- .../proxy/MicronautLambdaHandlerSpec.groovy | 352 ------------------ .../MicronautLambdaHandlerStatusSpec.groovy | 104 ------ .../aws/proxy/ObjectMapperListenerSpec.groovy | 2 - .../aws/proxy/ObjectMapperSpec.groovy | 1 - .../function/aws/proxy/ParametersSpec.groovy | 50 --- .../aws/proxy/ResponseStatusSpec.groovy | 168 --------- .../function/aws/proxy/StatusSpec.groovy | 99 ----- .../function/aws/proxy/VersionSpec.groovy | 81 ---- .../aws/proxy/filters/FilterErrorSpec.groovy | 304 --------------- .../aws/proxy/filters/FilterException.java | 4 - .../filters/FilterExceptionException.java | 4 - .../FilterExceptionExceptionHandler.groovy | 15 - .../filters/FilterExceptionHandler.groovy | 16 - .../proxy/filters/NextFilterException.java | 4 - .../filters/NextFilterExceptionHandler.groovy | 16 - settings.gradle.kts | 1 + .../build.gradle.kts | 12 + .../tck/lambda/LambdaServerUnderTest.java | 149 ++++++++ .../lambda/LambdaServerUnderTestProvider.java | 13 + .../tck/lambda/MultiValueHeadersAdapter.java | 79 ++++ ...onautLambdaHandlerHttpServerTestSuite.java | 15 + ...ut.http.server.tck.ServerUnderTestProvider | 1 + .../src/test/resources/logback.xml | 10 + 32 files changed, 310 insertions(+), 2017 deletions(-) create mode 100644 buildSrc/src/main/groovy/io.micronaut.build.internal.http-test-module.gradle delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodyArgumentsSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ConsumesSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/CookiesSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/DeleteWithoutBodySpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FiltersSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FluxSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerStatusSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ParametersSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ResponseStatusSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/StatusSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/VersionSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterErrorSpec.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterException.java delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionException.java delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionExceptionHandler.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionHandler.groovy delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterException.java delete mode 100644 function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterExceptionHandler.groovy create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/build.gradle.kts create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTest.java create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTestProvider.java create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/MultiValueHeadersAdapter.java create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/tests/MicronautLambdaHandlerHttpServerTestSuite.java create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/META-INF/services/io.micronaut.http.server.tck.ServerUnderTestProvider create mode 100644 test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/logback.xml diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.http-test-module.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.http-test-module.gradle new file mode 100644 index 0000000000..26f976de44 --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.http-test-module.gradle @@ -0,0 +1,25 @@ +plugins { + id "io.micronaut.build.internal.aws-base" + id("java-library") +} + +dependencies { + testAnnotationProcessor(platform("io.micronaut:micronaut-bom:$micronautVersion")) + testAnnotationProcessor "io.micronaut:micronaut-inject-java" + testImplementation(platform("io.micronaut:micronaut-bom:$micronautVersion")) + testImplementation "io.micronaut:micronaut-inject-java" + testImplementation("org.junit.jupiter:junit-jupiter-params") + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter-engine") + testImplementation("org.testcontainers:junit-jupiter") + testRuntimeOnly("ch.qos.logback:logback-classic") +} + +java { + sourceCompatibility = JavaVersion.toVersion("11") + targetCompatibility = JavaVersion.toVersion("11") +} + +tasks.named("test") { + useJUnitPlatform() +} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodyArgumentsSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodyArgumentsSpec.groovy deleted file mode 100644 index 17c9ed0ef8..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodyArgumentsSpec.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.MediaType -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Post -import io.micronaut.http.annotation.Produces -import spock.lang.AutoCleanup -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -class BodyArgumentsSpec extends Specification { - - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'BodyArgumentsSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1164") - void "test body arguments"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/body-arguments-test/getA', HttpMethod.POST.toString()) - builder.body('{"a":"A","b":"B"}') - builder.header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == 'A' - } - - @Controller('/body-arguments-test') - @Requires(property = 'spec.name', value = 'BodyArgumentsSpec') - static class BodyController { - - @Post(uri = "/getA") - @Produces(MediaType.TEXT_PLAIN) - String getA(String a) { - return a - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodySpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodySpec.groovy index 3bc321bcf3..68bde3e6d5 100644 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodySpec.groovy +++ b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/BodySpec.groovy @@ -34,7 +34,6 @@ import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream - class BodySpec extends Specification { @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( @@ -61,21 +60,6 @@ class BodySpec extends Specification { } - void "test custom body POJO"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-body/pojo', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body('{"x":10,"y":20}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 201 - response.body == '{"x":10,"y":20}' - - } - void "test plain text as binary"() { given: AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-body/bytes', HttpMethod.POST.toString()) @@ -123,50 +107,6 @@ class BodySpec extends Specification { } - - void "test custom body POJO - default to JSON"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-body/pojo', HttpMethod.POST.toString()) - builder.body('{"x":10,"y":20}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 201 - response.body == '{"x":10,"y":20}' - - } - - void "test custom body POJO with whole request"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-body/pojo-and-request', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body('{"x":10,"y":20}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 201 - response.body == '{"x":10,"y":20}' - - } - - void "test custom body POJO - reactive types"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-body/pojo-reactive', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body('{"x":10,"y":20}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 201 - response.body == '{"x":10,"y":20}' - } - @Controller('/response-body') @Requires(property = 'spec.name', value = 'BodySpec') static class BodyController { @@ -177,20 +117,6 @@ class BodySpec extends Specification { return data } - @Post(uri = "/pojo-and-request") - @Status(HttpStatus.CREATED) - Point postRequest(HttpRequest request) { - return request.body.orElse(null) - } - - - @Post(uri = "/pojo-reactive") - @Status(HttpStatus.CREATED) - @SingleResult - Publisher post(@Body Publisher data) { - return data - } - @Post(uri = "/bytes", consumes = MediaType.TEXT_PLAIN) @Status(HttpStatus.CREATED) String postBytes(@Body byte[] bytes) { diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ConsumesSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ConsumesSpec.groovy deleted file mode 100644 index 57f7f51905..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ConsumesSpec.groovy +++ /dev/null @@ -1,59 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.MediaType -import io.micronaut.http.annotation.Body -import io.micronaut.http.annotation.Consumes -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Post -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class ConsumesSpec extends Specification { - - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ConsumesSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - - void "test multiple consumes definition"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/consumes-test', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body('{"name":"Fred"}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '{"name":"Fred"}' - - } - - @Controller('/consumes-test') - @Requires(property = 'spec.name', value = 'ConsumesSpec') - static class ConsumesController { - - @Post('/') - @Consumes([MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON]) - Pojo save(@Body Pojo pojo) { - pojo - } - } - - static class Pojo { - String name - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/CookiesSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/CookiesSpec.groovy deleted file mode 100644 index 0d3a5b8f97..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/CookiesSpec.groovy +++ /dev/null @@ -1,87 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpRequest -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.CookieValue -import io.micronaut.http.annotation.Get -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class CookiesSpec extends Specification { - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'CookiesSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - void "test no cookies"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/cookies-test/all', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '{}' - } - - void "test getCookies method"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/cookies-test/all', HttpMethod.GET.toString()) - builder.cookie("one", "foo") - builder.cookie("two", "bar") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '{"one":"foo","two":"bar"}' - } - - void "test Cookie bind"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/cookies-test/bind', HttpMethod.GET.toString()) - builder.cookie("one", "foo") - builder.cookie("two", "bar") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '{"one":"foo","two":"bar"}' - } - - @Controller('/cookies-test') - @Requires(property = 'spec.name', value = 'CookiesSpec') - static class CookieController { - - @Get(uri = "/all") - Map all(HttpRequest request) { - Map map = [:] - for (entry in request.cookies) { - map.put(entry.key, entry.value.value) - } - return map - } - - @Get(uri = "/bind") - Map all(@CookieValue String one, @CookieValue String two) { - [ - one: one, - two: two - ] - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/DeleteWithoutBodySpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/DeleteWithoutBodySpec.groovy deleted file mode 100644 index c4df8b478a..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/DeleteWithoutBodySpec.groovy +++ /dev/null @@ -1,52 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.serverless.proxy.model.AwsProxyResponse -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpHeaderValues -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpStatus -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Delete -import io.micronaut.http.annotation.Header -import io.micronaut.http.annotation.PathVariable -import io.micronaut.http.annotation.Status -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class DeleteWithoutBodySpec extends Specification { - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'DeleteWithoutBodySpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - void "verifies it is possible to exposes a delete endpoint which is invoked without a body"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/sessions/sergio', HttpMethod.DELETE.toString()) - .header(HttpHeaders.AUTHORIZATION, HttpHeaderValues.AUTHORIZATION_PREFIX_BEARER + " xxx") - - when: - AwsProxyResponse response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - } - - @Requires(property = 'spec.name', value = 'DeleteWithoutBodySpec') - @Controller('/sessions') - static class SessionsController { - @Status(HttpStatus.OK) - @Delete("/{username}") - void delete(@PathVariable String username, - @Header(HttpHeaders.AUTHORIZATION) String authorization) { - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ErrorHandlerSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ErrorHandlerSpec.groovy index 2951943b71..345d735d3a 100644 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ErrorHandlerSpec.groovy +++ b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ErrorHandlerSpec.groovy @@ -5,26 +5,19 @@ import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext import com.amazonaws.serverless.proxy.model.AwsProxyResponse import com.amazonaws.services.lambda.runtime.Context import com.fasterxml.jackson.databind.ObjectMapper -import groovy.transform.InheritConstructors import io.micronaut.context.ApplicationContext import io.micronaut.context.annotation.Requires -import io.micronaut.core.annotation.Introspected -import io.micronaut.http.* -import io.micronaut.http.annotation.* -import io.micronaut.http.codec.CodecException -import io.micronaut.http.hateoas.JsonError -import io.micronaut.http.hateoas.Link -import io.micronaut.http.server.exceptions.ExceptionHandler +import io.micronaut.http.HttpHeaders +import io.micronaut.http.HttpMethod +import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Get +import io.micronaut.http.annotation.Produces import io.micronaut.security.annotation.Secured import io.micronaut.security.rules.SecurityRule import spock.lang.AutoCleanup -import spock.lang.Issue import spock.lang.Shared import spock.lang.Specification -import jakarta.inject.Singleton -import javax.validation.Valid -import javax.validation.constraints.Min import javax.ws.rs.core.MediaType class ErrorHandlerSpec extends Specification { @@ -41,131 +34,6 @@ class ErrorHandlerSpec extends Specification { @Shared Context lambdaContext = new MockLambdaContext() - @Shared - ObjectMapper objectMapper = handler.getApplicationContext().getBean(ObjectMapper.class) - - void 'test custom global exception handlers for POST with body'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/json/errors/global', HttpMethod.POST.toString()) - .header(HttpHeaders.CONTENT_TYPE, io.micronaut.http.MediaType.APPLICATION_JSON) - .body(objectMapper.writeValueAsString(new RequestObject(101))) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body.startsWith("{\"message\":\"Error: bad things when post and body in request\",\"") - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.APPLICATION_JSON - } - - void 'test custom global exception handlers'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/errors/global', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == 'Exception Handled' - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.TEXT_PLAIN - } - - void 'test custom global exception handlers declared in controller'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/errors/global-ctrl', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - verifyAll { - response.statusCode == 200 - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.TEXT_PLAIN - response.body == 'bad things happens globally' - } - } - - void 'test custom global status handlers declared in controller'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/errors/global-status-ctrl', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - verifyAll { - response.statusCode == 200 - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.TEXT_PLAIN - response.body == 'global status' - } - } - - void 'test local exception handlers'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/errors/local', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == 'bad things' - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.TEXT_PLAIN - } - - void 'json message format errors return 400'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/json/jsonBody', HttpMethod.POST.toString()).body("{\"numberField\": \"textInsteadOfNumber\"}") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 400 - response.body.contains 'Invalid JSON: Error decoding JSON stream for type' - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.APPLICATION_JSON - } - - void 'message validation errors return 400'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/json/jsonBody', HttpMethod.POST.toString()).body("{\"numberField\": 0}") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 400 - response.body.contains 'data.numberField: must be greater than or equal to 1' - response.multiValueHeaders.getFirst(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.APPLICATION_JSON - } - - void 'cors headers are present after exceptions'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/errors/global', HttpMethod.GET.toString()) - .header(HttpHeaders.ORIGIN, "http://localhost:8080") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.multiValueHeaders.getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) == 'http://localhost:8080' - } - - void 'cors headers are present after failed deserialisation'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/json/jsonBody', HttpMethod.POST.toString()) - .header(HttpHeaders.ORIGIN, "http://localhost:8080") - .body('{"numberField": "string is not a number"}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.multiValueHeaders.getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) == 'http://localhost:8080' - } - void 'secured controller returns 401'() { given: AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/secret', HttpMethod.GET.toString()) @@ -178,19 +46,6 @@ class ErrorHandlerSpec extends Specification { response.statusCode == 401 } - void 'cors headers are present after failed deserialisation when error handler is used'() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/json/errors/global', HttpMethod.POST.toString()) - .header(HttpHeaders.ORIGIN, "http://localhost:8080") - .body('{"numberField": "string is not a number"}') - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.multiValueHeaders.getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) == 'http://localhost:8080' - } - @Secured(SecurityRule.IS_AUTHENTICATED) @Controller('/secret') @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') @@ -201,146 +56,4 @@ class ErrorHandlerSpec extends Specification { "area 51 hosts an alien" } } - - @Secured(SecurityRule.IS_ANONYMOUS) - @Controller('/errors') - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class ErrorController { - - @Get('/global') - String globalHandler() { - throw new MyException("bad things") - } - - @Get('/global-ctrl') - String globalControllerHandler() { - throw new GloballyHandledException("bad things happens globally") - } - - @Get('/global-status-ctrl') - @Status(HttpStatus.I_AM_A_TEAPOT) - String globalControllerHandlerForStatus() { - return 'original global status' - } - - @Get('/local') - String localHandler() { - throw new AnotherException("bad things") - } - - @Error - @Produces(io.micronaut.http.MediaType.TEXT_PLAIN) - @Status(HttpStatus.OK) - String localHandler(AnotherException throwable) { - return throwable.getMessage() - } - } - - @Secured(SecurityRule.IS_ANONYMOUS) - @Issue("issues/761") - @Controller(value = '/json/errors', produces = io.micronaut.http.MediaType.APPLICATION_JSON) - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class JsonErrorController { - - @Post('/global') - String globalHandlerPost(@Body RequestObject object) { - throw new RuntimeException("bad things when post and body in request") - } - - @Error - HttpResponse errorHandler(HttpRequest request, RuntimeException exception) { - JsonError error = new JsonError("Error: " + exception.getMessage()) - .link(Link.SELF, Link.of(request.getUri())); - - return HttpResponse.status(HttpStatus.OK) - .body(error) - } - } - - @Introspected - static class RequestObject { - @Min(1L) - Integer numberField; - - RequestObject(Integer numberField) { - this.numberField = numberField - } - } - - @Secured(SecurityRule.IS_ANONYMOUS) - @Controller('/json') - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class JsonController { - @Post('/jsonBody') - String jsonBody(@Valid @Body RequestObject data) { - return "blah" - } - } - - @Secured(SecurityRule.IS_ANONYMOUS) - @Controller('/global-errors') - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class GlobalErrorController { - - @Error(global = true, exception = GloballyHandledException) - @Produces(io.micronaut.http.MediaType.TEXT_PLAIN) - @Status(HttpStatus.OK) - String globallyHandledException(GloballyHandledException throwable) { - return throwable.getMessage() - } - - @Error(global = true, status = HttpStatus.I_AM_A_TEAPOT) - @Produces(io.micronaut.http.MediaType.TEXT_PLAIN) - @Status(HttpStatus.OK) - String globalControllerHandlerForStatus() { - return 'global status' - } - - } - - @Singleton - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class CodecExceptionExceptionHandler - implements ExceptionHandler { - - @Override - HttpResponse handle(HttpRequest request, CodecException exception) { - return HttpResponse.badRequest("Invalid JSON: " + exception.getMessage()).contentType(MediaType.APPLICATION_JSON) - } - } - - @Singleton - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class RuntimeErrorHandler implements ExceptionHandler { - - @Override - HttpResponse handle(HttpRequest request, RuntimeException exception) { - return HttpResponse.serverError("Exception: " + exception.getMessage()) - .contentType(MediaType.TEXT_PLAIN) - } - } - - @Singleton - @Requires(property = 'spec.name', value = 'ErrorHandlerSpec') - static class MyErrorHandler implements ExceptionHandler { - - @Override - HttpResponse handle(HttpRequest request, MyException exception) { - return HttpResponse.ok("Exception Handled") - .contentType(MediaType.TEXT_PLAIN) - } - } - - - @InheritConstructors - static class MyException extends RuntimeException { - } - - @InheritConstructors - static class AnotherException extends RuntimeException { - } - - @InheritConstructors - static class GloballyHandledException extends Exception { - } } diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FiltersSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FiltersSpec.groovy deleted file mode 100644 index 4d7348f89a..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FiltersSpec.groovy +++ /dev/null @@ -1,131 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.serverless.proxy.model.AwsProxyResponse -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.core.async.publisher.Publishers -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.MutableHttpResponse -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Filter -import io.micronaut.http.annotation.Get -import io.micronaut.http.annotation.Produces -import io.micronaut.http.filter.HttpServerFilter -import io.micronaut.http.filter.ServerFilterChain -import io.micronaut.http.server.exceptions.ExceptionHandler -import org.reactivestreams.Publisher -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification -import io.micronaut.core.annotation.Nullable; -import jakarta.inject.Singleton - -class FiltersSpec extends Specification { - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'FiltersSpec', - 'micronaut.server.cors.enabled': true - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - void "test filters are run correctly"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/filter-test/ok', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == 'OK' - response.multiValueHeaders - response.multiValueHeaders.getFirst('X-Test-Filter') == 'true' - } - - void "filters are applied on non matching methods - cors filter works"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/filter-test/ok', HttpMethod.OPTIONS.toString()) - .header('Origin', 'https://micronaut.io') - .header('Access-Control-Request-Method', 'GET') - - when: - AwsProxyResponse response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.multiValueHeaders - response.multiValueHeaders.getFirst('Access-Control-Allow-Origin') == 'https://micronaut.io' - } - - void "filters are applied on non matching methods - cors filter disable if not preflight"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/filter-test/ok', HttpMethod.OPTIONS.toString()) - - when: - AwsProxyResponse response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 405 - } - - void "test filters are run correctly with custom exception handler"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/filter-test/exception', HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == 'Exception Handled' - response.multiValueHeaders - response.multiValueHeaders.getFirst('X-Test-Filter') == 'true' - } - - @Controller("/filter-test") - @Requires(property = 'spec.name', value = 'FiltersSpec') - static class TestController { - @Get("/ok") - String ok() { - return "OK" - } - - @Get("/exception") - void exception() { - throw new CustomException() - } - } - - @Filter("/filter-test/**") - @Requires(property = 'spec.name', value = 'FiltersSpec') - static class TestFilter implements HttpServerFilter { - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - return Publishers.map(chain.proceed(request), { mutableHttpResponse -> - mutableHttpResponse.getHeaders().add("X-Test-Filter", "true") - return mutableHttpResponse - }) - } - - } - - static class CustomException extends RuntimeException { - } - - @Produces - @Singleton - @Requires(property = 'spec.name', value = 'FiltersSpec') - static class CustomExceptionHandler implements ExceptionHandler { - @Override - HttpResponse handle(HttpRequest request, CustomException exception) { - return HttpResponse.ok("Exception Handled") - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FluxSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FluxSpec.groovy deleted file mode 100644 index ccfa86e20e..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/FluxSpec.groovy +++ /dev/null @@ -1,48 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpMethod -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import reactor.core.publisher.Flux -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class FluxSpec extends Specification { - - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'FluxSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - void "test getAll method"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder("/users", HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '["Joe","Lewis"]' - } - - @Controller("/users") - @Requires(property = 'spec.name', value = 'FluxSpec') - static class UserController { - - @Get - Flux getAll() { - return Flux.fromIterable(["Joe", "Lewis"]) - } - - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerSpec.groovy deleted file mode 100644 index 4656f81980..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerSpec.groovy +++ /dev/null @@ -1,352 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.serverless.proxy.model.AwsProxyResponse -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.core.annotation.Introspected -import io.micronaut.core.annotation.NonNull -import io.micronaut.function.aws.LambdaApplicationContextBuilder -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.MediaType -import io.micronaut.http.annotation.Body -import io.micronaut.http.annotation.Consumes -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import io.micronaut.http.annotation.Post -import io.micronaut.security.annotation.Secured -import io.micronaut.security.rules.SecurityRule -import spock.lang.Issue -import spock.lang.Specification - -import javax.validation.constraints.NotBlank - -class MicronautLambdaHandlerSpec extends Specification { - /* - Simple test to ensure that constructing with a builder or a fully-initialized ApplicationContext - has no effect on the behaviour. - */ - void "injected ApplicationContext preserves behaviour"() { - given: - MicronautLambdaHandler handler = new MicronautLambdaHandler(ApplicationContext.builder().properties([ - 'spec.name': 'MicronautLambdaHandlerSpec' - ])) - ApplicationContext context = new LambdaApplicationContextBuilder() - .properties([ - 'spec.name': 'MicronautLambdaHandlerSpec' - ]) - .build() - .start() - MicronautLambdaHandler injectedHandler = new MicronautLambdaHandler(context) - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/foo', HttpMethod.GET.toString()) - builder.queryString("param", "value") - - when: - def response = handler.handleRequest(builder.build(), new MockLambdaContext()) - def injectedResponse = injectedHandler.handleRequest(builder.build(), new MockLambdaContext()) - - then: - injectedResponse.statusCode == response.statusCode - injectedResponse.body == "value" - response.body == "value" - injectedResponse.headers == response.headers - - cleanup: - if (handler != null) - handler.close() - if (injectedHandler != null) - injectedHandler.close() - } - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/868") - void "test selected route reflects accept header"(){ - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/bar/ok', HttpMethod.GET.toString()) - builder.header("Accept", MediaType.APPLICATION_JSON) - - def response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response - response.body == "{\"status\":\"ok\"}" - - when: - builder = new AwsProxyRequestBuilder('/bar/ok', HttpMethod.GET.toString()) - builder.header("Accept", MediaType.TEXT_HTML) - - response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response - response.body == "
ok
" - - cleanup: - handler.close() - } - - void "test behavior of 404"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/does-not-exist', HttpMethod.GET.toString()) - builder.header("Accept", MediaType.APPLICATION_JSON) - - def response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response - response.statusCode == 404 - - cleanup: - handler.close() - } - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1410") - void "POST form url encoded body binding to pojo works"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED) - builder.body("message=World") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - } - - void "POST form url encoded body binding to pojo works if you don't specify body annotation"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/without-body-annotation', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED) - builder.body("message=World") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - } - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1410") - void "form-url-encoded with Body annotation and a nested attribute"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/nested-attribute', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED) - builder.body("message=World") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - - cleanup: - handler.close() - } - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1410") - void "application-json with Body annotation and a nested attribute"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/json-nested-attribute', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body("{\"message\":\"World\"}") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - - cleanup: - handler.close() - } - - void "application-json without Body annotation"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/json-without-body-annotation', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body("{\"message\":\"World\"}") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - - cleanup: - handler.close() - } - - void "application-json with Body annotation and a nested attribute and Map return rendered as JSON"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/json-nested-attribute-with-map-return', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body("{\"message\":\"World\"}") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"message":"Hello World"}' - - cleanup: - handler.close() - } - - void "application-json with Body annotation and Object return rendered as JSON"() { - given: - MicronautLambdaContainerHandler handler = instantiateHandler() - - when: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/form/json-with-body-annotation-and-with-object-return', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - builder.body("{\"message\":\"World\"}") - AwsProxyResponse response = handler.proxy(builder.build(), new MockLambdaContext()) - - then: - response.statusCode == 200 - response.body == '{"greeting":"Hello World"}' - - cleanup: - handler.close() - } - - @Controller - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerSpec') - @Secured(SecurityRule.IS_ANONYMOUS) - static class SimpleController { - @Get(uri = "/foo") - HttpResponse getParamValue(HttpRequest request) { - return HttpResponse.ok() - .body(request.getParameters().get("param")) - .header("foo", "bar") - } - } - - @Controller("/bar") - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerSpec') - @Secured(SecurityRule.IS_ANONYMOUS) - static class ProduceController { - @Get(value = "/ok", produces = MediaType.APPLICATION_JSON) - String getOkAsJson() { - return "{\"status\":\"ok\"}" - } - - @Get(value = "/ok", produces = MediaType.TEXT_HTML) - String getOkAsHtml() { - return "
ok
" - } - } - - @Introspected - static class MessageCreate { - - @NonNull - @NotBlank - private final String message; - - MessageCreate(@NonNull String message) { - this.message = message; - } - - @NonNull - String getMessage() { - return message; - } - } - - @Introspected - static class MyResponse { - - @NonNull - @NotBlank - private final String greeting; - - MyResponse(@NonNull String greeting) { - this.greeting = greeting - } - - @NonNull - String getGreeting() { - return greeting - } - } - - @Controller("/form") - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerSpec') - @Secured(SecurityRule.IS_ANONYMOUS) - static class FormController { - - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Post("/without-body-annotation") - String withoutBodyAnnotation(MessageCreate messageCreate) { - "{\"message\":\"Hello ${messageCreate.getMessage()}\"}"; - } - - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Post - String save(@Body MessageCreate messageCreate) { - "{\"message\":\"Hello ${messageCreate.getMessage()}\"}"; - } - - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Post("/nested-attribute") - String save(@Body("message") String value) { - "{\"message\":\"Hello ${value}\"}"; - } - - @Consumes(MediaType.APPLICATION_JSON) - @Post("/json-without-body-annotation") - String jsonWithoutBody(MessageCreate messageCreate) { - "{\"message\":\"Hello ${messageCreate.message}\"}"; - } - - @Consumes(MediaType.APPLICATION_JSON) - @Post("/json-nested-attribute") - String jsonNestedAttribute(@Body("message") String value) { - "{\"message\":\"Hello ${value}\"}"; - } - - @Consumes(MediaType.APPLICATION_JSON) - @Post("/json-nested-attribute-with-map-return") - Map jsonNestedAttributeWithMapReturn(@Body("message") String value) { - [message: "Hello ${value}".toString()] - } - - @Consumes(MediaType.APPLICATION_JSON) - @Post("/json-with-body-annotation-and-with-object-return") - MyResponse jsonNestedAttributeWithObjectReturn(@Body MessageCreate messageCreate) { - new MyResponse("Hello ${messageCreate.message}") - } - } - - private static MicronautLambdaContainerHandler instantiateHandler() { - new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'spec.name' : 'MicronautLambdaHandlerSpec', - 'micronaut.security.enabled': false - ]) - ) - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerStatusSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerStatusSpec.groovy deleted file mode 100644 index e15f21735c..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/MicronautLambdaHandlerStatusSpec.groovy +++ /dev/null @@ -1,104 +0,0 @@ -package io.micronaut.function.aws.proxy - - -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.serverless.proxy.model.AwsProxyRequest -import com.amazonaws.serverless.proxy.model.AwsProxyResponse -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.HttpStatus -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import io.micronaut.http.annotation.Produces -import io.micronaut.http.server.exceptions.ExceptionHandler -import io.micronaut.http.server.exceptions.response.ErrorContext -import io.micronaut.http.server.exceptions.response.ErrorResponseProcessor -import jakarta.inject.Singleton -import spock.lang.AutoCleanup -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -class MicronautLambdaHandlerStatusSpec extends Specification { - - @Shared - @AutoCleanup - MicronautLambdaHandler handler = new MicronautLambdaHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'MicronautLambdaHandlerStatusSpec' - ]) - ) - - @Shared - Context context = new MockLambdaContext() - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1387") - void "test controller returning HttpStatus"(String path) { - given: - AwsProxyRequest input = new AwsProxyRequest(); - input.setPath(path) - - when: - AwsProxyResponse response = handler.handleRequest(input, context) - - then: - response.statusCode == 418 - - where: - path << ['/http-status', '/http-response-status', '/http-exception'] - } - - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerStatusSpec') - @Controller('/http-status') - static class HttpStatusController { - - @Get - HttpStatus index() { - HttpStatus.I_AM_A_TEAPOT - } - } - - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerStatusSpec') - @Controller('/http-response-status') - static class HttpResponseStatusController { - - @Get - HttpResponse index() { - HttpResponse.status(HttpStatus.I_AM_A_TEAPOT) - } - } - - @Requires(property = 'spec.name', value = 'MicronautLambdaHandlerStatusSpec') - @Controller('/http-exception') - static class HttpResponseErrorController { - - @Get - HttpResponse index() { - throw new TeapotException() - } - } - - static class TeapotException extends RuntimeException { - } - - @Produces - @Singleton - static class TeapotExceptionHandler implements ExceptionHandler> { - private final ErrorResponseProcessor errorResponseProcessor - - TeapotExceptionHandler(ErrorResponseProcessor errorResponseProcessor) { - this.errorResponseProcessor = errorResponseProcessor - } - - @Override - HttpResponse handle(HttpRequest request, TeapotException e) { - errorResponseProcessor.processResponse(ErrorContext.builder(request) - .cause(e) - .build(), HttpResponse.status(HttpStatus.I_AM_A_TEAPOT)) - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperListenerSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperListenerSpec.groovy index b89f2626da..37daf520db 100644 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperListenerSpec.groovy +++ b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperListenerSpec.groovy @@ -12,8 +12,6 @@ import io.micronaut.inject.BeanDefinition import io.micronaut.inject.qualifiers.Qualifiers import spock.lang.Issue import spock.lang.Specification - -import jakarta.inject.Named import jakarta.inject.Singleton @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/186") diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperSpec.groovy index 74522ac0a3..a3a894c906 100644 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperSpec.groovy +++ b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ObjectMapperSpec.groovy @@ -1,6 +1,5 @@ package io.micronaut.function.aws.proxy - import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.PropertyNamingStrategy diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ParametersSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ParametersSpec.groovy deleted file mode 100644 index f6e29f4bd7..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ParametersSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpRequest -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class ParametersSpec extends Specification { - - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ParametersSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - void "test getAll method"() { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/parameters-test/all', HttpMethod.GET.toString()) - builder.queryString("test", "one") - builder.queryString("test", "two") - builder.queryString("test", "three+four") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 200 - response.body == '["one","two","three+four"]' - } - - @Controller('/parameters-test') - @Requires(property = 'spec.name', value = 'ParametersSpec') - static class BodyController { - - @Get(uri = "/all") - List all(HttpRequest request) { - return request.getParameters().getAll("test") - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ResponseStatusSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ResponseStatusSpec.groovy deleted file mode 100644 index 52369c698c..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/ResponseStatusSpec.groovy +++ /dev/null @@ -1,168 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpStatus -import io.micronaut.http.MediaType -import io.micronaut.http.annotation.* -import spock.lang.Specification - -import javax.validation.ConstraintViolationException - -class ResponseStatusSpec extends Specification { - - private static Context lambdaContext = new MockLambdaContext() - - void "test custom response status"() { - given: - - def handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ResponseStatusSpec' - ]) - ) - - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-status', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - builder.body("foo") - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 201 - response.body == 'foo' - - cleanup: - handler.close() - } - - void "test optional causes 404"() { - given: - - MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ResponseStatusSpec' - ]) - ) - - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-status/optional', HttpMethod.GET.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 404 - - cleanup: - handler.close() - } - - void "test null causes 404"() { - given: - MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ResponseStatusSpec' - ]) - ) - - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-status/null', HttpMethod.GET.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 404 - - cleanup: - handler.close() - } - - void "test void methods does not cause 404"() { - given: - - MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'ResponseStatusSpec' - ]) - ) - - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-status/delete-something', HttpMethod.DELETE.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 204 - - cleanup: - handler.close() - } - - void "test constraint violation causes 400"() { - given: - - MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'spec.name': 'ResponseStatusSpec', - 'micronaut.security.enabled':false - ]) - ) - - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder('/response-status/constraint-violation', HttpMethod.POST.toString()) - builder.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 400 - - cleanup: - handler.close() - } - - @Controller('/response-status') - @Requires(property = 'spec.name', value = 'ResponseStatusSpec') - static class StatusController { - - @Post(uri = "/", processes = MediaType.TEXT_PLAIN) - @Status(HttpStatus.CREATED) - String post(@Body String data) { - return data - } - - @Get(uri = "/optional", processes = MediaType.TEXT_PLAIN) - Optional optional() { - return Optional.empty() - } - - @Get(uri = "/null", processes = MediaType.TEXT_PLAIN) - String returnNull() { - return null - } - - @Post(uri = "/constraint-violation", processes = MediaType.TEXT_PLAIN) - String constraintViolation() { - throw new ConstraintViolationException("Failed", Collections.emptySet()) - } - - @Status(HttpStatus.NO_CONTENT) - @Delete(uri = "/delete-something", processes = MediaType.TEXT_PLAIN) - void deleteSomething() { - // do nothing - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/StatusSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/StatusSpec.groovy deleted file mode 100644 index cf198fc11f..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/StatusSpec.groovy +++ /dev/null @@ -1,99 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.HttpStatus -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import io.micronaut.http.annotation.Produces -import io.micronaut.http.server.exceptions.ExceptionHandler -import io.micronaut.http.server.exceptions.response.ErrorContext -import io.micronaut.http.server.exceptions.response.ErrorResponseProcessor -import spock.lang.AutoCleanup -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import jakarta.inject.Singleton - -class StatusSpec extends Specification { - - @Shared @AutoCleanup MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name': 'StatusSpec' - ]) - ) - @Shared Context lambdaContext = new MockLambdaContext() - - @Issue("https://github.com/micronaut-projects/micronaut-aws/issues/1387") - void "test controller returning HttpStatus"(String path) { - given: - AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder(path, HttpMethod.GET.toString()) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == 418 - - where: - path << ['/http-status', '/http-response-status', '/http-exception'] - } - - @Requires(property = 'spec.name', value = 'StatusSpec') - @Controller('/http-status') - static class HttpStatusController { - - @Get - HttpStatus index() { - HttpStatus.I_AM_A_TEAPOT - } - } - - @Requires(property = 'spec.name', value = 'StatusSpec') - @Controller('/http-response-status') - static class HttpResponseStatusController { - - @Get - HttpResponse index() { - HttpResponse.status(HttpStatus.I_AM_A_TEAPOT) - } - } - - @Requires(property = 'spec.name', value = 'StatusSpec') - @Controller('/http-exception') - static class HttpResponseErrorController { - - @Get - HttpResponse index() { - throw new TeapotException() - } - } - - static class TeapotException extends RuntimeException { - } - - @Produces - @Singleton - static class TeapotExceptionHandler implements ExceptionHandler> { - private final ErrorResponseProcessor errorResponseProcessor - - TeapotExceptionHandler(ErrorResponseProcessor errorResponseProcessor) { - this.errorResponseProcessor = errorResponseProcessor - } - - @Override - HttpResponse handle(HttpRequest request, TeapotException e) { - errorResponseProcessor.processResponse(ErrorContext.builder(request) - .cause(e) - .build(), HttpResponse.status(HttpStatus.I_AM_A_TEAPOT)) - } - } - -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/VersionSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/VersionSpec.groovy deleted file mode 100644 index 7cc0416099..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/VersionSpec.groovy +++ /dev/null @@ -1,81 +0,0 @@ -package io.micronaut.function.aws.proxy - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.serverless.proxy.model.AwsProxyRequest -import com.amazonaws.serverless.proxy.model.AwsProxyResponse -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.core.version.annotation.Version -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpMethod -import io.micronaut.http.HttpStatus -import io.micronaut.http.MediaType -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import spock.lang.AutoCleanup -import spock.lang.Shared -import spock.lang.Specification - -class VersionSpec extends Specification { - - @Shared - @AutoCleanup - MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties([ - 'micronaut.security.enabled': false, - 'spec.name' : 'VersionSpec', - 'micronaut.router.versioning.enabled' : true, - 'micronaut.router.versioning.header.enabled': true, - ]) - ) - - @Shared - Context lambdaContext = new MockLambdaContext() - - void 'test controller method without version (default)'() { - given: - AwsProxyRequest request = new AwsProxyRequestBuilder('/version/ping', HttpMethod.GET.name()) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .build() - - when: - AwsProxyResponse response = handler.proxy(request, lambdaContext) - - then: - response.statusCode == HttpStatus.OK.getCode() - response.body == 'pong v1' - } - - void 'test controller method with version 2'() { - given: - AwsProxyRequest request = new AwsProxyRequestBuilder('/version/ping', HttpMethod.GET.name()) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .header('X-API-VERSION', '2') - .build() - - when: - AwsProxyResponse response = handler.proxy(request, lambdaContext) - - then: - response.statusCode == HttpStatus.OK.getCode() - response.body == 'pong v2' - } - - @Controller('/version') - @Requires(property = 'spec.name', value = 'VersionSpec') - static class ConsumesController { - - @Get('/ping') - String pingV1() { - 'pong v1' - } - - @Version('2') - @Get('/ping') - String pingV2() { - 'pong v2' - } - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterErrorSpec.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterErrorSpec.groovy deleted file mode 100644 index d6ac6ba668..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterErrorSpec.groovy +++ /dev/null @@ -1,304 +0,0 @@ -package io.micronaut.function.aws.proxy.filters - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder -import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext -import com.amazonaws.services.lambda.runtime.Context -import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Requires -import io.micronaut.core.async.publisher.Publishers -import io.micronaut.core.util.StringUtils -import io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler -import io.micronaut.http.* -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Error -import io.micronaut.http.annotation.Filter -import io.micronaut.http.annotation.Get -import io.micronaut.http.annotation.Status -import io.micronaut.http.filter.HttpServerFilter -import io.micronaut.http.filter.ServerFilterChain -import io.micronaut.web.router.MethodBasedRouteMatch -import io.micronaut.web.router.RouteMatch -import org.reactivestreams.Publisher -import spock.lang.Ignore -import spock.lang.Specification - -import java.util.concurrent.atomic.AtomicInteger -import java.util.concurrent.atomic.AtomicReference - -class FilterErrorSpec extends Specification { - - final static SPEC_NAME = FilterErrorSpec.simpleName - - private Context lambdaContext = new MockLambdaContext() - - private static createHandler(Map props) { - new MicronautLambdaContainerHandler( - ApplicationContext.builder().properties(props) - ) - } - - private static requestBuilder(String path, HttpMethod method) { - new AwsProxyRequestBuilder(path, method.toString()) - } - - void 'test errors emitted from filters interacting with exception handlers'() { - given: - def handler = createHandler(['spec.name': SPEC_NAME]) - def context = handler.applicationContext - def builder = requestBuilder('/filter-error-spec', HttpMethod.GET) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - - and: - First first = context.getBean(First) - Next next = context.getBean(Next) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == HttpStatus.BAD_REQUEST.code - response.body == 'from filter exception handler' - - and: - first.executedCount.get() == 1 - first.responseStatus.getAndSet(null) == null - next.executedCount.get() == 0 - } - - void 'test errors emitted from second filter interacting with exception handlers'() { - given: - def handler = createHandler(['spec.name': SPEC_NAME]) - def context = handler.applicationContext - def builder = requestBuilder('/filter-error-spec', HttpMethod.GET) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .header('X-Passthru', 'true') - - and: - First first = context.getBean(First) - Next next = context.getBean(Next) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == HttpStatus.BAD_REQUEST.code - response.body == 'from NEXT filter exception handler' - - and: - first.executedCount.get() == 1 - first.responseStatus.getAndSet(null) == HttpStatus.BAD_REQUEST - next.executedCount.get() == 1 - } - - void 'test non once per request filter throwing error does not loop'() { - given: - def handler = createHandler(['spec.name': SPEC_NAME + '2']) - def context = handler.applicationContext - def builder = requestBuilder('/filter-error-spec', HttpMethod.GET) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - - and: - FirstEvery filter = context.getBean(FirstEvery) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == HttpStatus.BAD_REQUEST.code - response.body == 'from filter exception handler' - filter.executedCount.get() == 1 - } - - void 'test filter throwing exception handled by exception handler throwing exception'() { - given: - def handler = createHandler([ - 'spec.name': SPEC_NAME + '3', - 'micronaut.security.enabled': false, - ]) - def context = handler.applicationContext - def builder = requestBuilder('/filter-error-spec-3', HttpMethod.GET) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - - and: - ExceptionException filter = context.getBean(ExceptionException) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - - then: - response.statusCode == HttpStatus.INTERNAL_SERVER_ERROR.code - response.body.contains('from exception handler') - filter.executedCount.get() == 1 - filter.responseStatus.getAndSet(null) == HttpStatus.INTERNAL_SERVER_ERROR - } - - void "test the error route is the route match"() { - given: - def handler = createHandler([ - 'spec.name': SPEC_NAME + '4', - 'micronaut.security.enabled': false, - ]) - def context = handler.applicationContext - def builder = requestBuilder('/filter-error-spec-4/status', HttpMethod.GET) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - - and: - ExceptionRoute filter = context.getBean(ExceptionRoute) - - when: - def response = handler.proxy(builder.build(), lambdaContext) - def match = filter.routeMatch.getAndSet(null) - - then: - response.statusCode == HttpStatus.OK.code - match instanceof MethodBasedRouteMatch - ((MethodBasedRouteMatch) match).getName() == 'testStatus' - -// when: -// HttpResponse response = Flux.from(client.exchange("/filter-error-spec-4/exception", String)) -// .blockFirst() -// def match = filter.routeMatch.getAndSet(null) -// -// then: -// response.status() == HttpStatus.OK -// match instanceof MethodBasedRouteMatch -// ((MethodBasedRouteMatch) match).getName() == "testException" - } - - @Requires(property = 'spec.name', value = 'FilterErrorSpec') - @Filter(Filter.MATCH_ALL_PATTERN) - static class First implements HttpServerFilter { - AtomicInteger executedCount = new AtomicInteger(0) - AtomicReference responseStatus = new AtomicReference<>() - - private void setResponse(MutableHttpResponse r) { - responseStatus.set(r.status()) - } - - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - executedCount.incrementAndGet() - if (StringUtils.isTrue(request.getHeaders().get("X-Passthru"))) { - return Publishers.then(chain.proceed(request), this::setResponse) - } - return Publishers.just(new FilterException()) - } - - @Override - int getOrder() { - 10 - } - } - - @Requires(property = 'spec.name', value = 'FilterErrorSpec') - @Filter(Filter.MATCH_ALL_PATTERN) - static class Next implements HttpServerFilter { - AtomicInteger executedCount = new AtomicInteger(0) - - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - executedCount.incrementAndGet() - return Publishers.just(new NextFilterException()) - } - - @Override - int getOrder() { - 20 - } - } - - @Requires(property = 'spec.name', value = 'FilterErrorSpec2') - @Filter(Filter.MATCH_ALL_PATTERN) - static class FirstEvery implements HttpServerFilter { - AtomicInteger executedCount = new AtomicInteger(0) - - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - executedCount.incrementAndGet() - return Publishers.just(new FilterException()) - } - - @Override - int getOrder() { - 10 - } - } - - @Requires(property = 'spec.name', value = 'FilterErrorSpec3') - @Filter(Filter.MATCH_ALL_PATTERN) - static class ExceptionException implements HttpServerFilter { - AtomicInteger executedCount = new AtomicInteger(0) - AtomicReference responseStatus = new AtomicReference<>() - - private void setResponse(MutableHttpResponse r) { - responseStatus.set(r.status()) - } - - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - executedCount.incrementAndGet() - return Publishers.then(chain.proceed(request), this::setResponse) - } - - @Override - int getOrder() { - 10 - } - } - - @Requires(property = 'spec.name', value = 'FilterErrorSpec4') - @Filter(Filter.MATCH_ALL_PATTERN) - static class ExceptionRoute implements HttpServerFilter { - AtomicReference> routeMatch = new AtomicReference<>() - - @Override - Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - return Publishers.then(chain.proceed(request), { resp -> - routeMatch.set(resp.getAttribute(HttpAttributes.ROUTE_MATCH, RouteMatch).get()) - }) - } - - @Override - int getOrder() { - 10 - } - } - - @Controller("/filter-error-spec") - static class NeverReachedController { - @Get - String get() { - return "OK" - } - } - - @Controller("/filter-error-spec-3") - static class HandledByHandlerController { - @Get - String get() { - throw new FilterExceptionException() - } - } - - @Controller("/filter-error-spec-4") - static class HandledByErrorRouteController { - @Get("/exception") - String getException() { - throw new FilterExceptionException() - } - - @Get("/status") - HttpStatus getStatus() { - return HttpStatus.NOT_FOUND - } - - @Error(exception = FilterExceptionException) - @Status(HttpStatus.OK) - void testException() {} - - @Error(status = HttpStatus.NOT_FOUND) - @Status(HttpStatus.OK) - void testStatus() {} - } - -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterException.java b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterException.java deleted file mode 100644 index 9f03ff3408..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterException.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.micronaut.function.aws.proxy.filters; - -public class FilterException extends RuntimeException { -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionException.java b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionException.java deleted file mode 100644 index cf58fe3f71..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionException.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.micronaut.function.aws.proxy.filters; - -public class FilterExceptionException extends RuntimeException { -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionExceptionHandler.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionExceptionHandler.groovy deleted file mode 100644 index e99e8e6a19..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionExceptionHandler.groovy +++ /dev/null @@ -1,15 +0,0 @@ -package io.micronaut.function.aws.proxy.filters - -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.server.exceptions.ExceptionHandler -import jakarta.inject.Singleton - -@Singleton -class FilterExceptionExceptionHandler implements ExceptionHandler> { - - @Override - HttpResponse handle(HttpRequest request, FilterExceptionException exception) { - throw new RuntimeException('from exception handler') - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionHandler.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionHandler.groovy deleted file mode 100644 index c2671e74ba..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/FilterExceptionHandler.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package io.micronaut.function.aws.proxy.filters - -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.server.exceptions.ExceptionHandler - -import jakarta.inject.Singleton - -@Singleton -class FilterExceptionHandler implements ExceptionHandler> { - - @Override - HttpResponse handle(HttpRequest request, FilterException exception) { - return HttpResponse.badRequest("from filter exception handler") - } -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterException.java b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterException.java deleted file mode 100644 index 1a2026a03b..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterException.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.micronaut.function.aws.proxy.filters; - -public class NextFilterException extends RuntimeException { -} diff --git a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterExceptionHandler.groovy b/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterExceptionHandler.groovy deleted file mode 100644 index 005056c9a8..0000000000 --- a/function-aws-api-proxy/src/test/groovy/io/micronaut/function/aws/proxy/filters/NextFilterExceptionHandler.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package io.micronaut.function.aws.proxy.filters - -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.server.exceptions.ExceptionHandler - -import jakarta.inject.Singleton - -@Singleton -class NextFilterExceptionHandler implements ExceptionHandler> { - - @Override - HttpResponse handle(HttpRequest request, NextFilterException exception) { - return HttpResponse.badRequest("from NEXT filter exception handler") - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 7b769c0f77..31f3f42722 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,6 +36,7 @@ include("aws-apigateway") include("function-aws-test") include("test-suite") include("test-suite-aws-sdk-v2") +include("http-server-tck") include("test-suite-groovy") include("test-suite-kotlin") diff --git a/test-suite-http-server-tck-function-aws-api-proxy/build.gradle.kts b/test-suite-http-server-tck-function-aws-api-proxy/build.gradle.kts new file mode 100644 index 0000000000..db7a0363d1 --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("io.micronaut.build.internal.http-test-module") +} +repositories { + mavenCentral() +} +val micronautVersion: String by project +dependencies { + testImplementation(projects.functionAwsApiProxy) + testImplementation(projects.httpServerTck) + testImplementation(mn.micronaut.http.client) +} diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTest.java b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTest.java new file mode 100644 index 0000000000..122662e38e --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTest.java @@ -0,0 +1,149 @@ +package io.micronaut.http.server.tck.lambda; + +import com.amazonaws.serverless.exceptions.ContainerInitializationException; +import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; +import com.amazonaws.serverless.proxy.model.AwsProxyRequest; +import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext; +import com.amazonaws.serverless.proxy.model.AwsProxyResponse; +import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap; +import com.amazonaws.services.lambda.runtime.Context; +import io.micronaut.context.ApplicationContext; +import io.micronaut.context.ApplicationContextBuilder; +import io.micronaut.core.type.Argument; +import io.micronaut.function.aws.LambdaApplicationContextBuilder; +import io.micronaut.function.aws.proxy.MicronautLambdaHandler; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.MediaType; +import io.micronaut.http.MutableHttpParameters; +import io.micronaut.http.MutableHttpResponse; +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.http.client.netty.NettyClientHttpRequestFactory; +import io.micronaut.http.server.tck.ServerUnderTest; +import io.micronaut.http.simple.SimpleHttpResponseFactory; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LambdaServerUnderTest implements ServerUnderTest { + private MicronautLambdaHandler handler; + private Context lambdaContext; + + public LambdaServerUnderTest(Map properties) { + try { + ApplicationContextBuilder contextBuilder = new LambdaApplicationContextBuilder(); + contextBuilder.properties(properties); + this.handler = new MicronautLambdaHandler(contextBuilder); + this.lambdaContext = new MockLambdaContext(); + } catch (ContainerInitializationException e) { + throw new RuntimeException(e); + } + } + + @Override + public HttpResponse exchange(HttpRequest request, Argument bodyType) { + try { + AwsProxyRequest input = adaptRequest(request); + AwsProxyResponse awsProxyResponse = handler.handleRequest(input, lambdaContext); + return adaptReponse(awsProxyResponse); + } catch (UnsupportedEncodingException e) { + return new SimpleHttpResponseFactory().status(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + private AwsProxyRequest adaptRequest(HttpRequest request) throws UnsupportedEncodingException { + AwsProxyRequest input = new AwsProxyRequest(); + input.setHttpMethod(request.getMethodName()); + input.setRequestContext(new AwsProxyRequestContext() { + + }); + input.setPath(request.getPath()); + for (String headerName : request.getHeaders().names()) { + input.getMultiValueHeaders().put(headerName, request.getHeaders().getAll(headerName)); + } + MutableHttpParameters parameters = NettyClientHttpRequestFactory.INSTANCE.create(request.getMethod(), request.getUri().toString()).getParameters(); + Map> paramsMap = parameters.asMap(); + MultiValuedTreeMap multiValueQueryStringParameters = new MultiValuedTreeMap<>(); + for (String paramName : paramsMap.keySet()) { + multiValueQueryStringParameters.addAll(paramName, paramsMap.get(paramName)); + } + input.setMultiValueQueryStringParameters(multiValueQueryStringParameters); + + Map queryStringParameters = new HashMap<>(); + for (String paramName : parameters.names()) { + queryStringParameters.put(paramName, request.getParameters().get(paramName)); + } + input.setQueryStringParameters(queryStringParameters); + + if (request.getContentType().isPresent() && request.getContentType().get().equals(MediaType.APPLICATION_FORM_URLENCODED_TYPE)) { + Optional body = request.getBody(Map.class); + if (body.isPresent()) { + input.setBody(getDataString(body.get())); + input.setIsBase64Encoded(false); + } + Optional bodyString = request.getBody(String.class); + if (bodyString.isPresent()) { + input.setBody(bodyString.get()); + input.setIsBase64Encoded(false); + } + } else { + Optional body = request.getBody(String.class); + if (body.isPresent()) { + input.setBody(body.get()); + input.setIsBase64Encoded(false); + } + } + return input; + } + + private HttpResponse adaptReponse(AwsProxyResponse awsProxyResponse) { + MutableHttpResponse response = new SimpleHttpResponseFactory().status(HttpStatus.valueOf(awsProxyResponse.getStatusCode())); + if (awsProxyResponse.getMultiValueHeaders() != null) { + HttpHeaders headers = new MultiValueHeadersAdapter(awsProxyResponse.getMultiValueHeaders()); + for (String headerName : headers.names()) { + for (String value : headers.getAll(headerName)) { + response.header(headerName, value); + } + } + } + response.body(awsProxyResponse.getBody()); + + if (response.getStatus().getCode() >= 400) { + throw new HttpClientResponseException("error", response); + } + return response; + } + + private String getDataString(Map params) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder(); + boolean first = true; + for(Object k : params.keySet()) { + if (first) { + first = false; + } else { + result.append("&"); + } + result.append(URLEncoder.encode(k.toString(), "UTF-8")); + result.append("="); + result.append(URLEncoder.encode(params.get(k).toString(), "UTF-8")); + } + return result.toString(); + } + + @Override + public ApplicationContext getApplicationContext() { + return handler.getApplicationContext(); + } + + @Override + public void close() throws IOException { + this.handler.close(); + } +} diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTestProvider.java b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTestProvider.java new file mode 100644 index 0000000000..7b4a6e6892 --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/LambdaServerUnderTestProvider.java @@ -0,0 +1,13 @@ +package io.micronaut.http.server.tck.lambda; + +import io.micronaut.http.server.tck.ServerUnderTest; +import io.micronaut.http.server.tck.ServerUnderTestProvider; + +import java.util.Map; + +public class LambdaServerUnderTestProvider implements ServerUnderTestProvider { + @Override + public ServerUnderTest getServer(Map properties) { + return new LambdaServerUnderTest(properties); + } +} diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/MultiValueHeadersAdapter.java b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/MultiValueHeadersAdapter.java new file mode 100644 index 0000000000..b21a36650a --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/MultiValueHeadersAdapter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017-2022 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micronaut.http.server.tck.lambda; + +import com.amazonaws.serverless.proxy.model.Headers; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.convert.ArgumentConversionContext; +import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.util.CollectionUtils; +import io.micronaut.core.util.StringUtils; +import io.micronaut.http.HttpHeaders; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Adapt between {com.amazonaws.serverless.proxy.model.Headers} to {@link HttpHeaders} + */ +public class MultiValueHeadersAdapter implements HttpHeaders { + private final Headers multiValueHeaders; + public MultiValueHeadersAdapter(Headers headers) { + this.multiValueHeaders = headers; + } + + @Override + public List getAll(CharSequence name) { + if (StringUtils.isNotEmpty(name)) { + final List strings = multiValueHeaders.get(name.toString()); + if (CollectionUtils.isNotEmpty(strings)) { + return strings; + } + } + return Collections.emptyList(); + } + + @Nullable + @Override + public String get(CharSequence name) { + if (StringUtils.isNotEmpty(name)) { + return multiValueHeaders.getFirst(name.toString()); + } + return null; + } + + @Override + public Set names() { + return multiValueHeaders.keySet(); + } + + @Override + public Collection> values() { + return multiValueHeaders.values(); + } + + @Override + public Optional get(CharSequence name, ArgumentConversionContext conversionContext) { + final String v = get(name); + if (v != null) { + return ConversionService.SHARED.convert(v, conversionContext); + } + return Optional.empty(); + } +} diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/tests/MicronautLambdaHandlerHttpServerTestSuite.java b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/tests/MicronautLambdaHandlerHttpServerTestSuite.java new file mode 100644 index 0000000000..4b3d9cc8b4 --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/java/io/micronaut/http/server/tck/lambda/tests/MicronautLambdaHandlerHttpServerTestSuite.java @@ -0,0 +1,15 @@ +package io.micronaut.http.server.tck.lambda.tests; + +import io.micronaut.http.server.tck.HttpServerTestSuite; +import org.junit.jupiter.api.Disabled; + +import java.io.IOException; + +public class MicronautLambdaHandlerHttpServerTestSuite implements HttpServerTestSuite { + + @Disabled + @Override + public void testRemoteAddressComesFromIdentitySourceIp() throws IOException { + HttpServerTestSuite.super.testRemoteAddressComesFromIdentitySourceIp(); + } +} diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/META-INF/services/io.micronaut.http.server.tck.ServerUnderTestProvider b/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/META-INF/services/io.micronaut.http.server.tck.ServerUnderTestProvider new file mode 100644 index 0000000000..873222e8a8 --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/META-INF/services/io.micronaut.http.server.tck.ServerUnderTestProvider @@ -0,0 +1 @@ +io.micronaut.http.server.tck.lambda.LambdaServerUnderTestProvider diff --git a/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/logback.xml b/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/logback.xml new file mode 100644 index 0000000000..8eb8c3a817 --- /dev/null +++ b/test-suite-http-server-tck-function-aws-api-proxy/src/test/resources/logback.xml @@ -0,0 +1,10 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + +