Browse Source

Migrate AWS Lambda tests to Java (#5315)

* Migrate AWS Lambda tests to Java

* Only assert OTLP fields for links
Anuraag Agrawal 3 years ago
parent
commit
b9fac11c90
28 changed files with 1582 additions and 1216 deletions
  1. 1 0
      dependencyManagement/build.gradle.kts
  2. 0 27
      instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy
  3. 0 31
      instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy
  4. 37 0
      instrumentation/aws-lambda-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaSqsEventHandlerTest.java
  5. 45 0
      instrumentation/aws-lambda-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.java
  6. 0 31
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy
  7. 0 102
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsMessageHandlerTest.groovy
  8. 0 35
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy
  9. 0 232
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestApiGatewayWrapperTest.groovy
  10. 0 135
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestStreamWrapperPropagationTest.groovy
  11. 0 119
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestStreamWrapperTest.groovy
  12. 0 160
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestWrapperTest.groovy
  13. 0 38
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestWrapperTestBase.groovy
  14. 0 85
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingSqsEventWrapperTest.groovy
  15. 308 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaApiGatewayWrapperTest.java
  16. 40 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsEventHandlerTest.java
  17. 112 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsEventWrapperTest.java
  18. 168 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsMessageHandlerTest.java
  19. 162 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaStreamWrapperHttpPropagationTest.java
  20. 143 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaStreamWrapperTest.java
  21. 41 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.java
  22. 219 0
      instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaWrapperTest.java
  23. 3 0
      instrumentation/aws-lambda-1.0/testing/build.gradle.kts
  24. 0 109
      instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaRequestHandlerTest.groovy
  25. 0 112
      instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsHandlerTest.groovy
  26. 167 0
      instrumentation/aws-lambda-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsEventHandlerTest.java
  27. 120 0
      instrumentation/aws-lambda-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaTest.java
  28. 16 0
      testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/InstrumentationExtension.java

+ 1 - 0
dependencyManagement/build.gradle.kts

@@ -110,6 +110,7 @@ val DEPENDENCIES = listOf(
   "com.google.code.findbugs:annotations:3.0.1u2",
   "com.google.code.findbugs:jsr305:3.0.2",
   "org.codehaus.groovy:groovy-all:${groovyVersion}",
+  "org.junit-pioneer:junit-pioneer:1.5.0",
   "org.objenesis:objenesis:3.2",
   "org.spockframework:spock-core:2.0-groovy-3.0",
   "org.spockframework:spock-junit4:2.0-groovy-3.0",

+ 0 - 27
instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy

@@ -1,27 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.amazonaws.services.lambda.runtime.events.SQSEvent
-import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaSqsHandlerTest
-import io.opentelemetry.instrumentation.test.AgentTestTrait
-
-class AwsLambdaSqsHandlerTest extends AbstractAwsLambdaSqsHandlerTest implements AgentTestTrait {
-
-  static class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
-    @Override
-    Void handleRequest(SQSEvent input, Context context) {
-      return null
-    }
-  }
-
-  @Override
-  RequestHandler<SQSEvent, Void> handler() {
-    return new TestRequestHandler()
-  }
-}

+ 0 - 31
instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy

@@ -1,31 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaRequestHandlerTest
-import io.opentelemetry.instrumentation.test.AgentTestTrait
-import io.opentelemetry.javaagent.testing.common.AgentTestingExporterAccess
-
-class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements AgentTestTrait {
-
-  def cleanup() {
-    assert AgentTestingExporterAccess.forceFlushCalled()
-  }
-
-  static class TestRequestHandler implements RequestHandler<String, String> {
-    @Override
-    String handleRequest(String input, Context context) {
-      return doHandleRequest(input, context)
-    }
-  }
-
-  @Override
-  RequestHandler<String, String> handler() {
-    return new TestRequestHandler()
-  }
-}

+ 37 - 0
instrumentation/aws-lambda-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaSqsEventHandlerTest.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaSqsEventHandlerTest;
+import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
+
+  @Override
+  protected RequestHandler<SQSEvent, Void> handler() {
+    return new TestRequestHandler();
+  }
+
+  @Override
+  protected InstrumentationExtension testing() {
+    return testing;
+  }
+
+  private static final class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
+    @Override
+    public Void handleRequest(SQSEvent input, Context context) {
+      return null;
+    }
+  }
+}

+ 45 - 0
instrumentation/aws-lambda-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaTest;
+import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class AwsLambdaTest extends AbstractAwsLambdaTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
+
+  @Override
+  protected RequestHandler<String, String> handler() {
+    return new TestRequestHandler();
+  }
+
+  @Override
+  protected InstrumentationExtension testing() {
+    return testing;
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  private static final class TestRequestHandler implements RequestHandler<String, String> {
+
+    @Override
+    public String handleRequest(String input, Context context) {
+      return doHandleRequest(input, context);
+    }
+  }
+}

+ 0 - 31
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy

@@ -1,31 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.amazonaws.services.lambda.runtime.events.SQSEvent
-import io.opentelemetry.instrumentation.test.LibraryTestTrait
-import io.opentelemetry.sdk.OpenTelemetrySdk
-
-class AwsLambdaSqsHandlerTest extends AbstractAwsLambdaSqsHandlerTest implements LibraryTestTrait {
-
-  static class TestHandler extends TracingSqsEventHandler {
-
-    TestHandler(OpenTelemetrySdk openTelemetrySdk) {
-      super(openTelemetrySdk)
-    }
-
-    @Override
-    protected void handleEvent(SQSEvent event, Context context) {
-    }
-  }
-
-  @Override
-  RequestHandler<SQSEvent, Void> handler() {
-    return new TestHandler(testRunner().openTelemetrySdk)
-  }
-}

+ 0 - 102
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsMessageHandlerTest.groovy

