def db(app, account_id, client_id):
    event_store_db.create_all()

    operation_id = UniqueID()
    account_created_event = AccountCreated(operation_id=operation_id.value,
                                           client_id=client_id.value,
                                           account_id=account_id.value,
                                           account_name='test')
    account_credit_event = AccountCredited(operation_id=operation_id.value,
                                           dollars=23,
                                           cents=0,
                                           account_id=account_id.value)

    aggregate = AggregateModel(uuid=account_id.value,
                               version=AGGREGATE_VERSION)

    event1 = EventModel(uuid=str(UniqueID()),
                        aggregate_uuid=account_id.value,
                        name=account_created_event.__class__.__name__,
                        data=asdict(account_created_event))
    event2 = EventModel(uuid=str(UniqueID()),
                        aggregate_uuid=account_id.value,
                        name=account_credit_event.__class__.__name__,
                        data=asdict(account_credit_event))
    # Add aggregate and event to the db.
    event_store_db.session.add(aggregate)
    event_store_db.session.flush()
    event_store_db.session.add(event1)
    event_store_db.session.commit()
    event_store_db.session.add(event2)
    event_store_db.session.commit()

    yield event_store_db  # this is the object that the tests use

    event_store_db.drop_all()
Beispiel #2
0
def test_initialize_sets_uncommitted_changes():
    aggregate = applyless_aggregate()
    aggregate._initialize([
        BaseEvent(operation_id=str(UniqueID())),
        BaseEvent(operation_id=str(UniqueID()))
    ])
    assert len(aggregate.uncommitted_changes) == 2
Beispiel #3
0
def test_add_account_produces_account_added_events_with_new_account_id(
        new_client):
    new_account_id = UniqueID()
    new_client.add_account(new_account_id, UniqueID(), 'test')
    assert isinstance(new_client.uncommitted_changes[-1], AccountAddedToClient)
    assert new_client.uncommitted_changes[
        -1].account_id == new_account_id.value
def new_client():
    client = Client.create(ssn=SocialSecurityNumber(345456567),
                           last_name=LastName("test"),
                           first_name=FirstName("more"),
                           birthdate=Birthdate('23/04/1993'),
                           operation_id=UniqueID())
    client.add_account(UniqueID(), UniqueID())
    return client
Beispiel #5
0
def test_apply_event_is_called_for_each_event_passed_when_loading_aggregate():
    with patch.object(AggregateRoot, 'apply_event') as mock:
        AggregateRoot(
            EventStream([
                BaseEvent(operation_id=str(UniqueID())),
                BaseEvent(operation_id=str(UniqueID())),
                BaseEvent(operation_id=str(UniqueID()))
            ]))
    assert mock.call_count == 3
Beispiel #6
0
def test_maximum_debt_cannot_be_lower_than_balance(
        new_random_account_with_high_maximum_debt):
    new_random_account_with_high_maximum_debt.debit(
        new_random_account_with_high_maximum_debt.maximum_debt / Amount(2, 0),
        UniqueID())
    with pytest.raises(ValueError):
        new_random_account_with_high_maximum_debt.set_maximum_debt(
            new_random_account_with_high_maximum_debt.maximum_debt /
            Amount(3, 0), UniqueID())
def get_operation_id(args: Dict[Any, Any]) -> UniqueID:
    try:
        operation_id = args['operation_id']
        if operation_id:
            return UniqueID(operation_id)
        else:
            return UniqueID()
    except KeyError:
        return UniqueID()
Beispiel #8
0
def test_marking_changes_as_committed_adds_committed_events_operation_ids_to_committed_operations(
):
    aggregate = applyless_aggregate()
    event1 = BaseEvent(operation_id=str(UniqueID()))
    event2 = BaseEvent(operation_id=str(UniqueID()))
    aggregate.apply_event(event1)
    aggregate.apply_event(event2)
    aggregate.mark_changes_as_committed()
    assert event1.operation_id in aggregate.committed_operations
    assert event2.operation_id in aggregate.committed_operations
def test_save_events_passing_expected_version_for_new_aggregate_throws_concurrency_error(
        session: Session, postgres_event_store):
    account_id = UniqueID()
    account_created_event = AccountCreated(operation_id=str(UniqueID()),
                                           client_id=str(UniqueID()),
                                           account_id=str(account_id),
                                           account_name='test')
    with pytest.raises(ConcurrencyException):
        postgres_event_store.save_events(account_id, [account_created_event],
                                         expected_version=6)
def test_save_events_tries_to_create_new_aggregate_if_no_expected_version_passed(
        session: Session, postgres_event_store):
    account_id = UniqueID()
    account_created_event = AccountCreated(operation_id=str(UniqueID()),
                                           client_id=str(UniqueID()),
                                           account_id=str(account_id),
                                           account_name='test')
    postgres_event_store.save_events(account_id, [account_created_event])
    found = session.query(AggregateModel).filter(
        AggregateModel.uuid == account_id.value).all()
    assert len(found) == 1
