1336 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1336 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import json
 | |
| import sure  # noqa # pylint: disable=unused-import
 | |
| import pytest
 | |
| 
 | |
| import moto.server as server
 | |
| from moto.dynamodb_v20111205 import dynamodb_backends
 | |
| 
 | |
| """
 | |
| 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"
 | |
| 
 | |
| 
 | |
| @pytest.fixture(autouse=True, name="test_client")
 | |
| def fixture_test_client():
 | |
|     backend = server.create_backend_app("dynamodb_v20111205")
 | |
|     test_client = backend.test_client()
 | |
| 
 | |
|     yield test_client
 | |
| 
 | |
|     for _, backend in dynamodb_backends.items():
 | |
|         backend.reset()
 | |
| 
 | |
| 
 | |
| 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)
 | |
|     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(test_client):
 | |
| 
 | |
|     create_table(test_client)
 | |
| 
 | |
|     headers, res = put_item(test_client)
 | |
| 
 | |
|     # UpdateItem
 | |
|     headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem"
 | |
|     request_body = {
 | |
|         "TableName": TABLE_WITH_RANGE_NAME,
 | |
|         "Key": {
 | |
|             "HashKeyElement": {"S": "customer"},
 | |
|             "RangeKeyElement": {"N": "12341234"},
 | |
|         },
 | |
|         "AttributeUpdates": {"new_att": {"Value": {"SS": ["val"]}, "Action": "PUT"}},
 | |
|     }
 | |
|     res = test_client.post("/", headers=headers, json=request_body)
 | |
| 
 | |
|     # UpdateItem
 | |
|     headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem"
 | |
|     request_body = {
 | |
|         "TableName": TABLE_WITH_RANGE_NAME,
 | |
|         "Key": {
 | |
|             "HashKeyElement": {"S": "customer"},
 | |
|             "RangeKeyElement": {"N": "12341234"},
 | |
|         },
 | |
|         "AttributeUpdates": {"new_n": {"Value": {"N": "42"}, "Action": "PUT"}},
 | |
|     }
 | |
|     res = test_client.post("/", headers=headers, json=request_body)
 | |
|     res = json.loads(res.data)
 | |
| 
 | |
|     res["ConsumedCapacityUnits"].should.equal(0.5)
 | |
|     res["Attributes"].should.equal(
 | |
|         {
 | |
|             "hkey": "customer",
 | |
|             "name": "myname",
 | |
|             "rkey": "12341234",
 | |
|             "new_att": ["val"],
 | |
|             "new_n": "42",
 | |
|         }
 | |
|     )
 | |
| 
 | |
|     # UpdateItem - multiples
 | |
|     headers["X-Amz-Target"] = "DynamoDB_20111205.UpdateItem"
 | |
|     request_body = {
 | |
|         "TableName": TABLE_WITH_RANGE_NAME,
 | |
|         "Key": {
 | |
|             "HashKeyElement": {"S": "customer"},
 | |
|             "RangeKeyElement": {"N": "12341234"},
 | |
|         },
 | |
|         "AttributeUpdates": {
 | |
|             "new_n": {"Value": {"N": 7}, "Action": "ADD"},
 | |
|             "new_att": {"Value": {"S": "val2"}, "Action": "ADD"},
 | |
|             "name": {"Action": "DELETE"},
 | |
|         },
 | |
|     }
 | |
|     res = test_client.post("/", headers=headers, json=request_body)
 | |
|     res = json.loads(res.data)
 | |
| 
 | |
|     res["ConsumedCapacityUnits"].should.equal(0.5)
 | |
|     res["Attributes"].should.equal(
 | |
|         {
 | |
|             "hkey": "customer",
 | |
|             "rkey": "12341234",
 | |
|             "new_att": ["val", "val2"],
 | |
|             "new_n": "49",
 | |
|         }
 | |
|     )
 | |
| 
 | |
|     # 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("new_att").equal({"SS": ["val", "val2"]})
 | |
|     res["Item"].should.have.key("new_n").equal({"N": "49"})
 | |
|     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)
 | |
|     # 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(test_client):
 | |
|     create_table(test_client)
 | |
| 
 | |
|     # UpdateItem
 | |
|     headers = {"X-Amz-Target": "DynamoDB_20111205.UpdateItem"}
 | |
|     request_body = {
 | |
|         "TableName": "Table1",
 | |
|         "Key": {
 | |
|             "HashKeyElement": {"S": "customer"},
 | |
|             "RangeKeyElement": {"N": "12341234"},
 | |
|         },
 | |
|         "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"}
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_update_item_in_nonexisting_table(test_client):
 | |
|     # UpdateItem
 | |
|     headers = {"X-Amz-Target": "DynamoDB_20111205.UpdateItem"}
 | |
|     request_body = {
 | |
|         "TableName": "nonexistent",
 | |
|         "Key": {
 | |
|             "HashKeyElement": {"S": "customer"},
 | |
|             "RangeKeyElement": {"N": "12341234"},
 | |
|         },
 | |
|         "AttributeUpdates": {"new_att": {"Value": {"SS": ["val"]}, "Action": "PUT"}},
 | |
|     }
 | |
|     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_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": 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, 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"] = f"dynamodb.{region}.amazonaws.com"
 | |
|     request_body = {
 | |
|         "TableName": name,
 | |
|         "KeySchema": {
 | |
|             "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)
 |