testcontainers-aws 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- testcontainers_aws/__init__.py +12 -0
- testcontainers_aws/core.py +261 -0
- testcontainers_aws/fixtures.py +291 -0
- testcontainers_aws/services/__init__.py +17 -0
- testcontainers_aws/services/base.py +25 -0
- testcontainers_aws/services/dynamodb.py +168 -0
- testcontainers_aws/services/kinesis.py +181 -0
- testcontainers_aws/services/lambda_service.py +334 -0
- testcontainers_aws/services/s3.py +104 -0
- testcontainers_aws/services/sns.py +307 -0
- testcontainers_aws/services/sqs.py +167 -0
- testcontainers_aws-0.1.0.dist-info/METADATA +576 -0
- testcontainers_aws-0.1.0.dist-info/RECORD +16 -0
- testcontainers_aws-0.1.0.dist-info/WHEEL +5 -0
- testcontainers_aws-0.1.0.dist-info/licenses/LICENSE +20 -0
- testcontainers_aws-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
testcontainers-aws: Simplified AWS service testing with Testcontainers
|
|
3
|
+
|
|
4
|
+
Provides easy-to-use abstractions for testing AWS services using Testcontainers
|
|
5
|
+
and LocalStack. Automatically handles container lifecycle, service initialization,
|
|
6
|
+
and boto3 client configuration.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from testcontainers_aws.core import AWSTestEnvironment
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.0"
|
|
12
|
+
__all__ = ["AWSTestEnvironment"]
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Core AWS test environment orchestration."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Any
|
|
4
|
+
import boto3
|
|
5
|
+
from testcontainers.localstack import LocalStackContainer
|
|
6
|
+
|
|
7
|
+
from testcontainers_aws.services.s3 import S3ServiceManager
|
|
8
|
+
from testcontainers_aws.services.dynamodb import DynamoDBServiceManager
|
|
9
|
+
from testcontainers_aws.services.sqs import SQSServiceManager
|
|
10
|
+
from testcontainers_aws.services.kinesis import KinesisServiceManager
|
|
11
|
+
from testcontainers_aws.services.lambda_service import LambdaServiceManager
|
|
12
|
+
from testcontainers_aws.services.sns import SNSServiceManager
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AWSTestEnvironment:
|
|
16
|
+
"""
|
|
17
|
+
Orchestrates AWS services for testing using LocalStack.
|
|
18
|
+
|
|
19
|
+
Provides a unified interface to spin up and configure multiple AWS services
|
|
20
|
+
in a single container, with automatic boto3 client configuration and
|
|
21
|
+
helper methods for common testing operations.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
```python
|
|
25
|
+
with AWSTestEnvironment(services=['s3', 'dynamodb']) as aws:
|
|
26
|
+
s3 = aws.get_s3_client()
|
|
27
|
+
dynamodb = aws.get_dynamodb_client()
|
|
28
|
+
|
|
29
|
+
# Use clients for testing
|
|
30
|
+
s3.create_bucket(Bucket='test-bucket')
|
|
31
|
+
```
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Map service names to LocalStack service strings
|
|
35
|
+
SERVICE_MAP = {
|
|
36
|
+
's3': 's3',
|
|
37
|
+
'dynamodb': 'dynamodb',
|
|
38
|
+
'sqs': 'sqs',
|
|
39
|
+
'sns': 'sns',
|
|
40
|
+
'kinesis': 'kinesis',
|
|
41
|
+
'lambda': 'lambda',
|
|
42
|
+
'logs': 'logs',
|
|
43
|
+
'cloudformation': 'cloudformation',
|
|
44
|
+
'iam': 'iam',
|
|
45
|
+
'sts': 'sts',
|
|
46
|
+
'ssm': 'ssm',
|
|
47
|
+
'secretsmanager': 'secretsmanager',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
services: Optional[List[str]] = None,
|
|
53
|
+
init_config: Optional[Dict[str, Any]] = None,
|
|
54
|
+
image_tag: str = "latest",
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
Initialize AWS test environment.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
services: List of AWS services to enable (e.g., ['s3', 'dynamodb']).
|
|
61
|
+
If None, all common services are enabled.
|
|
62
|
+
init_config: Configuration for initializing resources (buckets, tables, etc.)
|
|
63
|
+
image_tag: LocalStack Docker image tag (default: 'latest')
|
|
64
|
+
"""
|
|
65
|
+
self.services = services or ['s3', 'dynamodb', 'sqs', 'kinesis']
|
|
66
|
+
self.init_config = init_config or {}
|
|
67
|
+
self.image_tag = image_tag
|
|
68
|
+
|
|
69
|
+
self._container: Optional[LocalStackContainer] = None
|
|
70
|
+
self._clients: Dict[str, Any] = {}
|
|
71
|
+
self._service_managers: Dict[str, Any] = {}
|
|
72
|
+
|
|
73
|
+
def __enter__(self) -> 'AWSTestEnvironment':
|
|
74
|
+
"""Start the container and initialize services."""
|
|
75
|
+
self.start()
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
79
|
+
"""Stop the container and cleanup."""
|
|
80
|
+
self.stop()
|
|
81
|
+
|
|
82
|
+
def start(self) -> None:
|
|
83
|
+
"""Start LocalStack container and initialize configured services."""
|
|
84
|
+
# Convert service names to LocalStack service strings
|
|
85
|
+
localstack_services = [self.SERVICE_MAP.get(s, s) for s in self.services]
|
|
86
|
+
|
|
87
|
+
# Create and start LocalStack container
|
|
88
|
+
self._container = LocalStackContainer(
|
|
89
|
+
image=f"localstack/localstack:{self.image_tag}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Set services to enable
|
|
93
|
+
for service in localstack_services:
|
|
94
|
+
self._container = self._container.with_services(service)
|
|
95
|
+
|
|
96
|
+
self._container.start()
|
|
97
|
+
|
|
98
|
+
# Initialize service managers
|
|
99
|
+
self._init_service_managers()
|
|
100
|
+
|
|
101
|
+
# Run initialization tasks
|
|
102
|
+
self._initialize_resources()
|
|
103
|
+
|
|
104
|
+
def stop(self) -> None:
|
|
105
|
+
"""Stop the LocalStack container."""
|
|
106
|
+
if self._container:
|
|
107
|
+
self._container.stop()
|
|
108
|
+
self._container = None
|
|
109
|
+
self._clients.clear()
|
|
110
|
+
self._service_managers.clear()
|
|
111
|
+
|
|
112
|
+
def _init_service_managers(self) -> None:
|
|
113
|
+
"""Initialize service manager instances."""
|
|
114
|
+
if 's3' in self.services:
|
|
115
|
+
self._service_managers['s3'] = S3ServiceManager(self)
|
|
116
|
+
|
|
117
|
+
if 'dynamodb' in self.services:
|
|
118
|
+
self._service_managers['dynamodb'] = DynamoDBServiceManager(self)
|
|
119
|
+
|
|
120
|
+
if 'sqs' in self.services:
|
|
121
|
+
self._service_managers['sqs'] = SQSServiceManager(self)
|
|
122
|
+
|
|
123
|
+
if 'kinesis' in self.services:
|
|
124
|
+
self._service_managers['kinesis'] = KinesisServiceManager(self)
|
|
125
|
+
|
|
126
|
+
if 'lambda' in self.services:
|
|
127
|
+
self._service_managers['lambda'] = LambdaServiceManager(self)
|
|
128
|
+
|
|
129
|
+
if 'sns' in self.services:
|
|
130
|
+
self._service_managers['sns'] = SNSServiceManager(self)
|
|
131
|
+
|
|
132
|
+
def _initialize_resources(self) -> None:
|
|
133
|
+
"""Initialize AWS resources based on init_config."""
|
|
134
|
+
# Initialize S3 buckets
|
|
135
|
+
if 's3_buckets' in self.init_config and 's3' in self._service_managers:
|
|
136
|
+
for bucket in self.init_config['s3_buckets']:
|
|
137
|
+
if isinstance(bucket, str):
|
|
138
|
+
self._service_managers['s3'].create_bucket(bucket)
|
|
139
|
+
elif isinstance(bucket, dict):
|
|
140
|
+
self._service_managers['s3'].create_bucket(**bucket)
|
|
141
|
+
|
|
142
|
+
# Initialize DynamoDB tables
|
|
143
|
+
if 'dynamodb_tables' in self.init_config and 'dynamodb' in self._service_managers:
|
|
144
|
+
for table in self.init_config['dynamodb_tables']:
|
|
145
|
+
self._service_managers['dynamodb'].create_table(**table)
|
|
146
|
+
|
|
147
|
+
# Initialize SQS queues
|
|
148
|
+
if 'sqs_queues' in self.init_config and 'sqs' in self._service_managers:
|
|
149
|
+
for queue in self.init_config['sqs_queues']:
|
|
150
|
+
if isinstance(queue, str):
|
|
151
|
+
self._service_managers['sqs'].create_queue(queue)
|
|
152
|
+
elif isinstance(queue, dict):
|
|
153
|
+
self._service_managers['sqs'].create_queue(**queue)
|
|
154
|
+
|
|
155
|
+
# Initialize Kinesis streams
|
|
156
|
+
if 'kinesis_streams' in self.init_config and 'kinesis' in self._service_managers:
|
|
157
|
+
for stream in self.init_config['kinesis_streams']:
|
|
158
|
+
if isinstance(stream, str):
|
|
159
|
+
self._service_managers['kinesis'].create_stream(stream)
|
|
160
|
+
elif isinstance(stream, dict):
|
|
161
|
+
self._service_managers['kinesis'].create_stream(**stream)
|
|
162
|
+
|
|
163
|
+
# Initialize SNS topics
|
|
164
|
+
if 'sns_topics' in self.init_config and 'sns' in self._service_managers:
|
|
165
|
+
for topic in self.init_config['sns_topics']:
|
|
166
|
+
if isinstance(topic, str):
|
|
167
|
+
self._service_managers['sns'].create_topic(topic)
|
|
168
|
+
elif isinstance(topic, dict):
|
|
169
|
+
self._service_managers['sns'].create_topic(**topic)
|
|
170
|
+
|
|
171
|
+
# Initialize Lambda functions
|
|
172
|
+
if 'lambda_functions' in self.init_config and 'lambda' in self._service_managers:
|
|
173
|
+
for function in self.init_config['lambda_functions']:
|
|
174
|
+
self._service_managers['lambda'].create_function(**function)
|
|
175
|
+
|
|
176
|
+
def get_client(self, service_name: str) -> Any:
|
|
177
|
+
"""
|
|
178
|
+
Get a boto3 client for the specified AWS service.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
service_name: AWS service name (e.g., 's3', 'dynamodb')
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Configured boto3 client for the service
|
|
185
|
+
"""
|
|
186
|
+
if service_name not in self._clients:
|
|
187
|
+
if not self._container:
|
|
188
|
+
raise RuntimeError("Container not started. Use 'with' statement or call start().")
|
|
189
|
+
|
|
190
|
+
endpoint_url = self._container.get_url()
|
|
191
|
+
|
|
192
|
+
self._clients[service_name] = boto3.client(
|
|
193
|
+
service_name,
|
|
194
|
+
endpoint_url=endpoint_url,
|
|
195
|
+
aws_access_key_id='test',
|
|
196
|
+
aws_secret_access_key='test',
|
|
197
|
+
region_name='us-east-1',
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return self._clients[service_name]
|
|
201
|
+
|
|
202
|
+
def get_s3_client(self):
|
|
203
|
+
"""Get pre-configured S3 client."""
|
|
204
|
+
return self.get_client('s3')
|
|
205
|
+
|
|
206
|
+
def get_dynamodb_client(self):
|
|
207
|
+
"""Get pre-configured DynamoDB client."""
|
|
208
|
+
return self.get_client('dynamodb')
|
|
209
|
+
|
|
210
|
+
def get_sqs_client(self):
|
|
211
|
+
"""Get pre-configured SQS client."""
|
|
212
|
+
return self.get_client('sqs')
|
|
213
|
+
|
|
214
|
+
def get_kinesis_client(self):
|
|
215
|
+
"""Get pre-configured Kinesis client."""
|
|
216
|
+
return self.get_client('kinesis')
|
|
217
|
+
|
|
218
|
+
def get_sns_client(self):
|
|
219
|
+
"""Get pre-configured SNS client."""
|
|
220
|
+
return self.get_client('sns')
|
|
221
|
+
|
|
222
|
+
def get_lambda_client(self):
|
|
223
|
+
"""Get pre-configured Lambda client."""
|
|
224
|
+
return self.get_client('lambda')
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def s3(self):
|
|
228
|
+
"""Access S3 service manager with helper methods."""
|
|
229
|
+
return self._service_managers.get('s3')
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def dynamodb(self):
|
|
233
|
+
"""Access DynamoDB service manager with helper methods."""
|
|
234
|
+
return self._service_managers.get('dynamodb')
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def sqs(self):
|
|
238
|
+
"""Access SQS service manager with helper methods."""
|
|
239
|
+
return self._service_managers.get('sqs')
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def kinesis(self):
|
|
243
|
+
"""Access Kinesis service manager with helper methods."""
|
|
244
|
+
return self._service_managers.get('kinesis')
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def lambda_(self):
|
|
248
|
+
"""Access Lambda service manager with helper methods."""
|
|
249
|
+
return self._service_managers.get('lambda')
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def sns(self):
|
|
253
|
+
"""Access SNS service manager with helper methods."""
|
|
254
|
+
return self._service_managers.get('sns')
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def endpoint_url(self) -> str:
|
|
258
|
+
"""Get the LocalStack endpoint URL."""
|
|
259
|
+
if not self._container:
|
|
260
|
+
raise RuntimeError("Container not started")
|
|
261
|
+
return self._container.get_url()
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Pytest fixtures for AWS testing with testcontainers."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from testcontainers_aws.core import AWSTestEnvironment
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture(scope='session')
|
|
8
|
+
def aws_environment():
|
|
9
|
+
"""
|
|
10
|
+
Session-scoped AWS test environment with common services.
|
|
11
|
+
|
|
12
|
+
Provides S3, DynamoDB, SQS, Kinesis, Lambda, and SNS services. The container is
|
|
13
|
+
shared across all tests in the session for performance.
|
|
14
|
+
|
|
15
|
+
Yields:
|
|
16
|
+
AWSTestEnvironment: Configured AWS environment
|
|
17
|
+
"""
|
|
18
|
+
with AWSTestEnvironment(services=['s3', 'dynamodb', 'sqs', 'kinesis', 'lambda', 'sns']) as aws:
|
|
19
|
+
yield aws
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture(scope='function')
|
|
23
|
+
def aws_environment_function():
|
|
24
|
+
"""
|
|
25
|
+
Function-scoped AWS test environment with common services.
|
|
26
|
+
|
|
27
|
+
Provides S3, DynamoDB, SQS, Kinesis, Lambda, and SNS services. A fresh container
|
|
28
|
+
is created for each test function for complete isolation.
|
|
29
|
+
|
|
30
|
+
Yields:
|
|
31
|
+
AWSTestEnvironment: Configured AWS environment
|
|
32
|
+
"""
|
|
33
|
+
with AWSTestEnvironment(services=['s3', 'dynamodb', 'sqs', 'kinesis', 'lambda', 'sns']) as aws:
|
|
34
|
+
yield aws
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture(scope='session')
|
|
38
|
+
def s3_client(aws_environment):
|
|
39
|
+
"""
|
|
40
|
+
Session-scoped S3 client.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
aws_environment: AWS environment fixture
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
boto3 S3 client configured for LocalStack
|
|
47
|
+
"""
|
|
48
|
+
return aws_environment.get_s3_client()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.fixture(scope='session')
|
|
52
|
+
def dynamodb_client(aws_environment):
|
|
53
|
+
"""
|
|
54
|
+
Session-scoped DynamoDB client.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
aws_environment: AWS environment fixture
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
boto3 DynamoDB client configured for LocalStack
|
|
61
|
+
"""
|
|
62
|
+
return aws_environment.get_dynamodb_client()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.fixture(scope='session')
|
|
66
|
+
def sqs_client(aws_environment):
|
|
67
|
+
"""
|
|
68
|
+
Session-scoped SQS client.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
aws_environment: AWS environment fixture
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
boto3 SQS client configured for LocalStack
|
|
75
|
+
"""
|
|
76
|
+
return aws_environment.get_sqs_client()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.fixture(scope='session')
|
|
80
|
+
def kinesis_client(aws_environment):
|
|
81
|
+
"""
|
|
82
|
+
Session-scoped Kinesis client.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
aws_environment: AWS environment fixture
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
boto3 Kinesis client configured for LocalStack
|
|
89
|
+
"""
|
|
90
|
+
return aws_environment.get_kinesis_client()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.fixture(scope='session')
|
|
94
|
+
def lambda_client(aws_environment):
|
|
95
|
+
"""
|
|
96
|
+
Session-scoped Lambda client.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
aws_environment: AWS environment fixture
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
boto3 Lambda client configured for LocalStack
|
|
103
|
+
"""
|
|
104
|
+
return aws_environment.get_lambda_client()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@pytest.fixture(scope='session')
|
|
108
|
+
def sns_client(aws_environment):
|
|
109
|
+
"""
|
|
110
|
+
Session-scoped SNS client.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
aws_environment: AWS environment fixture
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
boto3 SNS client configured for LocalStack
|
|
117
|
+
"""
|
|
118
|
+
return aws_environment.get_sns_client()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@pytest.fixture
|
|
122
|
+
def s3_bucket(aws_environment):
|
|
123
|
+
"""
|
|
124
|
+
Function-scoped S3 bucket that's automatically cleaned up.
|
|
125
|
+
|
|
126
|
+
Creates a test bucket and removes it after the test completes.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
aws_environment: AWS environment fixture
|
|
130
|
+
|
|
131
|
+
Yields:
|
|
132
|
+
str: Bucket name
|
|
133
|
+
"""
|
|
134
|
+
bucket_name = 'test-bucket'
|
|
135
|
+
aws_environment.s3.create_bucket(bucket_name)
|
|
136
|
+
|
|
137
|
+
yield bucket_name
|
|
138
|
+
|
|
139
|
+
# Cleanup
|
|
140
|
+
try:
|
|
141
|
+
aws_environment.s3.delete_bucket(bucket_name, force=True)
|
|
142
|
+
except Exception:
|
|
143
|
+
pass # Bucket might already be deleted
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@pytest.fixture
|
|
147
|
+
def dynamodb_table(aws_environment):
|
|
148
|
+
"""
|
|
149
|
+
Function-scoped DynamoDB table that's automatically cleaned up.
|
|
150
|
+
|
|
151
|
+
Creates a test table with a simple schema and removes it after the test.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
aws_environment: AWS environment fixture
|
|
155
|
+
|
|
156
|
+
Yields:
|
|
157
|
+
str: Table name
|
|
158
|
+
"""
|
|
159
|
+
table_name = 'test-table'
|
|
160
|
+
aws_environment.dynamodb.create_table(
|
|
161
|
+
name=table_name,
|
|
162
|
+
key_schema=[
|
|
163
|
+
{'AttributeName': 'id', 'KeyType': 'HASH'}
|
|
164
|
+
],
|
|
165
|
+
attribute_definitions=[
|
|
166
|
+
{'AttributeName': 'id', 'AttributeType': 'S'}
|
|
167
|
+
]
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
yield table_name
|
|
171
|
+
|
|
172
|
+
# Cleanup
|
|
173
|
+
try:
|
|
174
|
+
aws_environment.dynamodb.delete_table(table_name)
|
|
175
|
+
except Exception:
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@pytest.fixture
|
|
180
|
+
def sqs_queue(aws_environment):
|
|
181
|
+
"""
|
|
182
|
+
Function-scoped SQS queue that's automatically cleaned up.
|
|
183
|
+
|
|
184
|
+
Creates a test queue and removes it after the test completes.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
aws_environment: AWS environment fixture
|
|
188
|
+
|
|
189
|
+
Yields:
|
|
190
|
+
str: Queue URL
|
|
191
|
+
"""
|
|
192
|
+
queue_response = aws_environment.sqs.create_queue('test-queue')
|
|
193
|
+
queue_url = queue_response['QueueUrl']
|
|
194
|
+
|
|
195
|
+
yield queue_url
|
|
196
|
+
|
|
197
|
+
# Cleanup
|
|
198
|
+
try:
|
|
199
|
+
aws_environment.sqs.delete_queue(queue_url)
|
|
200
|
+
except Exception:
|
|
201
|
+
pass
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@pytest.fixture
|
|
205
|
+
def kinesis_stream(aws_environment):
|
|
206
|
+
"""
|
|
207
|
+
Function-scoped Kinesis stream that's automatically cleaned up.
|
|
208
|
+
|
|
209
|
+
Creates a test stream and removes it after the test completes.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
aws_environment: AWS environment fixture
|
|
213
|
+
|
|
214
|
+
Yields:
|
|
215
|
+
str: Stream name
|
|
216
|
+
"""
|
|
217
|
+
stream_name = 'test-stream'
|
|
218
|
+
aws_environment.kinesis.create_stream(stream_name, shard_count=1)
|
|
219
|
+
|
|
220
|
+
yield stream_name
|
|
221
|
+
|
|
222
|
+
# Cleanup
|
|
223
|
+
try:
|
|
224
|
+
aws_environment.kinesis.delete_stream(stream_name)
|
|
225
|
+
except Exception:
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@pytest.fixture
|
|
230
|
+
def sns_topic(aws_environment):
|
|
231
|
+
"""
|
|
232
|
+
Function-scoped SNS topic that's automatically cleaned up.
|
|
233
|
+
|
|
234
|
+
Creates a test topic and removes it after the test completes.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
aws_environment: AWS environment fixture
|
|
238
|
+
|
|
239
|
+
Yields:
|
|
240
|
+
str: Topic ARN
|
|
241
|
+
"""
|
|
242
|
+
response = aws_environment.sns.create_topic('test-topic')
|
|
243
|
+
topic_arn = response['TopicArn']
|
|
244
|
+
|
|
245
|
+
yield topic_arn
|
|
246
|
+
|
|
247
|
+
# Cleanup
|
|
248
|
+
try:
|
|
249
|
+
aws_environment.sns.delete_topic(topic_arn)
|
|
250
|
+
except Exception:
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@pytest.fixture
|
|
255
|
+
def lambda_function(aws_environment):
|
|
256
|
+
"""
|
|
257
|
+
Function-scoped Lambda function that's automatically cleaned up.
|
|
258
|
+
|
|
259
|
+
Creates a simple test Lambda function and removes it after the test.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
aws_environment: AWS environment fixture
|
|
263
|
+
|
|
264
|
+
Yields:
|
|
265
|
+
str: Function name
|
|
266
|
+
"""
|
|
267
|
+
from testcontainers_aws.services.lambda_service import create_lambda_zip
|
|
268
|
+
|
|
269
|
+
function_name = 'test-function'
|
|
270
|
+
code = create_lambda_zip("""
|
|
271
|
+
def handler(event, context):
|
|
272
|
+
return {
|
|
273
|
+
'statusCode': 200,
|
|
274
|
+
'body': 'Hello from Lambda!'
|
|
275
|
+
}
|
|
276
|
+
""")
|
|
277
|
+
|
|
278
|
+
aws_environment.lambda_.create_function(
|
|
279
|
+
function_name=function_name,
|
|
280
|
+
runtime='python3.11',
|
|
281
|
+
handler='index.handler',
|
|
282
|
+
code=code
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
yield function_name
|
|
286
|
+
|
|
287
|
+
# Cleanup
|
|
288
|
+
try:
|
|
289
|
+
aws_environment.lambda_.delete_function(function_name)
|
|
290
|
+
except Exception:
|
|
291
|
+
pass
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""AWS service managers for simplified resource management."""
|
|
2
|
+
|
|
3
|
+
from testcontainers_aws.services.s3 import S3ServiceManager
|
|
4
|
+
from testcontainers_aws.services.dynamodb import DynamoDBServiceManager
|
|
5
|
+
from testcontainers_aws.services.sqs import SQSServiceManager
|
|
6
|
+
from testcontainers_aws.services.kinesis import KinesisServiceManager
|
|
7
|
+
from testcontainers_aws.services.lambda_service import LambdaServiceManager
|
|
8
|
+
from testcontainers_aws.services.sns import SNSServiceManager
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"S3ServiceManager",
|
|
12
|
+
"DynamoDBServiceManager",
|
|
13
|
+
"SQSServiceManager",
|
|
14
|
+
"KinesisServiceManager",
|
|
15
|
+
"LambdaServiceManager",
|
|
16
|
+
"SNSServiceManager",
|
|
17
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Base service manager for AWS services."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from testcontainers_aws.core import AWSTestEnvironment
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BaseServiceManager:
|
|
10
|
+
"""Base class for AWS service managers."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, environment: 'AWSTestEnvironment'):
|
|
13
|
+
"""
|
|
14
|
+
Initialize service manager.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
environment: Parent AWSTestEnvironment instance
|
|
18
|
+
"""
|
|
19
|
+
self.environment = environment
|
|
20
|
+
self._client = None
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def client(self) -> Any:
|
|
24
|
+
"""Get the boto3 client for this service (implemented by subclasses)."""
|
|
25
|
+
raise NotImplementedError("Subclasses must implement the client property")
|