def test_should_not_be_winning_if_bid_lower_than_current_price() -> None:
    auction = AuctionFactory(bids=[Bid(id=1, bidder_id=1, amount=get_dollars("10.00"))])

    lower_bid_bidder_id = 2
    auction.place_bid(bidder_id=lower_bid_bidder_id, amount=get_dollars("5.00"))

    assert lower_bid_bidder_id not in auction.winners
Beispiel #2
0
def test_Auction_FirstBid_EmitsEvent(place_bid_uc: PlacingBid, event_bus: Mock,
                                     auction_id: AuctionId,
                                     auction_title: str) -> None:
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("100")))

    event_bus.post.assert_called_once_with(
        WinningBidPlaced(auction_id, 1, get_dollars("100"), auction_title))
Beispiel #3
0
def test_saves_auction_changes(
    connection: Connection,
    another_bidder_id: int,
    bid_model: RowProxy,
    auction_model_with_a_bid: RowProxy,
    ends_at: datetime,
    event_bus_mock: Mock,
) -> None:
    new_bid_price = get_dollars(bid_model.amount * 2)
    auction = Auction(
        id=auction_model_with_a_bid.id,
        title=auction_model_with_a_bid.title,
        starting_price=get_dollars(auction_model_with_a_bid.starting_price),
        ends_at=ends_at,
        bids=[
            Bid(bid_model.id, bid_model.bidder_id,
                get_dollars(bid_model.amount)),
            Bid(None, another_bidder_id, new_bid_price),
        ],
        ended=True,
    )

    SqlAlchemyAuctionsRepo(connection, event_bus_mock).save(auction)

    assert connection.execute(select([func.count()
                                      ]).select_from(bids)).scalar() == 2
    proxy = connection.execute(
        select([
            auctions
        ]).where(auctions.c.id == auction_model_with_a_bid.id)).first()
    assert proxy.current_price == new_bid_price.amount
    assert proxy.ended
Beispiel #4
0
def test_Auction_BidLowerThanCurrentPrice_IsLosing(
        place_bid_uc: PlacingBid,
        output_boundary: PlacingBidOutputBoundaryFake,
        auction_id: AuctionId) -> None:
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("5")))

    assert output_boundary.dto == PlacingBidOutputDto(
        is_winner=False, current_price=get_dollars("10"))
def test_BeginningAuction_SocksFor10DollarsEndingInFuture_emitsEvent(
        beginning_auction_uc: BeginningAuction, event_bus_mock: Mock) -> None:
    input_dto = BeginningAuctionInputDto(1, "Socks", get_dollars("10.00"),
                                         datetime.now() + timedelta(days=7))
    beginning_auction_uc.execute(input_dto)

    event_bus_mock.post.assert_called_once_with(
        AuctionBegan(1, get_dollars("10.00"), "Socks"))
Beispiel #6
0
def _row_to_dto(auction_proxy: RowProxy) -> AuctionDto:
    return AuctionDto(
        id=auction_proxy.id,
        title=auction_proxy.title,
        current_price=get_dollars(auction_proxy.current_price),
        starting_price=get_dollars(auction_proxy.starting_price),
        ends_at=auction_proxy.ends_at,
    )
def test_should_emit_winning_if_overbids() -> None:
    auction = AuctionFactory(bids=[Bid(id=1, bidder_id=1, amount=get_dollars("15.00"))])
    winning_amount = auction.current_price + get_dollars("1.00")

    auction.place_bid(bidder_id=2, amount=winning_amount)

    expected_winning_event = WinningBidPlaced(auction.id, 2, winning_amount, auction.title)
    expected_overbid_event = BidderHasBeenOverbid(auction.id, 1, winning_amount, auction.title)
    assert auction.domain_events == [expected_winning_event, expected_overbid_event]
def test_should_emit_event_upon_overbid() -> None:
    bid_that_will_lose = Bid(id=1, bidder_id=1, amount=get_dollars("15.00"))
    auction = AuctionFactory(bids=[bid_that_will_lose])

    new_bid_amount = get_dollars("20.00")
    auction.place_bid(bidder_id=2, amount=new_bid_amount)

    expected_event = BidderHasBeenOverbid(auction.id, bid_that_will_lose.bidder_id, new_bid_amount, auction.title)
    assert expected_event in auction.domain_events
Beispiel #9
0
def test_Auction_FirstBidHigherThanIntialPrice_IsWinning(
        place_bid_uc: PlacingBid,
        output_boundary: PlacingBidOutputBoundaryFake,
        auction_id: AuctionId) -> None:
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("100")))

    expected_dto = PlacingBidOutputDto(is_winner=True,
                                       current_price=get_dollars("100"))
    assert output_boundary.dto == expected_dto
