Skip to content

Commit 63fcd96

Browse files
committed
add contract tests for SecretsManager
1 parent b33c0d8 commit 63fcd96

File tree

5 files changed

+104
-3
lines changed

5 files changed

+104
-3
lines changed

test/contract-tests/images/applications/TestSimpleApp.AWSSDK.Core/Program.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Amazon.DynamoDBv2;
66
using Amazon.Kinesis;
77
using Amazon.S3;
8+
using Amazon.SecretsManager;
89
using Amazon.SimpleNotificationService;
910
using Amazon.SQS;
1011
using TestSimpleApp.AWSSDK.Core;
@@ -21,6 +22,7 @@
2122
.AddSingleton<IAmazonS3>(provider => new AmazonS3Client(new AmazonS3Config { ServiceURL = "http://localstack:4566", ForcePathStyle = true }))
2223
.AddSingleton<IAmazonSQS>(provider => new AmazonSQSClient(new AmazonSQSConfig { ServiceURL = "http://localstack:4566" }))
2324
.AddSingleton<IAmazonKinesis>(provider => new AmazonKinesisClient(new AmazonKinesisConfig { ServiceURL = "http://localstack:4566" }))
25+
.AddSingleton<IAmazonSecretsManager>(provider => new AmazonSecretsManagerClient(new AmazonSecretsManagerConfig { ServiceURL = "http://localstack:4566" }))
2426
.AddSingleton<IAmazonSimpleNotificationService>(provider => new AmazonSimpleNotificationServiceClient(new AmazonSimpleNotificationServiceConfig { ServiceURL = "http://localstack:4566" }))
2527
// Bedrock services are not supported by localstack, so we mock the API responses on the aws-application-signals-tests-testsimpleapp server.
2628
.AddSingleton<IAmazonBedrock>(provider => new AmazonBedrockClient(new AmazonBedrockConfig { ServiceURL = "http://localhost:8080" }))
@@ -32,17 +34,20 @@
3234
.AddKeyedSingleton<IAmazonS3>("fault-s3", new AmazonS3Client(AmazonClientConfigHelper.CreateConfig<AmazonS3Config>(true)))
3335
.AddKeyedSingleton<IAmazonSQS>("fault-sqs", new AmazonSQSClient(AmazonClientConfigHelper.CreateConfig<AmazonSQSConfig>(true)))
3436
.AddKeyedSingleton<IAmazonKinesis>("fault-kinesis", new AmazonKinesisClient(new AmazonKinesisConfig { ServiceURL = "http://localstack:4566" }))
37+
.AddKeyedSingleton<IAmazonSecretsManager>("fault-secretsmanager", new AmazonSecretsManagerClient(new AmazonSecretsManagerConfig { ServiceURL = "http://localstack:4566" }))
3538
.AddKeyedSingleton<IAmazonSimpleNotificationService>("fault-sns", new AmazonSimpleNotificationServiceClient(new AmazonSimpleNotificationServiceConfig { ServiceURL = "http://localstack:4566" }))
3639
//error client
3740
.AddKeyedSingleton<IAmazonDynamoDB>("error-ddb", new AmazonDynamoDBClient(AmazonClientConfigHelper.CreateConfig<AmazonDynamoDBConfig>()))
3841
.AddKeyedSingleton<IAmazonS3>("error-s3", new AmazonS3Client(AmazonClientConfigHelper.CreateConfig<AmazonS3Config>()))
3942
.AddKeyedSingleton<IAmazonSQS>("error-sqs", new AmazonSQSClient(AmazonClientConfigHelper.CreateConfig<AmazonSQSConfig>()))
4043
.AddKeyedSingleton<IAmazonKinesis>("error-kinesis", new AmazonKinesisClient(new AmazonKinesisConfig { ServiceURL = "http://localstack:4566" }))
44+
.AddKeyedSingleton<IAmazonSecretsManager>("error-secretsmanager", new AmazonSecretsManagerClient(new AmazonSecretsManagerConfig {ServiceURL = "http://localstack:4566" }))
4145
.AddKeyedSingleton<IAmazonSimpleNotificationService>("error-sns", new AmazonSimpleNotificationServiceClient(new AmazonSimpleNotificationServiceConfig { ServiceURL = "http://localstack:4566" }))
4246
.AddSingleton<S3Tests>()
4347
.AddSingleton<DynamoDBTests>()
4448
.AddSingleton<SQSTests>()
4549
.AddSingleton<KinesisTests>()
50+
.AddSingleton<SecretsManagerTests>()
4651
.AddSingleton<SNSTests>()
4752
.AddSingleton<BedrockTests>();
4853

