Skip to content

Commit 60c680c

Browse files
Add contract tests
1 parent 7cd8052 commit 60c680c

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def do_GET(self):
5454
self._handle_stepfunctions_request()
5555
if self.in_path("sns"):
5656
self._handle_sns_request()
57+
if self.in_path("cross-account"):
58+
self._handle_cross_account_request()
5759

5860
self._end_request(self.main_status)
5961

@@ -85,6 +87,23 @@ def do_PUT(self):
8587
def in_path(self, sub_path: str) -> bool:
8688
return sub_path in self.path
8789

90+
def _handle_cross_account_request(self) -> None:
91+
s3_client = boto3.client(
92+
"s3",
93+
endpoint_url=_AWS_SDK_S3_ENDPOINT,
94+
region_name="eu-central-1",
95+
aws_access_key_id="account_b_access_key_id",
96+
aws_secret_access_key="account_b_secret_access_key",
97+
aws_session_token="account_b_token",
98+
)
99+
if self.in_path("createbucket/account_b"):
100+
set_main_status(200)
101+
s3_client.create_bucket(
102+
Bucket="cross-account-bucket", CreateBucketConfiguration={"LocationConstraint": "eu-central-1"}
103+
)
104+
else:
105+
set_main_status(404)
106+
88107
def _handle_s3_request(self) -> None:
89108
s3_client: BaseClient = boto3.client("s3", endpoint_url=_AWS_SDK_S3_ENDPOINT, region_name=_AWS_REGION)
90109
if self.in_path(_ERROR):
@@ -151,6 +170,11 @@ def _handle_ddb_request(self) -> None:
151170
],
152171
BillingMode="PAY_PER_REQUEST",
153172
)
173+
elif self.in_path("describetable/some-table"):
174+
set_main_status(200)
175+
ddb_client.describe_table(
176+
TableName="put_test_table",
177+
)
154178
elif self.in_path("putitem/putitem-table/key"):
155179
set_main_status(200)
156180
item: dict = {"id": {"S": "1"}}
@@ -213,6 +237,11 @@ def _handle_kinesis_request(self) -> None:
213237
elif self.in_path("putrecord/my-stream"):
214238
set_main_status(200)
215239
kinesis_client.put_record(StreamName="test_stream", Data=b"test", PartitionKey="partition_key")
240+
elif self.in_path("describestream/my-stream"):
241+
set_main_status(200)
242+
kinesis_client.describe_stream(
243+
StreamName="test_stream", StreamARN="arn:aws:kinesis:us-west-2:000000000000:stream/test_stream"
244+
)
216245
else:
217246
set_main_status(404)
218247

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

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
AWS_LOCAL_OPERATION,
1717
AWS_LOCAL_SERVICE,
1818
AWS_REMOTE_OPERATION,
19+
AWS_REMOTE_RESOURCE_ACCESS_KEY,
20+
AWS_REMOTE_RESOURCE_ACCOUNT_ID,
1921
AWS_REMOTE_RESOURCE_IDENTIFIER,
22+
AWS_REMOTE_RESOURCE_REGION,
2023
AWS_REMOTE_RESOURCE_TYPE,
2124
AWS_REMOTE_SERVICE,
2225
AWS_SPAN_KIND,
@@ -50,6 +53,8 @@
5053
_AWS_STATE_MACHINE_ARN: str = "aws.stepfunctions.state_machine.arn"
5154
_AWS_ACTIVITY_ARN: str = "aws.stepfunctions.activity.arn"
5255
_AWS_SNS_TOPIC_ARN: str = "aws.sns.topic.arn"
56+
_AWS_DYNAMODB_TABLE_ARN: str = "aws.dynamodb.table.arn"
57+
_AWS_KINESIS_STREAM_ARN: str = "aws.kinesis.stream.arn"
5358

5459

5560
# pylint: disable=too-many-public-methods,too-many-lines
@@ -212,6 +217,29 @@ def test_dynamodb_create_table(self):
212217
span_name="DynamoDB.CreateTable",
213218
)
214219