@@ -1,102 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.events.SQSEvent
-import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
-import io.opentelemetry.sdk.OpenTelemetrySdk
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import static io.opentelemetry.api.trace.SpanKind.CONSUMER
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-
-class AwsLambdaSqsMessageHandlerTest extends LibraryInstrumentationSpecification {
-
-  private static final String AWS_TRACE_HEADER1 = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"
-  private static final String AWS_TRACE_HEADER2 = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad9;Sampled=1"
-
-  static class TestHandler extends TracingSqsMessageHandler {
-
-    TestHandler(OpenTelemetrySdk openTelemetrySdk) {
-      super(openTelemetrySdk)
-    }
-
-    @Override
-    protected void handleMessage(SQSEvent.SQSMessage event, Context context) {
-    }
-  }
-
-  def "messages with process spans"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def message1 = new SQSEvent.SQSMessage()
-    message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER1])
-    message1.setMessageId("message1")
-    message1.setEventSource("queue1")
-
-    def message2 = new SQSEvent.SQSMessage()
-    message2.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER2])
-    message2.setMessageId("message2")
-    message2.setEventSource("queue1")
-
-    def event = new SQSEvent()
-    event.setRecords([message1, message2])
-
-    new TestHandler(testRunner().openTelemetrySdk).handleRequest(event, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 4) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-        span(1) {
-          name("queue1 process")
-          kind CONSUMER
-          parentSpanId(span(0).spanId)
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-          }
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad9")
-        }
-        span(2) {
-          name("queue1 process")
-          kind CONSUMER
-          parentSpanId(span(1).spanId)
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-            "$SemanticAttributes.MESSAGING_MESSAGE_ID" "message1"
-            "$SemanticAttributes.MESSAGING_DESTINATION" "queue1"
-          }
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
-        }
-        span(3) {
-          name("queue1 process")
-          kind CONSUMER
-          parentSpanId(span(1).spanId)
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-            "$SemanticAttributes.MESSAGING_MESSAGE_ID" "message2"
-            "$SemanticAttributes.MESSAGING_DESTINATION" "queue1"
-          }
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad9")
-        }
-      }
-    }
-  }
-}

+ 0 - 35
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy

@@ -1,35 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import io.opentelemetry.instrumentation.test.LibraryTestTrait
-import io.opentelemetry.sdk.OpenTelemetrySdk
-
-class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements LibraryTestTrait {
-
-  def cleanup() {
-    assert forceFlushCalled()
-  }
-
-  static class TestRequestHandler extends TracingRequestHandler<String, String> {
-
-    TestRequestHandler(OpenTelemetrySdk openTelemetrySdk) {
-      super(openTelemetrySdk)
-    }
-
-    @Override
-    protected String doHandleRequest(String input, Context context) {
-      return AbstractAwsLambdaRequestHandlerTest.doHandleRequest(input, context)
-    }
-  }
-
-  @Override
-  RequestHandler<String, String> handler() {
-    return new TestRequestHandler(testRunner().openTelemetrySdk)
-  }
-}

+ 0 - 232
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestApiGatewayWrapperTest.groovy

@@ -1,232 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
-import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
-import com.google.common.collect.ImmutableMap
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-
-class TracingRequestApiGatewayWrapperTest extends TracingRequestWrapperTestBase {
-
-  static class TestApiGatewayEventHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
-
-    @Override
-    APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
-      if (input.getBody() == "hello") {
-        return new APIGatewayProxyResponseEvent()
-          .withStatusCode(200)
-          .withBody("world")
-      } else if (input.getBody() == "empty") {
-        return new APIGatewayProxyResponseEvent()
-      }
-      throw new IllegalStateException("bad request")
-    }
-  }
-
-  static class TestApiGatewayStringHandler implements RequestHandler<String, String> {
-
-    @Override
-    String handleRequest(String input, Context context) {
-      if (input == "hello") {
-        return "world"
-      }
-      throw new IllegalStateException("bad request")
-    }
-  }
-
-  static class TestApiGatewayIntegerHandler implements RequestHandler<Integer, String> {
-
-    @Override
-    String handleRequest(Integer input, Context context) {
-      if (input == 1) {
-        return "world"
-      }
-      throw new IllegalStateException("bad request")
-    }
-  }
-
-  static class CustomType {
-    String key, value
-  }
-
-  static class TestApiGatewayCustomTypeHandler implements RequestHandler<CustomType, String> {
-
-    @Override
-    String handleRequest(CustomType input, Context context) {
-      if (input.key == "hello") {
-        return "Hello " + input.value
-      }
-      throw new IllegalStateException("bad request")
-    }
-  }
-
-  def propagationHeaders() {
-    return Collections.singletonMap("traceparent", "00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01")
-  }
-
-  def "event handler traced with trace propagation"() {
-    given:
-    setLambda(TestApiGatewayEventHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
-
-    def headers = ImmutableMap.builder()
-      .putAll(propagationHeaders())
-      .put("User-Agent", "Test Client")
-      .put("host", "localhost:123")
-      .put("X-FORWARDED-PROTO", "http")
-      .build()
-    def input = new APIGatewayProxyRequestEvent()
-      .withHttpMethod("GET")
-      .withResource("/hello/{param}")
-      .withPath("/hello/world")
-      .withBody("hello")
-      .withQueryStringParamters(["a": "b", "c": "d"])
-      .withHeaders(headers)
-
-    when:
-    APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
-
-    then:
-    result.getBody() == "world"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          parentSpanId("0000000000000456")
-          traceId("4fd0b6131f19f39af59518d127b0cafe")
-          name("/hello/{param}")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-            "$SemanticAttributes.FAAS_TRIGGER" "http"
-            "$SemanticAttributes.HTTP_METHOD" "GET"
-            "$SemanticAttributes.HTTP_USER_AGENT" "Test Client"
-            "$SemanticAttributes.HTTP_URL" "http://localhost:123/hello/world?a=b&c=d"
-            "$SemanticAttributes.HTTP_STATUS_CODE" 200
-          }
-        }
-      }
-    }
-  }
-
-  def "event handler test empty request & response"() {
-    given:
-    setLambda(TestApiGatewayEventHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
-
-    def input = new APIGatewayProxyRequestEvent()
-      .withBody("empty")
-
-    when:
-    APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
-
-    then:
-    result.body == null
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-            "$SemanticAttributes.FAAS_TRIGGER" "http"
-          }
-        }
-      }
-    }
-  }
-
-  def "string handler test request"() {
-    given:
-    setLambda(TestApiGatewayStringHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
-
-    def input = new APIGatewayProxyRequestEvent()
-      .withBody("\"hello\"")
-
-    when:
-    APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
-
-    then:
-    result.body == "\"world\""
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-            "$SemanticAttributes.FAAS_TRIGGER" "http"
-          }
-        }
-      }
-    }
-  }
-
-  def "integer handler test request"() {
-    given:
-    setLambda(TestApiGatewayIntegerHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
-
-    def input = new APIGatewayProxyRequestEvent()
-      .withBody("1")
-
-    when:
-    APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
-
-    then:
-    result.body == "\"world\""
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-            "$SemanticAttributes.FAAS_TRIGGER" "http"
-          }
-        }
-      }
-    }
-  }
-
-  def "custom type handler test request"() {
-    given:
-    setLambda(TestApiGatewayCustomTypeHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
-
-    def input = new APIGatewayProxyRequestEvent()
-      .withBody("{\"key\":\"hello\", \"value\":\"General Kenobi\"}")
-
-    when:
-    APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
-
-    then:
-    result.body == "\"Hello General Kenobi\""
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-            "$SemanticAttributes.FAAS_TRIGGER" "http"
-          }
-        }
-      }
-    }
-  }
-}