Beispiel #11
0
 def wrapped(target_id):
     if account_id == target_id:
         account_created = AccountCreated(
             operation_id=str(UniqueID()),
             account_id=str(UniqueID()),
             client_id=account_id,
             account_name='test'
         )
         account = Account(EventStream([account_created]))
         account.set_maximum_debt(Amount(500, 0), UniqueID())
         return account
     return None
 def wrapped(target_id: UniqueID):
     if account_id == target_id:
         return EventStream([
             AccountCreated(operation_id=str(UniqueID()),
                            client_id=str(UniqueID()),
                            account_id=str(account_id),
                            account_name='test'),
             AccountCredited(dollars=20,
                             cents=0,
                             account_id=account_id.value,
                             operation_id=str(UniqueID))
         ],
                            version=2)
     return None
def test_save_events_adds_related_events_to_new_aggregate(
        session: Session, postgres_event_store):
    account_id = UniqueID()
    account_created_event = AccountCreated(operation_id=str(UniqueID()),
                                           client_id=str(UniqueID()),
                                           account_id=str(account_id),
                                           account_name='test')
    credit_event = AccountCredited(dollars=22,
                                   cents=0,
                                   account_id=str(account_id),
                                   operation_id=str(UniqueID()))
    postgres_event_store.save_events(
        aggregate_id=account_id, events=[account_created_event, credit_event])
    aggregate = session.query(AggregateModel).filter(
        AggregateModel.uuid == account_id.value).one()
    assert len(aggregate.events) == 2
def test_get_by_id_applies_event_stream(account_repo, fake_event_store):
    account_id = UniqueID()
    fake_event_store.load_stream = MagicMock(
        side_effect=return_based_on_id(account_id))
    account = account_repo.get_by_id(account_id)
    assert account.balance == Amount(20)
    assert account.version == 2
Beispiel #15
0
 def _(self, event: ClientCreated) -> None:
     self._client_id: UniqueID = UniqueID(event.client_id)
     self._ssn: SocialSecurityNumber = SocialSecurityNumber(event.ssn)
     self._first_name: FirstName = FirstName(event.first_name)
     self._last_name: LastName = LastName(event.last_name)
     self._birthdate: Birthdate = Birthdate(event.birthdate)
     self._accounts: List[UniqueID] = []
Beispiel #16
0
 def wrapper(target_id):
     client = return_based_on_id(client_id)(target_id)
     if client:
         client.add_account(account_id, UniqueID(), 'test')
         client.mark_changes_as_committed()
         return client
     return None
Beispiel #17
0
def test_remove_account_for_client_adds_removed_account_event_to_uncommitted_changes(
        fake_client_repo_with_accounts, client_id, account_id):
    remove_account_from_client(UniqueID(), client_id, account_id,
                               fake_client_repo_with_accounts)
    account_called_with: Client = fake_client_repo_with_accounts.save.call_args.args[
        0]
    assert isinstance(account_called_with.uncommitted_changes[-1],
                      AccountRemovedFromClient)
Beispiel #18
0
def test_remove_account_produces_account_removed_event_with_right_account_id(
        new_client_with_account):
    account_id = new_client_with_account.accounts[0]
    new_client_with_account.remove_account(account_id, UniqueID())
    assert isinstance(new_client_with_account.uncommitted_changes[-1],
                      AccountRemovedFromClient)
    assert new_client_with_account.uncommitted_changes[
        -1].account_id == account_id.value
Beispiel #19
0
def test_debit_adds_account_debited_event_to_uncommitted_changes(
        new_random_account_unlimited_debt, new_random_account_debit_event):
    amount = Amount(new_random_account_debit_event.dollars,
                    new_random_account_debit_event.cents)
    new_random_account_unlimited_debt.debit(amount, UniqueID())
    assert isinstance(
        new_random_account_unlimited_debt.uncommitted_changes[-1],
        AccountDebited)
Beispiel #20
0
def test_credit_adds_account_credited_event_to_uncommitted_changes(
        new_random_account, related_random_account_created_event,
        new_random_account_credit_event):
    account = Account(EventStream([related_random_account_created_event]))
    amount = Amount(new_random_account_credit_event.dollars,
                    new_random_account_credit_event.cents)
    account.credit(amount,
                   UniqueID(new_random_account_credit_event.operation_id))
    assert account.uncommitted_changes[-1] == new_random_account_credit_event
Beispiel #21
0
def add_account_to_client(operation_id: UniqueID, client_id: UniqueID,
                          repo: ClientWriteRepository,
                          new_account_name: str) -> UniqueID:
    client = repo.get_by_id(client_id)
    new_account_id = UniqueID()
    client.add_account(account_name=new_account_name,
                       account_id=new_account_id,
                       operation_id=operation_id)
    repo.save(client)
    return new_account_id
