Example #1
0
def test_bind_skip_table_setup(dynamodb, dynamodbstreams):
    # Required so engine doesn't pass boto3 to the wrapper
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    engine.session = Mock(spec=SessionWrapper)

    engine.bind(User, skip_table_setup=True)
    engine.session.create_table.assert_not_called()
    engine.session.validate_table.assert_not_called()
Example #2
0
def test_bind_configures_ttl(dynamodb, dynamodbstreams):
    # Required so engine doesn't pass boto3 to the wrapper
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    engine.session = Mock(spec=SessionWrapper)

    class MyUser(BaseModel):
        class Meta:
            ttl = {"column": "expiry"}
        id = Column(Integer, hash_key=True)
        expiry = Column(Timestamp)

    engine.bind(MyUser)
    engine.session.describe_table.assert_called_once_with("MyUser")
    engine.session.enable_ttl.assert_called_once_with("MyUser", MyUser)
Example #3
0
def test_default_table_name_template(dynamodb, dynamodbstreams, session):
    """When no table_name_template is provided, the default of '{table_name}' is used"""
    class LocalModel(BaseModel):
        class Meta:
            table_name = "my-table-name"
        id = Column(Integer, hash_key=True)

    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    # Replace mock clients immediately
    engine.session = session

    engine.bind(LocalModel)
    session.create_table.assert_called_once_with("my-table-name", LocalModel)
    session.validate_table.assert_called_once_with("my-table-name", LocalModel)
Example #4
0
def test_str_table_name_template(dynamodb, dynamodbstreams, session):
    """When a string is provided for table_name_template, .format is called on it with the key table_name"""
    class LocalModel(BaseModel):
        class Meta:
            table_name = "my-table-name"
        id = Column(Integer, hash_key=True)

    template = "prefix-{table_name}"
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams, table_name_template=template)
    # Replace mock clients immediately
    engine.session = session

    engine.bind(LocalModel)
    session.create_table.assert_called_once_with("prefix-my-table-name", LocalModel)
    session.validate_table.assert_called_once_with("prefix-my-table-name", LocalModel)
Example #5
0
def test_func_table_name_template(dynamodb, dynamodbstreams, session):
    """When a function is provided for table_name_template, it is called with the model as its sole argument."""
    class LocalModel(BaseModel):
        class Meta:
            table_name = "my-table-name"
        id = Column(Integer, hash_key=True)

    def template(model):
        assert issubclass(model, BaseModel)
        return "reverse-" + model.Meta.table_name[::-1]
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams, table_name_template=template)
    # Replace mock clients immediately
    engine.session = session

    engine.bind(LocalModel)
    expected = "reverse-eman-elbat-ym"
    session.create_table.assert_called_once_with(expected, LocalModel)
    session.validate_table.assert_called_once_with(expected, LocalModel)
Example #6
0
def test_bind_different_engines(dynamodb, dynamodbstreams):
    # Required so engine doesn't pass boto3 to the wrapper
    first_engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    second_engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)

    first_engine.session = Mock(spec=SessionWrapper)
    second_engine.session = Mock(spec=SessionWrapper)

    class Concrete(BaseModel):
        id = Column(Integer, hash_key=True)
    first_engine.bind(Concrete)
    second_engine.bind(Concrete)

    # Create/Validate are only called once per bind
    first_engine.session.create_table.assert_called_once_with("Concrete", Concrete)
    first_engine.session.validate_table.assert_called_once_with("Concrete", Concrete)
    second_engine.session.create_table.assert_called_once_with("Concrete", Concrete)
    second_engine.session.validate_table.assert_called_once_with("Concrete", Concrete)
Example #7
0
def test_bind_skip_table_setup(dynamodb, dynamodbstreams, caplog):
    # Required so engine doesn't pass boto3 to the wrapper
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    engine.session = Mock(spec=SessionWrapper)

    engine.bind(User, skip_table_setup=True)
    engine.session.create_table.assert_not_called()
    engine.session.validate_table.assert_not_called()

    assert caplog.record_tuples == [
        ("bloop.engine", logging.DEBUG,
         "binding non-abstract models ['Admin', 'User']"),
        ("bloop.engine", logging.INFO,
         "skip_table_setup is True; not trying to create tables or validate models during bind"
         ),
        ("bloop.engine", logging.INFO,
         "successfully bound 2 models to the engine"),
    ]
Example #8
0
def test_bind_skip_table_setup(dynamodb, dynamodbstreams, caplog):
    # Required so engine doesn't pass boto3 to the wrapper
    engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    engine.session = Mock(spec=SessionWrapper)

    class MyUser(BaseModel):
        id = Column(Integer, hash_key=True)

    caplog.handler.records.clear()

    engine.bind(MyUser, skip_table_setup=True)
    engine.session.create_table.assert_not_called()
    engine.session.validate_table.assert_not_called()

    assert caplog.record_tuples == [
        ("bloop.engine", logging.DEBUG, "binding non-abstract models ['MyUser']"),
        ("bloop.engine", logging.INFO,
         "skip_table_setup is True; not trying to create tables or validate models during bind"),
        ("bloop.engine", logging.INFO, "successfully bound 1 models to the engine"),
    ]
Example #9
0
def test_bind_different_engines(dynamodb, dynamodbstreams):
    # Required so engine doesn't pass boto3 to the wrapper
    first_engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)
    second_engine = Engine(dynamodb=dynamodb, dynamodbstreams=dynamodbstreams)

    first_engine.session = Mock(spec=SessionWrapper)
    second_engine.session = Mock(spec=SessionWrapper)

    class Concrete(BaseModel):
        id = Column(Integer, hash_key=True)

    first_engine.bind(Concrete)
    second_engine.bind(Concrete)

    # Create/Validate are only called once per bind
    first_engine.session.create_table.assert_called_once_with(Concrete)
    first_engine.session.validate_table.assert_called_once_with(Concrete)
    second_engine.session.create_table.assert_called_once_with(Concrete)
    second_engine.session.validate_table.assert_called_once_with(Concrete)

    # The model (and its columns) are bound to each engine's TypeEngine,
    # regardless of how many times the model has been bound already
    assert Concrete in first_engine.type_engine.bound_types
    assert Concrete in second_engine.type_engine.bound_types