Skip to content

Commit b4c5c87

Browse files
authored
Merge branch 'main' into update-dockerfile-with-scratch
2 parents 5c758e9 + 912dd93 commit b4c5c87

File tree

13 files changed

+231
-258
lines changed

13 files changed

+231
-258
lines changed

.github/workflows/main_build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ jobs:
102102
# Application Signals specific e2e tests for ec2
103103
application-signals-python-e2e-ec2-test:
104104
needs: [ build ]
105-
uses: aws-observability/aws-application-signals-test-framework/.github/workflows/application-signals-python-e2e-ec2-test.yml@main
105+
uses: aws-observability/aws-application-signals-test-framework/.github/workflows/application-signals-python-e2e-ec2-default-test.yml@main
106106
secrets: inherit
107107
with:
108108
aws-region: ${{ needs.build.outputs.aws_default_region }}

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Contributions via pull requests are much appreciated. Before sending us a pull r
2323
1. You are working against the latest source on the *main* branch.
2424
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
2525
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
26+
4. You are not mixing substantial refactoring changes in with functional changes.
27+
1. If refactoring is desirable, publish a separate refactoring PR first, followed by a functional change PR. This will ensure safe and efficient reviews.
28+
2. PRs that do not meet these expectations will be rejected.
2629

2730
To send us a pull request, please:
2831

@@ -32,6 +35,7 @@ To send us a pull request, please:
3235
4. Commit to your fork using clear commit messages.
3336
5. Send us a pull request, answering any default questions in the pull request interface.
3437
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38+
7. Please do not squash commits between revisions, this makes review challenging, as the diff between revisions is harder to find and review.
3539

3640
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
3741
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).

contract-tests/images/applications/botocore/botocore_server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import requests
1111
from botocore.client import BaseClient
1212
from botocore.config import Config
13-
from typing_extensions import override
13+
from typing_extensions import Tuple, override
1414

1515
_PORT: int = 8080
1616
_ERROR: str = "error"
@@ -253,7 +253,7 @@ def prepare_aws_server() -> None:
253253

254254
def main() -> None:
255255
prepare_aws_server()
256-
server_address: tuple[str, int] = ("0.0.0.0", _PORT)
256+
server_address: Tuple[str, int] = ("0.0.0.0", _PORT)
257257
request_handler_class: type = RequestHandler
258258
requests_server: ThreadingHTTPServer = ThreadingHTTPServer(server_address, request_handler_class)
259259
atexit.register(requests_server.shutdown)

contract-tests/images/applications/pymysql/pymysql_server.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
import pymysql
1010
from typing_extensions import override
1111

12-
_PORT: int = 8080
13-
_SUCCESS: str = "success"
12+
_CREATE_DATABASE: str = "create_database"
13+
_DROP_TABLE: str = "drop_table"
1414
_ERROR: str = "error"
1515
_FAULT: str = "fault"
16+
_PORT: int = 8080
1617

1718
_DB_HOST = os.getenv("DB_HOST")
1819
_DB_USER = os.getenv("DB_USER")
@@ -26,11 +27,17 @@ class RequestHandler(BaseHTTPRequestHandler):
2627
def do_GET(self):
2728
status_code: int = 200
2829
conn = pymysql.connect(host=_DB_HOST, user=_DB_USER, password=_DB_PASS, database=_DB_NAME)
29-
if self.in_path(_SUCCESS):
30+
conn.autocommit = True # CREATE DATABASE cannot run in a transaction block
31+
if self.in_path(_DROP_TABLE):
3032
cur = conn.cursor()
3133
cur.execute("DROP TABLE IF EXISTS test_table")
3234
cur.close()
3335
status_code = 200
36+
elif self.in_path(_CREATE_DATABASE):
37+
cur = conn.cursor()
38+
cur.execute("CREATE DATABASE test_database")
39+
cur.close()
40+
status_code = 200
3441
elif self.in_path(_FAULT):
3542
cur = conn.cursor()
3643
try:

contract-tests/tests/test/amazon/base/contract_test_base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ def get_application_extra_environment_variables(self) -> Dict[str, str]:
193193
def get_application_network_aliases(self) -> List[str]:
194194
return []
195195

196-
def get_application_image_name(self) -> str:
196+
@staticmethod
197+
def get_application_image_name() -> str:
197198
return None
198199

