|
10 | 10 | from botocore.exceptions import ClientError |
11 | 11 | from localstack.aws.connect import connect_to |
12 | 12 | from localstack.utils.aws.arns import sqs_queue_arn, sqs_queue_url_for_arn |
| 13 | +from localstack.utils.aws.resources import create_dynamodb_table |
13 | 14 | from localstack.utils.net import wait_for_port_open |
| 15 | +from localstack.utils.strings import short_uid |
14 | 16 | from localstack.utils.sync import retry |
15 | 17 |
|
16 | 18 | from aws_replicator.client.auth_proxy import start_aws_auth_proxy |
@@ -243,3 +245,81 @@ def test_sqs_requests(start_aws_proxy, cleanups): |
243 | 245 | "Attributes" |
244 | 246 | ]["QueueArn"] |
245 | 247 | assert result == queue_arn_aws |
| 248 | + |
| 249 | + |
| 250 | +class TestDynamoDBRequests: |
| 251 | + region_name = "us-east-1" |
| 252 | + |
| 253 | + @pytest.fixture(scope="class") |
| 254 | + def dynamodb_client_aws(self): |
| 255 | + return boto3.client("dynamodb", region_name=self.region_name) |
| 256 | + |
| 257 | + @pytest.fixture |
| 258 | + def create_dynamodb_table_aws(self, dynamodb_client_aws): |
| 259 | + tables = [] |
| 260 | + |
| 261 | + def factory(**kwargs): |
| 262 | + kwargs["client"] = dynamodb_client_aws |
| 263 | + if "table_name" not in kwargs: |
| 264 | + kwargs["table_name"] = f"test-table-{short_uid()}" |
| 265 | + if "partition_key" not in kwargs: |
| 266 | + kwargs["partition_key"] = "id" |
| 267 | + |
| 268 | + tables.append(kwargs["table_name"]) |
| 269 | + |
| 270 | + return create_dynamodb_table(**kwargs) |
| 271 | + |
| 272 | + yield factory |
| 273 | + |
| 274 | + # cleanup |
| 275 | + for table in tables: |
| 276 | + try: |
| 277 | + dynamodb_client_aws.delete_table(TableName=table) |
| 278 | + except Exception as e: |
| 279 | + print(f"error cleaning up table {table}: {e}", table, e) |
| 280 | + |
| 281 | + def test_dynamodb_requests_read_only( |
| 282 | + self, start_aws_proxy, create_dynamodb_table_aws, dynamodb_client_aws |
| 283 | + ): |
| 284 | + # create clients |
| 285 | + dynamodb_client = connect_to(region_name=self.region_name).dynamodb |
| 286 | + |
| 287 | + # start proxy - only forwarding requests for read operations |
| 288 | + config = ProxyConfig( |
| 289 | + services={"dynamodb": {"resources": ".*", "read_only": True}}, |
| 290 | + bind_host=PROXY_BIND_HOST, |
| 291 | + ) |
| 292 | + start_aws_proxy(config) |
| 293 | + |
| 294 | + # create table in AWS |
| 295 | + table_name = f"test-table-{short_uid()}" |
| 296 | + create_dynamodb_table_aws(table_name=table_name) |
| 297 | + tables_aws = dynamodb_client_aws.list_tables()["TableNames"] |
| 298 | + assert table_name in tables_aws |
| 299 | + |
| 300 | + # assert that local call for this table is proxied |
| 301 | + tables_local = dynamodb_client.list_tables()["TableNames"] |
| 302 | + assert table_name in tables_local |
| 303 | + |
| 304 | + item = {"id": {"S": "123"}, "value": {"S": "foobar"}} |
| 305 | + # put item via AWS client |
| 306 | + dynamodb_client_aws.put_item(TableName=table_name, Item=item) |
| 307 | + |
| 308 | + # get item via AWS client |
| 309 | + result = dynamodb_client_aws.get_item(TableName=table_name, Key={"id": {"S": "123"}}) |
| 310 | + assert result["Item"] == item |
| 311 | + |
| 312 | + # get item via local client |
| 313 | + result = dynamodb_client.get_item(TableName=table_name, Key={"id": {"S": "123"}}) |
| 314 | + assert result["Item"] == item |
| 315 | + |
| 316 | + # assert that scan operation is working |
| 317 | + result = dynamodb_client.scan(TableName=table_name) |
| 318 | + assert len(result["Items"]) == 1 |
| 319 | + |
| 320 | + # assert that write operation is NOT working - it's sent to localstack, which cannot find the table |
| 321 | + item3 = {"id": {"S": "789"}, "value": {"S": "foobar3"}} |
| 322 | + with pytest.raises(ClientError) as exc: |
| 323 | + dynamodb_client.put_item(TableName=table_name, Item=item3) |
| 324 | + |
| 325 | + assert exc.match("ResourceNotFoundException") |
0 commit comments