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()
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)
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)
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)
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)
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
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)
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"), ]
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"), ]