+ 0 - 135
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestStreamWrapperPropagationTest.groovy

@@ -1,135 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestStreamHandler
-import com.fasterxml.jackson.databind.JsonNode
-import com.fasterxml.jackson.databind.ObjectMapper
-import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-import org.junit.Rule
-import org.junit.contrib.java.lang.system.EnvironmentVariables
-import spock.lang.Shared
-
-import java.nio.charset.Charset
-
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-import static io.opentelemetry.api.trace.StatusCode.ERROR
-
-class TracingRequestStreamWrapperPropagationTest extends LibraryInstrumentationSpecification {
-
-  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
-
-  @Rule
-  public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
-
-  static class TestRequestHandler implements RequestStreamHandler {
-
-    @Override
-    void handleRequest(InputStream input, OutputStream output, Context context) {
-
-      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))
-
-      JsonNode root = OBJECT_MAPPER.readTree(input)
-      String body = root.get("body").asText()
-      if (body == "hello") {
-        writer.write("world")
-        writer.flush()
-        writer.close()
-      } else {
-        throw new IllegalArgumentException("bad argument")
-      }
-    }
-  }
-
-  @Shared
-  TracingRequestStreamWrapper wrapper
-
-  def setup() {
-    environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, "io.opentelemetry.instrumentation.awslambda.v1_0.TracingRequestStreamWrapperPropagationTest\$TestRequestHandler::handleRequest")
-    wrapper = new TracingRequestStreamWrapper(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
-  }
-
-  def cleanup() {
-    environmentVariables.clear(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY)
-  }
-
-  def "handler traced with trace propagation"() {
-    when:
-    String content =
-      "{" +
-        "\"headers\" : {" +
-        "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\"" +
-        "}," +
-        "\"body\" : \"hello\"" +
-        "}"
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    def input = new ByteArrayInputStream(content.getBytes(Charset.defaultCharset()))
-    def output = new ByteArrayOutputStream()
-
-    wrapper.handleRequest(input, output, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          parentSpanId("0000000000000456")
-          traceId("4fd0b6131f19f39af59518d127b0cafe")
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler traced with exception and trace propagation"() {
-    when:
-    String content =
-      "{" +
-        "\"headers\" : {" +
-        "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\"" +
-        "}," +
-        "\"body\" : \"bye\"" +
-        "}"
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    def input = new ByteArrayInputStream(content.getBytes(Charset.defaultCharset()))
-    def output = new ByteArrayOutputStream()
-
-    def thrown
-    try {
-      wrapper.handleRequest(input, output, context)
-    } catch (Throwable t) {
-      thrown = t
-    }
-
-    then:
-    thrown != null
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          parentSpanId("0000000000000456")
-          traceId("4fd0b6131f19f39af59518d127b0cafe")
-          name("my_function")
-          kind SERVER
-          status ERROR
-          errorEvent(IllegalArgumentException, "bad argument")
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-}

+ 0 - 119
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestStreamWrapperTest.groovy

@@ -1,119 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestStreamHandler
-import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-import org.junit.Rule
-import org.junit.contrib.java.lang.system.EnvironmentVariables
-import spock.lang.Shared
-
-import java.nio.charset.Charset
-
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-import static io.opentelemetry.api.trace.StatusCode.ERROR
-
-class TracingRequestStreamWrapperTest extends LibraryInstrumentationSpecification {
-
-  @Rule
-  public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
-
-  static class TestRequestHandler implements RequestStreamHandler {
-
-    @Override
-    void handleRequest(InputStream input, OutputStream output, Context context) {
-
-      BufferedReader reader = new BufferedReader(new InputStreamReader(input))
-      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))
-      String line = reader.readLine()
-      if (line == "hello") {
-        writer.write("world")
-        writer.flush()
-        writer.close()
-      } else {
-        throw new IllegalArgumentException("bad argument")
-      }
-    }
-  }
-
-  @Shared
-  TracingRequestStreamWrapper wrapper
-
-  def setup() {
-    environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, "io.opentelemetry.instrumentation.awslambda.v1_0.TracingRequestStreamWrapperTest\$TestRequestHandler::handleRequest")
-    wrapper = new TracingRequestStreamWrapper(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
-  }
-
-  def cleanup() {
-    environmentVariables.clear(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY)
-  }
-
-  def "handler traced"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
-    def input = new ByteArrayInputStream("hello\n".getBytes(Charset.defaultCharset()))
-    def output = new ByteArrayOutputStream()
-
-    wrapper.handleRequest(input, output, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler traced with exception"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
-    def input = new ByteArrayInputStream("bye".getBytes(Charset.defaultCharset()))
-    def output = new ByteArrayOutputStream()
-
-    def thrown
-    try {
-      wrapper.handleRequest(input, output, context)
-    } catch (Throwable t) {
-      thrown = t
-    }
-
-    then:
-    thrown != null
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          status ERROR
-          errorEvent(IllegalArgumentException, "bad argument")
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-}

+ 0 - 160
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestWrapperTest.groovy

