From b78d6a8c747319f3c4c6b68a78adcbf6a018a405 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Mon, 15 Jul 2024 12:59:53 +0000 Subject: [PATCH 1/2] test: add unit tests for Runtime API --- .../pom.xml | 10 +- .../LambdaRuntimeApiClientImplTest.java | 382 ++++++++++++++++++ 2 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java diff --git a/aws-lambda-java-runtime-interface-client/pom.xml b/aws-lambda-java-runtime-interface-client/pom.xml index 24e73a8d..df42879b 100644 --- a/aws-lambda-java-runtime-interface-client/pom.xml +++ b/aws-lambda-java-runtime-interface-client/pom.xml @@ -34,7 +34,7 @@ UTF-8 UTF-8 - 0.8.8 + 0.8.12 2.4 3.1.1 5.9.2 @@ -87,6 +87,12 @@ 4.11.0 test + + com.squareup.okhttp3 + mockwebserver + 4.12.0 + test + @@ -112,7 +118,7 @@ maven-surefire-plugin 3.0.0-M9 - ${argLineForReflectionTestOnly} + ${argLineForReflectionTestOnly} ${argLine} diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java new file mode 100644 index 00000000..40cd3e88 --- /dev/null +++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java @@ -0,0 +1,382 @@ +/* +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package com.amazonaws.services.lambda.runtime.api.client.runtimeapi; + +import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.ErrorRequest; +import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.StackElement; +import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayErrorCause; +import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.fail; +import okhttp3.HttpUrl; +import static java.net.HttpURLConnection.HTTP_ACCEPTED; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; +import okhttp3.mockwebserver.MockWebServer; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; + +public class LambdaRuntimeApiClientImplTest { + + MockWebServer mockWebServer; + LambdaRuntimeApiClientImpl lambdaRuntimeApiClientImpl; + + String[] errorStackStrace = { "item0", "item1", "item2" }; + ErrorRequest errorRequest = new ErrorRequest("testErrorMessage", "testErrorType", errorStackStrace); + + String requestId = "1234"; + + @BeforeEach + void setUp() { + mockWebServer = new MockWebServer(); + String hostnamePort = getHostnamePort(); + lambdaRuntimeApiClientImpl = new LambdaRuntimeApiClientImpl(hostnamePort); + } + + @Test + public void reportInitErrorTest() { + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportInitError(lambdaError); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/init/error"; + assertEquals(expectedUrl, actualUrl.toString()); + + String userAgentHeader = recordedRequest.getHeader("User-Agent"); + assertTrue(userAgentHeader.startsWith("aws-lambda-java/")); + + String lambdaRuntimeErrorTypeHeader = recordedRequest.getHeader("Lambda-Runtime-Function-Error-Type"); + assertEquals("Runtime.AfterRestoreError", lambdaRuntimeErrorTypeHeader); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("{\"errorMessage\":\"testErrorMessage\",\"errorType\":\"testErrorType\",\"stackTrace\":[\"item0\",\"item1\",\"item2\"]}", actualBody); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportInitErrorTestWrongStatusCode() { + int errorStatusCode = HTTP_INTERNAL_ERROR; + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(errorStatusCode); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportInitError(lambdaError); + fail(); + } catch(LambdaRuntimeClientException e) { + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/init/error"; + String expectedMessage = expectedUrl + " Response code: '" + errorStatusCode + "'."; + assertEquals(expectedMessage, e.getLocalizedMessage()); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportRestoreErrorTest() { + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportRestoreError(lambdaError); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/restore/error"; + assertEquals(expectedUrl, actualUrl.toString()); + + String userAgentHeader = recordedRequest.getHeader("User-Agent"); + assertTrue(userAgentHeader.startsWith("aws-lambda-java/")); + + String lambdaRuntimeErrorTypeHeader = recordedRequest.getHeader("Lambda-Runtime-Function-Error-Type"); + assertEquals("Runtime.AfterRestoreError", lambdaRuntimeErrorTypeHeader); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("{\"errorMessage\":\"testErrorMessage\",\"errorType\":\"testErrorType\",\"stackTrace\":[\"item0\",\"item1\",\"item2\"]}", actualBody); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportRestoreErrorTestWrongStatusCode() { + int errorStatusCode = HTTP_INTERNAL_ERROR; + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(errorStatusCode); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportRestoreError(lambdaError); + fail(); + } catch(LambdaRuntimeClientException e) { + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/restore/error"; + String expectedMessage = expectedUrl + " Response code: '" + errorStatusCode + "'."; + assertEquals(expectedMessage, e.getLocalizedMessage()); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportInvocationErrorTest() { + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportInvocationError(requestId, lambdaError); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/invocation/1234/error"; + assertEquals(expectedUrl, actualUrl.toString()); + + String userAgentHeader = recordedRequest.getHeader("User-Agent"); + assertTrue(userAgentHeader.startsWith("aws-lambda-java/")); + + String lambdaRuntimeErrorTypeHeader = recordedRequest.getHeader("Lambda-Runtime-Function-Error-Type"); + assertEquals("Runtime.AfterRestoreError", lambdaRuntimeErrorTypeHeader); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("{\"errorMessage\":\"testErrorMessage\",\"errorType\":\"testErrorType\",\"stackTrace\":[\"item0\",\"item1\",\"item2\"]}", actualBody); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportInvocationErrorTestWrongStatusCode() { + int errorStatusCode = HTTP_INTERNAL_ERROR; + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(errorStatusCode); + mockWebServer.enqueue(mockResponse); + + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + lambdaRuntimeApiClientImpl.reportInvocationError(requestId, lambdaError); + fail(); + } catch(LambdaRuntimeClientException e) { + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/invocation/1234/error"; + String expectedMessage = expectedUrl + " Response code: '" + errorStatusCode + "'."; + assertEquals(expectedMessage, e.getLocalizedMessage()); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportLambdaErrorWithXRayTest() { + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + String workingDirectory = "my-test-directory"; + List paths = new ArrayList(); + paths.add("path-0"); + paths.add("path-1"); + paths.add("path-2"); + + List stackElements0 = new ArrayList<>(); + stackElements0.add(new StackElement("label0", "path0", 0)); + stackElements0.add(new StackElement("label1", "path1", 1)); + stackElements0.add(new StackElement("label2", "path2", 2)); + XRayException xRayException0 = new XRayException("my-test-message0", "my-test-type0", stackElements0); + + List stackElements1 = new ArrayList<>(); + stackElements1.add(new StackElement("label10", "path10", 0)); + stackElements1.add(new StackElement("label11", "path11", 11)); + stackElements1.add(new StackElement("label12", "path12", 12)); + XRayException xRayException1 = new XRayException("my-test-message1", "my-test-type0", stackElements1); + + List exceptions = new ArrayList<>(); + exceptions.add(xRayException0); + exceptions.add(xRayException1); + + XRayErrorCause xRayErrorCause = new XRayErrorCause(workingDirectory, exceptions, paths); + LambdaError lambdaError = new LambdaError(errorRequest, xRayErrorCause, rapidErrorType); + lambdaRuntimeApiClientImpl.reportInvocationError(requestId, lambdaError); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + String xrayErrorCauseHeader = recordedRequest.getHeader("Lambda-Runtime-Function-XRay-Error-Cause"); + assertEquals("{\"working_directory\":\"my-test-directory\",\"exceptions\":[{\"message\":\"my-test-message0\",\"type\":\"my-test-type0\",\"stack\":[{\"label\":\"label0\"," + + "\"path\":\"path0\",\"line\":0},{\"label\":\"label1\",\"path\":\"path1\",\"line\":1},{\"label\":\"label2\",\"path\":\"path2\",\"line\":2}]},{\"message\":\"my-test-message1\"," + + "\"type\":\"my-test-type0\",\"stack\":[{\"label\":\"label10\",\"path\":\"path10\",\"line\":0},{\"label\":\"label11\",\"path\":\"path11\",\"line\":11},{\"label\":\"label12\"," + + "\"path\":\"path12\",\"line\":12}]}],\"paths\":[\"path-0\",\"path-1\",\"path-2\"]}", xrayErrorCauseHeader); + } catch(Exception e) { + fail(); + } + } + + @Test + public void reportInvocationSuccessTest() { + try { + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + String response = "{\"msg\":\"test\"}"; + lambdaRuntimeApiClientImpl.reportInvocationSuccess(requestId, response.getBytes()); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/invocation/1234/response"; + assertEquals(expectedUrl, actualUrl.toString()); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("{\"msg\":\"test\"}", actualBody); + } catch(Exception e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void restoreNextTest() { + try { + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_OK); + mockWebServer.enqueue(mockResponse); + + lambdaRuntimeApiClientImpl.restoreNext(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/restore/next"; + assertEquals(expectedUrl, actualUrl.toString()); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("", actualBody); + } catch(Exception e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void restoreNextWrongStatusCodeTest() { + int errorStatusCode = HTTP_INTERNAL_ERROR; + try { + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(errorStatusCode); + mockWebServer.enqueue(mockResponse); + + lambdaRuntimeApiClientImpl.restoreNext(); + fail(); + } catch(LambdaRuntimeClientException e) { + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/restore/next"; + String expectedMessage = expectedUrl + " Response code: '" + errorStatusCode + "'."; + assertEquals(expectedMessage, e.getLocalizedMessage()); + } catch(Exception e) { + fail(); + } + } + + @Test + public void nextTest() { + try { + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockResponse.setHeader("lambda-runtime-aws-request-id", "1234567890"); + mockResponse.setHeader("Content-Type", "application/json"); + mockWebServer.enqueue(mockResponse); + + lambdaRuntimeApiClientImpl.nextInvocation(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + HttpUrl actualUrl = recordedRequest.getRequestUrl(); + String expectedUrl = "http://" + getHostnamePort() + "/2018-06-01/runtime/invocation/next"; + assertEquals(expectedUrl, actualUrl.toString()); + + String actualBody = recordedRequest.getBody().readUtf8(); + assertEquals("", actualBody); + } catch(Exception e) { + fail(); + } + } + + + @Test + public void createUrlMalformedTest() { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + LambdaError lambdaError = new LambdaError(errorRequest, rapidErrorType); + RuntimeException thrown = assertThrows(RuntimeException.class, ()->{ + lambdaRuntimeApiClientImpl.reportLambdaError("invalidurl", lambdaError, 100); + }); + assertTrue(thrown.getLocalizedMessage().contains("java.net.MalformedURLException")); + } + + @Test + public void lambdaReportErrorXRayHeaderTooLongTest() { + try { + RapidErrorType rapidErrorType = RapidErrorType.AfterRestoreError; + + MockResponse mockResponse = new MockResponse(); + mockResponse.setResponseCode(HTTP_ACCEPTED); + mockWebServer.enqueue(mockResponse); + + String workingDirectory = "my-test-directory"; + List paths = new ArrayList(); + paths.add("path-0"); + + List stackElements = new ArrayList<>(); + stackElements.add(new StackElement("label0", "path0", 0)); + XRayException xRayException = new XRayException("my-test-message0", "my-test-type0", stackElements); + + List exceptions = new ArrayList<>(); + exceptions.add(xRayException); + + XRayErrorCause xRayErrorCause = new XRayErrorCause(workingDirectory, exceptions, paths); + LambdaError lambdaError = new LambdaError(errorRequest, xRayErrorCause, rapidErrorType); + lambdaRuntimeApiClientImpl.reportLambdaError("http://" + getHostnamePort(), lambdaError, 10); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + String xrayErrorCauseHeader = recordedRequest.getHeader("Lambda-Runtime-Function-XRay-Error-Cause"); + assertNull(xrayErrorCauseHeader); + } catch(Exception e) { + fail(); + } + } + + private String getHostnamePort() { + return mockWebServer.getHostName() + ":" + mockWebServer.getPort(); + } +} \ No newline at end of file From 2a3beb80bc53e5f89c0e231970cc364321bbdd1a Mon Sep 17 00:00:00 2001 From: Maxime David Date: Thu, 1 Aug 2024 10:36:02 +0100 Subject: [PATCH 2/2] test: add unit tests for Runtime API --- .../client/runtimeapi/LambdaRuntimeApiClientImplTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java index 40cd3e88..1b6f3136 100644 --- a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java +++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImplTest.java @@ -5,11 +5,12 @@ package com.amazonaws.services.lambda.runtime.api.client.runtimeapi; -import org.junit.Before; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; + import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -18,7 +19,6 @@ import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayErrorCause; import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayException; -import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -30,9 +30,9 @@ import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; +@DisabledOnOs(OS.MAC) public class LambdaRuntimeApiClientImplTest { MockWebServer mockWebServer;