public async Task Confirmation_token_cant_be_used_twice_by_different_owners_for_the_same_resource() { var reservationService = new SqlReservationService(); // given a fixed quantity of some resource where the resource has been used var word = Any.Word(); var ownerToken = Any.Guid().ToString(); var promoCode = "promo-code-" + word; var reservedValue = Any.Guid().ToString(); var confirmationToken = Any.Guid().ToString(); await reservationService.Reserve(reservedValue, promoCode, reservedValue, TimeSpan.FromDays(-1)); await reservationService.Reserve(Any.Guid().ToString(), promoCode, reservedValue, TimeSpan.FromDays(-1)); //act await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, confirmationToken : confirmationToken); //assert Action reserve = () => { var result = reservationService.ReserveAny( scope: promoCode, ownerToken: Any.FullName(), lease: TimeSpan.FromMinutes(2), confirmationToken: confirmationToken) .Result; }; reserve.ShouldThrow <DbUpdateException>(); }
public async Task When_confirmation_token_is_used_twice_for_the_same_unconfirmed_reservation_then_ReserveAny_extends_the_lease() { var reservationService = new SqlReservationService(); // given a fixed quantity of some resource where the resource has been used //todo:(this needs to be done via an interface rather then just calling reserve multiple times) var word = Any.Word(); var ownerToken = Any.Guid().ToString(); var promoCode = "promo-code-" + word; var reservedValue = Any.Guid().ToString(); var confirmationToken = Any.Guid().ToString(); await reservationService.Reserve(reservedValue, promoCode, reservedValue, TimeSpan.FromDays(-1)); await reservationService.Reserve(Any.Guid().ToString(), promoCode, reservedValue, TimeSpan.FromDays(-1)); //act var firstAttempt = await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, confirmationToken : confirmationToken); //assert var secondAttempt = await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, lease : TimeSpan.FromMinutes(2), confirmationToken : confirmationToken); secondAttempt.Should() .NotBeNull() .And .Be(firstAttempt); }
public async Task If_a_fixed_quantity_of_resource_had_been_depleted_then_reservations_cant_be_made() { var reservationService = new SqlReservationService(); // given a fixed quantity of some resource where the resource has been used var word = Any.Word(); var ownerToken = Any.Guid().ToString(); var promoCode = "promo-code-" + word; var reservedValue = Any.Guid().ToString(); var userConfirmationCode = Any.Guid().ToString(); await reservationService.Reserve(reservedValue, promoCode, reservedValue, TimeSpan.FromDays(-1)); //act var result = await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, lease : TimeSpan.FromMinutes(-2), confirmationToken : userConfirmationCode); result.Should().Be(reservedValue); await reservationService.Confirm(userConfirmationCode, promoCode, ownerToken); //assert result = await reservationService.ReserveAny( scope : promoCode, ownerToken : Any.FullName(), lease : TimeSpan.FromMinutes(2), confirmationToken : Any.Guid().ToString()); result.Should().BeNull(); }
public async Task The_value_returned_by_the_reservation_service_can_be_used_for_confirmation() { var reservationService = new SqlReservationService(); // given a fixed quantity of some resource, e.g. promo codes: var ownerToken = "owner-token-" + Any.Email(); var promoCode = "promo-code-" + Any.Word(); var reservedValue = Any.Email(); await reservationService.Reserve(reservedValue, scope : promoCode, ownerToken : ownerToken, lease : TimeSpan.FromDays(-1)); //act var value = await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, lease : TimeSpan.FromMinutes(2)); value.Should().NotBeNull(); await reservationService.Confirm(value, promoCode, ownerToken); // assert using (var db = new ReservationServiceDbContext()) { var reservation = db.Set <ReservedValue>() .Single(v => v.Value == reservedValue && v.Scope == promoCode && v.Expiration == null); reservation.ConfirmationToken.Should().Be(value); } }
public async Task Reservations_can_be_placed_for_one_of_a_fixed_quantity_of_a_resource() { var reservationService = new SqlReservationService(); // given a fixed quantity of some resource, e.g. promo codes: var word = Any.Word(); var ownerToken = Any.Guid().ToString(); var promoCode = "promo-code-" + word; var reservedValue = Any.Guid().ToString(); var userConfirmationCode = Any.Guid().ToString(); await reservationService.Reserve(reservedValue, promoCode, reservedValue, TimeSpan.FromDays(-1)); //act var result = await reservationService.ReserveAny( scope : promoCode, ownerToken : ownerToken, lease : TimeSpan.FromMinutes(2), confirmationToken : userConfirmationCode); result.Should().Be(reservedValue); await reservationService.Confirm(userConfirmationCode, promoCode, ownerToken); // assert using (var db = new ReservationServiceDbContext()) { db.Set <ReservedValue>() .Should().Contain(v => v.Value == reservedValue && v.Scope == promoCode && v.Expiration == null); } }
public async Task When_simultaneous_reservations_are_placed_for_one_of_a_fixed_quantity_of_a_resource_then_different_values_are_reserved() { //arrange var barrier = new Barrier(2); var reservationService = new SqlReservationService(() => new ReservationServiceDbContextThatForcesConcurrencyDuringSave(barrier)); // given a fixed quantity of some resource, e.g. promo codes: var promoCode = "promo-code-" + Any.Word(); var reservedValue1 = "firstValue:" + Any.CamelCaseName(); var reservedValue2 = "SecondValue:" + Any.CamelCaseName(); await reservationService.Reserve(reservedValue1, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); await reservationService.Reserve(reservedValue2, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); //act var result = await reservationService.ReserveAny( scope: promoCode, ownerToken: Any.FullName(), lease: TimeSpan.FromMinutes(2), confirmationToken: Any.CamelCaseName()); var result2 = await reservationService.ReserveAny( scope: promoCode, ownerToken: Any.FullName(), lease: TimeSpan.FromMinutes(2), confirmationToken: Any.CamelCaseName()); //assert result.Should().NotBe(result2); }
public async Task When_simultaneous_reservations_are_placed_for_one_of_a_fixed_quantity_of_a_resource_then_different_values_are_reserved() { //arrange var barrier = new Barrier(2); var reservationService = new SqlReservationService(() => new ReservationServiceDbContextThatForcesConcurrencyDuringSave(barrier)); // given a fixed quantity of some resource, e.g. promo codes: var promoCode = "promo-code-" + Any.Word(); var reservedValue1 = "firstValue:" + Any.CamelCaseName(); var reservedValue2 = "SecondValue:" + Any.CamelCaseName(); await reservationService.Reserve(reservedValue1, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); await reservationService.Reserve(reservedValue2, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); //act var result = await reservationService.ReserveAny( scope : promoCode, ownerToken : Any.FullName(), lease : TimeSpan.FromMinutes(2), confirmationToken : Any.CamelCaseName()); var result2 = await reservationService.ReserveAny( scope : promoCode, ownerToken : Any.FullName(), lease : TimeSpan.FromMinutes(2), confirmationToken : Any.CamelCaseName()); //assert result.Should().NotBe(result2); }
public async Task When_ReserveAny_is_called_for_a_scope_that_has_no_entries_at_all_then_it_returns_false() { var reservationService = new SqlReservationService(); var value = await reservationService.ReserveAny(Any.CamelCaseName(), Any.CamelCaseName(), TimeSpan.FromMinutes(1)); value.Should().BeNull(); }
public async Task When_simultaneous_reservations_are_placed_for_one_of_a_fixed_quantity_of_a_resource_then_different_values_are_reserved() { //arrange var reservationService1 = new SqlReservationService(); var reservationService2 = new SqlReservationService(); // given a fixed quantity of some resource, e.g. promo codes: var promoCode = "promo-code-" + Any.Word(); var reservedValue1 = "firstValue:" + Any.Guid(); var reservedValue2 = "SecondValue:" + Any.Guid(); await reservationService1.Reserve(reservedValue1, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); await reservationService2.Reserve(reservedValue2, promoCode, Any.CamelCaseName(), TimeSpan.FromDays(-1)); //Both services retrieve the same entry on the first reservation attempt //A subsequent call will give a different entry var db1 = new ReservationServiceDbContext(); var db2 = new ReservationServiceDbContext(); reservationService1.CreateReservationServiceDbContext = () => db1; reservationService2.CreateReservationServiceDbContext = () => db2; var entry1 = db1.ReservedValues.Single(r => r.Value == reservedValue1); var entry_1 = db2.ReservedValues.Single(r => r.Value == reservedValue1); var entry2 = db2.ReservedValues.Single(r => r.Value == reservedValue2); var queue = new Queue <ReservedValue>(new[] { entry_1, entry2 }); reservationService1.GetValueToReserve = (reservedValues, scope, now) => Task.FromResult(entry1); reservationService2.GetValueToReserve = (reservedValues, scope, now) => Task.FromResult(queue.Dequeue()); //act var result = await reservationService1.ReserveAny( scope : promoCode, ownerToken : Any.FullName(), lease : TimeSpan.FromMinutes(2), confirmationToken : Any.CamelCaseName()); var result2 = await reservationService2.ReserveAny( scope : promoCode, ownerToken : Any.FullName(), lease : TimeSpan.FromMinutes(2), confirmationToken : Any.CamelCaseName()); //assert result.Should().NotBe(result2); }