Beispiel #10
0
def test_Auction_Overbid_IsWinning(
        place_bid_uc: PlacingBid,
        output_boundary: PlacingBidOutputBoundaryFake,
        auction_id: AuctionId) -> None:
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("100")))

    place_bid_uc.execute(PlacingBidInputDto(2, auction_id, get_dollars("120")))

    assert output_boundary.dto == PlacingBidOutputDto(
        is_winner=True, current_price=get_dollars("120"))
def test_should_return_highest_bids_user_id_for_winners_list() -> None:
    auction = AuctionFactory(
        bids=[
            Bid(id=1, bidder_id=1, amount=get_dollars("101")),
            Bid(id=2, bidder_id=2, amount=get_dollars("15")),
            Bid(id=3, bidder_id=3, amount=get_dollars("100")),
        ]
    )

    assert auction.winners == [1]
Beispiel #12
0
def test_Auction_OverbidFromWinner_EmitsWinningBidEventOnly(
        place_bid_uc: PlacingBid, event_bus: Mock, auction_id: AuctionId,
        auction_title: str) -> None:
    place_bid_uc.execute(PlacingBidInputDto(3, auction_id, get_dollars("100")))
    event_bus.post.reset_mock()

    place_bid_uc.execute(PlacingBidInputDto(3, auction_id, get_dollars("120")))

    event_bus.post.assert_called_once_with(
        WinningBidPlaced(auction_id, 3, get_dollars("120"), auction_title))
Beispiel #13
0
def test_PlacingBid_BiddingOnEndedAuction_RaisesException(
        beginning_auction_uc: BeginningAuction,
        place_bid_uc: PlacingBid) -> None:
    yesterday = datetime.now(tz=pytz.UTC) - timedelta(days=1)
    with freeze_time(yesterday):
        beginning_auction_uc.execute(
            BeginningAuctionInputDto(1, "Bar", get_dollars("1.00"),
                                     yesterday + timedelta(hours=1)))

    with pytest.raises(BidOnEndedAuction):
        place_bid_uc.execute(PlacingBidInputDto(1, 1, get_dollars("2.00")))
Beispiel #14
0
 def _row_to_entity(self, auction_proxy: RowProxy,
                    bids_proxies: List[RowProxy]) -> Auction:
     auction_bids = [
         Bid(bid.id, bid.bidder_id, get_dollars(bid.amount))
         for bid in bids_proxies
     ]
     return Auction(
         auction_proxy.id,
         auction_proxy.title,
         get_dollars(auction_proxy.starting_price),
         auction_bids,
         auction_proxy.ends_at.replace(tzinfo=pytz.UTC),
         auction_proxy.ended,
     )
def test_should_emit_winning_event_if_the_first_offer() -> None:
    auction = AuctionFactory()
    winning_amount = auction.current_price + get_dollars("1.00")

    auction.place_bid(bidder_id=1, amount=winning_amount)

    assert auction.domain_events == [WinningBidPlaced(auction.id, 1, winning_amount, auction.title)]
def test_should_emit_auction_ended(yesterday: datetime) -> None:
    auction = AuctionFactory(bids=[Bid(id=1, bidder_id=1, amount=get_dollars("15.00"))], ends_at=yesterday)

    auction.end_auction()

    expected_event = AuctionEnded(auction.id, auction.winners[0], auction.current_price, auction.title)
    assert auction.domain_events == [expected_event]
def test_should_withdraw_the_only_bid() -> None:
    auction = AuctionFactory(bids=[Bid(id=1, bidder_id=1, amount=get_dollars("50"))])

    auction.withdraw_bids([1])

    assert auction.winners == []
    assert auction.current_price == auction.starting_price
def test_adding_new_payment_is_reflected_on_pending_payments_list(
        facade: PaymentsFacade, connection: Connection,
        event_bus: Mock) -> None:
    customer_id = 1
    assert facade.get_pending_payments(customer_id) == []

    payment_uuid = uuid.uuid4()
    amount = get_dollars("15.00")
    description = "Example"
    # with patch.object(event_bus, "post") as post_mock:
    facade.start_new_payment(payment_uuid, customer_id, amount, description)

    (row, ) = connection.execute(payments.select()).fetchall()
    assert dict(row) == {
        "uuid": str(payment_uuid),
        "customer_id": customer_id,
        "amount": int(amount.amount * 100),
        "currency": amount.currency.iso_code,
        "status": PaymentStatus.NEW.value,
        "description": description,
        "charge_id": None,
    }

    pending_payments = facade.get_pending_payments(customer_id)

    assert pending_payments == [
        PaymentDto(payment_uuid, amount, description, PaymentStatus.NEW.value)
    ]
    event_bus.post.assert_called_once_with(
        PaymentStarted(payment_uuid, customer_id))