@@ -1,160 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-import static io.opentelemetry.api.trace.StatusCode.ERROR
-
-class TracingRequestWrapperTest extends TracingRequestWrapperTestBase {
-
-  static class TestRequestHandlerString implements RequestHandler<String, String> {
-
-    @Override
-    String handleRequest(String input, Context context) {
-      if (input == "hello") {
-        return "world"
-      }
-      throw new IllegalArgumentException("bad argument")
-    }
-  }
-
-  static class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
-
-    @Override
-    String handleRequest(Integer input, Context context) {
-      if (input == 1) {
-        return "world"
-      }
-      throw new IllegalArgumentException("bad argument")
-    }
-  }
-
-  static class CustomType {
-    String key, value
-  }
-
-  static class TestRequestHandlerCustomType implements RequestHandler<CustomType, String> {
-
-    @Override
-    String handleRequest(CustomType input, Context context) {
-      if (input.key == "hello there") {
-        return input.value
-      }
-      throw new IllegalArgumentException("bad argument")
-    }
-  }
-
-  def "handler string traced"() {
-    given:
-    setLambda(TestRequestHandlerString.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
-
-    when:
-    def result = wrapper.handleRequest("hello", context)
-
-    then:
-    result == "world"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler with exception"() {
-    given:
-    setLambda(TestRequestHandlerString.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
-
-    when:
-    def thrown
-    try {
-      wrapper.handleRequest("goodbye", context)
-    } catch (Throwable t) {
-      thrown = t
-    }
-
-    then:
-    thrown != null
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          status ERROR
-          errorEvent(IllegalArgumentException, "bad argument")
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler integer traced"() {
-    given:
-    setLambda(TestRequestHandlerInteger.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
-
-    when:
-    def result = wrapper.handleRequest(1, context)
-
-    then:
-    result == "world"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler custom type traced"() {
-    given:
-    setLambda(TestRequestHandlerCustomType.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
-
-    when:
-    CustomType ct = new CustomType()
-    ct.key = "hello there"
-    ct.value = "General Kenobi"
-    def result = wrapper.handleRequest(ct, context)
-
-    then:
-    result == "General Kenobi"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-}

+ 0 - 38
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestWrapperTestBase.groovy

@@ -1,38 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
-import org.junit.Rule
-import org.junit.contrib.java.lang.system.EnvironmentVariables
-import spock.lang.Shared
-
-import java.util.function.BiFunction
-
-class TracingRequestWrapperTestBase extends LibraryInstrumentationSpecification {
-
-  @Rule
-  public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
-
-  @Shared
-  TracingRequestWrapperBase wrapper
-
-  @Shared
-  Context context
-
-  def setup() {
-    context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
-  }
-
-  def setLambda(handler, Closure<TracingRequestWrapperBase> wrapperConstructor, BiFunction<?, Class, Object> mapper) {
-    environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, handler)
-    wrapper = wrapperConstructor.call(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration(), mapper)
-  }
-}

+ 0 - 85
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/TracingSqsEventWrapperTest.groovy

@@ -1,85 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.amazonaws.services.lambda.runtime.events.SQSEvent
-import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-import org.junit.Rule
-import org.junit.contrib.java.lang.system.EnvironmentVariables
-
-import static io.opentelemetry.api.trace.SpanKind.CONSUMER
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-
-class TracingSqsEventWrapperTest extends LibraryInstrumentationSpecification {
-
-  @Rule
-  public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
-
-  TracingSqsEventWrapper wrapper
-  Context context
-
-  def setup() {
-    context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-    context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
-  }
-
-  def setLambda(handler, Closure<TracingSqsEventWrapper> wrapperConstructor) {
-    environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, handler)
-    wrapper = wrapperConstructor.call(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
-  }
-
-  static class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
-
-    @Override
-    Void handleRequest(SQSEvent input, Context context) {
-      return null
-    }
-
-  }
-
-
-  def "handler event traced"() {
-    given:
-    setLambda(TestRequestHandler.getName() + "::handleRequest", TracingSqsEventWrapper.metaClass.&invokeConstructor)
-
-    when:
-    SQSEvent event = new SQSEvent()
-    SQSEvent.SQSMessage record = new SQSEvent.SQSMessage()
-    record.setEventSource("otel")
-    record.setAttributes(Collections.emptyMap())
-    event.setRecords(Arrays.asList(record))
-    wrapper.handleRequest(event, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 2) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
-            "$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-        span(1) {
-          name("otel process")
-          kind CONSUMER
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-          }
-        }
-      }
-    }
-  }
-}

+ 308 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaApiGatewayWrapperTest.java

@@ -0,0 +1,308 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class AwsLambdaApiGatewayWrapperTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+    when(context.getInvokedFunctionArn())
+        .thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerApiGateway::handleRequest")
+  void tracedWithHttpPropagation() {
+    TracingRequestApiGatewayWrapper wrapper =
+        new TracingRequestApiGatewayWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestApiGatewayWrapper::map);
+
+    Map<String, String> headers = new HashMap<>();
+    headers.put("traceparent", "00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01");
+    headers.put("User-Agent", "Test Client");
+    headers.put("host", "localhost:123");
+    headers.put("X-FORWARDED-PROTO", "http");
+    Map<String, String> query = new HashMap<>();
+    query.put("a", "b");
+    query.put("c", "d");
+    APIGatewayProxyRequestEvent input =
+        new APIGatewayProxyRequestEvent()
+            .withHttpMethod("GET")
+            .withResource("/hello/{param}")
+            .withPath("/hello/world")
+            .withBody("hello")
+            .withQueryStringParameters(query)
+            .withHeaders(headers);
+
+    APIGatewayProxyResponseEvent result =
+        (APIGatewayProxyResponseEvent) wrapper.handleRequest(input, context);
+
+    assertThat(result.getBody()).isEqualTo("world");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("/hello/{param}")
+                        .hasKind(SpanKind.SERVER)
+                        .hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
+                        .hasParentSpanId("0000000000000456")
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
+                                        entry(SemanticAttributes.FAAS_TRIGGER, "http"),
+                                        entry(SemanticAttributes.HTTP_METHOD, "GET"),
+                                        entry(SemanticAttributes.HTTP_USER_AGENT, "Test Client"),
+                                        entry(
+                                            SemanticAttributes.HTTP_URL,
+                                            "http://localhost:123/hello/world?a=b&c=d"),
+                                        entry(SemanticAttributes.HTTP_STATUS_CODE, 200L)))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerApiGateway::handleRequest")
+  void handlerTraced_empty() {
+    TracingRequestApiGatewayWrapper wrapper =
+        new TracingRequestApiGatewayWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestApiGatewayWrapper::map);
+    APIGatewayProxyResponseEvent result =
+        (APIGatewayProxyResponseEvent)
+            wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("empty"), context);
+
+    assertThat(result.getBody()).isNull();
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
+                                        entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerString::handleRequest")
+  void handlerTraced_string() {
+    TracingRequestApiGatewayWrapper wrapper =
+        new TracingRequestApiGatewayWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestApiGatewayWrapper::map);
+    APIGatewayProxyResponseEvent result =
+        (APIGatewayProxyResponseEvent)
+            wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("\"hello\""), context);
+
+    assertThat(result.getBody()).isEqualTo("\"world\"");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
+                                        entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerInteger::handleRequest")
+  void handlerTraced_integer() {
+    TracingRequestApiGatewayWrapper wrapper =
+        new TracingRequestApiGatewayWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestApiGatewayWrapper::map);
+    APIGatewayProxyResponseEvent result =
+        (APIGatewayProxyResponseEvent)
+            wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("1"), context);
+
+    assertThat(result.getBody()).isEqualTo("\"world\"");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
+                                        entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerCustomType::handleRequest")
+  void handlerTraced_customType() {
+    TracingRequestApiGatewayWrapper wrapper =
+        new TracingRequestApiGatewayWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestApiGatewayWrapper::map);
+    APIGatewayProxyResponseEvent result =
+        (APIGatewayProxyResponseEvent)
+            wrapper.handleRequest(
+                new APIGatewayProxyRequestEvent()
+                    .withBody("{\"key\":\"hello\", \"value\":\"General Kenobi\"}"),
+                context);
+
+    assertThat(result.getBody()).isEqualTo("\"General Kenobi\"");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
+                                        entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
+  }
+
+  public static class TestRequestHandlerApiGateway
+      implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
+
+    @Override
+    public APIGatewayProxyResponseEvent handleRequest(
+        APIGatewayProxyRequestEvent input, Context context) {
+      if (input.getBody().equals("hello")) {
+        return new APIGatewayProxyResponseEvent().withStatusCode(200).withBody("world");
+      } else if (input.getBody().equals("empty")) {
+        return new APIGatewayProxyResponseEvent();
+      }
+      throw new IllegalStateException("bad request");
+    }
+  }
+
+  public static final class TestRequestHandlerString implements RequestHandler<String, String> {
+
+    @Override
+    public String handleRequest(String input, Context context) {
+      if (input.equals("hello")) {
+        return "world";
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+
+  public static final class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
+
+    @Override
+    public String handleRequest(Integer input, Context context) {
+      if (input == 1) {
+        return "world";
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+
+  public static class CustomType {
+    public String key;
+    public String value;
+  }
+
+  public static final class TestRequestHandlerCustomType
+      implements RequestHandler<CustomType, String> {
+
+    @Override
+    public String handleRequest(CustomType input, Context context) {
+      if (input.key.equals("hello")) {
+        return input.value;
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+}

+ 40 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsEventHandlerTest.java

@@ -0,0 +1,40 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Override
+  protected RequestHandler<SQSEvent, Void> handler() {
+    return new TestHandler(testing.getOpenTelemetrySdk());
+  }
+
+  @Override
+  protected InstrumentationExtension testing() {
+    return testing;
+  }
+
+  private static final class TestHandler extends TracingSqsEventHandler {
+
+    TestHandler(OpenTelemetrySdk openTelemetrySdk) {
+      super(openTelemetrySdk);
+    }
+
+    @Override
+    protected void handleEvent(SQSEvent event, Context context) {}
+  }
+}

+ 112 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsEventWrapperTest.java

@@ -0,0 +1,112 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+@SetEnvironmentVariable(
+    key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+    value =
+        "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaSqsEventWrapperTest$TestRequestHandler::handleRequest")
+public class AwsLambdaSqsEventWrapperTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+    when(context.getInvokedFunctionArn())
+        .thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void eventTraced() {
+    SQSEvent event = new SQSEvent();
+    SQSEvent.SQSMessage record = newMessage();
+    record.setEventSource("otel");
+    record.setAttributes(Collections.emptyMap());
+    event.setRecords(Collections.singletonList(record));
+
+    TracingSqsEventWrapper wrapper =
+        new TracingSqsEventWrapper(
+            testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
+    wrapper.handleRequest(event, context);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
+                span ->
+                    span.hasName("otel process")
+                        .hasKind(SpanKind.CONSUMER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                        entry(
+                                            SemanticAttributes.MESSAGING_OPERATION, "process")))));
+  }
+
+  public static final class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
+    @Override
+    public Void handleRequest(SQSEvent input, Context context) {
+      return null;
+    }
+  }
+
+  // Constructor private in early versions.
+  private static SQSEvent.SQSMessage newMessage() {
+    try {
+      Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
+      return ctor.newInstance();
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+  }
+}

+ 168 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsMessageHandlerTest.java

@@ -0,0 +1,168 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.TraceFlags;
+import io.opentelemetry.api.trace.TraceState;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.trace.data.LinkData;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class AwsLambdaSqsMessageHandlerTest {
+
+  private static final String AWS_TRACE_HEADER1 =
+      "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1";
+  private static final String AWS_TRACE_HEADER2 =
+      "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad9;Sampled=1";
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void processSpans() {
+    SQSEvent.SQSMessage message1 = newMessage();
+    message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER1));
+    message1.setMessageId("message1");
+    message1.setEventSource("queue1");
+
+    SQSEvent.SQSMessage message2 = newMessage();
+    message2.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER2));
+    message2.setMessageId("message2");
+    message2.setEventSource("queue1");
+
+    SQSEvent event = new SQSEvent();
+    event.setRecords(Arrays.asList(message1, message2));
+
+    new TestHandler(testing.getOpenTelemetrySdk()).handleRequest(event, context);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
+                span ->
+                    span.hasName("queue1 process")
+                        .hasKind(SpanKind.CONSUMER)
+                        .hasParentSpanId(trace.getSpan(0).getSpanId())
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                        entry(SemanticAttributes.MESSAGING_OPERATION, "process")))
+                        .hasLinks(
+                            LinkData.create(
+                                SpanContext.createFromRemoteParent(
+                                    "5759e988bd862e3fe1be46a994272793",
+                                    "53995c3f42cd8ad8",
+                                    TraceFlags.getSampled(),
+                                    TraceState.getDefault())),
+                            LinkData.create(
+                                SpanContext.createFromRemoteParent(
+                                    "5759e988bd862e3fe1be46a994272793",
+                                    "53995c3f42cd8ad9",
+                                    TraceFlags.getSampled(),
+                                    TraceState.getDefault()))),
+                span ->
+                    span.hasName("queue1 process")
+                        .hasKind(SpanKind.CONSUMER)
+                        .hasParentSpanId(trace.getSpan(1).getSpanId())
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                        entry(SemanticAttributes.MESSAGING_OPERATION, "process"),
+                                        entry(SemanticAttributes.MESSAGING_MESSAGE_ID, "message1"),
+                                        entry(SemanticAttributes.MESSAGING_DESTINATION, "queue1")))
+                        .hasLinks(
+                            LinkData.create(
+                                SpanContext.createFromRemoteParent(
+                                    "5759e988bd862e3fe1be46a994272793",
+                                    "53995c3f42cd8ad8",
+                                    TraceFlags.getSampled(),
+                                    TraceState.getDefault()))),
+                span ->
+                    span.hasName("queue1 process")
+                        .hasKind(SpanKind.CONSUMER)
+                        .hasParentSpanId(trace.getSpan(1).getSpanId())
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                assertThat(attrs)
+                                    .containsOnly(
+                                        entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                        entry(SemanticAttributes.MESSAGING_OPERATION, "process"),
+                                        entry(SemanticAttributes.MESSAGING_MESSAGE_ID, "message2"),
+                                        entry(SemanticAttributes.MESSAGING_DESTINATION, "queue1")))
+                        .hasLinks(
+                            LinkData.create(
+                                SpanContext.createFromRemoteParent(
+                                    "5759e988bd862e3fe1be46a994272793",
+                                    "53995c3f42cd8ad9",
+                                    TraceFlags.getSampled(),
+                                    TraceState.getDefault())))));
+  }
+
+  // Constructor private in early versions.
+  private static SQSEvent.SQSMessage newMessage() {
+    try {
+      Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
+      return ctor.newInstance();
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+  }
+
+  private static final class TestHandler extends TracingSqsMessageHandler {
+
+    TestHandler(OpenTelemetrySdk openTelemetrySdk) {
+      super(openTelemetrySdk);
+    }
+
+    @Override
+    protected void handleMessage(SQSEvent.SQSMessage message, Context context) {}
+  }
+}