199200
def get_application_wait_pattern(self) -> str:
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
from typing import Dict, List
4+
5+
from mock_collector_client import ResourceScopeMetric, ResourceScopeSpan
6+
from typing_extensions import override
7+
8+
from amazon.base.contract_test_base import ContractTestBase
9+
from amazon.utils.application_signals_constants import (
10+
AWS_LOCAL_OPERATION,
11+
AWS_LOCAL_SERVICE,
12+
AWS_REMOTE_OPERATION,
13+
AWS_REMOTE_RESOURCE_IDENTIFIER,
14+
AWS_REMOTE_RESOURCE_TYPE,
15+
AWS_REMOTE_SERVICE,
16+
AWS_SPAN_KIND,
17+
)
18+
from opentelemetry.proto.common.v1.common_pb2 import AnyValue, KeyValue
19+
from opentelemetry.proto.metrics.v1.metrics_pb2 import ExponentialHistogramDataPoint, Metric
20+
from opentelemetry.proto.trace.v1.trace_pb2 import Span
21+
from opentelemetry.trace import StatusCode
22+
23+
DATABASE_HOST: str = "mydb"
24+
DATABASE_USER: str = "root"
25+
DATABASE_PASSWORD: str = "example"
26+
DATABASE_NAME: str = "testdb"
27+
28+
29+
class DatabaseContractTestBase(ContractTestBase):
30+
@staticmethod
31+
def get_remote_service() -> str:
32+
return None
33+
34+
@staticmethod
35+
def get_database_port() -> int:
36+
return None
37+
38+
def get_remote_resource_identifier(self) -> str:
39+
return f"{DATABASE_NAME}|{DATABASE_HOST}|{self.get_database_port()}"
40+
41+
@override
42+
def get_application_extra_environment_variables(self) -> Dict[str, str]:
43+
return {
44+
"DB_HOST": DATABASE_HOST,
45+
"DB_USER": DATABASE_USER,
46+
"DB_PASS": DATABASE_PASSWORD,
47+
"DB_NAME": DATABASE_NAME,
48+
}
49+
50+
def assert_drop_table_succeeds(self) -> None:
51+
self.mock_collector_client.clear_signals()
52+
self.do_test_requests("drop_table", "GET", 200, 0, 0, sql_command="DROP TABLE")
53+
54+
def assert_create_database_succeeds(self) -> None:
55+
self.mock_collector_client.clear_signals()
56+
self.do_test_requests("create_database", "GET", 200, 0, 0, sql_command="CREATE DATABASE")
57+
58+
def assert_fault(self) -> None:
59+
self.mock_collector_client.clear_signals()
60+
self.do_test_requests("fault", "GET", 500, 0, 1, sql_command="SELECT DISTINCT")
61+
62+
@override
63+
def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSpan], path: str, **kwargs) -> None:
64+
target_spans: List[Span] = []
65+
for resource_scope_span in resource_scope_spans:
66+
# pylint: disable=no-member
67+
if resource_scope_span.span.kind == Span.SPAN_KIND_CLIENT:
68+
target_spans.append(resource_scope_span.span)
69+
70+
self.assertEqual(len(target_spans), 1)
71+
self._assert_aws_attributes(target_spans[0].attributes, **kwargs)
72+
73+
@override
74+
def _assert_semantic_conventions_span_attributes(
75+
self, resource_scope_spans: List[ResourceScopeSpan], method: str, path: str, status_code: int, **kwargs
76+
) -> None:
77+
target_spans: List[Span] = []
78+
for resource_scope_span in resource_scope_spans:
79+
# pylint: disable=no-member
80+
if resource_scope_span.span.kind == Span.SPAN_KIND_CLIENT:
81+
target_spans.append(resource_scope_span.span)
82+
83+
self.assertEqual(target_spans[0].name, kwargs.get("sql_command").split()[0])
84+
if status_code == 200:
85+
self.assertEqual(target_spans[0].status.code, StatusCode.UNSET.value)
86+
else:
87+
self.assertEqual(target_spans[0].status.code, StatusCode.ERROR.value)
88+
89+
self._assert_semantic_conventions_attributes(target_spans[0].attributes, kwargs.get("sql_command"))
90+
91+
def _assert_semantic_conventions_attributes(self, attributes_list: List[KeyValue], command: str) -> None:
92+
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
93+
self.assertTrue(attributes_dict.get("db.statement").string_value.startswith(command))
94+
self._assert_str_attribute(attributes_dict, "db.system", self.get_remote_service())
95+
self._assert_str_attribute(attributes_dict, "db.name", DATABASE_NAME)
96+
self._assert_str_attribute(attributes_dict, "net.peer.name", DATABASE_HOST)
97+
self._assert_int_attribute(attributes_dict, "net.peer.port", self.get_database_port())
98+
self.assertTrue("server.address" not in attributes_dict)
99+
self.assertTrue("server.port" not in attributes_dict)
100+
self.assertTrue("db.operation" not in attributes_dict)
101+
102+
@override
103+
def _assert_aws_attributes(self, attributes_list: List[KeyValue], **kwargs) -> None:
104+
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
105+
self._assert_str_attribute(attributes_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
106+
# InternalOperation as OTEL does not instrument the basic server we are using, so the client span is a local
107+
# root.
108+
self._assert_str_attribute(attributes_dict, AWS_LOCAL_OPERATION, "InternalOperation")
109+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_SERVICE, self.get_remote_service())
110+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_OPERATION, kwargs.get("sql_command"))
111+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_TYPE, "DB::Connection")
112+
self._assert_str_attribute(
113+
attributes_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, self.get_remote_resource_identifier()
114+
)
115+
# See comment above AWS_LOCAL_OPERATION
116+
self._assert_str_attribute(attributes_dict, AWS_SPAN_KIND, "LOCAL_ROOT")
117+
118+
@override
119+
def _assert_metric_attributes(
120+
self, resource_scope_metrics: List[ResourceScopeMetric], metric_name: str, expected_sum: int, **kwargs
121+
) -> None:
122+
target_metrics: List[Metric] = []
123+
for resource_scope_metric in resource_scope_metrics:
124+
if resource_scope_metric.metric.name.lower() == metric_name.lower():
125+
target_metrics.append(resource_scope_metric.metric)
126+
127+
self.assertEqual(len(target_metrics), 1)
128+
target_metric: Metric = target_metrics[0]
129+
dp_list: List[ExponentialHistogramDataPoint] = target_metric.exponential_histogram.data_points
130+
131+
self.assertEqual(len(dp_list), 2)
132+
dependency_dp: ExponentialHistogramDataPoint = dp_list[0]
133+
service_dp: ExponentialHistogramDataPoint = dp_list[1]
134+
if len(dp_list[1].attributes) > len(dp_list[0].attributes):
135+
dependency_dp = dp_list[1]
136+
service_dp = dp_list[0]
137+
attribute_dict: Dict[str, AnyValue] = self._get_attributes_dict(dependency_dp.attributes)
138+
self._assert_str_attribute(attribute_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
139+
# See comment on AWS_LOCAL_OPERATION in _assert_aws_attributes
140+
self._assert_str_attribute(attribute_dict, AWS_LOCAL_OPERATION, "InternalOperation")
141+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_SERVICE, self.get_remote_service())
142+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_OPERATION, kwargs.get("sql_command"))
143+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_TYPE, "DB::Connection")
144+
self._assert_str_attribute(
145+
attribute_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, self.get_remote_resource_identifier()
146+
)
147+
self._assert_str_attribute(attribute_dict, AWS_SPAN_KIND, "CLIENT")
148+
self.check_sum(metric_name, dependency_dp.sum, expected_sum)
149+
150+
attribute_dict: Dict[str, AnyValue] = self._get_attributes_dict(service_dp.attributes)
151+
# See comment on AWS_LOCAL_OPERATION in _assert_aws_attributes
152+
self._assert_str_attribute(attribute_dict, AWS_LOCAL_OPERATION, "InternalOperation")
153+
self._assert_str_attribute(attribute_dict, AWS_SPAN_KIND, "LOCAL_ROOT")
154+
self.check_sum(metric_name, service_dp.sum, expected_sum)