220+
def test_dynamodb_describe_table(self):
221+
self.do_test_requests(
222+
"ddb/describetable/some-table",
223+
"GET",
224+
200,
225+
0,
226+
0,
227+
remote_service="AWS::DynamoDB",
228+
remote_operation="DescribeTable",
229+
remote_resource_type="AWS::DynamoDB::Table",
230+
remote_resource_identifier="put_test_table",
231+
remote_resource_account_id="000000000000",
232+
remote_resource_region="us-west-2",
233+
cloudformation_primary_identifier="put_test_table",
234+
request_specific_attributes={
235+
SpanAttributes.AWS_DYNAMODB_TABLE_NAMES: ["put_test_table"],
236+
},
237+
response_specific_attributes={
238+
_AWS_DYNAMODB_TABLE_ARN: r"arn:aws:dynamodb:us-west-2:000000000000:table/put_test_table",
239+
},
240+
span_name="DynamoDB.DescribeTable",
241+
)
242+
215243
def test_dynamodb_put_item(self):
216244
self.do_test_requests(
217245
"ddb/putitem/putitem-table/key",
@@ -379,6 +407,26 @@ def test_kinesis_put_record(self):
379407
span_name="Kinesis.PutRecord",
380408
)
381409

410+
def test_kinesis_describe_stream(self):
411+
self.do_test_requests(
412+
"kinesis/describestream/my-stream",
413+
"GET",
414+
200,
415+
0,
416+
0,
417+
remote_service="AWS::Kinesis",
418+
remote_operation="DescribeStream",
419+
remote_resource_type="AWS::Kinesis::Stream",
420+
remote_resource_identifier="test_stream",
421+
cloudformation_primary_identifier="test_stream",
422+
remote_resource_account_id="000000000000",
423+
remote_resource_region="us-west-2",
424+
request_specific_attributes={
425+
_AWS_KINESIS_STREAM_NAME: "test_stream",
426+
},
427+
span_name="Kinesis.DescribeStream",
428+
)
429+
382430
def test_kinesis_error(self):
383431
self.do_test_requests(
384432
"kinesis/error",
@@ -905,6 +953,26 @@ def test_stepfunctions_fault(self):
905953
span_name="SFN.ListStateMachineVersions",
906954
)
907955

956+
def test_cross_account(self):
957+
self.do_test_requests(
958+
"cross-account/createbucket/account_b",
959+
"GET",
960+
200,
961+
0,
962+
0,
963+
remote_service="AWS::S3",
964+
remote_operation="CreateBucket",
965+
remote_resource_type="AWS::S3::Bucket",
966+
remote_resource_identifier="cross-account-bucket",
967+
cloudformation_primary_identifier="cross-account-bucket",
968+
request_specific_attributes={
969+
SpanAttributes.AWS_S3_BUCKET: "cross-account-bucket",
970+
},
971+
remote_resource_access_key="account_b_access_key_id",
972+
remote_resource_region="eu-central-1",
973+
span_name="S3.CreateBucket",
974+
)
975+
908976
# TODO: Add contract test for lambda event source mapping resource
909977

910978
@override
@@ -924,6 +992,9 @@ def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSp
924992
kwargs.get("remote_resource_type", "None"),
925993
kwargs.get("remote_resource_identifier", "None"),
926994
kwargs.get("cloudformation_primary_identifier", "None"),
995+
kwargs.get("remote_resource_account_id", "None"),
996+
kwargs.get("remote_resource_access_key", "None"),
997+
kwargs.get("remote_resource_region", "None"),
927998
)
928999

9291000
def _assert_aws_attributes(
@@ -935,6 +1006,9 @@ def _assert_aws_attributes(
9351006
remote_resource_type: str,
9361007
remote_resource_identifier: str,
9371008
cloudformation_primary_identifier: str,
1009+
remote_resource_account_id: str,
1010+
remote_resource_access_key: str,
1011+
remote_resource_region: str,
9381012
) -> None:
9391013
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
9401014
self._assert_str_attribute(attributes_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
@@ -961,8 +1035,16 @@ def _assert_aws_attributes(
9611035
self._assert_str_attribute(
9621036
attributes_dict, AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER, cloudformation_primary_identifier
9631037
)
964-
# See comment above AWS_LOCAL_OPERATION
965-
self._assert_str_attribute(attributes_dict, AWS_SPAN_KIND, span_kind)
1038+
if remote_resource_account_id != "None":
1039+
assert remote_resource_identifier != "None"
1040+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_ACCOUNT_ID, remote_resource_account_id)
1041+
self.assertIsNone(attributes_dict.get(AWS_REMOTE_RESOURCE_ACCESS_KEY))
1042+
if remote_resource_access_key != "None":
1043+
assert remote_resource_identifier != "None"
1044+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_ACCESS_KEY, remote_resource_access_key)
1045+
self.assertIsNone(attributes_dict.get(AWS_REMOTE_RESOURCE_ACCOUNT_ID))
1046+
if remote_resource_region != "None":
1047+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_REGION, remote_resource_region)
9661048

9671049
@override
9681050
def _assert_semantic_conventions_span_attributes(
@@ -1050,13 +1132,26 @@ def _assert_metric_attributes(
10501132
self._assert_str_attribute(attribute_dict, AWS_SPAN_KIND, "CLIENT")
10511133
remote_resource_type = kwargs.get("remote_resource_type", "None")
10521134
remote_resource_identifier = kwargs.get("remote_resource_identifier", "None")
1135+
remote_resource_account_id = kwargs.get("remote_resource_account_id", "None")
1136+
remote_resource_access_key = kwargs.get("remote_resource_access_key", "None")
1137+
remote_resource_region = kwargs.get("remote_resource_region", "None")
10531138
if remote_resource_type != "None":
10541139
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_TYPE, remote_resource_type)
10551140
if remote_resource_identifier != "None":
10561141
if self._is_valid_regex(remote_resource_identifier):
10571142
self._assert_match_attribute(attribute_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, remote_resource_identifier)
10581143
else:
10591144
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, remote_resource_identifier)
1145+
if remote_resource_account_id != "None":
1146+
assert remote_resource_identifier != "None"
1147+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_ACCOUNT_ID, remote_resource_account_id)
1148+
self.assertIsNone(attribute_dict.get(AWS_REMOTE_RESOURCE_ACCESS_KEY))
1149+
if remote_resource_access_key != "None":
1150+
assert remote_resource_identifier != "None"
1151+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_ACCESS_KEY, remote_resource_access_key)
1152+
self.assertIsNone(attribute_dict.get(AWS_REMOTE_RESOURCE_ACCOUNT_ID))
1153+
if remote_resource_region != "None":
1154+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_REGION, remote_resource_region)
10601155
self.check_sum(metric_name, dependency_dp.sum, expected_sum)
10611156

10621157
attribute_dict: Dict[str, AnyValue] = self._get_attributes_dict(service_dp.attributes)

contract-tests/tests/test/amazon/utils/application_signals_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
AWS_REMOTE_DB_USER: str = "aws.remote.db.user"
2323
AWS_REMOTE_SERVICE: str = "aws.remote.service"
2424
AWS_REMOTE_OPERATION: str = "aws.remote.operation"
25+
AWS_REMOTE_RESOURCE_ACCESS_KEY: str = "aws.remote.resource.account.access_key"
26+
AWS_REMOTE_RESOURCE_ACCOUNT_ID: str = "aws.remote.resource.account.id"
27+
AWS_REMOTE_RESOURCE_REGION: str = "aws.remote.resource.region"
2528
AWS_REMOTE_RESOURCE_TYPE: str = "aws.remote.resource.type"
2629
AWS_REMOTE_RESOURCE_IDENTIFIER: str = "aws.remote.resource.identifier"
2730
AWS_SPAN_KIND: str = "aws.span.kind"

0 commit comments

Comments
 (0)