@@ -126,6 +131,14 @@
126131
app.MapGet("kinesis/fault", (KinesisTests kinesis) => kinesis.Fault()).WithName("kinesis-fault").WithOpenApi();
127132
app.MapGet("kinesis/error", (KinesisTests kinesis) => kinesis.Error()).WithName("kinesis-error").WithOpenApi();
128133

134+
app.MapGet("secretsmanager/createsecret/some-secret", (SecretsManagerTests secretsManager) => secretsManager.CreateSecret())
135+
.WithName("create-secret")
136+
.WithOpenApi();
137+
138+
app.MapGet("secretsmanager/getsecretvalue/some-secret", (SecretsManagerTests secretsManager) => secretsManager.GetSecretValue())
139+
.WithName("get-secret-value")
140+
.WithOpenApi();
141+
129142
app.MapGet("sns/createtopic/some-topic", (SNSTests sns) => sns.CreateTopic())
130143
.WithName("create-topic")
131144
.WithOpenApi();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Amazon.SecretsManager;
2+
using Amazon.SecretsManager.Model;
3+
4+
namespace TestSimpleApp.AWSSDK.Core;
5+
6+
public class SecretsManagerTests(
7+
IAmazonSecretsManager secretsManager,
8+
[FromKeyedServices("fault-secretsmanager")] IAmazonSecretsManager faultSecretsManager,
9+
[FromKeyedServices("error-secretsmanager")] IAmazonSecretsManager errorSecretsManager,
10+
ILogger<SecretsManagerTests> logger) : ContractTest(logger)
11+
{
12+
public Task<CreateSecretResponse> CreateSecret()
13+
{
14+
return secretsManager.CreateSecretAsync(new CreateSecretRequest {
15+
Name = "test-secret", SecretString = "{\"key\":\"test\",\"value\":\"test\"}"
16+
});
17+
}
18+
19+
public Task<GetSecretValueResponse> GetSecretValue()
20+
{
21+
return secretsManager.GetSecretValueAsync(new GetSecretValueRequest { SecretId = "test-secret" });
22+
}
23+
24+
protected override Task CreateFault(CancellationToken cancellationToken)
25+
{
26+
return faultSecretsManager.CreateSecretAsync(new CreateSecretRequest { Name = "test-secret" }, cancellationToken);
27+
}
28+
29+
protected override Task CreateError(CancellationToken cancellationToken)
30+
{
31+
return errorSecretsManager.DeleteSecretAsync(new DeleteSecretRequest { SecretId = "arn:aws:us-east-1:000000000000:test-secret-error" });
32+
}
33+
}

test/contract-tests/images/applications/TestSimpleApp.AWSSDK.Core/TestSimpleApp.AWSSDK.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<PackageReference Include="AWSSDK.DynamoDBv2" Version="4.0.0-preview" />
1111
<PackageReference Include="AWSSDK.Kinesis" Version="4.0.0-preview" />
1212
<PackageReference Include="AWSSDK.S3" Version="4.0.0-preview" />
13+
<PackageReference Include="AWSSDK.SecretsManager" Version="4.0.0-preview" />
1314
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="4.0.0-preview" />
1415
<PackageReference Include="AWSSDK.SQS" Version="4.0.0-preview" />
1516
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />

test/contract-tests/tests/test/amazon/awssdk/awssdk_test.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424
_logger: Logger = getLogger(__name__)
2525
_logger.setLevel(INFO)
2626

