Skip to content

Commit 0a1dbff

Browse files
authored
Merge pull request #812 from jerry-shao/main
Adding Application Signals Contract Test for MySQL
2 parents e8f1e8c + 447e93f commit 0a1dbff

File tree

7 files changed

+416
-511
lines changed

7 files changed

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

0 commit comments

Comments
 (0)