Skip to content

Commit 78568b2

Browse files
Add contract tests
1 parent 79a5a32 commit 78568b2

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",
@@ -878,6 +926,26 @@ def test_stepfunctions_fault(self):
878926
span_name="SFN.ListStateMachineVersions",
879927
)
880928

929+
def test_cross_account(self):
930+
self.do_test_requests(
931+
"cross-account/createbucket/account_b",
932+
"GET",
933+
200,
934+
0,
935+
0,
936+
remote_service="AWS::S3",
937+
remote_operation="CreateBucket",
938+
remote_resource_type="AWS::S3::Bucket",
939+
remote_resource_identifier="cross-account-bucket",
940+
cloudformation_primary_identifier="cross-account-bucket",
941+
request_specific_attributes={
942+
SpanAttributes.AWS_S3_BUCKET: "cross-account-bucket",
943+
},
944+
remote_resource_access_key="account_b_access_key_id",
945+
remote_resource_region="eu-central-1",
946+
span_name="S3.CreateBucket",
947+
)
948+
881949
# TODO: Add contract test for lambda event source mapping resource
882950

883951
@override
@@ -897,6 +965,9 @@ def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSp
897965
kwargs.get("remote_resource_type", "None"),
898966
kwargs.get("remote_resource_identifier", "None"),
899967
kwargs.get("cloudformation_primary_identifier", "None"),
968+
kwargs.get("remote_resource_account_id", "None"),
969+
kwargs.get("remote_resource_access_key", "None"),
970+
kwargs.get("remote_resource_region", "None"),
900971
)
901972

902973
def _assert_aws_attributes(
@@ -908,6 +979,9 @@ def _assert_aws_attributes(
908979
remote_resource_type: str,
909980
remote_resource_identifier: str,
910981
cloudformation_primary_identifier: str,
982+
remote_resource_account_id: str,
983+
remote_resource_access_key: str,
984+
remote_resource_region: str,
911985
) -> None:
912986
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
913987
self._assert_str_attribute(attributes_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
@@ -934,8 +1008,16 @@ def _assert_aws_attributes(
9341008
self._assert_str_attribute(
9351009
attributes_dict, AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER, cloudformation_primary_identifier
9361010
)
937-
# See comment above AWS_LOCAL_OPERATION
938-
self._assert_str_attribute(attributes_dict, AWS_SPAN_KIND, span_kind)
1011+
if remote_resource_account_id != "None":
1012+
assert remote_resource_identifier != "None"
1013+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_ACCOUNT_ID, remote_resource_account_id)
1014+
self.assertIsNone(attributes_dict.get(AWS_REMOTE_RESOURCE_ACCESS_KEY))
1015+
if remote_resource_access_key != "None":
1016+
assert remote_resource_identifier != "None"
1017+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_ACCESS_KEY, remote_resource_access_key)
1018+
self.assertIsNone(attributes_dict.get(AWS_REMOTE_RESOURCE_ACCOUNT_ID))
1019+
if remote_resource_region != "None":
1020+
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_REGION, remote_resource_region)
9391021

9401022
@override
9411023
def _assert_semantic_conventions_span_attributes(
@@ -1023,13 +1105,26 @@ def _assert_metric_attributes(
10231105
self._assert_str_attribute(attribute_dict, AWS_SPAN_KIND, "CLIENT")
10241106
remote_resource_type = kwargs.get("remote_resource_type", "None")
10251107
remote_resource_identifier = kwargs.get("remote_resource_identifier", "None")
1108+
remote_resource_account_id = kwargs.get("remote_resource_account_id", "None")
1109+
remote_resource_access_key = kwargs.get("remote_resource_access_key", "None")
1110+
remote_resource_region = kwargs.get("remote_resource_region", "None")
10261111
if remote_resource_type != "None":
10271112
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_TYPE, remote_resource_type)
10281113
if remote_resource_identifier != "None":
10291114
if self._is_valid_regex(remote_resource_identifier):
10301115
self._assert_match_attribute(attribute_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, remote_resource_identifier)
10311116
else:
10321117
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, remote_resource_identifier)
1118+
if remote_resource_account_id != "None":
1119+
assert remote_resource_identifier != "None"
1120+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_ACCOUNT_ID, remote_resource_account_id)
1121+
self.assertIsNone(attribute_dict.get(AWS_REMOTE_RESOURCE_ACCESS_KEY))
1122+
if remote_resource_access_key != "None":
1123+
assert remote_resource_identifier != "None"
1124+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_ACCESS_KEY, remote_resource_access_key)
1125+
self.assertIsNone(attribute_dict.get(AWS_REMOTE_RESOURCE_ACCOUNT_ID))
1126+
if remote_resource_region != "None":
1127+
self._assert_str_attribute(attribute_dict, AWS_REMOTE_RESOURCE_REGION, remote_resource_region)
10331128
self.check_sum(metric_name, dependency_dp.sum, expected_sum)
10341129

10351130
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)