Skip to content

Commit

Permalink
Merge client, tables tests into test_session #52
Browse files Browse the repository at this point in the history
  • Loading branch information
numberoverzero committed Aug 21, 2016
1 parent 358dc8e commit cf61382
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 138 deletions.
16 changes: 11 additions & 5 deletions tests/unit/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
]


# BASE MODEL =============================================================================================== BASE MODEL


def test_default_model_init():
"""Missing attributes are set to `None`"""
user = User(id=uuid.uuid4(), email="user@domain.com")
Expand Down Expand Up @@ -241,7 +244,7 @@ class Concrete(BaseModel):
assert not Concrete.Meta.abstract


def test_str(engine):
def test_model_str(engine):
"""Different strings for None and missing"""
new_user = User()
loaded_empty_user = engine._load(User, None)
Expand All @@ -252,7 +255,10 @@ def test_str(engine):
assert str(loaded_empty_user) == "User(age=None, email=None, id=None, joined=None, name=None)"


# COLUMN TESTS =========================================================================================== COLUMN TESTS
# END BASE MODEL ======================================================================================= END BASE MODEL


# COLUMN ======================================================================================================= COLUMN


def test_column_equals_alias_exists():
Expand Down Expand Up @@ -361,10 +367,10 @@ def test_column_repr_path():
column.hash_key = True
assert repr(column[3]["foo"]["bar"][2][1]) == "<Column[User.foo[3].foo.bar[2][1]=hash]>"

# END COLUMN TESTS =================================================================================== END COLUMN TESTS
# END COLUMN =============================================================================================== END COLUMN


# INDEX TESTS ============================================================================================= INDEX TESTS
# INDEX ========================================================================================================= INDEX


def test_index_dynamo_name():
Expand Down Expand Up @@ -466,4 +472,4 @@ def test_gsi_repr():
assert repr(index) == "<GSI[User.by_foo=all]>"


# END INDEX TESTS ===================================================================================== END INDEX TESTS
# END INDEX ================================================================================================= END INDEX
165 changes: 165 additions & 0 deletions tests/unit/test_client.py → tests/unit/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
from bloop.session import (
BATCH_GET_ITEM_CHUNK_SIZE,
SessionWrapper,
create_table_request,
expected_table_description,
ready,
sanitized_table_description,
simple_table_status,
)
from bloop.types import String
from bloop.util import ordered
Expand Down Expand Up @@ -41,6 +45,9 @@ def client_error(code):
return botocore.exceptions.ClientError(error_response, operation_name)


# LOAD ITEMS =============================================================================================== LOAD ITEMS


def test_batch_get_raises(session, dynamodb_client):
cause = dynamodb_client.batch_get_item.side_effect = client_error("FooError")
request = {"TableName": {"Keys": ["key"], "ConsistentRead": False}}
Expand Down Expand Up @@ -212,6 +219,12 @@ def handle(RequestItems):
assert response == expected_response


# END LOAD ITEMS ======================================================================================= END LOAD ITEMS


# CREATE TABLE =========================================================================================== CREATE TABLE