27-
_AWS_SNS_TOPIC_ARN: str = "aws.sns.topic.arn"
2827
_AWS_SQS_QUEUE_URL: str = "aws.queue_url"
2928
_AWS_SQS_QUEUE_NAME: str = "aws.sqs.queue_name"
3029
_AWS_KINESIS_STREAM_NAME: str = "aws.kinesis.stream_name"
30+
_AWS_SECRETSMANAGER_SECRET_ARN: str = "aws.secretsmanager.secret.arn"
31+
_AWS_SNS_TOPIC_ARN: str = "aws.sns.topic.arn"
3132
_AWS_BEDROCK_GUARDRAIL_ID: str = "aws.bedrock.guardrail.id"
3233
_AWS_BEDROCK_AGENT_ID: str = "aws.bedrock.agent.id"
3334
_AWS_BEDROCK_KNOWLEDGE_BASE_ID: str = "aws.bedrock.knowledge_base.id"
@@ -84,7 +85,7 @@ def set_up_dependency_container(cls):
8485
cls._local_stack: LocalStackContainer = (
8586
LocalStackContainer(image="localstack/localstack:3.0.2")
8687
.with_name("localstack")
87-
.with_services("s3", "sns", "sqs", "dynamodb", "kinesis")
88+
.with_services("s3", "secretsmanager", "sns", "sqs", "dynamodb", "kinesis")
8889
.with_env("DEFAULT_REGION", "us-west-2")
8990
.with_kwargs(network=NETWORK_NAME, networking_config=local_stack_networking_config)
9091
)
@@ -307,6 +308,42 @@ def test_kinesis_error(self):
307308
# span_name="Kinesis.CreateStream",
308309
# )
309310

311+
def test_secretsmanager_create_secret(self):
312+
self.do_test_requests(
313+
"secretsmanager/createsecret/some-secret",
314+
"GET",
315+
200,
316+
0,
317+
0,
318+
rpc_service="Secrets Manager",
319+
remote_service="AWS::SecretsManager",
320+
remote_operation="CreateSecret",
321+
remote_resource_type="AWS::SecretsManager::Secret",
322+
remote_resource_identifier=r"arn:aws:secretsmanager:us-east-1:000000000000:secret:test-secret-[a-zA-Z0-9]{6}$",
323+
request_response_specific_attributes={
324+
_AWS_SECRETSMANAGER_SECRET_ARN: r"arn:aws:secretsmanager:us-east-1:000000000000:secret:test-secret-[a-zA-Z0-9]{6}$",
325+
},
326+
span_name="Secrets Manager.CreateSecret",
327+
)
328+
329+
def test_secretsmanager_get_secret_value(self):
330+
self.do_test_requests(
331+
"secretsmanager/getsecretvalue/some-secret",
332+
"GET",
333+
200,
334+
0,
335+
0,
336+
rpc_service="Secrets Manager",
337+
remote_service="AWS::SecretsManager",
338+
remote_operation="GetSecretValue",
339+
remote_resource_type="AWS::SecretsManager::Secret",
340+
remote_resource_identifier=r"arn:aws:secretsmanager:us-east-1:000000000000:secret:test-secret-[a-zA-Z0-9]{6}$",
341+
request_response_specific_attributes={
342+
_AWS_SECRETSMANAGER_SECRET_ARN: r"arn:aws:secretsmanager:us-east-1:000000000000:secret:test-secret-[a-zA-Z0-9]{6}$",
343+
},
344+
span_name="Secrets Manager.GetSecretValue",
345+
)
346+
310347
def test_sns_create_topic(self):
311348
self.do_test_requests(
312349
"sns/createtopic/some-topic",

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
import time
4+
import re
45
from logging import INFO, Logger, getLogger
56
from typing import Dict, List
67
from unittest import TestCase
@@ -162,11 +163,27 @@ def _get_attributes_dict(self, attributes_list: List[KeyValue]) -> Dict[str, Any
162163
attributes_dict[key] = value
163164
return attributes_dict
164165

166+
def _is_regex(self, value: str) -> bool:
167+
try:
168+
re.compile(value)
169+
return True
170+
except re.error:
171+
return False
172+
165173
def _assert_str_attribute(self, attributes_dict: Dict[str, AnyValue], key: str, expected_value: str):
166174
self.assertIn(key, attributes_dict)
167175
actual_value: AnyValue = attributes_dict[key]
168176
self.assertIsNotNone(actual_value)
169-
self.assertEqual(expected_value, actual_value.string_value)
177+
if self._is_regex(expected_value):
178+
self.assertRegex(actual_value.string_value, expected_value)
179+
else:
180+
self.assertEqual(expected_value, actual_value.string_value)
181+
182+
def _assert_regex_attribute(self, attributes_dict: Dict[str, AnyValue], key: str, expected_value: str):
183+
self.assertIn(key, attributes_dict)
184+
actual_value: AnyValue = attributes_dict[key]
185+
self.assertIsNotNone(actual_value)
186+
self.assertRegex(actual_value.string_value, expected_value)
170187

171188
def _assert_int_attribute(self, attributes_dict: Dict[str, AnyValue], key: str, expected_value: int) -> None:
172189
self.assertIn(key, attributes_dict)

0 commit comments

Comments
 (0)