diff --git a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DecoratorRegistry.java b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DecoratorRegistry.java index 7774594713f2..ecdc3c38b06e 100644 --- a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DecoratorRegistry.java +++ b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DecoratorRegistry.java @@ -20,6 +20,7 @@ private static Map loadDecorators() { Map result = new HashMap<>(); result.put("ahc", new HttpSpanDecorator()); result.put("ampq", new MessagingSpanDecorator("ampq")); + result.put("aws-s3", new S3SpanDecorator()); result.put("aws-sns", new MessagingSpanDecorator("aws-sns")); result.put("aws-sqs", new MessagingSpanDecorator("aws-sqs")); result.put("cometd", new MessagingSpanDecorator("cometd")); diff --git a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/S3SpanDecorator.java b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/S3SpanDecorator.java new file mode 100644 index 000000000000..00f3150ee173 --- /dev/null +++ b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/S3SpanDecorator.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachecamel.decorators; + +import io.opentelemetry.api.trace.SpanKind; + +public class S3SpanDecorator extends BaseSpanDecorator { + + @Override + public SpanKind getInitiatorSpanKind() { + return SpanKind.INTERNAL; + } + + @Override + public SpanKind getReceiverSpanKind() { + return SpanKind.INTERNAL; + } +} diff --git a/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/AwsConnector.groovy b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/AwsConnector.groovy new file mode 100644 index 000000000000..249a782f8325 --- /dev/null +++ b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/AwsConnector.groovy @@ -0,0 +1,147 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachecamel + +import com.amazonaws.services.s3.AmazonS3Client +import com.amazonaws.services.s3.model.BucketNotificationConfiguration +import com.amazonaws.services.s3.model.ObjectListing +import com.amazonaws.services.s3.model.QueueConfiguration +import com.amazonaws.services.s3.model.S3Event +import com.amazonaws.services.s3.model.S3ObjectSummary +import com.amazonaws.services.s3.model.SetBucketNotificationConfigurationRequest +import com.amazonaws.services.s3.model.TopicConfiguration +import com.amazonaws.services.sns.AmazonSNSAsyncClient +import com.amazonaws.services.sns.model.CreateTopicResult +import com.amazonaws.services.sns.model.SetTopicAttributesRequest +import com.amazonaws.services.sqs.AmazonSQSAsyncClient +import com.amazonaws.services.sqs.model.GetQueueAttributesRequest +import com.amazonaws.services.sqs.model.PurgeQueueRequest +import com.amazonaws.services.sqs.model.ReceiveMessageRequest + +class AwsConnector { + + + private AmazonSQSAsyncClient sqsClient + private AmazonS3Client s3Client + private AmazonSNSAsyncClient snsClient + + static liveAws() { + AwsConnector awsConnector = new AwsConnector() + + awsConnector.sqsClient = AmazonSQSAsyncClient.asyncBuilder() + .build() + + awsConnector.s3Client = AmazonS3Client.builder() + .build() + + awsConnector.snsClient = AmazonSNSAsyncClient.asyncBuilder() + .build() + + return awsConnector + } + + def createQueue(String queueName) { + println "Create queue ${queueName}" + return sqsClient.createQueue(queueName).getQueueUrl() + } + + def getQueueArn(String queueUrl) { + println "Get ARN for queue ${queueUrl}" + return sqsClient.getQueueAttributes( + new GetQueueAttributesRequest(queueUrl) + .withAttributeNames("QueueArn")).getAttributes() + .get("QueueArn") + } + + def setTopicPublishingPolicy(String topicArn) { + println "Set policy for topic ${topicArn}" + snsClient.setTopicAttributes(new SetTopicAttributesRequest(topicArn, "Policy", String.format(SNS_POLICY, topicArn))) + } + + private static final String SNS_POLICY = "{" + + " \"Statement\": [" + + " {" + + " \"Effect\": \"Allow\"," + + " \"Principal\": \"*\"," + + " \"Action\": \"sns:Publish\"," + + " \"Resource\": \"%s\"" + + " }]" + + "}" + + def setQueuePublishingPolicy(String queueUrl, String queueArn) { + println "Set policy for queue ${queueArn}" + sqsClient.setQueueAttributes(queueUrl, Collections.singletonMap("Policy", String.format(SQS_POLICY, queueArn))) + } + + private static final String SQS_POLICY = "{" + + " \"Statement\": [" + + " {" + + " \"Effect\": \"Allow\"," + + " \"Principal\": \"*\"," + + " \"Action\": \"sqs:SendMessage\"," + + " \"Resource\": \"%s\"" + + " }]" + + "}" + + def createBucket(String bucketName) { + println "Create bucket ${bucketName}" + s3Client.createBucket(bucketName) + } + + def deleteBucket(String bucketName) { + println "Delete bucket ${bucketName}" + ObjectListing objectListing = s3Client.listObjects(bucketName) + Iterator objIter = objectListing.getObjectSummaries().iterator() + while (objIter.hasNext()) { + s3Client.deleteObject(bucketName, objIter.next().getKey()) + } + s3Client.deleteBucket(bucketName) + } + + def enableS3ToSqsNotifications(String bucketName, String sqsQueueArn) { + println "Enable notification for bucket ${bucketName} to queue ${sqsQueueArn}" + BucketNotificationConfiguration notificationConfiguration = new BucketNotificationConfiguration() + notificationConfiguration.addConfiguration("sqsQueueConfig", + new QueueConfiguration(sqsQueueArn, EnumSet.of(S3Event.ObjectCreatedByPut))) + s3Client.setBucketNotificationConfiguration(new SetBucketNotificationConfigurationRequest( + bucketName, notificationConfiguration)) + } + + def enableS3ToSnsNotifications(String bucketName, String snsTopicArn) { + println "Enable notification for bucket ${bucketName} to topic ${snsTopicArn}" + BucketNotificationConfiguration notificationConfiguration = new BucketNotificationConfiguration() + notificationConfiguration.addConfiguration("snsTopicConfig", + new TopicConfiguration(snsTopicArn, EnumSet.of(S3Event.ObjectCreatedByPut))) + s3Client.setBucketNotificationConfiguration(new SetBucketNotificationConfigurationRequest( + bucketName, notificationConfiguration)) + } + + def createTopicAndSubscribeQueue(String topicName, String queueArn) { + println "Create topic ${topicName} and subscribe to queue ${queueArn}" + CreateTopicResult ctr = snsClient.createTopic(topicName) + snsClient.subscribe(ctr.getTopicArn(), "sqs", queueArn) + return ctr.getTopicArn() + } + + def receiveMessage(String queueUrl) { + println "Receive message from queue ${queueUrl}" + return sqsClient.receiveMessage(new ReceiveMessageRequest(queueUrl).withWaitTimeSeconds(20)) + } + + def purgeQueue(String queueUrl) { + println "Purge queue ${queueUrl}" + sqsClient.purgeQueue(new PurgeQueueRequest(queueUrl)) + } + + def putSampleData(String bucketName) { + println "Put sample data to bucket ${bucketName}" + s3Client.putObject(bucketName, "otelTestKey", "otelTestData") + } + + def publishSampleNotification(String topicArn) { + snsClient.publish(topicArn, "Hello There") + } +} diff --git a/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3CamelTest.groovy b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3CamelTest.groovy new file mode 100644 index 000000000000..1827b6318cd9 --- /dev/null +++ b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3CamelTest.groovy @@ -0,0 +1,398 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachecamel + +import static io.opentelemetry.api.trace.SpanKind.CLIENT +import static io.opentelemetry.api.trace.SpanKind.CONSUMER +import static io.opentelemetry.api.trace.SpanKind.INTERNAL + +import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification +import org.apache.camel.CamelContext +import org.apache.camel.ProducerTemplate +import org.springframework.boot.SpringApplication +import org.testcontainers.shaded.com.google.common.collect.ImmutableMap +import spock.lang.Ignore +import spock.lang.Shared + +@Ignore("Does not work with localstack - X-Ray features needed") +class S3CamelTest extends AgentInstrumentationSpecification { + + @Shared + AwsConnector awsConnector + + def setupSpec() { + awsConnector = AwsConnector.liveAws() + } + + def startCamelApp(String bucketName, String queueName) { + def app = new SpringApplication(S3Config) + app.setDefaultProperties(ImmutableMap.of("bucketName", bucketName, "queueName", queueName)) + return app.run() + } + + def "camel S3 producer - camel SQS consumer"() { + setup: + String bucketName = "bucket-test-s3-sqs-camel" + String queueName = "s3SqsCamelTest" + + // setup infra + String queueUrl = awsConnector.createQueue(queueName) + awsConnector.createBucket(bucketName) + + String queueArn = awsConnector.getQueueArn(queueUrl) + awsConnector.setQueuePublishingPolicy(queueUrl, queueArn) + awsConnector.enableS3ToSqsNotifications(bucketName, queueArn) + + // consume test message from AWS + awsConnector.receiveMessage(queueUrl) + + // wait for setup traces + waitAndClearSetupTraces(queueUrl, queueName, bucketName) + + when: + def applicationContext = startCamelApp(bucketName, queueName) + def camelContext = applicationContext.getBean(CamelContext) + ProducerTemplate template = camelContext.createProducerTemplate() + template.sendBody("direct:input", "{\"type\": \"hello\"}") + + then: + assertTraces(6) { + trace(0, 1) { + span(0) { + name "SQS.ListQueues" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ListQueues" + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + } + trace(1, 1) { + span(0) { + name "S3.ListObjects" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ListObjects" + "aws.service" "Amazon S3" + "aws.bucket.name" bucketName + "http.flavor" "1.1" + "http.method" "GET" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + trace(2, 5) { + span(0) { + name "input" + kind INTERNAL + hasNoParent() + attributes { + "apache-camel.uri" "direct://input" + } + } + span(1) { + name "aws-s3" + kind INTERNAL + childOf span(0) + attributes { + "apache-camel.uri" "aws-s3://${bucketName}?amazonS3Client=%23s3Client" + } + } + span(2) { + name "S3.PutObject" + kind CLIENT + childOf span(1) + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "PutObject" + "aws.service" "Amazon S3" + "aws.bucket.name" bucketName + "http.flavor" "1.1" + "http.method" "PUT" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + span(3) { + name "SQS.ReceiveMessage" + kind CONSUMER + childOf span(2) + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ReceiveMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "http.user_agent" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + span(4) { + name queueName + kind INTERNAL + childOf span(2) + attributes { + "apache-camel.uri" "aws-sqs://${queueName}?amazonSQSClient=%23sqsClient&delay=1000" + "messaging.destination" queueName + "messaging.message_id" String + } + } + } + // HTTP "client" receiver span, one per each SQS request + trace(3, 1) { + span(0) { + name "SQS.ReceiveMessage" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ReceiveMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + } + // camel polling + trace(4, 1) { + span(0) { + name "SQS.ReceiveMessage" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ReceiveMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + } + // camel cleaning received msg + trace(5, 1) { + span(0) { + name "SQS.DeleteMessage" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "DeleteMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + } + } + + cleanup: + awsConnector.deleteBucket(bucketName) + awsConnector.purgeQueue(queueUrl) + } + + def waitAndClearSetupTraces(queueUrl, queueName, bucketName) { + assertTraces(7) { + trace(0, 1) { + span(0) { + name "SQS.CreateQueue" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "CreateQueue" + "aws.queue.name" queueName + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.peer.port" { it == null || Number } + "net.transport" "IP.TCP" + } + } + } + trace(1, 1) { + span(0) { + name "S3.CreateBucket" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "CreateBucket" + "aws.service" "Amazon S3" + "aws.bucket.name" bucketName + "http.flavor" "1.1" + "http.method" "PUT" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + trace(2, 1) { + span(0) { + name "SQS.GetQueueAttributes" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "GetQueueAttributes" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + trace(3, 1) { + span(0) { + name "SQS.SetQueueAttributes" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "SetQueueAttributes" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + trace(4, 1) { + span(0) { + name "S3.SetBucketNotificationConfiguration" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "SetBucketNotificationConfiguration" + "aws.service" "Amazon S3" + "aws.bucket.name" bucketName + "http.flavor" "1.1" + "http.method" "PUT" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + trace(5, 1) { + span(0) { + name "SQS.ReceiveMessage" + kind CLIENT + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ReceiveMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + // http receive span + trace(6, 1) { + span(0) { + name "SQS.ReceiveMessage" + kind CONSUMER + hasNoParent() + attributes { + "aws.agent" "java-aws-sdk" + "aws.endpoint" String + "aws.operation" "ReceiveMessage" + "aws.queue.url" queueUrl + "aws.service" "AmazonSQS" + "http.flavor" "1.1" + "http.method" "POST" + "http.status_code" 200 + "http.url" String + "http.user_agent" String + "net.peer.name" String + "net.transport" "IP.TCP" + "net.peer.port" { it == null || Number } + } + } + } + } + clearExportedData() + } +} \ No newline at end of file diff --git a/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3Config.groovy b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3Config.groovy new file mode 100644 index 000000000000..efe2057c7ada --- /dev/null +++ b/instrumentation/apache-camel-2.20/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/apachecamel/S3Config.groovy @@ -0,0 +1,70 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachecamel + +import com.amazonaws.services.s3.AmazonS3Client +import com.amazonaws.services.sns.AmazonSNSAsyncClient +import com.amazonaws.services.sns.AmazonSNSClient +import com.amazonaws.services.sqs.AmazonSQSAsyncClient +import com.amazonaws.services.sqs.AmazonSQSClient +import org.apache.camel.LoggingLevel +import org.apache.camel.builder.RouteBuilder +import org.apache.camel.component.aws.s3.S3Constants +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.SpringBootConfiguration +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.context.annotation.Bean + +@SpringBootConfiguration +@EnableAutoConfiguration +class S3Config { + + @Bean + RouteBuilder sqsDirectlyFromS3ConsumerRoute(@Value("\${queueName}") String queueName) { + return new RouteBuilder() { + + @Override + void configure() throws Exception { + from("aws-sqs://${queueName}?amazonSQSClient=#sqsClient&delay=1000") + .log(LoggingLevel.INFO, "test", "RECEIVER got body : \${body}") + .log(LoggingLevel.INFO, "test", "RECEIVER got headers : \${headers}") + } + } + } + + @Bean + RouteBuilder s3ToSqsProducerRoute(@Value("\${bucketName}") String bucketName) { + return new RouteBuilder() { + + @Override + void configure() throws Exception { + from("direct:input") + .log(LoggingLevel.INFO, "test", "SENDING body: \${body}") + .log(LoggingLevel.INFO, "test", "SENDING headers: \${headers}") + .convertBodyTo(byte[].class) + .setHeader(S3Constants.KEY,simple("test-data")) + .to("aws-s3://${bucketName}?amazonS3Client=#s3Client") + } + } + } + + @Bean + AmazonSQSClient sqsClient() { + return AmazonSQSAsyncClient.asyncBuilder() + .build() + } + + @Bean + AmazonSNSClient snsClient() { + return AmazonSNSAsyncClient.asyncBuilder() + .build() + } + + @Bean + AmazonS3Client s3Client() { + return AmazonS3Client.builder().build() + } +} diff --git a/instrumentation/apache-camel-2.20/javaagent/src/test/resources/logback-test.xml b/instrumentation/apache-camel-2.20/javaagent/src/test/resources/logback-test.xml index 035ae9ded86a..06d0ba8a82bb 100644 --- a/instrumentation/apache-camel-2.20/javaagent/src/test/resources/logback-test.xml +++ b/instrumentation/apache-camel-2.20/javaagent/src/test/resources/logback-test.xml @@ -18,5 +18,6 @@ + diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/aws-sdk-1.11-javaagent-unittests.gradle b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/aws-sdk-1.11-javaagent-unittests.gradle new file mode 100644 index 000000000000..3c4f1a06843d --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/aws-sdk-1.11-javaagent-unittests.gradle @@ -0,0 +1,11 @@ +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + api project(':testing-common') + testImplementation project(':instrumentation:aws-sdk:aws-sdk-1.11:javaagent') + + testImplementation group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.0' + testImplementation group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '1.11.106' + + testImplementation deps.assertj +} diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/src/test/java/TracingRequestHandlerTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/src/test/java/TracingRequestHandlerTest.java new file mode 100644 index 000000000000..b40659b48b40 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent-unittests/src/test/java/TracingRequestHandlerTest.java @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import static io.opentelemetry.instrumentation.testing.util.TraceUtils.withClientSpan; +import static org.assertj.core.api.Assertions.assertThat; + +import com.amazonaws.DefaultRequest; +import com.amazonaws.Request; +import com.amazonaws.Response; +import com.amazonaws.http.HttpResponse; +import com.amazonaws.services.sqs.model.SendMessageRequest; +import com.amazonaws.services.sqs.model.SendMessageResult; +import io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.TracingRequestHandler; +import java.net.URI; +import org.apache.http.client.methods.HttpGet; +import org.junit.Test; + +public class TracingRequestHandlerTest { + + private Response response(Request request) { + return new Response<>(new SendMessageResult(), new HttpResponse(request, new HttpGet())); + } + + private Request request() { + Request request = new DefaultRequest<>(new SendMessageRequest(), "test"); + request.setEndpoint(URI.create("http://test.uri")); + return request; + } + + @Test + public void shouldNotSetScopeAndNotFailIfClientSpanAlreadyPresent() { + // given + TracingRequestHandler underTest = new TracingRequestHandler(); + Request request = request(); + + withClientSpan( + "test", + () -> { + // when + underTest.beforeRequest(request); + // then - no exception and scope not set + assertThat(request.getHandlerContext(TracingRequestHandler.SCOPE)).isNull(); + underTest.afterResponse(request, response(request)); + }); + } + + @Test + public void shouldSetScopeIfClientSpanNotPresent() { + // given + TracingRequestHandler underTest = new TracingRequestHandler(); + Request request = request(); + + // when + underTest.beforeRequest(request); + // then - no exception and scope not set + assertThat(request.getHandlerContext(TracingRequestHandler.SCOPE)).isNotNull(); + underTest.afterResponse(request, response(request)); + } +} diff --git a/settings.gradle b/settings.gradle index 5cc9cd966fd4..c96fbfe1d35d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -76,6 +76,7 @@ include ':instrumentation:aws-lambda-1.0:javaagent' include ':instrumentation:aws-lambda-1.0:library' include ':instrumentation:aws-lambda-1.0:testing' include ':instrumentation:aws-sdk:aws-sdk-1.11:javaagent' +include ':instrumentation:aws-sdk:aws-sdk-1.11:javaagent-unittests' include ':instrumentation:aws-sdk:aws-sdk-1.11:library' include ':instrumentation:aws-sdk:aws-sdk-1.11:testing' include ':instrumentation:aws-sdk:aws-sdk-2.2:javaagent'