Migrate AWS Lambda tests to Java (#5315)
* Migrate AWS Lambda tests to Java * Only assert OTLP fields for links
This commit is contained in:
parent
186c657b4e
commit
b9fac11c90
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")))));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue