|
11 | 11 | from botocore.config import Config |
12 | 12 | from botocore.exceptions import ClientError |
13 | 13 | from localstack_snapshot.snapshots.transformer import SortingTransformer |
| 14 | +from localstack_snapshot.snapshots.transformer_utility import TransformerUtility |
14 | 15 |
|
15 | 16 | from localstack import config |
16 | 17 | from localstack.aws.api.dynamodb import ( |
@@ -1490,32 +1491,101 @@ def test_create_duplicate_table(self, dynamodb_create_table_with_parameters, sna |
1490 | 1491 | ) |
1491 | 1492 | snapshot.match("Error", ctx.value) |
1492 | 1493 |
|
1493 | | - @markers.aws.only_localstack( |
1494 | | - reason="timing issues - needs a check to see if table is successfully deleted" |
| 1494 | + @markers.aws.validated |
| 1495 | + @markers.snapshot.skip_snapshot_verify( |
| 1496 | + paths=[ |
| 1497 | + "$..TableDescription.TableStatus", # DDBLocal directly goes to ACTIVE status |
| 1498 | + "$..Table.ProvisionedThroughput.LastDecreaseDateTime", # Not returned by DDBLocal |
| 1499 | + "$..Table.ProvisionedThroughput.LastIncreaseDateTime", # Not returned by DDBLocal |
| 1500 | + # The following attributes (prefixed TableDescription) are returned by DDBLocal DeleteTable but not in parity with AWS |
| 1501 | + "$..TableDescription.AttributeDefinitions", |
| 1502 | + "$..TableDescription.CreationDateTime", |
| 1503 | + "$..TableDescription.KeySchema", |
| 1504 | + "$..TableDescription.ProvisionedThroughput.LastDecreaseDateTime", |
| 1505 | + "$..TableDescription.ProvisionedThroughput.LastIncreaseDateTime", |
| 1506 | + "$..TableDescription.TableId", |
| 1507 | + ] |
1495 | 1508 | ) |
1496 | | - def test_delete_table(self, dynamodb_create_table, aws_client): |
| 1509 | + def test_table_crud(self, aws_client, cleanups, snapshot, dynamodb_wait_for_table_active): |
| 1510 | + snapshot.add_transformer( |
| 1511 | + [ |
| 1512 | + TransformerUtility.key_value("TableName"), |
| 1513 | + TransformerUtility.key_value("TableArn"), |
| 1514 | + ] |
| 1515 | + ) |
| 1516 | + |
1497 | 1517 | table_name = f"test-ddb-table-{short_uid()}" |
1498 | 1518 |
|
1499 | | - tables_before = len(aws_client.dynamodb.list_tables()["TableNames"]) |
| 1519 | + # CreateTable |
| 1520 | + response = aws_client.dynamodb.create_table( |
| 1521 | + TableName=table_name, |
| 1522 | + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], |
| 1523 | + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], |
| 1524 | + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, |
| 1525 | + ) |
| 1526 | + cleanups.append(lambda: aws_client.dynamodb.delete_table(TableName=table_name)) |
| 1527 | + snapshot.match("create-table", response) |
| 1528 | + |
| 1529 | + dynamodb_wait_for_table_active(table_name=table_name) |
1500 | 1530 |
|
1501 | | - dynamodb_create_table( |
1502 | | - table_name=table_name, |
1503 | | - partition_key=PARTITION_KEY, |
| 1531 | + # ListTables |
| 1532 | + assert table_name in aws_client.dynamodb.list_tables()["TableNames"] |
| 1533 | + |
| 1534 | + # DescribeTable |
| 1535 | + response = aws_client.dynamodb.describe_table(TableName=table_name) |
| 1536 | + snapshot.match("describe-table", response) |
| 1537 | + |
| 1538 | + # DeleteTable |
| 1539 | + response = aws_client.dynamodb.delete_table(TableName=table_name) |
| 1540 | + snapshot.match("delete-table", response) |
| 1541 | + |
| 1542 | + # ListTable: after DeleteTable |
| 1543 | + retry( |
| 1544 | + lambda: table_name not in aws_client.dynamodb.list_tables()["TableNames"], |
| 1545 | + sleep=1, |
| 1546 | + retries=30, |
1504 | 1547 | ) |
1505 | 1548 |
|
1506 | | - table_list = aws_client.dynamodb.list_tables() |
1507 | | - # TODO: fix assertion, to enable parallel test execution! |
1508 | | - assert tables_before + 1 == len(table_list["TableNames"]) |
1509 | | - assert table_name in table_list["TableNames"] |
| 1549 | + # DeleteTable: delete non-existent table |
| 1550 | + with pytest.raises(ClientError) as exc: |
| 1551 | + aws_client.dynamodb.delete_table(TableName="non-existent") |
| 1552 | + snapshot.match("delete-non-existent-table", exc.value.response) |
1510 | 1553 |
|
1511 | | - aws_client.dynamodb.delete_table(TableName=table_name) |
| 1554 | + @markers.aws.validated |
| 1555 | + @markers.snapshot.skip_snapshot_verify( |
| 1556 | + paths=[ |
| 1557 | + "$..TableDescription.TableStatus", # DDBLocal directly goes to ACTIVE status |
| 1558 | + "$..Table.ProvisionedThroughput.LastDecreaseDateTime", # Not returned by DDBLocal |
| 1559 | + "$..Table.ProvisionedThroughput.LastIncreaseDateTime", # Not returned by DDBLocal |
| 1560 | + ] |
| 1561 | + ) |
| 1562 | + def test_table_warm_throughput( |
| 1563 | + self, dynamodb_create_table_with_parameters, snapshot, aws_client |
| 1564 | + ): |
| 1565 | + """ |
| 1566 | + This test ensures that WarmThroughput params provided to CreateTable are reflected in DescribeTable |
| 1567 | + """ |
1512 | 1568 |
|
1513 | | - table_list = aws_client.dynamodb.list_tables() |
1514 | | - assert tables_before == len(table_list["TableNames"]) |
| 1569 | + snapshot.add_transformer( |
| 1570 | + [ |
| 1571 | + TransformerUtility.key_value("TableName"), |
| 1572 | + TransformerUtility.key_value("TableArn"), |
| 1573 | + ] |
| 1574 | + ) |
1515 | 1575 |
|
1516 | | - with pytest.raises(Exception) as ctx: |
1517 | | - aws_client.dynamodb.delete_table(TableName=table_name) |
1518 | | - assert ctx.match("ResourceNotFoundException") |
| 1576 | + table_name = f"test-ddb-table-{short_uid()}" |
| 1577 | + |
| 1578 | + response = dynamodb_create_table_with_parameters( |
| 1579 | + TableName=table_name, |
| 1580 | + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], |
| 1581 | + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], |
| 1582 | + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, |
| 1583 | + WarmThroughput={"ReadUnitsPerSecond": 1000, "WriteUnitsPerSecond": 1200}, |
| 1584 | + ) |
| 1585 | + snapshot.match("create-table", response) |
| 1586 | + |
| 1587 | + response = aws_client.dynamodb.describe_table(TableName=table_name) |
| 1588 | + snapshot.match("describe-table", response) |
1519 | 1589 |
|
1520 | 1590 | @markers.aws.validated |
1521 | 1591 | def test_transaction_write_items( |
@@ -1947,9 +2017,14 @@ def test_dynamodb_create_table_with_sse_specification( |
1947 | 2017 | assert result["TableDescription"]["SSEDescription"]["KMSMasterKeyArn"] == kms_master_key_arn |
1948 | 2018 |
|
1949 | 2019 | @markers.aws.validated |
| 2020 | + @markers.snapshot.skip_snapshot_verify( |
| 2021 | + paths=["$..KeyMetadata.CurrentKeyMaterialId"] # Not supported by LS |
| 2022 | + ) |
1950 | 2023 | def test_dynamodb_create_table_with_partial_sse_specification( |
1951 | 2024 | self, dynamodb_create_table_with_parameters, snapshot, aws_client |
1952 | 2025 | ): |
| 2026 | + snapshot.add_transformer(TransformerUtility.key_value("CurrentKeyMaterialId")) |
| 2027 | + |
1953 | 2028 | table_name = f"test_table_{short_uid()}" |
1954 | 2029 | sse_specification = {"Enabled": True} |
1955 | 2030 |
|
@@ -1979,9 +2054,14 @@ def test_dynamodb_create_table_with_partial_sse_specification( |
1979 | 2054 | assert "SSESpecification" not in result["Table"] |
1980 | 2055 |
|
1981 | 2056 | @markers.aws.validated |
| 2057 | + @markers.snapshot.skip_snapshot_verify( |
| 2058 | + paths=["$..KeyMetadata.CurrentKeyMaterialId"] # Not supported by LS |
| 2059 | + ) |
1982 | 2060 | def test_dynamodb_update_table_without_sse_specification_change( |
1983 | 2061 | self, dynamodb_create_table_with_parameters, snapshot, aws_client |
1984 | 2062 | ): |
| 2063 | + snapshot.add_transformer(TransformerUtility.key_value("CurrentKeyMaterialId")) |
| 2064 | + |
1985 | 2065 | table_name = f"test_table_{short_uid()}" |
1986 | 2066 |
|
1987 | 2067 | sse_specification = {"Enabled": True} |
@@ -2284,6 +2364,7 @@ def test_data_encoding_consistency( |
2284 | 2364 | paths=[ |
2285 | 2365 | "$..PointInTimeRecoveryDescription..EarliestRestorableDateTime", |
2286 | 2366 | "$..PointInTimeRecoveryDescription..LatestRestorableDateTime", |
| 2367 | + "$..ContinuousBackupsDescription.PointInTimeRecoveryDescription.RecoveryPeriodInDays", |
2287 | 2368 | ] |
2288 | 2369 | ) |
2289 | 2370 | @markers.aws.validated |
@@ -2638,6 +2719,8 @@ def _get_records_amount(record_amount: int): |
2638 | 2719 | @pytest.mark.parametrize("billing_mode", ["PAY_PER_REQUEST", "PROVISIONED"]) |
2639 | 2720 | @markers.snapshot.skip_snapshot_verify( |
2640 | 2721 | paths=[ |
| 2722 | + # Warm throughput for GSI is not implemented in LS. DDB Local doesn't support it either. |
| 2723 | + "$..Table.GlobalSecondaryIndexes..WarmThroughput", |
2641 | 2724 | # LS returns those and not AWS, probably because no changes happened there yet |
2642 | 2725 | "$..ProvisionedThroughput.LastDecreaseDateTime", |
2643 | 2726 | "$..ProvisionedThroughput.LastIncreaseDateTime", |
|
0 commit comments