def test_create_table(session, dynamodb_client):
expected = {
"LocalSecondaryIndexes": [
Expand Down Expand Up @@ -286,6 +299,12 @@ def test_create_already_exists(session, dynamodb_client):
assert dynamodb_client.create_table.call_count == 1


# END CREATE TABLE =================================================================================== END CREATE TABLE


# DELETE ITEM ============================================================================================= DELETE ITEM


def test_delete_item(session, dynamodb_client):
request = {"foo": "bar"}
session.delete_item(request)
Expand All @@ -311,6 +330,12 @@ def test_delete_item_condition_failed(session, dynamodb_client):
dynamodb_client.delete_item.assert_called_once_with(**request)


# END DELETE ITEM ===================================================================================== END DELETE ITEM


# SAVE ITEM ================================================================================================= SAVE ITEM


def test_save_item(session, dynamodb_client):
request = {"foo": "bar"}
session.save_item(request)
Expand All @@ -336,6 +361,12 @@ def test_save_item_condition_failed(session, dynamodb_client):
dynamodb_client.update_item.assert_called_once_with(**request)


# END SAVE ITEM ========================================================================================= END SAVE ITEM


# QUERY SCAN SEARCH ================================================================================= QUERY SCAN SEARCH


@pytest.mark.parametrize("response, expected", [
({}, (0, 0)),
({"Count": -1}, (-1, -1)),
Expand Down Expand Up @@ -369,6 +400,9 @@ def test_search_unknown(session):
assert "foo" in str(excinfo.value)


# VALIDATION HELPERS =============================================================================== VALIDATION HELPERS


def test_validate_compares_tables(session, dynamodb_client):
description = expected_table_description(User)
description["TableStatus"] = "ACTIVE"
Expand Down Expand Up @@ -439,3 +473,134 @@ def test_validate_raises(session, dynamodb_client):
with pytest.raises(BloopException) as excinfo:
session.validate_table(User)
assert excinfo.value.__cause__ is cause


# END VALIDATION HELPERS ======================================================================= END VALIDATION HELPERS


# TABLE HELPERS ========================================================================================= TABLE HELPERS


def assert_unordered(obj, other):
assert ordered(obj) == ordered(other)


def test_create_simple():
expected = {
'AttributeDefinitions': [
{'AttributeName': 'id', 'AttributeType': 'S'}],
'KeySchema': [{'AttributeName': 'id', 'KeyType': 'HASH'}],
'ProvisionedThroughput': {
'ReadCapacityUnits': 1,
'WriteCapacityUnits': 1},
'TableName': 'Simple'}
assert_unordered(create_table_request(SimpleModel), expected)


def test_create_complex():
expected = {
'AttributeDefinitions': [
{'AttributeType': 'S', 'AttributeName': 'date'},
{'AttributeType': 'S', 'AttributeName': 'email'},
{'AttributeType': 'S', 'AttributeName': 'joined'},
{'AttributeType': 'S', 'AttributeName': 'name'}],
'GlobalSecondaryIndexes': [{
'IndexName': 'by_email',
'KeySchema': [{'KeyType': 'HASH', 'AttributeName': 'email'}],
'Projection': {'ProjectionType': 'ALL'},
'ProvisionedThroughput': {
'ReadCapacityUnits': 4, 'WriteCapacityUnits': 5}}],
'KeySchema': [{'KeyType': 'HASH', 'AttributeName': 'name'},
{'KeyType': 'RANGE', 'AttributeName': 'date'}],
'LocalSecondaryIndexes': [{
'IndexName': 'by_joined',
'KeySchema': [
{'KeyType': 'HASH', 'AttributeName': 'name'},
{'KeyType': 'RANGE', 'AttributeName': 'joined'}],
'Projection': {
'NonKeyAttributes': ['joined', 'email', 'date', 'name'],
'ProjectionType': 'INCLUDE'}}],
'ProvisionedThroughput': {
'ReadCapacityUnits': 3, 'WriteCapacityUnits': 2},
'TableName': 'CustomTableName'}
assert_unordered(create_table_request(ComplexModel), expected)


def test_expected_description():
# Eventually expected_table_description will probably diverge from create_table
# This will guard against (or coverage should show) if there's drift
create = create_table_request(ComplexModel)
expected = expected_table_description(ComplexModel)
assert_unordered(create, expected)


def test_sanitize_drop_empty_lists():
expected = expected_table_description(ComplexModel)
# Start from the same base, but inject an unnecessary NonKeyAttributes
description = expected_table_description(ComplexModel)
index = description["GlobalSecondaryIndexes"][0]
index["Projection"]["NonKeyAttributes"] = []

assert_unordered(expected, sanitized_table_description(description))


def test_sanitize_drop_empty_indexes():
expected = expected_table_description(SimpleModel)
# Start from the same base, but inject an unnecessary NonKeyAttributes
description = expected_table_description(SimpleModel)
description["GlobalSecondaryIndexes"] = []

assert_unordered(expected, sanitized_table_description(description))


def test_sanitize_expected():
expected = expected_table_description(User)
# Add some extra fields
description = {
'AttributeDefinitions': [
{'AttributeType': 'S', 'AttributeName': 'email'},
{'AttributeType': 'S', 'AttributeName': 'id'}],
'CreationDateTime': 'EXTRA_FIELD',
'ItemCount': 'EXTRA_FIELD',
'KeySchema': [{'AttributeName': 'id', 'KeyType': 'HASH'}],
'GlobalSecondaryIndexes': [{
'IndexArn': 'EXTRA_FIELD',
'IndexName': 'by_email',
'IndexSizeBytes': 'EXTRA_FIELD',
'IndexStatus': 'EXTRA_FIELD',
'KeySchema': [{'AttributeName': 'email', 'KeyType': 'HASH'}],
'Projection': {'ProjectionType': 'ALL'},
'ProvisionedThroughput': {
'NumberOfDecreasesToday': 'EXTRA_FIELD',
'ReadCapacityUnits': 1,
'WriteCapacityUnits': 1}}],
'ProvisionedThroughput': {
'LastDecreaseDateTime': 'EXTRA_FIELD',
'LastIncreaseDateTime': 'EXTRA_FIELD',
'NumberOfDecreasesToday': 'EXTRA_FIELD',
'ReadCapacityUnits': 1,
'WriteCapacityUnits': 1},
'TableArn': 'EXTRA_FIELD',
'TableName': 'User',
'TableSizeBytes': 'EXTRA_FIELD',
'TableStatus': 'EXTRA_FIELD'}
sanitized = sanitized_table_description(description)
assert_unordered(expected, sanitized)


@pytest.mark.parametrize("table_status, gsi_status, expected_status", [
("ACTIVE", "ACTIVE", ready),
("ACTIVE", None, ready),
("ACTIVE", "BUSY", None),
("BUSY", "ACTIVE", None),
("BUSY", "BUSY", None)
])
def test_simple_status(table_status, gsi_status, expected_status):
"""Status is busy because table isn't ACTIVE, no GSIs"""
description = {"TableStatus": table_status}
if gsi_status is not None:
description["GlobalSecondaryIndexes"] = [{"IndexStatus": gsi_status}]
assert simple_table_status(description) == expected_status


# END TABLE HELPERS ================================================================================= END TABLE HELPERS

0 comments on commit cf61382

Please sign in to comment.