Beispiel #22
0
def test_applying_new_event_with_same_operation_id_as_already_committed_event_raises_app_exception(
):
    aggregate = applyless_aggregate()
    operation_id = UniqueID()
    event1 = BaseEvent(operation_id=operation_id.value)
    event2 = BaseEvent(operation_id=operation_id.value)
    aggregate.apply_event(event1)
    aggregate.mark_changes_as_committed()
    with pytest.raises(OperationDuplicate):
        aggregate.apply_event(event2)
Beispiel #23
0
def test_create_client_adds_created_event_to_uncommitted_changes(
        fake_client_repo):
    create_client(
        UniqueID(),
        ClientDetailsDTO(social_security_number=123543234,
                         first_name="asd",
                         last_name="fdsf",
                         birthdate="12/04/2012"), fake_client_repo)
    account_called_with: Client = fake_client_repo.save.call_args.args[0]
    assert isinstance(account_called_with.uncommitted_changes[-1],
                      ClientCreated)
Beispiel #24
0
 def wrapped(target_id):
     if client_id == target_id:
         client_created = ClientCreated(
             operation_id=str(UniqueID()),
             client_id=client_id.value,
             ssn=SocialSecurityNumber(123456789).value,
             first_name=FirstName('asd').value,
             last_name=LastName('asd').value,
             birthdate=Birthdate('22/01/1900').value)
         client = Client(EventStream([client_created]))
         return client
     return None
Beispiel #25
0
 def create(ssn: SocialSecurityNumber, first_name: FirstName,
            last_name: LastName, birthdate: Birthdate,
            operation_id: UniqueID) -> 'Client':
     created_event = ClientCreated(client_id=str(UniqueID()),
                                   ssn=ssn.value,
                                   first_name=first_name.value,
                                   last_name=last_name.value,
                                   birthdate=birthdate.value,
                                   operation_id=operation_id.value)
     client = Client(EventStream([created_event]))
     client._initialize([created_event])
     return client
Beispiel #26
0
def create_account(
        operation_id: UniqueID,
        account_name: str,
        account_id: UniqueID,
        client_id: UniqueID,
        account_repo: AccountWriteRepository,
        default_maximum_debt: Optional[AmountDTO] = None) -> Account:
    account = Account.create(client_id, account_id, operation_id, account_name)
    if default_maximum_debt:
        account.set_maximum_debt(
            Amount(default_maximum_debt.dollars, default_maximum_debt.cents),
            UniqueID())
    account_repo.save(account)
    return account
Beispiel #27
0
 def save_events(self,
                 aggregate_id: UniqueID,
                 events: List[BaseEvent],
                 expected_version: Optional[int] = None) -> None:
     if expected_version and expected_version != -1:
         self._update_aggregate_version_check(aggregate_id,
                                              expected_version)
     else:
         self._create_aggregate(aggregate_id)
     for event in events:
         self.session.add(
             EventModel(uuid=str(UniqueID()),
                        aggregate_uuid=str(aggregate_id),
                        name=event.__class__.__name__,
                        data=asdict(event)))
Beispiel #28
0
 def post(self, client_id: str) -> (str, int):
     try:
         args = client_add_account_parser.parse_args()
         operation_id = get_operation_id(args)
         new_account_name = args['account_name']
         with get_client_write_repo() as client_repo:
             new_account_id = add_account_to_client(operation_id, UniqueID(client_id), client_repo, new_account_name)
         return Response(
             status=StatusCodes.CREATED.value,
             headers={
                 'Location': request.base_url + f'/{new_account_id}'
             }
         )
     except AppException as e:
         return {'message': str(e)}, e.status
     except BadRequest as e:
         return e.data['errors'], e.code
     except ValueError as e:
         return {'message': str(e)}, StatusCodes.INVALID_USER_DATA.value
     except Exception as e:
         logger.error(e)
         return str(e), StatusCodes.INTERNAL_SERVER_ERROR.value
Beispiel #29
0
 def patch(self, account_id):
     """
     Change account balance, credit or debit the account
     """
     try:
         args = account_balance_parser.parse_args()
         operation_id = get_operation_id(args)
         action = args['action']
         amount = AmountDTO(dollars=args['dollars'], cents=args['cents'])
         with get_account_write_repo() as account_repo:
             action_func = self._get_func_by_action(action)
             action_func(operation_id, UniqueID(account_id), account_repo,
                         amount)
     except AppException as e:
         return {'message': str(e)}, e.status
     except BadRequest as e:
         return e.data['errors'], e.code
     except ValueError as e:
         return {'message': str(e)}, StatusCodes.INVALID_REQUEST.value
     except Exception as e:
         logger.error(e)
         return str(e), StatusCodes.INTERNAL_SERVER_ERROR.value
Beispiel #30
0
def test_str_function_on_unique_id():
    g_id = UniqueID('asd')
    assert str(g_id) == 'asd'