+ 162 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaStreamWrapperHttpPropagationTest.java

@@ -0,0 +1,162 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+@SetEnvironmentVariable(
+    key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+    value =
+        "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaStreamWrapperHttpPropagationTest$TestRequestHandler::handleRequest")
+public class AwsLambdaStreamWrapperHttpPropagationTest {
+
+  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+    when(context.getInvokedFunctionArn())
+        .thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void handlerTraced() throws Exception {
+    String content =
+        "{"
+            + "\"headers\" : {"
+            + "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\""
+            + "},"
+            + "\"body\" : \"hello\""
+            + "}";
+    InputStream input = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+    OutputStream output = new ByteArrayOutputStream();
+
+    TracingRequestStreamWrapper wrapper =
+        new TracingRequestStreamWrapper(
+            testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
+    wrapper.handleRequest(input, output, context);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
+                        .hasParentSpanId("0000000000000456")
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  void handlerTracedWithException() {
+    String content =
+        "{"
+            + "\"headers\" : {"
+            + "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\""
+            + "},"
+            + "\"body\" : \"bye\""
+            + "}";
+    InputStream input = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+    OutputStream output = new ByteArrayOutputStream();
+
+    TracingRequestStreamWrapper wrapper =
+        new TracingRequestStreamWrapper(
+            testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
+
+    Throwable thrown = catchThrowable(() -> wrapper.handleRequest(input, output, context));
+    assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
+                        .hasParentSpanId("0000000000000456")
+                        .hasStatus(StatusData.error())
+                        .hasException(thrown)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  public static final class TestRequestHandler implements RequestStreamHandler {
+
+    @Override
+    public void handleRequest(InputStream input, OutputStream output, Context context)
+        throws IOException {
+      JsonNode root = OBJECT_MAPPER.readTree(input);
+      String body = root.get("body").asText();
+      BufferedWriter writer =
+          new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
+      if (body.equals("hello")) {
+        writer.write("world");
+        writer.flush();
+        writer.close();
+      } else {
+        throw new IllegalArgumentException("bad argument");
+      }
+    }
+  }
+}

+ 143 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaStreamWrapperTest.java

@@ -0,0 +1,143 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+@SetEnvironmentVariable(
+    key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+    value =
+        "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaStreamWrapperTest$TestRequestHandler::handleRequest")
+public class AwsLambdaStreamWrapperTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+    when(context.getInvokedFunctionArn())
+        .thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void handlerTraced() throws Exception {
+    InputStream input = new ByteArrayInputStream("hello\n".getBytes(StandardCharsets.UTF_8));
+    OutputStream output = new ByteArrayOutputStream();
+
+    TracingRequestStreamWrapper wrapper =
+        new TracingRequestStreamWrapper(
+            testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
+    wrapper.handleRequest(input, output, context);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  void handlerTracedWithException() {
+    InputStream input = new ByteArrayInputStream("bye\n".getBytes(StandardCharsets.UTF_8));
+    OutputStream output = new ByteArrayOutputStream();
+
+    TracingRequestStreamWrapper wrapper =
+        new TracingRequestStreamWrapper(
+            testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
+
+    Throwable thrown = catchThrowable(() -> wrapper.handleRequest(input, output, context));
+    assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
+
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasStatus(StatusData.error())
+                        .hasException(thrown)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  public static final class TestRequestHandler implements RequestStreamHandler {
+
+    @Override
+    public void handleRequest(InputStream input, OutputStream output, Context context)
+        throws IOException {
+      BufferedReader reader =
+          new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
+      BufferedWriter writer =
+          new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
+      String line = reader.readLine();
+      if (line.equals("hello")) {
+        writer.write("world");
+        writer.flush();
+        writer.close();
+      } else {
+        throw new IllegalArgumentException("bad argument");
+      }
+    }
+  }
+}

+ 41 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.java

@@ -0,0 +1,41 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class AwsLambdaTest extends AbstractAwsLambdaTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Override
+  protected RequestHandler<String, String> handler() {
+    return new TestRequestHandler(testing.getOpenTelemetrySdk());
+  }
+
+  @Override
+  protected InstrumentationExtension testing() {
+    return testing;
+  }
+
+  private static final class TestRequestHandler extends TracingRequestHandler<String, String> {
+
+    TestRequestHandler(OpenTelemetrySdk openTelemetrySdk) {
+      super(openTelemetrySdk);
+    }
+
+    @Override
+    protected String doHandleRequest(String input, Context context) {
+      return AbstractAwsLambdaTest.doHandleRequest(input, context);
+    }
+  }
+}

+ 219 - 0
instrumentation/aws-lambda-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaWrapperTest.java

@@ -0,0 +1,219 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class AwsLambdaWrapperTest {
+
+  @RegisterExtension
+  public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+    when(context.getInvokedFunctionArn())
+        .thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing.forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
+  void handlerTraced() {
+    TracingRequestWrapper wrapper =
+        new TracingRequestWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestWrapper::map);
+    Object result = wrapper.handleRequest("hello", context);
+
+    assertThat(result).isEqualTo("world");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
+  void handlerTracedWithException() {
+    TracingRequestWrapper wrapper =
+        new TracingRequestWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestWrapper::map);
+    Throwable thrown = catchThrowable(() -> wrapper.handleRequest("goodbye", context));
+
+    assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasStatus(StatusData.error())
+                        .hasException(thrown)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerInteger::handleRequest")
+  void handlerTraced_integer() {
+    TracingRequestWrapper wrapper =
+        new TracingRequestWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestWrapper::map);
+    Object result = wrapper.handleRequest(1, context);
+
+    assertThat(result).isEqualTo("world");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
+      value =
+          "io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerCustomType::handleRequest")
+  void handlerTraced_custom() {
+    TracingRequestWrapper wrapper =
+        new TracingRequestWrapper(
+            testing.getOpenTelemetrySdk(),
+            WrappedLambda.fromConfiguration(),
+            TracingRequestWrapper::map);
+    CustomType ct = new CustomType();
+    ct.key = "hello there";
+    ct.value = "General Kenobi";
+    Object result = wrapper.handleRequest(ct, context);
+
+    assertThat(result).isEqualTo("General Kenobi");
+    testing.waitAndAssertTraces(
+        trace ->
+            trace.hasSpansSatisfyingExactly(
+                span ->
+                    span.hasName("my_function")
+                        .hasKind(SpanKind.SERVER)
+                        .hasAttributesSatisfying(
+                            attrs ->
+                                OpenTelemetryAssertions.assertThat(attrs)
+                                    .containsOnly(
+                                        entry(
+                                            ResourceAttributes.FAAS_ID,
+                                            "arn:aws:lambda:us-east-1:123456789:function:test"),
+                                        entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
+                                        entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  public static final class TestRequestHandlerString implements RequestHandler<String, String> {
+
+    @Override
+    public String handleRequest(String input, Context context) {
+      if (input.equals("hello")) {
+        return "world";
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+
+  public static final class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
+
+    @Override
+    public String handleRequest(Integer input, Context context) {
+      if (input == 1) {
+        return "world";
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+
+  private static class CustomType {
+    String key;
+    String value;
+  }
+
+  public static final class TestRequestHandlerCustomType
+      implements RequestHandler<CustomType, String> {
+
+    @Override
+    public String handleRequest(CustomType input, Context context) {
+      if (input.key.equals("hello there")) {
+        return input.value;
+      }
+      throw new IllegalArgumentException("bad argument");
+    }
+  }
+}

+ 3 - 0
instrumentation/aws-lambda-1.0/testing/build.gradle.kts

@@ -8,6 +8,9 @@ dependencies {
   api("com.amazonaws:aws-lambda-java-core:1.0.0")
   api("com.amazonaws:aws-lambda-java-events:2.2.1")
 
+  api("org.junit-pioneer:junit-pioneer")
+  api("org.mockito:mockito-junit-jupiter")
+
   implementation("com.google.guava:guava")
 
   implementation("org.codehaus.groovy:groovy-all")

+ 0 - 109
instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaRequestHandlerTest.groovy

@@ -1,109 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.github.stefanbirkner.systemlambda.SystemLambda
-import io.opentelemetry.instrumentation.test.InstrumentationSpecification
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-import static io.opentelemetry.api.trace.StatusCode.ERROR
-
-abstract class AbstractAwsLambdaRequestHandlerTest extends InstrumentationSpecification {
-
-  protected static String doHandleRequest(String input, Context context) {
-    if (input == "hello") {
-      return "world"
-    }
-    throw new IllegalArgumentException("bad argument")
-  }
-
-  abstract RequestHandler<String, String> handler()
-
-  def "handler traced"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def result = handler().handleRequest("hello", context)
-
-    then:
-    result == "world"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler traced with exception"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def thrown
-    try {
-      handler().handleRequest("goodbye", context)
-    } catch (Throwable t) {
-      thrown = t
-    }
-
-    then:
-    thrown != null
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          status ERROR
-          errorEvent(IllegalArgumentException, "bad argument")
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-
-  def "handler links to lambda trace"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def result
-    SystemLambda.withEnvironmentVariable("_X_AMZN_TRACE_ID", "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=0000000000000456;Sampled=1")
-      .execute({
-        result = handler().handleRequest("hello", context)
-      })
-
-    then:
-    result == "world"
-    assertTraces(1) {
-      trace(0, 1) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          parentSpanId("0000000000000456")
-          traceId("8a3c60f7d188f8fa79d48a391a778fa6")
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-      }
-    }
-  }
-}

+ 0 - 112
instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsHandlerTest.groovy

@@ -1,112 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awslambda.v1_0
-
-import com.amazonaws.services.lambda.runtime.Context
-import com.amazonaws.services.lambda.runtime.RequestHandler
-import com.amazonaws.services.lambda.runtime.events.SQSEvent
-import io.opentelemetry.instrumentation.test.InstrumentationSpecification
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
-
-import static io.opentelemetry.api.trace.SpanKind.CONSUMER
-import static io.opentelemetry.api.trace.SpanKind.SERVER
-
-abstract class AbstractAwsLambdaSqsHandlerTest extends InstrumentationSpecification {
-
-  private static final String AWS_TRACE_HEADER = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"
-
-  abstract RequestHandler<SQSEvent, Void> handler()
-
-  def "messages from same source"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def message1 = new SQSEvent.SQSMessage()
-    message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER])
-    message1.setMessageId("message1")
-    message1.setEventSource("queue1")
-
-    def message2 = new SQSEvent.SQSMessage()
-    message2.setAttributes([:])
-    message2.setMessageId("message2")
-    message2.setEventSource("queue1")
-
-    def event = new SQSEvent()
-    event.setRecords([message1, message2])
-
-    handler().handleRequest(event, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 2) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-        span(1) {
-          name("queue1 process")
-          kind CONSUMER
-          parentSpanId(span(0).spanId)
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-          }
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
-        }
-      }
-    }
-  }
-
-  def "messages from different source"() {
-    when:
-    def context = Mock(Context)
-    context.getFunctionName() >> "my_function"
-    context.getAwsRequestId() >> "1-22-333"
-
-    def message1 = new SQSEvent.SQSMessage()
-    message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER])
-    message1.setMessageId("message1")
-    message1.setEventSource("queue1")
-
-    def message2 = new SQSEvent.SQSMessage()
-    message2.setAttributes([:])
-    message2.setMessageId("message2")
-    message2.setEventSource("queue2")
-
-    def event = new SQSEvent()
-    event.setRecords([message1, message2])
-
-    handler().handleRequest(event, context)
-
-    then:
-    assertTraces(1) {
-      trace(0, 2) {
-        span(0) {
-          name("my_function")
-          kind SERVER
-          attributes {
-            "$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
-          }
-        }
-        span(1) {
-          name("multiple_sources process")
-          kind CONSUMER
-          parentSpanId(span(0).spanId)
-          attributes {
-            "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
-            "$SemanticAttributes.MESSAGING_OPERATION" "process"
-          }
-          hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
-        }
-      }
-    }
-  }
-}

+ 167 - 0
instrumentation/aws-lambda-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsEventHandlerTest.java

@@ -0,0 +1,167 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public abstract class AbstractAwsLambdaSqsEventHandlerTest {
+
+  private static final String AWS_TRACE_HEADER =
+      "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1";
+
+  protected abstract RequestHandler<SQSEvent, Void> handler();
+
+  protected abstract InstrumentationExtension testing();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing().forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void sameSource() {
+    SQSEvent.SQSMessage message1 = newMessage();
+    message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER));
+    message1.setMessageId("message1");
+    message1.setEventSource("queue1");
+
+    SQSEvent.SQSMessage message2 = newMessage();
+    message2.setAttributes(Collections.emptyMap());
+    message2.setMessageId("message2");
+    message2.setEventSource("queue1");
+
+    SQSEvent event = new SQSEvent();
+    event.setRecords(Arrays.asList(message1, message2));
+
+    handler().handleRequest(event, context);
+
+    testing()
+        .waitAndAssertTraces(
+            trace ->
+                trace.hasSpansSatisfyingExactly(
+                    span ->
+                        span.hasName("my_function")
+                            .hasKind(SpanKind.SERVER)
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
+                    span ->
+                        span.hasName("queue1 process")
+                            .hasKind(SpanKind.CONSUMER)
+                            .hasParentSpanId(trace.getSpan(0).getSpanId())
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                            entry(
+                                                SemanticAttributes.MESSAGING_OPERATION, "process")))
+                            .hasLinksSatisfying(
+                                links ->
+                                    assertThat(links)
+                                        .singleElement()
+                                        .satisfies(
+                                            link -> {
+                                              assertThat(link.getSpanContext().getTraceId())
+                                                  .isEqualTo("5759e988bd862e3fe1be46a994272793");
+                                              assertThat(link.getSpanContext().getSpanId())
+                                                  .isEqualTo("53995c3f42cd8ad8");
+                                            }))));
+  }
+
+  @Test
+  void differentSource() {
+    SQSEvent.SQSMessage message1 = newMessage();
+    message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER));
+    message1.setMessageId("message1");
+    message1.setEventSource("queue1");
+
+    SQSEvent.SQSMessage message2 = newMessage();
+    message2.setAttributes(Collections.emptyMap());
+    message2.setMessageId("message2");
+    message2.setEventSource("queue2");
+
+    SQSEvent event = new SQSEvent();
+    event.setRecords(Arrays.asList(message1, message2));
+
+    handler().handleRequest(event, context);
+
+    testing()
+        .waitAndAssertTraces(
+            trace ->
+                trace.hasSpansSatisfyingExactly(
+                    span ->
+                        span.hasName("my_function")
+                            .hasKind(SpanKind.SERVER)
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
+                    span ->
+                        span.hasName("multiple_sources process")
+                            .hasKind(SpanKind.CONSUMER)
+                            .hasParentSpanId(trace.getSpan(0).getSpanId())
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
+                                            entry(
+                                                SemanticAttributes.MESSAGING_OPERATION, "process")))
+                            .hasLinksSatisfying(
+                                links ->
+                                    assertThat(links)
+                                        .singleElement()
+                                        .satisfies(
+                                            link -> {
+                                              assertThat(link.getSpanContext().getTraceId())
+                                                  .isEqualTo("5759e988bd862e3fe1be46a994272793");
+                                              assertThat(link.getSpanContext().getSpanId())
+                                                  .isEqualTo("53995c3f42cd8ad8");
+                                            }))));
+  }
+
+  // Constructor private in early versions.
+  private static SQSEvent.SQSMessage newMessage() {
+    try {
+      Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
+      ctor.setAccessible(true);
+      return ctor.newInstance();
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+  }
+}

