From ad57f812df29a186c390e6d1a898cddd00cdf246 Mon Sep 17 00:00:00 2001 From: Omar Nasr Date: Wed, 12 Jun 2024 16:27:14 +0000 Subject: [PATCH 1/2] Creating contract-tests for successful 'CREATE DATABASE' for MySQL and Postgres. --- .../test/jdbc/JdbcContractTestBase.java | 325 +++--------------- .../appsignals/test/jdbc/JdbcH2Test.java | 6 +- .../appsignals/test/jdbc/JdbcMySQLTest.java | 17 +- .../test/jdbc/JdbcPostgresTest.java | 17 +- .../test/jdbc/operationtests/DBOperation.java | 38 ++ .../JdbcCreateDatabaseOperationTester.java | 47 +++ .../operationtests/JdbcOperationTester.java | 260 ++++++++++++++ .../JdbcOperationTesterProvider.java | 38 ++ .../JdbcSelectOperationTester.java | 57 +++ .../amazon/opentelemetry/AppController.java | 19 +- 10 files changed, 526 insertions(+), 298 deletions(-) create mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java create mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java create mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java create mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java create mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java index 833e37734b..fe228894ca 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java @@ -15,25 +15,19 @@ package software.amazon.opentelemetry.appsignals.test.jdbc; -import static io.opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertThat; -import io.opentelemetry.proto.common.v1.KeyValue; -import io.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint; -import java.util.List; import java.util.Set; import software.amazon.opentelemetry.appsignals.test.base.ContractTestBase; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.JdbcOperationTester; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.JdbcOperationTesterProvider; import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants; -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeMetric; -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; -import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; -public class JdbcContractTestBase extends ContractTestBase { +public abstract class JdbcContractTestBase extends ContractTestBase { protected static final String DB_NAME = "testdb"; - protected static final String DB_USER = "sa"; + protected static final String DB_USER = "root"; protected static final String DB_PASSWORD = "password"; - protected static final String DB_OPERATION = "SELECT"; protected static final String DB_RESOURCE_TYPE = "DB::Connection"; @Override @@ -46,264 +40,29 @@ protected String getApplicationWaitPattern() { return ".*Application Ready.*"; } - protected void assertAwsSpanAttributes( - List resourceScopeSpans, - String method, - String path, - String dbSystem, - String dbOperation, - String type, - String identifier) { - assertThat(resourceScopeSpans) - .satisfiesOnlyOnce( - rss -> { - assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); - var attributesList = rss.getSpan().getAttributesList(); - assertAwsAttributes( - attributesList, method, path, dbSystem, dbOperation, type, identifier); - }); - } - - protected void assertAwsAttributes( - List attributesList, - String method, - String endpoint, - String dbSystem, - String dbOperation, - String type, - String identifier) { - var assertions = - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(String.format("%s /%s", method, endpoint)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(getApplicationOtelServiceName()); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); - assertThat(attribute.getValue().getStringValue()).isEqualTo("CLIENT"); - }); - if (type != null && identifier != null) { - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(type); - }); - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); - assertThat(attribute.getValue().getStringValue()).isEqualTo(identifier); - }); - } - } - - protected void assertSemanticConventionsSpanAttributes( - List resourceScopeSpans, - String otelStatusCode, - String dbSqlTable, - String dbSystem, - String dbOperation, - String dbUser, - String dbName, - String jdbcUrl) { - assertThat(resourceScopeSpans) - .satisfiesOnlyOnce( - rss -> { - assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); - assertThat(rss.getSpan().getName()) - .isEqualTo(String.format("%s %s.%s", dbOperation, dbName, dbSqlTable)); - assertThat(rss.getSpan().getStatus().getCode().toString()).isEqualTo(otelStatusCode); - var attributesList = rss.getSpan().getAttributesList(); - assertSemanticConventionsAttributes( - attributesList, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl); - }); - } - - protected void assertSemanticConventionsAttributes( - List attributesList, - String dbSqlTable, - String dbSystem, - String dbOperation, - String dbUser, - String dbName, - String jdbcUrl) { - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.DB_CONNECTION_STRING); - assertThat(attribute.getValue().getStringValue()).isEqualTo(jdbcUrl); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbName); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SQL_TABLE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSqlTable); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo( - String.format("%s count(*) from %s", dbOperation.toLowerCase(), dbSqlTable)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_USER); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbUser); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_OPERATION); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SYSTEM); - assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem); - }); - } - - protected void assertMetricAttributes( - List resourceScopeMetrics, - String method, - String path, - String metricName, - Double expectedSum, - String dbSystem, - String dbOperation, - String type, - String identifier) { - assertThat(resourceScopeMetrics) - .anySatisfy( - metric -> { - assertThat(metric.getMetric().getName()).isEqualTo(metricName); - List dpList = - metric.getMetric().getExponentialHistogram().getDataPointsList(); - assertThat(dpList) - .satisfiesOnlyOnce( - dp -> { - List attributesList = dp.getAttributesList(); - assertThat(attributesList).isNotNull(); - var assertions = - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo("CLIENT"); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(String.format("%s /%s", method, path)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(getApplicationOtelServiceName()); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(dbSystem); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(dbOperation); - }); - if (type != null && identifier != null) { - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(type); - }); - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(identifier); - }); - } - - if (expectedSum != null) { - double actualSum = dp.getSum(); - switch (metricName) { - case AppSignalsConstants.LATENCY_METRIC: - assertThat(actualSum).isStrictlyBetween(0.0, expectedSum); - break; - default: - assertThat(actualSum).isEqualTo(expectedSum); - } - } - }); - }); - } - protected void assertSuccess( String dbSystem, - String dbOperation, + DBOperation dbOperation, String dbUser, String dbName, String jdbcUrl, String type, String identifier) { - var path = "success"; + var path = "success/" + dbOperation.name(); var method = "GET"; var otelStatusCode = "STATUS_CODE_UNSET"; var dbSqlTable = "employee"; - + var otelApplicationImageName = getApplicationOtelServiceName(); + JdbcOperationTester operationTester = + JdbcOperationTesterProvider.getOperationTester( + dbOperation, dbSystem, dbUser, jdbcUrl, dbName, dbSqlTable); var response = appClient.get(path).aggregate().join(); assertThat(response.status().isSuccess()).isTrue(); var traces = mockCollectorClient.getTraces(); - assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation, type, identifier); - assertSemanticConventionsSpanAttributes( - traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl); + operationTester.assertAwsSpanAttributes( + traces, method, path, type, identifier, otelApplicationImageName); + operationTester.assertSemanticConventionsSpanAttributes(traces, otelStatusCode); var metrics = mockCollectorClient.getMetrics( @@ -311,57 +70,58 @@ protected void assertSuccess( AppSignalsConstants.LATENCY_METRIC, AppSignalsConstants.ERROR_METRIC, AppSignalsConstants.FAULT_METRIC)); - assertMetricAttributes( + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, - dbSystem, - dbOperation, type, - identifier); - assertMetricAttributes( + identifier, + otelApplicationImageName); + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, - dbSystem, - dbOperation, type, - identifier); - assertMetricAttributes( + identifier, + otelApplicationImageName); + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.FAULT_METRIC, 0.0, - dbSystem, - dbOperation, type, - identifier); + identifier, + otelApplicationImageName); } protected void assertFault( String dbSystem, - String dbOperation, + DBOperation dbOperation, String dbUser, String dbName, String jdbcUrl, String type, String identifier) { - var path = "fault"; + var path = "fault/" + dbOperation; var method = "GET"; var otelStatusCode = "STATUS_CODE_ERROR"; var dbSqlTable = "userrr"; + var otelApplicationImageName = getApplicationOtelServiceName(); + JdbcOperationTester operationTester = + JdbcOperationTesterProvider.getOperationTester( + dbOperation, dbSystem, dbUser, jdbcUrl, dbName, dbSqlTable); var response = appClient.get(path).aggregate().join(); assertThat(response.status().isServerError()).isTrue(); var traces = mockCollectorClient.getTraces(); - assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation, type, identifier); - assertSemanticConventionsSpanAttributes( - traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl); + operationTester.assertAwsSpanAttributes( + traces, method, path, type, identifier, otelApplicationImageName); + operationTester.assertSemanticConventionsSpanAttributes(traces, otelStatusCode); var metrics = mockCollectorClient.getMetrics( @@ -369,35 +129,32 @@ protected void assertFault( AppSignalsConstants.LATENCY_METRIC, AppSignalsConstants.ERROR_METRIC, AppSignalsConstants.FAULT_METRIC)); - assertMetricAttributes( + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, - dbSystem, - dbOperation, type, - identifier); - assertMetricAttributes( + identifier, + otelApplicationImageName); + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, - dbSystem, - dbOperation, type, - identifier); - assertMetricAttributes( + identifier, + otelApplicationImageName); + operationTester.assertMetricAttributes( metrics, method, path, AppSignalsConstants.FAULT_METRIC, 1.0, - dbSystem, - dbOperation, type, - identifier); + identifier, + otelApplicationImageName); } } diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java index ab5b69da57..e7ba625bff 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.testcontainers.junit.jupiter.Testcontainers; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -32,12 +33,13 @@ public class JdbcH2Test extends JdbcContractTestBase { @Test public void testSuccess() { - assertSuccess(DB_SYSTEM, DB_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); + assertSuccess( + DB_SYSTEM, DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); } @Test public void testFault() { - assertFault(DB_SYSTEM, DB_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); + assertFault(DB_SYSTEM, DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); } @Override diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java index f9be5b6cab..98ce0848a3 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java @@ -17,15 +17,19 @@ import java.util.List; import java.util.Map; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.lifecycle.Startable; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(Lifecycle.PER_CLASS) @@ -48,11 +52,16 @@ public void afterEach() { mySQLContainer.stop(); } - @Test - public void testSuccess() { + private static Stream dbOperations() { + return Stream.of(DBOperation.SELECT, DBOperation.CREATE_DATABASE); + } + + @ParameterizedTest + @MethodSource("dbOperations") + public void testSuccess(DBOperation operation) { assertSuccess( DB_SYSTEM, - DB_OPERATION, + operation, DB_USER, DB_NAME, DB_CONNECTION_STRING, @@ -64,7 +73,7 @@ public void testSuccess() { public void testFault() { assertFault( DB_SYSTEM, - DB_OPERATION, + DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java index 056c7c448d..0d89a21811 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java @@ -17,14 +17,18 @@ import java.util.List; import java.util.Map; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.lifecycle.Startable; +import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -48,11 +52,16 @@ public void afterEach() { postgreSqlContainer.stop(); } - @Test - public void testSuccess() { + private static Stream dbOperations() { + return Stream.of(DBOperation.SELECT, DBOperation.CREATE_DATABASE); + } + + @ParameterizedTest + @MethodSource("dbOperations") + public void testSuccess(DBOperation operation) { assertSuccess( DB_SYSTEM, - DB_OPERATION, + operation, DB_USER, DB_NAME, DB_CONNECTION_STRING, @@ -64,7 +73,7 @@ public void testSuccess() { public void testFault() { assertFault( DB_SYSTEM, - DB_OPERATION, + DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java new file mode 100644 index 0000000000..164a4bd291 --- /dev/null +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; + +public enum DBOperation { + CREATE_DATABASE("CREATE DATABASE", "testdb2"), + SELECT("SELECT", "testdb"); + + DBOperation(String value, String targetDB) { + this.value = value; + this.targetDB = targetDB; + } + + private final String value; + private final String targetDB; + + public String getTargetDB() { + return targetDB; + } + + @Override + public String toString() { + return value; + } +} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java new file mode 100644 index 0000000000..2fdcd6a563 --- /dev/null +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java @@ -0,0 +1,47 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation.CREATE_DATABASE; + +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; + +public class JdbcCreateDatabaseOperationTester extends JdbcOperationTester { + + public JdbcCreateDatabaseOperationTester( + String dbSystem, String dbUser, String jdbcUrl, String dbName, String dbTable) { + super(dbSystem, dbUser, jdbcUrl, dbName, CREATE_DATABASE.toString(), dbTable); + } + + @Override + protected void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan) { + assertThat(resourceScopeSpan.getSpan().getName()).isEqualTo(String.format("%s", this.dbName)); + + var attributesList = resourceScopeSpan.getSpan().getAttributesList(); + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo( + String.format( + "%s %s", + CREATE_DATABASE.toString().toLowerCase(), CREATE_DATABASE.getTargetDB())); + }); + } +} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java new file mode 100644 index 0000000000..c9b4f7a9fb --- /dev/null +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java @@ -0,0 +1,260 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; + +import static io.opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint; +import java.util.List; +import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants; +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeMetric; +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; + +public abstract class JdbcOperationTester { + + protected final String dbSystem; + protected final String dbUser; + protected final String jdbcUrl; + protected final String dbName; + protected final String dbOperation; + protected final String dbTable; + + protected JdbcOperationTester( + String dbSystem, + String dbUser, + String jdbcUrl, + String dbName, + String dbOperation, + String dbTable) { + this.dbSystem = dbSystem; + this.dbUser = dbUser; + this.jdbcUrl = jdbcUrl; + this.dbName = dbName; + this.dbOperation = dbOperation; + this.dbTable = dbTable; + } + + public void assertAwsSpanAttributes( + List resourceScopeSpans, + String method, + String path, + String type, + String identifier, + String applicationOtelServiceName) { + assertThat(resourceScopeSpans) + .satisfiesOnlyOnce( + rss -> { + assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); + var attributesList = rss.getSpan().getAttributesList(); + assertAwsAttributes( + attributesList, method, path, type, identifier, applicationOtelServiceName); + }); + } + + private void assertAwsAttributes( + List attributesList, + String method, + String endpoint, + String type, + String identifier, + String applicationOtelServiceName) { + var assertions = + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(String.format("%s /%s", method, endpoint)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(applicationOtelServiceName); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbSystem); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbOperation); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); + assertThat(attribute.getValue().getStringValue()).isEqualTo("CLIENT"); + }); + if (type != null && identifier != null) { + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(type); + }); + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); + assertThat(attribute.getValue().getStringValue()).isEqualTo(identifier); + }); + } + } + + public void assertSemanticConventionsSpanAttributes( + List resourceScopeSpans, String otelStatusCode) { + assertThat(resourceScopeSpans) + .satisfiesOnlyOnce( + rss -> { + assertOperationSemanticConventions(rss); + assertSemanticConventionsCommon(rss, otelStatusCode); + }); + } + + protected abstract void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan); + + private void assertSemanticConventionsCommon(ResourceScopeSpan rss, String otelStatusCode) { + assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); + assertThat(rss.getSpan().getStatus().getCode().toString()).isEqualTo(otelStatusCode); + var attributesList = rss.getSpan().getAttributesList(); + assertSemanticConventionsAttributes(attributesList); + } + + protected void assertSemanticConventionsAttributes(List attributesList) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.DB_CONNECTION_STRING); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.jdbcUrl); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_NAME); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbName); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_USER); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbUser); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SYSTEM); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbSystem); + }); + } + + public void assertMetricAttributes( + List resourceScopeMetrics, + String method, + String path, + String metricName, + Double expectedSum, + String type, + String identifier, + String applicationOtelServiceName) { + assertThat(resourceScopeMetrics) + .anySatisfy( + metric -> { + assertThat(metric.getMetric().getName()).isEqualTo(metricName); + List dpList = + metric.getMetric().getExponentialHistogram().getDataPointsList(); + assertThat(dpList) + .satisfiesOnlyOnce( + dp -> { + List attributesList = dp.getAttributesList(); + assertThat(attributesList).isNotNull(); + var assertions = + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo("CLIENT"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(String.format("%s /%s", method, path)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(applicationOtelServiceName); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(this.dbSystem); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(this.dbOperation); + }); + if (type != null && identifier != null) { + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(type); + }); + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(identifier); + }); + } + + if (expectedSum != null) { + double actualSum = dp.getSum(); + switch (metricName) { + case AppSignalsConstants.LATENCY_METRIC: + assertThat(actualSum).isStrictlyBetween(0.0, expectedSum); + break; + default: + assertThat(actualSum).isEqualTo(expectedSum); + } + } + }); + }); + } +} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java new file mode 100644 index 0000000000..06fa212323 --- /dev/null +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; + +public class JdbcOperationTesterProvider { + + private JdbcOperationTesterProvider() {} + + public static JdbcOperationTester getOperationTester( + DBOperation operation, + String dbSystem, + String dbUser, + String jdbcUrl, + String dbName, + String dbTable) { + switch (operation) { + case CREATE_DATABASE: + return new JdbcCreateDatabaseOperationTester(dbSystem, dbUser, jdbcUrl, dbName, dbTable); + case SELECT: + return new JdbcSelectOperationTester(dbSystem, dbUser, jdbcUrl, dbName, dbTable); + default: + throw new UnsupportedOperationException("No tests for operation: " + operation); + } + } +} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java new file mode 100644 index 0000000000..b08661ccd2 --- /dev/null +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation.SELECT; + +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; + +public class JdbcSelectOperationTester extends JdbcOperationTester { + + public JdbcSelectOperationTester( + String dbSystem, String dbUser, String jdbcUrl, String dbName, String dbTable) { + super(dbSystem, dbUser, jdbcUrl, dbName, SELECT.toString(), dbTable); + } + + @Override + protected void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan) { + assertThat(resourceScopeSpan.getSpan().getName()) + .isEqualTo(String.format("%s %s.%s", SELECT, this.dbName, this.dbTable)); + + var attributesList = resourceScopeSpan.getSpan().getAttributesList(); + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo( + String.format( + "%s count(*) from %s", SELECT.toString().toLowerCase(), this.dbTable)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SQL_TABLE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbTable); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_OPERATION); + assertThat(attribute.getValue().getStringValue()).isEqualTo(SELECT.toString()); + }); + } +} diff --git a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java index 7019c57c7b..8789554862 100644 --- a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java +++ b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java @@ -46,18 +46,29 @@ public void prepareDB() { logger.info("Application Ready"); } - @GetMapping("/success") + @GetMapping("/success/CREATE_DATABASE") @ResponseBody - public ResponseEntity success() { + public ResponseEntity successCreateDatabase() { + try { + jdbcTemplate.execute("create database testdb2"); + } catch (Exception ex) { + return ResponseEntity.badRequest().body("failed"); + } + return ResponseEntity.ok().body("success"); + } + + @GetMapping("/success/SELECT") + @ResponseBody + public ResponseEntity successSelect() { int count = jdbcTemplate.queryForObject("select count(*) from employee", Integer.class); return (count == 1) ? ResponseEntity.ok().body("success") : ResponseEntity.badRequest().body("failed"); } - @GetMapping("/fault") + @GetMapping("/fault/SELECT") @ResponseBody - public ResponseEntity failure() { + public ResponseEntity failureSelect() { int count = jdbcTemplate.queryForObject("select count(*) from userrr", Integer.class); return ResponseEntity.ok().body("success"); } From b468d572be2dc48a34934683b9059625dd31a4f2 Mon Sep 17 00:00:00 2001 From: Omar Nasr Date: Wed, 19 Jun 2024 13:16:39 +0000 Subject: [PATCH 2/2] Addressing PR comments to simplify code use methods instead of abstractions --- .../test/jdbc/JdbcContractTestBase.java | 347 ++++++++++++++++-- .../appsignals/test/jdbc/JdbcH2Test.java | 9 +- .../appsignals/test/jdbc/JdbcMySQLTest.java | 27 +- .../test/jdbc/JdbcPostgresTest.java | 27 +- .../test/jdbc/operationtests/DBOperation.java | 38 -- .../JdbcCreateDatabaseOperationTester.java | 47 --- .../operationtests/JdbcOperationTester.java | 260 ------------- .../JdbcOperationTesterProvider.java | 38 -- .../JdbcSelectOperationTester.java | 57 --- .../amazon/opentelemetry/AppController.java | 8 +- 10 files changed, 344 insertions(+), 514 deletions(-) delete mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java delete mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java delete mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java delete mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java delete mode 100644 appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java index fe228894ca..2704dec3c9 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java @@ -15,19 +15,26 @@ package software.amazon.opentelemetry.appsignals.test.jdbc; +import static io.opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT; import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint; +import java.util.List; import java.util.Set; import software.amazon.opentelemetry.appsignals.test.base.ContractTestBase; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.JdbcOperationTester; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.JdbcOperationTesterProvider; import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants; +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeMetric; +import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; -public abstract class JdbcContractTestBase extends ContractTestBase { +public class JdbcContractTestBase extends ContractTestBase { protected static final String DB_NAME = "testdb"; + protected static final String CREATE_DB_NAME = "testdb2"; protected static final String DB_USER = "root"; protected static final String DB_PASSWORD = "password"; + protected static final String DB_SELECT_OPERATION = "SELECT"; + protected static final String DB_CREATE_DATABASE_OPERATION = "CREATE DATABASE"; protected static final String DB_RESOURCE_TYPE = "DB::Connection"; @Override @@ -40,29 +47,289 @@ protected String getApplicationWaitPattern() { return ".*Application Ready.*"; } + protected void assertAwsSpanAttributes( + List resourceScopeSpans, + String method, + String path, + String dbSystem, + String dbOperation, + String type, + String identifier) { + assertThat(resourceScopeSpans) + .satisfiesOnlyOnce( + rss -> { + assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); + var attributesList = rss.getSpan().getAttributesList(); + assertAwsAttributes( + attributesList, method, path, dbSystem, dbOperation, type, identifier); + }); + } + + protected void assertAwsAttributes( + List attributesList, + String method, + String endpoint, + String dbSystem, + String dbOperation, + String type, + String identifier) { + var assertions = + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(String.format("%s /%s", method, endpoint)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(getApplicationOtelServiceName()); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); + assertThat(attribute.getValue().getStringValue()).isEqualTo("CLIENT"); + }); + if (type != null && identifier != null) { + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(type); + }); + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); + assertThat(attribute.getValue().getStringValue()).isEqualTo(identifier); + }); + } + } + + protected void assertSemanticConventionsSpanAttributes( + List resourceScopeSpans, + String otelStatusCode, + String dbSqlTable, + String dbSystem, + String dbOperation, + String dbUser, + String dbName, + String jdbcUrl) { + assertThat(resourceScopeSpans) + .satisfiesOnlyOnce( + rss -> { + assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); + assertThat(rss.getSpan().getStatus().getCode().toString()).isEqualTo(otelStatusCode); + assertSemanticConventionForOperation(rss, dbOperation, dbName, dbSqlTable); + var attributesList = rss.getSpan().getAttributesList(); + assertSemanticConventionsAttributes( + attributesList, dbSystem, dbUser, dbName, jdbcUrl); + assertSemanticConventionsAttributesForOperation( + attributesList, dbOperation, dbSqlTable); + }); + } + + private void assertSemanticConventionForOperation( + ResourceScopeSpan rss, String dbOperation, String dbName, String dbSqlTable) { + if (dbOperation.equals(DB_CREATE_DATABASE_OPERATION)) { + assertThat(rss.getSpan().getName()).isEqualTo(String.format("%s", dbName)); + } else if (dbOperation.equals(DB_SELECT_OPERATION)) { + assertThat(rss.getSpan().getName()) + .isEqualTo(String.format("%s %s.%s", dbOperation, dbName, dbSqlTable)); + } + } + + protected void assertSemanticConventionsAttributes( + List attributesList, + String dbSystem, + String dbUser, + String dbName, + String jdbcUrl) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.DB_CONNECTION_STRING); + assertThat(attribute.getValue().getStringValue()).isEqualTo(jdbcUrl); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_NAME); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbName); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_USER); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbUser); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SYSTEM); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem); + }); + } + + private void assertSemanticConventionsAttributesForOperation( + List attributesList, String dbOperation, String dbSqlTable) { + if (dbOperation.equals(DB_CREATE_DATABASE_OPERATION)) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(String.format("%s %s", dbOperation.toLowerCase(), CREATE_DB_NAME)); + }); + } else if (dbOperation.equals(DB_SELECT_OPERATION)) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SQL_TABLE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSqlTable); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo( + String.format( + "%s count(*) from %s", dbOperation.toLowerCase(), dbSqlTable)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_OPERATION); + assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation); + }); + } + } + + protected void assertMetricAttributes( + List resourceScopeMetrics, + String method, + String path, + String metricName, + Double expectedSum, + String dbSystem, + String dbOperation, + String type, + String identifier) { + assertThat(resourceScopeMetrics) + .anySatisfy( + metric -> { + assertThat(metric.getMetric().getName()).isEqualTo(metricName); + List dpList = + metric.getMetric().getExponentialHistogram().getDataPointsList(); + assertThat(dpList) + .satisfiesOnlyOnce( + dp -> { + List attributesList = dp.getAttributesList(); + assertThat(attributesList).isNotNull(); + var assertions = + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo("CLIENT"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(String.format("%s /%s", method, path)); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(getApplicationOtelServiceName()); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(dbSystem); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(dbOperation); + }); + if (type != null && identifier != null) { + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(type); + }); + assertions.satisfiesOnlyOnce( + (attribute) -> { + assertThat(attribute.getKey()) + .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); + assertThat(attribute.getValue().getStringValue()) + .isEqualTo(identifier); + }); + } + + if (expectedSum != null) { + double actualSum = dp.getSum(); + switch (metricName) { + case AppSignalsConstants.LATENCY_METRIC: + assertThat(actualSum).isStrictlyBetween(0.0, expectedSum); + break; + default: + assertThat(actualSum).isEqualTo(expectedSum); + } + } + }); + }); + } + protected void assertSuccess( String dbSystem, - DBOperation dbOperation, + String dbOperation, String dbUser, String dbName, String jdbcUrl, String type, String identifier) { - var path = "success/" + dbOperation.name(); + var path = "success/" + dbOperation; var method = "GET"; var otelStatusCode = "STATUS_CODE_UNSET"; var dbSqlTable = "employee"; - var otelApplicationImageName = getApplicationOtelServiceName(); - JdbcOperationTester operationTester = - JdbcOperationTesterProvider.getOperationTester( - dbOperation, dbSystem, dbUser, jdbcUrl, dbName, dbSqlTable); + var response = appClient.get(path).aggregate().join(); assertThat(response.status().isSuccess()).isTrue(); var traces = mockCollectorClient.getTraces(); - operationTester.assertAwsSpanAttributes( - traces, method, path, type, identifier, otelApplicationImageName); - operationTester.assertSemanticConventionsSpanAttributes(traces, otelStatusCode); + assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation, type, identifier); + assertSemanticConventionsSpanAttributes( + traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl); var metrics = mockCollectorClient.getMetrics( @@ -70,38 +337,41 @@ protected void assertSuccess( AppSignalsConstants.LATENCY_METRIC, AppSignalsConstants.ERROR_METRIC, AppSignalsConstants.FAULT_METRIC)); - operationTester.assertMetricAttributes( + assertMetricAttributes( metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); - operationTester.assertMetricAttributes( + identifier); + assertMetricAttributes( metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); - operationTester.assertMetricAttributes( + identifier); + assertMetricAttributes( metrics, method, path, AppSignalsConstants.FAULT_METRIC, 0.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); + identifier); } protected void assertFault( String dbSystem, - DBOperation dbOperation, + String dbOperation, String dbUser, String dbName, String jdbcUrl, @@ -111,17 +381,13 @@ protected void assertFault( var method = "GET"; var otelStatusCode = "STATUS_CODE_ERROR"; var dbSqlTable = "userrr"; - var otelApplicationImageName = getApplicationOtelServiceName(); - JdbcOperationTester operationTester = - JdbcOperationTesterProvider.getOperationTester( - dbOperation, dbSystem, dbUser, jdbcUrl, dbName, dbSqlTable); var response = appClient.get(path).aggregate().join(); assertThat(response.status().isServerError()).isTrue(); var traces = mockCollectorClient.getTraces(); - operationTester.assertAwsSpanAttributes( - traces, method, path, type, identifier, otelApplicationImageName); - operationTester.assertSemanticConventionsSpanAttributes(traces, otelStatusCode); + assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation, type, identifier); + assertSemanticConventionsSpanAttributes( + traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl); var metrics = mockCollectorClient.getMetrics( @@ -129,32 +395,35 @@ protected void assertFault( AppSignalsConstants.LATENCY_METRIC, AppSignalsConstants.ERROR_METRIC, AppSignalsConstants.FAULT_METRIC)); - operationTester.assertMetricAttributes( + assertMetricAttributes( metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); - operationTester.assertMetricAttributes( + identifier); + assertMetricAttributes( metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); - operationTester.assertMetricAttributes( + identifier); + assertMetricAttributes( metrics, method, path, AppSignalsConstants.FAULT_METRIC, 1.0, + dbSystem, + dbOperation, type, - identifier, - otelApplicationImageName); + identifier); } } diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java index e7ba625bff..487874b84c 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcH2Test.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.testcontainers.junit.jupiter.Testcontainers; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -32,14 +31,14 @@ public class JdbcH2Test extends JdbcContractTestBase { private static final String DB_PLATFORM = "org.hibernate.dialect.H2Dialect"; @Test - public void testSuccess() { + public void testSuccessSelect() { assertSuccess( - DB_SYSTEM, DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); + DB_SYSTEM, DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); } @Test - public void testFault() { - assertFault(DB_SYSTEM, DBOperation.SELECT, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); + public void testFaultSelect() { + assertFault(DB_SYSTEM, DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, null, null); } @Override diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java index 98ce0848a3..5fa126e344 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcMySQLTest.java @@ -17,19 +17,15 @@ import java.util.List; import java.util.Map; -import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.lifecycle.Startable; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(Lifecycle.PER_CLASS) @@ -52,16 +48,23 @@ public void afterEach() { mySQLContainer.stop(); } - private static Stream dbOperations() { - return Stream.of(DBOperation.SELECT, DBOperation.CREATE_DATABASE); + @Test + public void testSuccessCreateDatabase() { + assertSuccess( + DB_SYSTEM, + DB_CREATE_DATABASE_OPERATION, + DB_USER, + DB_NAME, + DB_CONNECTION_STRING, + DB_RESOURCE_TYPE, + MYSQL_IDENTIFIER); } - @ParameterizedTest - @MethodSource("dbOperations") - public void testSuccess(DBOperation operation) { + @Test + public void testSuccessSelect() { assertSuccess( DB_SYSTEM, - operation, + DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, @@ -70,10 +73,10 @@ public void testSuccess(DBOperation operation) { } @Test - public void testFault() { + public void testFaultSelect() { assertFault( DB_SYSTEM, - DBOperation.SELECT, + DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java index 0d89a21811..be873d4590 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcPostgresTest.java @@ -17,18 +17,14 @@ import java.util.List; import java.util.Map; -import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.lifecycle.Startable; -import software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -52,16 +48,23 @@ public void afterEach() { postgreSqlContainer.stop(); } - private static Stream dbOperations() { - return Stream.of(DBOperation.SELECT, DBOperation.CREATE_DATABASE); + @Test + public void testSuccessCreateDatabase() { + assertSuccess( + DB_SYSTEM, + DB_CREATE_DATABASE_OPERATION, + DB_USER, + DB_NAME, + DB_CONNECTION_STRING, + DB_RESOURCE_TYPE, + POSTGRES_IDENTIFIER); } - @ParameterizedTest - @MethodSource("dbOperations") - public void testSuccess(DBOperation operation) { + @Test + public void testSuccessSelect() { assertSuccess( DB_SYSTEM, - operation, + DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, @@ -70,10 +73,10 @@ public void testSuccess(DBOperation operation) { } @Test - public void testFault() { + public void testFaultSelect() { assertFault( DB_SYSTEM, - DBOperation.SELECT, + DB_SELECT_OPERATION, DB_USER, DB_NAME, DB_CONNECTION_STRING, diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java deleted file mode 100644 index 164a4bd291..0000000000 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/DBOperation.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; - -public enum DBOperation { - CREATE_DATABASE("CREATE DATABASE", "testdb2"), - SELECT("SELECT", "testdb"); - - DBOperation(String value, String targetDB) { - this.value = value; - this.targetDB = targetDB; - } - - private final String value; - private final String targetDB; - - public String getTargetDB() { - return targetDB; - } - - @Override - public String toString() { - return value; - } -} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java deleted file mode 100644 index 2fdcd6a563..0000000000 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcCreateDatabaseOperationTester.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; - -import static org.assertj.core.api.Assertions.assertThat; -import static software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation.CREATE_DATABASE; - -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; -import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; - -public class JdbcCreateDatabaseOperationTester extends JdbcOperationTester { - - public JdbcCreateDatabaseOperationTester( - String dbSystem, String dbUser, String jdbcUrl, String dbName, String dbTable) { - super(dbSystem, dbUser, jdbcUrl, dbName, CREATE_DATABASE.toString(), dbTable); - } - - @Override - protected void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan) { - assertThat(resourceScopeSpan.getSpan().getName()).isEqualTo(String.format("%s", this.dbName)); - - var attributesList = resourceScopeSpan.getSpan().getAttributesList(); - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo( - String.format( - "%s %s", - CREATE_DATABASE.toString().toLowerCase(), CREATE_DATABASE.getTargetDB())); - }); - } -} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java deleted file mode 100644 index c9b4f7a9fb..0000000000 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTester.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; - -import static io.opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT; -import static org.assertj.core.api.Assertions.assertThat; - -import io.opentelemetry.proto.common.v1.KeyValue; -import io.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint; -import java.util.List; -import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants; -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeMetric; -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; -import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; - -public abstract class JdbcOperationTester { - - protected final String dbSystem; - protected final String dbUser; - protected final String jdbcUrl; - protected final String dbName; - protected final String dbOperation; - protected final String dbTable; - - protected JdbcOperationTester( - String dbSystem, - String dbUser, - String jdbcUrl, - String dbName, - String dbOperation, - String dbTable) { - this.dbSystem = dbSystem; - this.dbUser = dbUser; - this.jdbcUrl = jdbcUrl; - this.dbName = dbName; - this.dbOperation = dbOperation; - this.dbTable = dbTable; - } - - public void assertAwsSpanAttributes( - List resourceScopeSpans, - String method, - String path, - String type, - String identifier, - String applicationOtelServiceName) { - assertThat(resourceScopeSpans) - .satisfiesOnlyOnce( - rss -> { - assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); - var attributesList = rss.getSpan().getAttributesList(); - assertAwsAttributes( - attributesList, method, path, type, identifier, applicationOtelServiceName); - }); - } - - private void assertAwsAttributes( - List attributesList, - String method, - String endpoint, - String type, - String identifier, - String applicationOtelServiceName) { - var assertions = - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(String.format("%s /%s", method, endpoint)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(applicationOtelServiceName); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbSystem); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbOperation); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); - assertThat(attribute.getValue().getStringValue()).isEqualTo("CLIENT"); - }); - if (type != null && identifier != null) { - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(type); - }); - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); - assertThat(attribute.getValue().getStringValue()).isEqualTo(identifier); - }); - } - } - - public void assertSemanticConventionsSpanAttributes( - List resourceScopeSpans, String otelStatusCode) { - assertThat(resourceScopeSpans) - .satisfiesOnlyOnce( - rss -> { - assertOperationSemanticConventions(rss); - assertSemanticConventionsCommon(rss, otelStatusCode); - }); - } - - protected abstract void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan); - - private void assertSemanticConventionsCommon(ResourceScopeSpan rss, String otelStatusCode) { - assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT); - assertThat(rss.getSpan().getStatus().getCode().toString()).isEqualTo(otelStatusCode); - var attributesList = rss.getSpan().getAttributesList(); - assertSemanticConventionsAttributes(attributesList); - } - - protected void assertSemanticConventionsAttributes(List attributesList) { - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.DB_CONNECTION_STRING); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.jdbcUrl); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbName); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_USER); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbUser); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SYSTEM); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbSystem); - }); - } - - public void assertMetricAttributes( - List resourceScopeMetrics, - String method, - String path, - String metricName, - Double expectedSum, - String type, - String identifier, - String applicationOtelServiceName) { - assertThat(resourceScopeMetrics) - .anySatisfy( - metric -> { - assertThat(metric.getMetric().getName()).isEqualTo(metricName); - List dpList = - metric.getMetric().getExponentialHistogram().getDataPointsList(); - assertThat(dpList) - .satisfiesOnlyOnce( - dp -> { - List attributesList = dp.getAttributesList(); - assertThat(attributesList).isNotNull(); - var assertions = - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_SPAN_KIND); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo("CLIENT"); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(String.format("%s /%s", method, path)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(applicationOtelServiceName); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(this.dbSystem); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(this.dbOperation); - }); - if (type != null && identifier != null) { - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_TYPE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(type); - }); - assertions.satisfiesOnlyOnce( - (attribute) -> { - assertThat(attribute.getKey()) - .isEqualTo(AppSignalsConstants.AWS_REMOTE_RESOURCE_IDENTIFIER); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo(identifier); - }); - } - - if (expectedSum != null) { - double actualSum = dp.getSum(); - switch (metricName) { - case AppSignalsConstants.LATENCY_METRIC: - assertThat(actualSum).isStrictlyBetween(0.0, expectedSum); - break; - default: - assertThat(actualSum).isEqualTo(expectedSum); - } - } - }); - }); - } -} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java deleted file mode 100644 index 06fa212323..0000000000 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcOperationTesterProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; - -public class JdbcOperationTesterProvider { - - private JdbcOperationTesterProvider() {} - - public static JdbcOperationTester getOperationTester( - DBOperation operation, - String dbSystem, - String dbUser, - String jdbcUrl, - String dbName, - String dbTable) { - switch (operation) { - case CREATE_DATABASE: - return new JdbcCreateDatabaseOperationTester(dbSystem, dbUser, jdbcUrl, dbName, dbTable); - case SELECT: - return new JdbcSelectOperationTester(dbSystem, dbUser, jdbcUrl, dbName, dbTable); - default: - throw new UnsupportedOperationException("No tests for operation: " + operation); - } - } -} diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java deleted file mode 100644 index b08661ccd2..0000000000 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/operationtests/JdbcSelectOperationTester.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.opentelemetry.appsignals.test.jdbc.operationtests; - -import static org.assertj.core.api.Assertions.assertThat; -import static software.amazon.opentelemetry.appsignals.test.jdbc.operationtests.DBOperation.SELECT; - -import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan; -import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; - -public class JdbcSelectOperationTester extends JdbcOperationTester { - - public JdbcSelectOperationTester( - String dbSystem, String dbUser, String jdbcUrl, String dbName, String dbTable) { - super(dbSystem, dbUser, jdbcUrl, dbName, SELECT.toString(), dbTable); - } - - @Override - protected void assertOperationSemanticConventions(ResourceScopeSpan resourceScopeSpan) { - assertThat(resourceScopeSpan.getSpan().getName()) - .isEqualTo(String.format("%s %s.%s", SELECT, this.dbName, this.dbTable)); - - var attributesList = resourceScopeSpan.getSpan().getAttributesList(); - assertThat(attributesList) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT); - assertThat(attribute.getValue().getStringValue()) - .isEqualTo( - String.format( - "%s count(*) from %s", SELECT.toString().toLowerCase(), this.dbTable)); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SQL_TABLE); - assertThat(attribute.getValue().getStringValue()).isEqualTo(this.dbTable); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_OPERATION); - assertThat(attribute.getValue().getStringValue()).isEqualTo(SELECT.toString()); - }); - } -} diff --git a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java index 8789554862..81b1ff32ec 100644 --- a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java +++ b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java @@ -46,14 +46,10 @@ public void prepareDB() { logger.info("Application Ready"); } - @GetMapping("/success/CREATE_DATABASE") + @GetMapping("/success/CREATE DATABASE") @ResponseBody public ResponseEntity successCreateDatabase() { - try { - jdbcTemplate.execute("create database testdb2"); - } catch (Exception ex) { - return ResponseEntity.badRequest().body("failed"); - } + jdbcTemplate.execute("create database testdb2"); return ResponseEntity.ok().body("success"); }