contract-tests/tests/test/amazon/botocore/botocore_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def get_application_network_aliases(self) -> List[str]:
4949
return ["error.test", "fault.test"]
5050

5151
@override
52-
def get_application_image_name(self) -> str:
52+
@staticmethod
53+
def get_application_image_name() -> str:
5354
return "aws-application-signals-tests-botocore-app"
5455

5556
@classmethod

contract-tests/tests/test/amazon/django/django_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
class DjangoTest(ContractTestBase):
1717
@override
18-
def get_application_image_name(self) -> str:
18+
@staticmethod
19+
def get_application_image_name() -> str:
1920
return "aws-application-signals-tests-django-app"
2021

2122
@override

contract-tests/tests/test/amazon/misc/configuration_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818
class ConfigurationTest(ContractTestBase):
1919
@override
20-
def get_application_image_name(self) -> str:
20+
@staticmethod
21+
def get_application_image_name() -> str:
2122
return "aws-application-signals-tests-django-app"
2223

2324
@override

contract-tests/tests/test/amazon/misc/resource_attributes_test_base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def _get_k8s_attributes():
3030

3131
class ResourceAttributesTest(ContractTestBase):
3232
@override
33-
def get_application_image_name(self) -> str:
33+
@staticmethod
34+
def get_application_image_name() -> str:
3435
return "aws-application-signals-tests-django-app"
3536

3637
@override

0 commit comments

Comments
 (0)