+ 120 - 0
instrumentation/aws-lambda-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaTest.java

@@ -0,0 +1,120 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awslambda.v1_0;
+
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.when;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junitpioneer.jupiter.SetEnvironmentVariable;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public abstract class AbstractAwsLambdaTest {
+
+  protected static String doHandleRequest(String input, Context context) {
+    if (input.equals("hello")) {
+      return "world";
+    }
+    throw new IllegalArgumentException("bad argument");
+  }
+
+  protected abstract RequestHandler<String, String> handler();
+
+  protected abstract InstrumentationExtension testing();
+
+  @Mock private Context context;
+
+  @BeforeEach
+  void setUp() {
+    when(context.getFunctionName()).thenReturn("my_function");
+    when(context.getAwsRequestId()).thenReturn("1-22-333");
+  }
+
+  @AfterEach
+  void tearDown() {
+    assertThat(testing().forceFlushCalled()).isTrue();
+  }
+
+  @Test
+  void handlerTraced() {
+    String result = handler().handleRequest("hello", context);
+    assertThat(result).isEqualTo("world");
+
+    testing()
+        .waitAndAssertTraces(
+            trace ->
+                trace.hasSpansSatisfyingExactly(
+                    span ->
+                        span.hasName("my_function")
+                            .hasKind(SpanKind.SERVER)
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(
+                                                SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  void handlerTracedWithException() {
+    Throwable thrown = catchThrowable(() -> handler().handleRequest("goodbye", context));
+    assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
+
+    testing()
+        .waitAndAssertTraces(
+            trace ->
+                trace.hasSpansSatisfyingExactly(
+                    span ->
+                        span.hasName("my_function")
+                            .hasKind(SpanKind.SERVER)
+                            .hasStatus(StatusData.error())
+                            .hasException(thrown)
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(
+                                                SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+
+  @Test
+  @SetEnvironmentVariable(
+      key = "_X_AMZN_TRACE_ID",
+      value = "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=0000000000000456;Sampled=1")
+  void handlerLinksToInfrastructureTrace() {
+    String result = handler().handleRequest("hello", context);
+    assertThat(result).isEqualTo("world");
+
+    testing()
+        .waitAndAssertTraces(
+            trace ->
+                trace.hasSpansSatisfyingExactly(
+                    span ->
+                        span.hasName("my_function")
+                            .hasKind(SpanKind.SERVER)
+                            .hasTraceId("8a3c60f7d188f8fa79d48a391a778fa6")
+                            .hasParentSpanId("0000000000000456")
+                            .hasAttributesSatisfying(
+                                attrs ->
+                                    assertThat(attrs)
+                                        .containsOnly(
+                                            entry(
+                                                SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
+  }
+}

+ 16 - 0
testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/InstrumentationExtension.java

@@ -11,9 +11,11 @@ import static org.awaitility.Awaitility.await;
 import io.opentelemetry.api.OpenTelemetry;
 import io.opentelemetry.context.ContextStorage;
 import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner;
+import io.opentelemetry.instrumentation.testing.LibraryTestRunner;
 import io.opentelemetry.instrumentation.testing.util.ContextStorageCloser;
 import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable;
 import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
 import io.opentelemetry.sdk.metrics.data.MetricData;
 import io.opentelemetry.sdk.testing.assertj.TraceAssert;
 import io.opentelemetry.sdk.trace.data.SpanData;
@@ -108,6 +110,7 @@ public abstract class InstrumentationExtension
   }
 
   @SafeVarargs
+  @SuppressWarnings("varargs")
   public final void waitAndAssertTraces(Consumer<TraceAssert>... assertions) {
     testRunner.waitAndAssertTraces(assertions);
   }
@@ -166,6 +169,19 @@ public abstract class InstrumentationExtension
     return testRunner.runWithServerSpan(spanName, callback);
   }
 
+  /** Returns whether forceFlush was called. */
+  public boolean forceFlushCalled() {
+    return testRunner.forceFlushCalled();
+  }
+
+  /** Returns the {@link OpenTelemetrySdk} initialied for library tests. */
+  public OpenTelemetrySdk getOpenTelemetrySdk() {
+    if (testRunner instanceof LibraryTestRunner) {
+      return ((LibraryTestRunner) testRunner).getOpenTelemetrySdk();
+    }
+    throw new IllegalStateException("Can only be called from library instrumentation tests.");
+  }
+
   protected InstrumentationTestRunner getTestRunner() {
     return testRunner;
   }