Beispiel #19
0
class BeginningAuctionInputDtoFactory(factory.Factory):
    class Meta:
        model = BeginningAuctionInputDto

    auction_id = factory.Sequence(lambda n: n)
    title = factory.Faker("name")
    starting_price = get_dollars("0.99")
    ends_at = factory.Faker("future_datetime", end_date="+7d")
Beispiel #20
0
def test_gets_existing_auction(
    connection: Connection,
    auction_model_with_a_bid: RowProxy,
    bid_model: RowProxy,
    ends_at: datetime,
    event_bus_mock: Mock,
) -> None:
    auction = SqlAlchemyAuctionsRepo(connection, event_bus_mock).get(
        auction_model_with_a_bid.id)

    assert auction.id == auction_model_with_a_bid.id
    assert auction.title == auction_model_with_a_bid.title
    assert auction.starting_price == get_dollars(
        auction_model_with_a_bid.starting_price)
    assert auction.current_price == get_dollars(bid_model.amount)
    assert auction.ends_at == ends_at
    assert set(auction.bids) == {
        Bid(bid_model.id, bid_model.bidder_id, get_dollars(bid_model.amount))
    }
class AuctionFactory(factory.Factory):
    class Meta:
        model = Auction

    id = factory.Sequence(lambda n: n)
    bids = factory.List([])
    title = factory.Faker("name")
    starting_price = get_dollars("10.00")
    ends_at = factory.Faker("future_datetime", end_date="+7d")
    ended = False
Beispiel #22
0
def test_AuctionsRepo_UponSavingAuction_PostsPendingEventsViaEventBus(
        connection: Connection, another_bidder_id: int,
        auction_model_with_a_bid: RowProxy, event_bus_mock: Mock) -> None:
    repo = SqlAlchemyAuctionsRepo(connection, event_bus_mock)
    auction = repo.get(auction_model_with_a_bid.id)
    auction.place_bid(another_bidder_id,
                      auction.current_price + get_dollars("1.00"))

    repo.save(auction)

    event_bus_mock.post.assert_called()
Beispiel #23
0
def test_AuctionsRepo_UponSavingAuction_ClearsPendingEvents(
        connection: Connection, another_bidder_id: int,
        auction_model_with_a_bid: RowProxy, event_bus_mock: Mock) -> None:
    repo = SqlAlchemyAuctionsRepo(connection, event_bus_mock)
    auction = repo.get(auction_model_with_a_bid.id)
    auction.place_bid(another_bidder_id,
                      auction.current_price + get_dollars("1.00"))

    repo.save(auction)

    assert len(auction.domain_events) == 0
def test_charge_then_capture(api_consumer: ApiConsumer, source: str,
                             api_key: str) -> None:
    charge_id = api_consumer.charge(get_dollars("15.00"), source)
    api_consumer.capture(charge_id)

    response = requests.get(f"{Request.url}/v1/charges/{charge_id}",
                            auth=(api_key, ""))
    capture_json = response.json()
    assert capture_json["amount"] == 1500  # cents
    assert capture_json["currency"] == "usd"
    assert capture_json["captured"]
Beispiel #25
0
def test_Auction_OverbidFromOtherBidder_EmitsEvent(place_bid_uc: PlacingBid,
                                                   event_bus: Mock,
                                                   auction_id: AuctionId,
                                                   auction_title: str) -> None:
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("100")))
    event_bus.post.reset_mock()

    place_bid_uc.execute(PlacingBidInputDto(2, auction_id, get_dollars("120")))

    event_bus.post.assert_has_calls(
        [
            call(
                WinningBidPlaced(auction_id, 2, get_dollars("120"),
                                 auction_title)),
            call(
                BidderHasBeenOverbid(auction_id, 1, get_dollars("120"),
                                     auction_title)),
        ],
        any_order=True,
    )
    assert event_bus.post.call_count == 2
