Skip to content

Commit f149d05

Browse files
committed
Adding Application Signals Contract Test for MySQL
1 parent e8f1e8c commit f149d05

File tree

7 files changed

+417
-511
lines changed

7 files changed

+417
-511
lines changed

appsignals-tests/contract-tests/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ dependencies {
5858
implementation(project(":appsignals-tests:images:grpc:grpc-base"))
5959
testImplementation("org.testcontainers:kafka:1.19.3")
6060
testImplementation("org.testcontainers:postgresql:1.19.3")
61+
testImplementation("org.testcontainers:mysql:1.19.8")
62+
testImplementation("com.mysql:mysql-connector-j:8.4.0")
6163
}
6264

6365
project.evaluationDependsOn(":otelagent")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.opentelemetry.appsignals.test.jdbc;
17+
18+
import static io.opentelemetry.proto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import io.opentelemetry.proto.common.v1.KeyValue;
22+
import io.opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint;
23+
import io.opentelemetry.proto.trace.v1.Status.StatusCode;
24+
import java.util.List;
25+
import java.util.Set;
26+
import software.amazon.opentelemetry.appsignals.test.base.ContractTestBase;
27+
import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants;
28+
import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeMetric;
29+
import software.amazon.opentelemetry.appsignals.test.utils.ResourceScopeSpan;
30+
import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants;
31+
32+
public class JdbcContractTestBase extends ContractTestBase {
33+
protected static final String DB_NAME = "testdb";
34+
protected static final String DB_USER = "sa";
35+
protected static final String DB_PASSWORD = "password";
36+
protected static final String DB_OPERATION = "SELECT";
37+
38+
@Override
39+
protected String getApplicationImageName() {
40+
return "aws-appsignals-tests-jdbc-app";
41+
}
42+
43+
@Override
44+
protected String getApplicationWaitPattern() {
45+
return ".*Application Ready.*";
46+
}
47+
48+
protected void assertAwsSpanAttributes(
49+
List<ResourceScopeSpan> resourceScopeSpans,
50+
String method,
51+
String path,
52+
String dbSystem,
53+
String dbOperation) {
54+
assertThat(resourceScopeSpans)
55+
.satisfiesOnlyOnce(
56+
rss -> {
57+
assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT);
58+
var attributesList = rss.getSpan().getAttributesList();
59+
assertAwsAttributes(attributesList, method, path, dbSystem, dbOperation);
60+
});
61+
}
62+
63+
protected void assertAwsAttributes(
64+
List<KeyValue> attributesList,
65+
String method,
66+
String endpoint,
67+
String dbSystem,
68+
String dbOperation) {
69+
assertThat(attributesList)
70+
.satisfiesOnlyOnce(
71+
attribute -> {
72+
assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION);
73+
assertThat(attribute.getValue().getStringValue())
74+
.isEqualTo(String.format("%s /%s", method, endpoint));
75+
})
76+
.satisfiesOnlyOnce(
77+
attribute -> {
78+
assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE);
79+
assertThat(attribute.getValue().getStringValue())
80+
.isEqualTo(getApplicationOtelServiceName());
81+
})
82+
.satisfiesOnlyOnce(
83+
attribute -> {
84+
assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE);
85+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem);
86+
})
87+
.satisfiesOnlyOnce(
88+
attribute -> {
89+
assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION);
90+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation);
91+
})
92+
.satisfiesOnlyOnce(
93+
attribute -> {
94+
assertThat(attribute.getKey()).isEqualTo(AppSignalsConstants.AWS_SPAN_KIND);
95+
assertThat(attribute.getValue().getStringValue()).isEqualTo("CLIENT");
96+
});
97+
}
98+
99+
protected void assertSemanticConventionsSpanAttributes(
100+
List<ResourceScopeSpan> resourceScopeSpans,
101+
StatusCode otelStatusCode,
102+
String dbSqlTable,
103+
String dbSystem,
104+
String dbOperation,
105+
String dbUser,
106+
String dbName,
107+
String jdbcUrl) {
108+
assertThat(resourceScopeSpans)
109+
.satisfiesOnlyOnce(
110+
rss -> {
111+
assertThat(rss.getSpan().getKind()).isEqualTo(SPAN_KIND_CLIENT);
112+
assertThat(rss.getSpan().getName())
113+
.isEqualTo(String.format("%s %s.%s", dbOperation, dbName, dbSqlTable));
114+
assertThat(rss.getSpan().getStatus().getCode()).isEqualTo(otelStatusCode);
115+
var attributesList = rss.getSpan().getAttributesList();
116+
assertSemanticConventionsAttributes(
117+
attributesList, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl);
118+
});
119+
}
120+
121+
protected void assertSemanticConventionsAttributes(
122+
List<KeyValue> attributesList,
123+
String dbSqlTable,
124+
String dbSystem,
125+
String dbOperation,
126+
String dbUser,
127+
String dbName,
128+
String jdbcUrl) {
129+
assertThat(attributesList)
130+
.satisfiesOnlyOnce(
131+
attribute -> {
132+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID);
133+
})
134+
.satisfiesOnlyOnce(
135+
attribute -> {
136+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME);
137+
})
138+
.satisfiesOnlyOnce(
139+
attribute -> {
140+
assertThat(attribute.getKey())
141+
.isEqualTo(SemanticConventionsConstants.DB_CONNECTION_STRING);
142+
assertThat(attribute.getValue().getStringValue()).isEqualTo(jdbcUrl);
143+
})
144+
.satisfiesOnlyOnce(
145+
attribute -> {
146+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_NAME);
147+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbName);
148+
})
149+
.satisfiesOnlyOnce(
150+
attribute -> {
151+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SQL_TABLE);
152+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSqlTable);
153+
})
154+
.satisfiesOnlyOnce(
155+
attribute -> {
156+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_STATEMENT);
157+
assertThat(attribute.getValue().getStringValue())
158+
.isEqualTo(
159+
String.format("%s count(*) from %s", dbOperation.toLowerCase(), dbSqlTable));
160+
})
161+
.satisfiesOnlyOnce(
162+
attribute -> {
163+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_USER);
164+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbUser);
165+
})
166+
.satisfiesOnlyOnce(
167+
attribute -> {
168+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_OPERATION);
169+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbOperation);
170+
})
171+
.satisfiesOnlyOnce(
172+
attribute -> {
173+
assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.DB_SYSTEM);
174+
assertThat(attribute.getValue().getStringValue()).isEqualTo(dbSystem);
175+
});
176+
}
177+
178+
protected void assertMetricAttributes(
179+
List<ResourceScopeMetric> resourceScopeMetrics,
180+
String method,
181+
String path,
182+
String metricName,
183+
Double expectedSum,
184+
String dbSystem,
185+
String dbOperation) {
186+
assertThat(resourceScopeMetrics)
187+
.anySatisfy(
188+
metric -> {
189+
assertThat(metric.getMetric().getName()).isEqualTo(metricName);
190+
List<ExponentialHistogramDataPoint> dpList =
191+
metric.getMetric().getExponentialHistogram().getDataPointsList();
192+
assertThat(dpList)
193+
.satisfiesOnlyOnce(
194+
dp -> {
195+
List<KeyValue> attributesList = dp.getAttributesList();
196+
assertThat(attributesList).isNotNull();
197+
assertThat(attributesList)
198+
.satisfiesOnlyOnce(
199+
attribute -> {
200+
assertThat(attribute.getKey())
201+
.isEqualTo(AppSignalsConstants.AWS_SPAN_KIND);
202+
assertThat(attribute.getValue().getStringValue())
203+
.isEqualTo("CLIENT");
204+
})
205+
.satisfiesOnlyOnce(
206+
attribute -> {
207+
assertThat(attribute.getKey())
208+
.isEqualTo(AppSignalsConstants.AWS_LOCAL_OPERATION);
209+
assertThat(attribute.getValue().getStringValue())
210+
.isEqualTo(String.format("%s /%s", method, path));
211+
})
212+
.satisfiesOnlyOnce(
213+
attribute -> {
214+
assertThat(attribute.getKey())
215+
.isEqualTo(AppSignalsConstants.AWS_LOCAL_SERVICE);
216+
assertThat(attribute.getValue().getStringValue())
217+
.isEqualTo(getApplicationOtelServiceName());
218+
})
219+
.satisfiesOnlyOnce(
220+
attribute -> {
221+
assertThat(attribute.getKey())
222+
.isEqualTo(AppSignalsConstants.AWS_REMOTE_SERVICE);
223+
assertThat(attribute.getValue().getStringValue())
224+
.isEqualTo(dbSystem);
225+
})
226+
.satisfiesOnlyOnce(
227+
attribute -> {
228+
assertThat(attribute.getKey())
229+
.isEqualTo(AppSignalsConstants.AWS_REMOTE_OPERATION);
230+
assertThat(attribute.getValue().getStringValue())
231+
.isEqualTo(dbOperation);
232+
});
233+
234+
if (expectedSum != null) {
235+
double actualSum = dp.getSum();
236+
switch (metricName) {
237+
case AppSignalsConstants.LATENCY_METRIC:
238+
assertThat(actualSum).isStrictlyBetween(0.0, expectedSum);
239+
break;
240+
default:
241+
assertThat(actualSum).isEqualTo(expectedSum);
242+
}
243+
}
244+
});
245+
});
246+
}
247+
248+
protected void assertSuccess(
249+
String dbSystem, String dbOperation, String dbUser, String dbName, String jdbcUrl) {
250+
var path = "success";
251+
var method = "GET";
252+
var otelStatusCode = StatusCode.STATUS_CODE_UNSET;
253+
var dbSqlTable = "employee";
254+
255+
var response = appClient.get(path).aggregate().join();
256+
assertThat(response.status().isSuccess()).isTrue();
257+
258+
var traces = mockCollectorClient.getTraces();
259+
assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation);
260+
assertSemanticConventionsSpanAttributes(
261+
traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl);
262+
263+
var metrics =
264+
mockCollectorClient.getMetrics(
265+
Set.of(
266+
AppSignalsConstants.LATENCY_METRIC,
267+
AppSignalsConstants.ERROR_METRIC,
268+
AppSignalsConstants.FAULT_METRIC));
269+
assertMetricAttributes(
270+
metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, dbSystem, dbOperation);
271+
assertMetricAttributes(
272+
metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, dbSystem, dbOperation);
273+
assertMetricAttributes(
274+
metrics, method, path, AppSignalsConstants.FAULT_METRIC, 0.0, dbSystem, dbOperation);
275+
}
276+
277+
protected void assertFault(
278+
String dbSystem, String dbOperation, String dbUser, String dbName, String jdbcUrl) {
279+
var path = "fault";
280+
var method = "GET";
281+
var otelStatusCode = StatusCode.STATUS_CODE_ERROR;
282+
var dbSqlTable = "userrr";
283+
var response = appClient.get(path).aggregate().join();
284+
assertThat(response.status().isServerError()).isTrue();
285+
286+
var traces = mockCollectorClient.getTraces();
287+
assertAwsSpanAttributes(traces, method, path, dbSystem, dbOperation);
288+
assertSemanticConventionsSpanAttributes(
289+
traces, otelStatusCode, dbSqlTable, dbSystem, dbOperation, dbUser, dbName, jdbcUrl);
290+
291+
var metrics =
292+
mockCollectorClient.getMetrics(
293+
Set.of(
294+
AppSignalsConstants.LATENCY_METRIC,
295+
AppSignalsConstants.ERROR_METRIC,
296+
AppSignalsConstants.FAULT_METRIC));
297+
assertMetricAttributes(
298+
metrics, method, path, AppSignalsConstants.LATENCY_METRIC, 5000.0, dbSystem, dbOperation);
299+
assertMetricAttributes(
300+
metrics, method, path, AppSignalsConstants.ERROR_METRIC, 0.0, dbSystem, dbOperation);
301+
assertMetricAttributes(
302+
metrics, method, path, AppSignalsConstants.FAULT_METRIC, 1.0, dbSystem, dbOperation);
303+
}
304+
}

0 commit comments

Comments
 (0)