diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py index 0a8369b1e..4b89c0bae 100644 --- a/tests/test_dynamodb/test_dynamodb.py +++ b/tests/test_dynamodb/test_dynamodb.py @@ -11,6 +11,7 @@ from moto.dynamodb import dynamodb_backend from boto.exception import DynamoDBResponseError +# Has boto3 equivalent @mock_dynamodb_deprecated def test_list_tables(): name = "TestTable" @@ -33,6 +34,7 @@ def test_list_tables_layer_1(): res.should.equal(expected) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_describe_missing_table(): conn = boto.connect_dynamodb("the_key", "the_secret") @@ -40,6 +42,8 @@ def test_describe_missing_table(): conn.describe_table("messages") +# Has boto3 equivalent +# This test is pointless though, as we treat DynamoDB as a global resource @mock_dynamodb_deprecated def test_dynamodb_with_connect_to_region(): # this will work if connected with boto.connect_dynamodb() diff --git a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py index 6986ae9b3..904731525 100644 --- a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py @@ -25,6 +25,7 @@ def create_table(conn): return table +# Has boto3 equivalent @freeze_time("2012-01-14") @mock_dynamodb_deprecated def test_create_table(): @@ -51,6 +52,7 @@ def test_create_table(): conn.describe_table("messages").should.equal(expected) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_table(): conn = boto.connect_dynamodb() @@ -65,6 +67,7 @@ def test_delete_table(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_update_table_throughput(): conn = boto.connect_dynamodb() @@ -79,6 +82,7 @@ def test_update_table_throughput(): table.write_units.should.equal(6) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_item_add_and_describe_and_update(): conn = boto.connect_dynamodb() @@ -128,6 +132,7 @@ def test_item_add_and_describe_and_update(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_item_put_without_table(): conn = boto.connect_dynamodb() @@ -138,6 +143,7 @@ def test_item_put_without_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_get_missing_item(): conn = boto.connect_dynamodb() @@ -149,6 +155,7 @@ def test_get_missing_item(): table.has_item("foobar", "more").should.equal(False) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_get_item_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -159,6 +166,7 @@ def test_get_item_with_undeclared_table(): ).should.throw(DynamoDBKeyNotFoundError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_get_item_without_range_key(): conn = boto.connect_dynamodb() @@ -182,6 +190,7 @@ def test_get_item_without_range_key(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item(): conn = boto.connect_dynamodb() @@ -208,6 +217,7 @@ def test_delete_item(): item.delete.when.called_with().should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item_with_attribute_response(): conn = boto.connect_dynamodb() @@ -245,6 +255,7 @@ def test_delete_item_with_attribute_response(): item.delete.when.called_with().should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -255,6 +266,7 @@ def test_delete_item_with_undeclared_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_query(): conn = boto.connect_dynamodb() @@ -299,6 +311,7 @@ def test_query(): results.response["Items"].should.have.length_of(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_query_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -313,6 +326,7 @@ def test_query_with_undeclared_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_scan(): conn = boto.connect_dynamodb() @@ -364,6 +378,7 @@ def test_scan(): results.response["Items"].should.have.length_of(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_scan_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -390,6 +405,7 @@ def test_scan_after_has_item(): list(table.scan()).should.equal([]) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_write_batch(): conn = boto.connect_dynamodb() @@ -438,6 +454,7 @@ def test_write_batch(): table.item_count.should.equal(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_batch_read(): conn = boto.connect_dynamodb() diff --git a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py index c5031b5d1..f0baa7c9d 100644 --- a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py +++ b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py @@ -22,6 +22,7 @@ def create_table(conn): return table +# Has boto3 equivalent @freeze_time("2012-01-14") @mock_dynamodb_deprecated def test_create_table(): @@ -47,6 +48,7 @@ def test_create_table(): conn.describe_table("messages").should.equal(expected) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_table(): conn = boto.connect_dynamodb() @@ -61,6 +63,7 @@ def test_delete_table(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_update_table_throughput(): conn = boto.connect_dynamodb() @@ -75,6 +78,7 @@ def test_update_table_throughput(): table.write_units.should.equal(6) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_item_add_and_describe_and_update(): conn = boto.connect_dynamodb() @@ -114,6 +118,7 @@ def test_item_add_and_describe_and_update(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_item_put_without_table(): conn = boto.connect_dynamodb() @@ -123,6 +128,7 @@ def test_item_put_without_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_get_missing_item(): conn = boto.connect_dynamodb() @@ -133,6 +139,7 @@ def test_get_missing_item(): ) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_get_item_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -142,6 +149,7 @@ def test_get_item_with_undeclared_table(): ).should.throw(DynamoDBKeyNotFoundError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item(): conn = boto.connect_dynamodb() @@ -166,6 +174,7 @@ def test_delete_item(): item.delete.when.called_with().should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item_with_attribute_response(): conn = boto.connect_dynamodb() @@ -200,6 +209,7 @@ def test_delete_item_with_attribute_response(): item.delete.when.called_with().should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_delete_item_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -209,6 +219,7 @@ def test_delete_item_with_undeclared_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_query(): conn = boto.connect_dynamodb() @@ -226,6 +237,7 @@ def test_query(): results.response["Items"].should.have.length_of(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_query_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -235,6 +247,7 @@ def test_query_with_undeclared_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_scan(): conn = boto.connect_dynamodb() @@ -286,6 +299,7 @@ def test_scan(): results.response["Items"].should.have.length_of(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_scan_with_undeclared_table(): conn = boto.connect_dynamodb() @@ -301,6 +315,7 @@ def test_scan_with_undeclared_table(): ).should.throw(DynamoDBResponseError) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_scan_after_has_item(): conn = boto.connect_dynamodb() @@ -312,6 +327,7 @@ def test_scan_after_has_item(): list(table.scan()).should.equal([]) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_write_batch(): conn = boto.connect_dynamodb() @@ -358,6 +374,7 @@ def test_write_batch(): table.item_count.should.equal(1) +# Has boto3 equivalent @mock_dynamodb_deprecated def test_batch_read(): conn = boto.connect_dynamodb() diff --git a/tests/test_dynamodb/test_server.py b/tests/test_dynamodb/test_server.py index aa70373d8..2f039bc03 100644 --- a/tests/test_dynamodb/test_server.py +++ b/tests/test_dynamodb/test_server.py @@ -1,24 +1,100 @@ from __future__ import unicode_literals import json +import pytest import sure # noqa +from moto import mock_dynamodb import moto.server as server """ Test the different server responses +Docs: +https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Appendix.APIv20111205.html """ +TABLE_NAME = "my_table_name" +TABLE_WITH_RANGE_NAME = "my_table_with_range_name" -def test_table_list(): - backend = server.create_backend_app("dynamodb") - test_client = backend.test_client() + +@pytest.fixture(autouse=True) +def test_client(): + with mock_dynamodb(): + backend = server.create_backend_app("dynamodb") + test_client = backend.test_client() + + yield test_client + + +def test_404(test_client): res = test_client.get("/") res.status_code.should.equal(404) + +def test_table_list(test_client): headers = {"X-Amz-Target": "TestTable.ListTables"} res = test_client.get("/", headers=headers) - res.data.should.contain(b"TableNames") + json.loads(res.data).should.equal({"TableNames": []}) + + +def test_create_table(test_client): + res = create_table(test_client) + res = json.loads(res.data)["Table"] + res.should.have.key("CreationDateTime") + del res["CreationDateTime"] + res.should.equal( + { + "KeySchema": { + "HashKeyElement": {"AttributeName": "hkey", "AttributeType": "S"}, + "RangeKeyElement": {"AttributeName": "rkey", "AttributeType": "N"}, + }, + "ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 10}, + "TableName": TABLE_WITH_RANGE_NAME, + "TableStatus": "ACTIVE", + "ItemCount": 0, + "TableSizeBytes": 0, + } + ) + + headers = {"X-Amz-Target": "TestTable.ListTables"} + res = test_client.get("/", headers=headers) + res = json.loads(res.data) + res.should.equal({"TableNames": [TABLE_WITH_RANGE_NAME]}) + + +def test_create_table_without_range_key(test_client): + res = create_table(test_client, use_range_key=False) + res = json.loads(res.data)["Table"] + res.should.have.key("CreationDateTime") + del res["CreationDateTime"] + res.should.equal( + { + "KeySchema": { + "HashKeyElement": {"AttributeName": "hkey", "AttributeType": "S"} + }, + "ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 10}, + "TableName": TABLE_NAME, + "TableStatus": "ACTIVE", + "ItemCount": 0, + "TableSizeBytes": 0, + } + ) + + headers = {"X-Amz-Target": "TestTable.ListTables"} + res = test_client.get("/", headers=headers) + res = json.loads(res.data) + res.should.equal({"TableNames": [TABLE_NAME]}) + + +# This test is pointless, as we treat DynamoDB as a global resource +def test_create_table_in_different_regions(test_client): + create_table(test_client) + create_table(test_client, name="Table2", region="us-west-2") + + headers = {"X-Amz-Target": "TestTable.ListTables"} + res = test_client.get("/", headers=headers) + res = json.loads(res.data) + res.should.equal({"TableNames": [TABLE_WITH_RANGE_NAME, "Table2"]}) def test_update_item(): @@ -32,7 +108,7 @@ def test_update_item(): # UpdateItem headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem" request_body = { - "TableName": "Table1", + "TableName": TABLE_WITH_RANGE_NAME, "Key": { "HashKeyElement": {"S": "customer"}, "RangeKeyElement": {"N": "12341234"}, @@ -44,7 +120,7 @@ def test_update_item(): # UpdateItem headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem" request_body = { - "TableName": "Table1", + "TableName": TABLE_WITH_RANGE_NAME, "Key": { "HashKeyElement": {"S": "customer"}, "RangeKeyElement": {"N": "12341234"}, @@ -68,7 +144,7 @@ def test_update_item(): # UpdateItem - multiples headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem" request_body = { - "TableName": "Table1", + "TableName": TABLE_WITH_RANGE_NAME, "Key": { "HashKeyElement": {"S": "customer"}, "RangeKeyElement": {"N": "12341234"}, @@ -95,7 +171,7 @@ def test_update_item(): # GetItem headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" request_body = { - "TableName": "Table1", + "TableName": TABLE_WITH_RANGE_NAME, "Key": { "HashKeyElement": {"S": "customer"}, "RangeKeyElement": {"N": "12341234"}, @@ -108,6 +184,844 @@ def test_update_item(): res["Item"].shouldnt.have.key("name") +@pytest.mark.parametrize( + "use_range_key", [True, False], ids=["using range key", "using hash key only"] +) +def test_delete_table(use_range_key, test_client): + create_table(test_client, use_range_key=use_range_key) + + headers = {"X-Amz-Target": "DynamoDB_20111205.DeleteTable"} + name = TABLE_WITH_RANGE_NAME if use_range_key else TABLE_NAME + test_client.post("/", headers=headers, json={"TableName": name}) + + headers = {"X-Amz-Target": "DynamoDB_20111205.ListTables"} + res = test_client.post("/", headers=headers) + res = json.loads(res.data) + res.should.equal({"TableNames": []}) + + +def test_delete_unknown_table(test_client): + headers = {"X-Amz-Target": "DynamoDB_20111205.DeleteTable"} + res = test_client.post("/", headers=headers, json={"TableName": "unknown_table"}) + res.status_code.should.equal(400) + + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_describe_table(test_client): + create_table(test_client) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.DescribeTable", + "Content-Type": "application/x-amz-json-1.0", + } + res = test_client.post( + "/", headers=headers, json={"TableName": TABLE_WITH_RANGE_NAME} + ) + res = json.loads(res.data)["Table"] + res.should.have.key("CreationDateTime") + del res["CreationDateTime"] + res.should.equal( + { + "KeySchema": { + "HashKeyElement": {"AttributeName": "hkey", "AttributeType": "S"}, + "RangeKeyElement": {"AttributeName": "rkey", "AttributeType": "N"}, + }, + "ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 10}, + "TableName": TABLE_WITH_RANGE_NAME, + "TableStatus": "ACTIVE", + "ItemCount": 0, + "TableSizeBytes": 0, + } + ) + + +def test_describe_missing_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.DescribeTable", + "Content-Type": "application/x-amz-json-1.0", + } + res = test_client.post("/", headers=headers, json={"TableName": "unknown_table"}) + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +@pytest.mark.parametrize( + "use_range_key", [True, False], ids=["using range key", "using hash key only"] +) +def test_update_table(test_client, use_range_key): + table_name = TABLE_WITH_RANGE_NAME if use_range_key else TABLE_NAME + create_table(test_client, use_range_key=use_range_key) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.UpdateTable", + "Content-Type": "application/x-amz-json-1.0", + } + request_data = { + "TableName": table_name, + "ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 15}, + } + test_client.post("/", headers=headers, json=request_data) + + # DescribeTable - verify the throughput is persisted + headers = { + "X-Amz-Target": "DynamoDB_20111205.DescribeTable", + "Content-Type": "application/x-amz-json-1.0", + } + res = test_client.post("/", headers=headers, json={"TableName": table_name}) + throughput = json.loads(res.data)["Table"]["ProvisionedThroughput"] + + throughput.should.equal({"ReadCapacityUnits": 5, "WriteCapacityUnits": 15}) + + +def test_put_return_none(test_client): + create_table(test_client) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.PutItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Item": { + "hkey": {"S": "customer"}, + "rkey": {"N": "12341234"}, + "name": {"S": "myname"}, + }, + "ReturnValues": "NONE", + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + # This seems wrong - it should return nothing, considering return_values is set to none + res["Attributes"].should.equal( + {"hkey": "customer", "name": "myname", "rkey": "12341234"} + ) + + +def test_put_return_none_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.PutItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "Item": {"hkey": {"S": "customer"}, "name": {"S": "myname"}}, + "ReturnValues": "NONE", + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + print(res) + # This seems wrong - it should return nothing, considering return_values is set to none + res["Attributes"].should.equal({"hkey": "customer", "name": "myname"}) + + +def test_put_item_from_unknown_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.PutItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": "unknown_table", + "Item": { + "hkey": {"S": "customer"}, + "rkey": {"N": "12341234"}, + "name": {"S": "myname"}, + }, + "ReturnValues": "NONE", + } + res = test_client.post("/", headers=headers, json=request_body) + + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_get_item_from_unknown_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.GetItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": "unknown_table", + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341234"}, + }, + } + res = test_client.post("/", headers=headers, json=request_body) + + res.status_code.should.equal(404) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +@pytest.mark.parametrize( + "use_range_key", [True, False], ids=["using range key", "using hash key only"] +) +def test_get_unknown_item_from_table(use_range_key, test_client): + create_table(test_client, use_range_key=use_range_key) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.GetItem", + "Content-Type": "application/x-amz-json-1.0", + } + table_name = TABLE_WITH_RANGE_NAME if use_range_key else TABLE_NAME + request_body = { + "TableName": table_name, + "Key": {"HashKeyElement": {"S": "customer"}}, + } + if use_range_key: + request_body["Key"]["RangeKeyElement"] = {"N": "12341234"} + res = test_client.post("/", headers=headers, json=request_body) + + res.status_code.should.equal(404) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_get_item_without_range_key(test_client): + create_table(test_client) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.GetItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": {"HashKeyElement": {"S": "customer"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazon.coral.validate#ValidationException"} + ) + + +def test_put_and_get_item(test_client): + create_table(test_client) + + headers, res = put_item(test_client) + + res["ConsumedCapacityUnits"].should.equal(1) + res["Attributes"].should.equal( + {"hkey": "customer", "name": "myname", "rkey": "12341234"} + ) + + # GetItem + headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341234"}, + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res["ConsumedCapacityUnits"].should.equal(0.5) + res["Item"].should.equal( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341234"}} + ) + + # GetItem - return single attribute + headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341234"}, + }, + "AttributesToGet": ["name"], + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res["ConsumedCapacityUnits"].should.equal(0.5) + res["Item"].should.equal({"name": {"S": "myname"}}) + + +def test_put_and_get_item_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + headers, res = put_item(test_client, use_range_key=False) + + res["ConsumedCapacityUnits"].should.equal(1) + res["Attributes"].should.equal({"hkey": "customer", "name": "myname"}) + + # GetItem + headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" + request_body = { + "TableName": TABLE_NAME, + "Key": {"HashKeyElement": {"S": "customer"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res["ConsumedCapacityUnits"].should.equal(0.5) + res["Item"].should.equal({"hkey": {"S": "customer"}, "name": {"S": "myname"}}) + + # GetItem - return single attribute + headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" + request_body = { + "TableName": TABLE_NAME, + "Key": {"HashKeyElement": {"S": "customer"}}, + "AttributesToGet": ["name"], + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res["ConsumedCapacityUnits"].should.equal(0.5) + res["Item"].should.equal({"name": {"S": "myname"}}) + + +def test_scan_simple(test_client): + create_table(test_client) + + put_item(test_client) + put_item(test_client, rkey="12341235") + put_item(test_client, rkey="12341236") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": TABLE_WITH_RANGE_NAME} + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(3) + res.should.have.key("ScannedCount").equal(3) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(3) + + items = res["Items"] + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341234"}} + ) + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341235"}} + ) + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341236"}} + ) + + +def test_scan_with_filter(test_client): + create_table(test_client) + + put_item(test_client, rkey="1230", name="somename") + put_item(test_client, rkey="1234", name=None) + put_item(test_client, rkey="1246") + + # SCAN specific item + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": { + "rkey": {"AttributeValueList": [{"S": "1234"}], "ComparisonOperator": "EQ"} + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(1) + res.should.have.key("ScannedCount").equal(3) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(1) + + items = res["Items"] + items.should.contain({"hkey": {"S": "customer"}, "rkey": {"N": "1234"}}) + + # SCAN begins_with + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": { + "rkey": { + "AttributeValueList": [{"S": "124"}], + "ComparisonOperator": "BEGINS_WITH", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1246"}} + ) + + # SCAN contains + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": { + "name": { + "AttributeValueList": [{"S": "mena"}], + "ComparisonOperator": "CONTAINS", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "somename"}, "rkey": {"N": "1230"}} + ) + + # SCAN null + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": {"name": {"ComparisonOperator": "NULL"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.contain({"hkey": {"S": "customer"}, "rkey": {"N": "1234"}}) + + # SCAN NOT NULL + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": {"name": {"ComparisonOperator": "NOT_NULL"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.equal( + [ + { + "hkey": {"S": "customer"}, + "name": {"S": "somename"}, + "rkey": {"N": "1230"}, + }, + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1246"}}, + ] + ) + + # SCAN between + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "ScanFilter": { + "rkey": { + "AttributeValueList": [{"S": "1230"}, {"S": "1240"}], + "ComparisonOperator": "BETWEEN", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "somename"}, "rkey": {"N": "1230"}} + ) + + +def test_scan_with_filter_in_table_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + put_item(test_client, use_range_key=False, hkey="customer1", name=None) + put_item(test_client, use_range_key=False, hkey="customer2") + put_item(test_client, use_range_key=False, hkey="customer3", name="special") + + # SCAN specific item + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "ScanFilter": { + "name": { + "AttributeValueList": [{"S": "special"}], + "ComparisonOperator": "EQ", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(1) + res.should.have.key("ScannedCount").equal(3) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(1) + + items = res["Items"] + items.should.contain({"hkey": {"S": "customer3"}, "name": {"S": "special"}}) + + # SCAN begins_with + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "ScanFilter": { + "hkey": { + "AttributeValueList": [{"S": "cust"}], + "ComparisonOperator": "BEGINS_WITH", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.have.length_of(3) # all customers start with cust + + # SCAN contains + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "ScanFilter": { + "name": { + "AttributeValueList": [{"S": "yna"}], + "ComparisonOperator": "CONTAINS", + } + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.have.equal([{"hkey": {"S": "customer2"}, "name": {"S": "myname"}}]) + + # SCAN null + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "ScanFilter": {"name": {"ComparisonOperator": "NULL"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.equal([{"hkey": {"S": "customer1"}}]) + + # SCAN NOT NULL + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "ScanFilter": {"name": {"ComparisonOperator": "NOT_NULL"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.have.length_of(2) + items.should.contain({"hkey": {"S": "customer2"}, "name": {"S": "myname"}}) + items.should.contain({"hkey": {"S": "customer3"}, "name": {"S": "special"}}) + + +def test_scan_with_undeclared_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": "unknown_table"} + res = test_client.post("/", headers=headers, json=request_body) + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_query_in_table_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + put_item(test_client, use_range_key=False) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": TABLE_NAME, "HashKeyValue": {"S": "customer"}} + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(1) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(1) + + items = res["Items"] + items.should.contain({"hkey": {"S": "customer"}, "name": {"S": "myname"}}) + + # QUERY for unknown value + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": TABLE_NAME, "HashKeyValue": {"S": "unknown-value"}} + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + # TODO: We should not get any results here + # res.should.have.key("Count").equal(0) + # res.should.have.key("Items").length_of(0) + + +def test_query_item_by_hash_only(test_client): + create_table(test_client) + + put_item(test_client) + put_item(test_client, rkey="12341235") + put_item(test_client, rkey="12341236") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(3) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(3) + + items = res["Items"] + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341234"}} + ) + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341235"}} + ) + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341236"}} + ) + + +def test_query_item_by_range_key(test_client): + create_table(test_client, use_range_key=True) + + put_item(test_client, rkey="1234") + put_item(test_client, rkey="1235") + put_item(test_client, rkey="1247") + + # GT some + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "1235"}], + "ComparisonOperator": "GT", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(1) + res.should.have.key("ConsumedCapacityUnits").equal(1) + res.should.have.key("Items").length_of(1) + + items = res["Items"] + items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1247"}} + ) + + # GT all + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "0"}], + "ComparisonOperator": "GT", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(3) + res.should.have.key("Items").length_of(3) + + # GT none + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "9999"}], + "ComparisonOperator": "GT", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res["ConsumedCapacityUnits"].should.equal(1) + res["Items"].should.equal([]) + res["Count"].should.equal(0) + + # CONTAINS some + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "24"}], + "ComparisonOperator": "CONTAINS", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.equal( + [{"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1247"}}] + ) + + # BEGINS_WITH + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "123"}], + "ComparisonOperator": "BEGINS_WITH", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.equal( + [ + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1234"}}, + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1235"}}, + ] + ) + + # CONTAINS + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "0"}, {"N": "1240"}], + "ComparisonOperator": "BETWEEN", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + items = json.loads(res.data)["Items"] + + items.should.equal( + [ + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1234"}}, + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "1235"}}, + ] + ) + + +def test_query_item_with_undeclared_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.Query", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": "unknown_table", + "HashKeyValue": {"S": "customer"}, + "RangeKeyCondition": { + "AttributeValueList": [{"N": "1235"}], + "ComparisonOperator": "GT", + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_delete_item(test_client): + create_table(test_client) + + put_item(test_client) + put_item(test_client, rkey="12341235") + put_item(test_client, rkey="12341236") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.DeleteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341236"}, + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res.should.equal({"Attributes": [], "ConsumedCapacityUnits": 0.5}) + + # GetItem + headers["X-Amz-Target"] = "DynamoDB_20111205.GetItem" + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341234"}, + }, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res["Item"].should.have.key("hkey").equal({"S": "customer"}) + res["Item"].should.have.key("rkey").equal({"N": "12341234"}) + res["Item"].should.have.key("name").equal({"S": "myname"}) + + def test_update_item_that_doesnt_exist(): backend = server.create_backend_app("dynamodb") test_client = backend.test_client() @@ -125,6 +1039,75 @@ def test_update_item_that_doesnt_exist(): "AttributeUpdates": {"new_att": {"Value": {"SS": ["val"]}, "Action": "PUT"}}, } res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res.should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_delete_item_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + put_item(test_client, use_range_key=False) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.DeleteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_NAME, + "Key": {"HashKeyElement": {"S": "customer"}}, + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res.should.equal({"Attributes": [], "ConsumedCapacityUnits": 0.5}) + + +def test_delete_item_with_return_values(test_client): + create_table(test_client) + + put_item(test_client) + put_item(test_client, rkey="12341235") + put_item(test_client, rkey="12341236") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.DeleteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341236"}, + }, + "ReturnValues": "ALL_OLD", + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + res.should.equal( + { + "Attributes": {"hkey": "customer", "name": "myname", "rkey": "12341236"}, + "ConsumedCapacityUnits": 0.5, + } + ) + + +def test_delete_unknown_item(test_client): + create_table(test_client) + + headers = { + "X-Amz-Target": "DynamoDB_20111205.DeleteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": TABLE_WITH_RANGE_NAME, + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341236"}, + }, + "ReturnValues": "ALL_OLD", + } + res = test_client.post("/", headers=headers, json=request_body) res.status_code.should.equal(400) json.loads(res.data).should.equal( {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} @@ -152,36 +1135,209 @@ def test_update_item_in_nonexisting_table(): ) -def put_item(test_client, rkey="12341234"): +def test_delete_from_unknown_table(test_client): + headers = { + "X-Amz-Target": "DynamoDB_20111205.DeleteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "TableName": "unknown_table", + "Key": { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341236"}, + }, + "ReturnValues": "ALL_OLD", + } + res = test_client.post("/", headers=headers, json=request_body) + res.status_code.should.equal(400) + json.loads(res.data).should.equal( + {"__type": "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"} + ) + + +def test_batch_get_item(test_client): + create_table(test_client) + + put_item(test_client) + put_item(test_client, rkey="12341235") + put_item(test_client, rkey="12341236") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.BatchGetItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "RequestItems": { + TABLE_WITH_RANGE_NAME: { + "Keys": [ + { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341235"}, + }, + { + "HashKeyElement": {"S": "customer"}, + "RangeKeyElement": {"N": "12341236"}, + }, + ], + } + } + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data)["Responses"] + + res.should.have.key("UnprocessedKeys").equal({}) + table_items = [i["Item"] for i in res[TABLE_WITH_RANGE_NAME]["Items"]] + table_items.should.have.length_of(2) + + table_items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341235"}} + ) + table_items.should.contain( + {"hkey": {"S": "customer"}, "name": {"S": "myname"}, "rkey": {"N": "12341236"}} + ) + + +def test_batch_get_item_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + put_item(test_client, use_range_key=False, hkey="customer1") + put_item(test_client, use_range_key=False, hkey="customer2") + put_item(test_client, use_range_key=False, hkey="customer3") + + headers = { + "X-Amz-Target": "DynamoDB_20111205.BatchGetItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "RequestItems": { + TABLE_NAME: { + "Keys": [ + {"HashKeyElement": {"S": "customer1"}}, + {"HashKeyElement": {"S": "customer3"}}, + ], + } + } + } + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data)["Responses"] + + res.should.have.key("UnprocessedKeys").equal({}) + table_items = [i["Item"] for i in res[TABLE_NAME]["Items"]] + table_items.should.have.length_of(2) + + table_items.should.contain({"hkey": {"S": "customer1"}, "name": {"S": "myname"}}) + table_items.should.contain({"hkey": {"S": "customer3"}, "name": {"S": "myname"}}) + + +def test_batch_write_item(test_client): + create_table(test_client) + + # BATCH-WRITE + headers = { + "X-Amz-Target": "DynamoDB_20111205.BatchWriteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "RequestItems": { + TABLE_WITH_RANGE_NAME: [ + { + "PutRequest": { + "Item": {"hkey": {"S": "customer"}, "rkey": {"S": "1234"}} + } + }, + { + "PutRequest": { + "Item": {"hkey": {"S": "customer"}, "rkey": {"S": "1235"}} + } + }, + ], + } + } + test_client.post("/", headers=headers, json=request_body) + + # SCAN - verify all items are present + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": TABLE_WITH_RANGE_NAME} + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(2) + + +def test_batch_write_item_without_range_key(test_client): + create_table(test_client, use_range_key=False) + + # BATCH-WRITE + headers = { + "X-Amz-Target": "DynamoDB_20111205.BatchWriteItem", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = { + "RequestItems": { + TABLE_NAME: [ + {"PutRequest": {"Item": {"hkey": {"S": "customer"}}}}, + {"PutRequest": {"Item": {"hkey": {"S": "customer2"}}}}, + ], + } + } + test_client.post("/", headers=headers, json=request_body) + + # SCAN - verify all items are present + headers = { + "X-Amz-Target": "DynamoDB_20111205.Scan", + "Content-Type": "application/x-amz-json-1.0", + } + request_body = {"TableName": TABLE_NAME} + res = test_client.post("/", headers=headers, json=request_body) + res = json.loads(res.data) + + res.should.have.key("Count").equal(2) + + +def put_item( + test_client, hkey="customer", rkey="12341234", name="myname", use_range_key=True +): + table_name = TABLE_WITH_RANGE_NAME if use_range_key else TABLE_NAME headers = { "X-Amz-Target": "DynamoDB_20111205.PutItem", "Content-Type": "application/x-amz-json-1.0", } request_body = { - "TableName": "Table1", - "Item": { - "hkey": {"S": "customer"}, - "rkey": {"N": rkey}, - "name": {"S": "myname"}, - }, + "TableName": table_name, + "Item": {"hkey": {"S": hkey}}, "ReturnValues": "ALL_OLD", } + if name: + request_body["Item"]["name"] = {"S": name} + if rkey and use_range_key: + request_body["Item"]["rkey"] = {"N": rkey} res = test_client.post("/", headers=headers, json=request_body) res = json.loads(res.data) return headers, res -def create_table(test_client): +def create_table(test_client, name=None, region=None, use_range_key=True): + if not name: + name = TABLE_WITH_RANGE_NAME if use_range_key else TABLE_NAME headers = { "X-Amz-Target": "DynamoDB_20111205.CreateTable", "Content-Type": "application/x-amz-json-1.0", } + if region: + headers["Host"] = "dynamodb.{}.amazonaws.com".format(region) request_body = { - "TableName": "Table1", + "TableName": name, "KeySchema": { - "HashKeyElement": {"AttributeName": "hkey", "AttributeType": "S"}, - "RangeKeyElement": {"AttributeName": "rkey", "AttributeType": "N"}, + "HashKeyElement": {"AttributeName": "hkey", "AttributeType": "S"} }, "ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 10}, } + if use_range_key: + request_body["KeySchema"]["RangeKeyElement"] = { + "AttributeName": "rkey", + "AttributeType": "N", + } return test_client.post("/", headers=headers, json=request_body)