Beispiel #26
0
def test_removes_withdrawn_bids(connection: Connection, bid_model: RowProxy,
                                auction_model_with_a_bid: dict,
                                ends_at: datetime,
                                event_bus_mock: Mock) -> None:
    auction = Auction(
        id=auction_model_with_a_bid.id,
        title=auction_model_with_a_bid.title,
        starting_price=get_dollars(auction_model_with_a_bid.starting_price),
        ends_at=ends_at,
        bids=[
            Bid(bid_model.id, bid_model.bidder_id,
                get_dollars(bid_model.amount))
        ],
        ended=False,
    )
    auction.withdraw_bids([bid_model.id])

    SqlAlchemyAuctionsRepo(connection, event_bus_mock).save(auction)

    assert connection.execute(select([func.count()
                                      ]).select_from(bids)).scalar() == 0
Beispiel #27
0
def test_Auction_OverbidFromOtherBidder_EmitsEvents(
        beginning_auction_uc: BeginningAuction, place_bid_uc: PlacingBid,
        event_bus: Mock) -> None:
    auction_id = 1
    tomorrow = datetime.now(tz=pytz.UTC) + timedelta(days=1)
    beginning_auction_uc.execute(
        BeginningAuctionInputDto(auction_id, "Foo", get_dollars("1.00"),
                                 tomorrow))
    place_bid_uc.execute(PlacingBidInputDto(1, auction_id, get_dollars("2.0")))

    event_bus.post.reset_mock()
    place_bid_uc.execute(PlacingBidInputDto(2, auction_id, get_dollars("3.0")))

    event_bus.post.assert_has_calls(
        [
            call(WinningBidPlaced(auction_id, 2, get_dollars("3.0"), "Foo")),
            call(BidderHasBeenOverbid(auction_id, 1, get_dollars("3.0"),
                                      "Foo")),
        ],
        any_order=True,
    )
    assert event_bus.post.call_count == 2
def test_unsuccessful_charge(facade: PaymentsFacade, inserted_payment: dict,
                             connection: Connection, event_bus: Mock) -> None:
    payment_uuid = uuid.UUID(inserted_payment["uuid"])

    with patch.object(ApiConsumer, "charge",
                      side_effect=PaymentFailedError) as charge_mock:
        facade.charge(payment_uuid, inserted_payment["customer_id"], "token")

    charge_mock.assert_called_once_with(
        get_dollars(inserted_payment["amount"] / 100), "token")
    assert get_payment(
        connection,
        inserted_payment["uuid"]).status == PaymentStatus.FAILED.value
    event_bus.post.assert_called_once_with(
        PaymentFailed(payment_uuid, inserted_payment["customer_id"]))
def test_successful_charge_updates_status(facade: PaymentsFacade,
                                          inserted_payment: dict,
                                          connection: Connection,
                                          event_bus: Mock) -> None:
    payment_uuid = uuid.UUID(inserted_payment["uuid"])
    charge_id = "SOME_CHARGE_ID"

    with patch.object(ApiConsumer, "charge",
                      return_value=charge_id) as charge_mock:
        facade.charge(uuid.UUID(inserted_payment["uuid"]),
                      inserted_payment["customer_id"], "token")

    charge_mock.assert_called_once_with(
        get_dollars(inserted_payment["amount"] / 100), "token")
    payment_row = get_payment(connection, inserted_payment["uuid"])
    assert payment_row.status == PaymentStatus.CHARGED.value
    assert payment_row.charge_id == charge_id
    event_bus.post.assert_called_once_with(
        PaymentCharged(payment_uuid, inserted_payment["customer_id"]))
Beispiel #30
0
def test_should_start_new_payment_upon_auction_ended(
    saga: PayingForWonItemSaga,
    payments_facade_mock: Mock,
    customer_relationship_mock: Mock,
    mocked_uuid4: uuid.UUID,
    saga_data: PayingForWonItemSagaData,
) -> None:
    event = AuctionEnded(auction_id=1,
                         winner_id=2,
                         winning_bid=get_dollars("99.99"),
                         auction_title="irrelevant")
    saga.handle(event, saga_data)

    payments_facade_mock.start_new_payment.assert_called_once_with(
        mocked_uuid4, event.winner_id, event.winning_bid, event.auction_title)
    customer_relationship_mock.send_email_about_winning.assert_called_once_with(
        event.winner_id, event.winning_bid, event.auction_title)
    assert saga_data.state == SagaState.PAYMENT_STARTED
    assert saga_data.winning_bid == event.winning_bid
    assert saga_data.auction_title == event.auction_title
    assert saga_data.timeout_at == datetime.now() + timedelta(days=3)
    assert saga_data.winner_id == event.winner_id
    assert saga_data.auction_id == event.auction_id