Ejemplo n.º 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()
Ejemplo n.º 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)
Ejemplo n.º 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)
Ejemplo n.º 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)
Ejemplo n.º 5
0
def test_malformed_table_name_template(dynamodb, dynamodbstreams):
    """When a string is provided that doesn't have the correct format key {table_name}, InvalidTemplate is raised"""
    template = "prefix-{wrong_key}"
    with pytest.raises(InvalidTemplate):
        Engine(dynamodb=dynamodb,
               dynamodbstreams=dynamodbstreams,
               table_name_template=template)
Ejemplo n.º 6
0
def test_wrong_type_table_name_template(dynamodb, dynamodbstreams):
    """When the template is neither a string nor a function is provided, ValueError is raised."""
    template = object()
    with pytest.raises(ValueError):
        # noinspection PyTypeChecker
        Engine(dynamodb=dynamodb,
               dynamodbstreams=dynamodbstreams,
               table_name_template=template)
Ejemplo n.º 7
0
def test_get_table_name(dynamodb, dynamodbstreams):
    def transform_table_name(model):
        return f"transform.{model.Meta.table_name}"

    engine = Engine(dynamodb=dynamodb,
                    dynamodbstreams=dynamodbstreams,
                    table_name_template=transform_table_name)
    obj = HashAndRange()
    assert get_table_name(engine, obj) == "transform.HashAndRange"
Ejemplo n.º 8
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)
Ejemplo n.º 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", 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)
Ejemplo n.º 10
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"),
    ]
Ejemplo n.º 11
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"),
    ]
Ejemplo n.º 12
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
Ejemplo n.º 13
0
def test_get_table_name(dynamodb, dynamodbstreams):
    def transform_table_name(model):
        return f"transform.{model.Meta.table_name}"

    class HashAndRange(BaseModel):
        class Meta:
            table_name = "custom.name"

        foo = Column(Integer, hash_key=True)
        bar = Column(Integer, range_key=True)

    engine = Engine(dynamodb=dynamodb,
                    dynamodbstreams=dynamodbstreams,
                    table_name_template=transform_table_name)
    obj = HashAndRange()
    assert get_table_name(engine, obj) == "transform.custom.name"