Skip to content

Commit

Permalink
Added stub for process managers
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Sep 3, 2024
1 parent f506c6b commit ddd616b
Show file tree
Hide file tree
Showing 9 changed files with 950 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
using Bogus;
using BusinessProcesses.Core;
using BusinessProcesses.Version2_ImmutableEntities.ProcessManagers.GroupCheckouts;
using BusinessProcesses.Version2_ImmutableEntities.ProcessManagers.GuestStayAccounts;
using Xunit;
using Xunit.Abstractions;
using Database = BusinessProcesses.Core.Database;

namespace BusinessProcesses.Version2_ImmutableEntities.ProcessManagers;

using static GuestStayAccountEvent;
using static GuestStayAccountCommand;
using static GroupCheckoutCommand;
using static GroupCheckoutsConfig;
using static GuestStayAccountsConfig;

public class BusinessProcessTests
{
[Fact]
public async Task GroupCheckoutForMultipleGuestStayWithoutPaymentsAndCharges_ShouldComplete()
{
// Given;
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];

await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1)));
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1)));
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1)));
publishedMessages.Reset();
// And
var groupCheckoutId = Guid.NewGuid();
var clerkId = Guid.NewGuid();
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now);

// When
await groupCheckoutFacade.InitiateGroupCheckout(command);

// Then
publishedMessages.ShouldReceiveMessages(
[
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now),
new CheckOutGuest(guestStays[0], now, groupCheckoutId),
new GuestCheckedOut(guestStays[0], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[0], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[0], now),
new CheckOutGuest(guestStays[1], now, groupCheckoutId),
new GuestCheckedOut(guestStays[1], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[1], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[1], now),
new CheckOutGuest(guestStays[2], now, groupCheckoutId),
new GuestCheckedOut(guestStays[2], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GroupCheckoutCompleted(groupCheckoutId, guestStays, now),
]
);
}

[Fact]
public async Task GroupCheckoutForMultipleGuestStayWithAllStaysSettled_ShouldComplete()
{
// Given;
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()];

await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[0], now.AddHours(-1)));

await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[1], amounts[1], now.AddHours(-2)));

await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[2], now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[2] / 2, now.AddHours(-1)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[2] / 2, now.AddHours(-1)));
publishedMessages.Reset();
// And
var groupCheckoutId = Guid.NewGuid();
var clerkId = Guid.NewGuid();
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now);

// When
await groupCheckoutFacade.InitiateGroupCheckout(command);

// Then
publishedMessages.ShouldReceiveMessages(
[
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now),
new CheckOutGuest(guestStays[0], now, groupCheckoutId),
new GuestCheckedOut(guestStays[0], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[0], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[0], now),
new CheckOutGuest(guestStays[1], now, groupCheckoutId),
new GuestCheckedOut(guestStays[1], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[1], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[1], now),
new CheckOutGuest(guestStays[2], now, groupCheckoutId),
new GuestCheckedOut(guestStays[2], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GroupCheckoutCompleted(groupCheckoutId, guestStays, now),
]
);
}

[Fact]
public async Task GroupCheckoutForMultipleGuestStayWithOneSettledAndRestUnsettled_ShouldFail()
{
// Given;
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()];

// 🟢 settled
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[0], now.AddHours(-1)));

// 🛑 payment without charge
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1)));

// 🛑 payment without charge
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[2], amounts[2], now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[2], amounts[2] / 2, now.AddHours(-1)));
publishedMessages.Reset();
// And
var groupCheckoutId = Guid.NewGuid();
var clerkId = Guid.NewGuid();
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now);

// When
await groupCheckoutFacade.InitiateGroupCheckout(command);

// Then
publishedMessages.ShouldReceiveMessages(
[
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now),
new CheckOutGuest(guestStays[0], now, groupCheckoutId),
new GuestCheckedOut(guestStays[0], now, groupCheckoutId),
new RecordGuestCheckoutCompletion(groupCheckoutId, guestStays[0], now),
new GroupCheckoutEvent.GuestCheckoutCompleted(groupCheckoutId, guestStays[0], now),
new CheckOutGuest(guestStays[1], now, groupCheckoutId),
new RecordGuestCheckoutFailure(groupCheckoutId, guestStays[1], now),
new GuestCheckoutFailed(guestStays[1], GuestCheckoutFailed.FailureReason.BalanceNotSettled, now,
groupCheckoutId),
new GroupCheckoutEvent.GuestCheckoutFailed(groupCheckoutId, guestStays[1], now),
new CheckOutGuest(guestStays[2], now, groupCheckoutId),
new RecordGuestCheckoutFailure(groupCheckoutId, guestStays[2], now),
new GuestCheckoutFailed(guestStays[2], GuestCheckoutFailed.FailureReason.BalanceNotSettled, now,
groupCheckoutId),
new GroupCheckoutEvent.GuestCheckoutFailed(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GroupCheckoutFailed(
groupCheckoutId,
[guestStays[0]],
[guestStays[1], guestStays[2]],
now
),
]
);
}


[Fact]
public async Task GroupCheckoutForMultipleGuestStayWithAllUnsettled_ShouldFail()
{
// Given;
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()];

// 🛑 charge without payment
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2)));

// 🛑 payment without charge
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1)));

// 🛑 payment without charge
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[2], amounts[2], now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[2], amounts[2] / 2, now.AddHours(-1)));
publishedMessages.Reset();
// And
var groupCheckoutId = Guid.NewGuid();
var clerkId = Guid.NewGuid();
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now);

// When
await groupCheckoutFacade.InitiateGroupCheckout(command);

// Then
publishedMessages.ShouldReceiveMessages(
[
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now),
new CheckOutGuest(guestStays[0], now, groupCheckoutId),
new GuestCheckoutFailed(guestStays[0], GuestCheckoutFailed.FailureReason.BalanceNotSettled, now,
groupCheckoutId),
new RecordGuestCheckoutFailure(groupCheckoutId, guestStays[0], now),
new GroupCheckoutEvent.GuestCheckoutFailed(groupCheckoutId, guestStays[0], now),
new CheckOutGuest(guestStays[1], now, groupCheckoutId),
new GuestCheckoutFailed(guestStays[1], GuestCheckoutFailed.FailureReason.BalanceNotSettled, now,
groupCheckoutId),
new RecordGuestCheckoutFailure(groupCheckoutId, guestStays[1], now),
new GroupCheckoutEvent.GuestCheckoutFailed(groupCheckoutId, guestStays[1], now),
new CheckOutGuest(guestStays[2], now, groupCheckoutId),
new GuestCheckoutFailed(guestStays[2], GuestCheckoutFailed.FailureReason.BalanceNotSettled, now,
groupCheckoutId),
new RecordGuestCheckoutFailure(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GuestCheckoutFailed(groupCheckoutId, guestStays[2], now),
new GroupCheckoutEvent.GroupCheckoutFailed(
groupCheckoutId,
[],
[guestStays[0], guestStays[1], guestStays[2]],
now
),
]
);
}

private readonly Database database = new();
private readonly EventBus eventBus = new();
private readonly CommandBus commandBus = new();
private readonly MessageCatcher publishedMessages = new();
private readonly GuestStayFacade guestStayFacade;
private readonly GroupCheckoutFacade groupCheckoutFacade;
private readonly Faker generate = new();
private readonly DateTimeOffset now = DateTimeOffset.Now;
private readonly ITestOutputHelper testOutputHelper;

public BusinessProcessTests(ITestOutputHelper testOutputHelper)
{
this.testOutputHelper = testOutputHelper;
guestStayFacade = new GuestStayFacade(database, eventBus);
groupCheckoutFacade = new GroupCheckoutFacade(database, eventBus);

eventBus.Use(publishedMessages.Catch);
commandBus.Use(publishedMessages.Catch);

ConfigureGroupCheckouts(eventBus, commandBus, groupCheckoutFacade);
ConfigureGuestStayAccounts(commandBus, guestStayFacade);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using Bogus;
using BusinessProcesses.Core;
using BusinessProcesses.Version2_ImmutableEntities.ProcessManagers.GuestStayAccounts;
using Xunit;
using Xunit.Abstractions;
using Database = BusinessProcesses.Core.Database;

namespace BusinessProcesses.Version2_ImmutableEntities.ProcessManagers;

using static GuestStayAccountEvent;
using static GuestStayAccountCommand;

public class EntityDefinitionTests
{
[Fact]
public async Task CheckingInGuest_Succeeds()
{
// Given
var guestStayId = Guid.NewGuid();
var command = new CheckInGuest(guestStayId, now);
publishedMessages.Reset();

// When
await guestStayFacade.CheckInGuest(command);

// Then
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckedIn(guestStayId, now));
}

[Fact]
public async Task RecordingChargeForCheckedInGuest_Succeeds()
{
// Given
var guestStayId = Guid.NewGuid();
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1)));
publishedMessages.Reset();
// And
var amount = generate.Finance.Amount();
var command = new RecordCharge(guestStayId, amount, now);

// When
await guestStayFacade.RecordCharge(command);

// Then
publishedMessages.ShouldReceiveSingleMessage(new ChargeRecorded(guestStayId, amount, now));
}

[Fact]
public async Task RecordingPaymentForCheckedInGuest_Succeeds()
{
// Given
var guestStayId = Guid.NewGuid();
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1)));
publishedMessages.Reset();
// And
var amount = generate.Finance.Amount();
var command = new RecordPayment(guestStayId, amount, now);

// When
await guestStayFacade.RecordPayment(command);

// Then
publishedMessages.ShouldReceiveSingleMessage(new PaymentRecorded(guestStayId, amount, now));
}

[Fact]
public async Task RecordingPaymentForCheckedInGuestWithCharge_Succeeds()
{
// Given
var guestStayId = Guid.NewGuid();
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, generate.Finance.Amount(), now.AddHours(-1)));
publishedMessages.Reset();
// And
var amount = generate.Finance.Amount();
var command = new RecordPayment(guestStayId, amount, now);

// When
await guestStayFacade.RecordPayment(command);

// Then
publishedMessages.ShouldReceiveSingleMessage(new PaymentRecorded(guestStayId, amount, now));
}

[Fact]
public async Task CheckingOutGuestWithSettledBalance_Succeeds()
{
// Given
var guestStayId = Guid.NewGuid();

var amount = generate.Finance.Amount();
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, amount, now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStayId, amount, now.AddHours(-1)));
publishedMessages.Reset();
// And
var command = new CheckOutGuest(guestStayId, now);

// When
await guestStayFacade.CheckOutGuest(command);

// Then
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckedOut(guestStayId, now));
}

[Fact]
public async Task CheckingOutGuestWithSettledBalance_FailsWithGuestCheckoutFailed()
{
// Given
var guestStayId = Guid.NewGuid();

var amount = generate.Finance.Amount();
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1)));
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, amount + 10, now.AddHours(-2)));
await guestStayFacade.RecordPayment(new RecordPayment(guestStayId, amount, now.AddHours(-1)));
publishedMessages.Reset();
// And
var command = new CheckOutGuest(guestStayId, now);

// When
try
{
await guestStayFacade.CheckOutGuest(command);
}
catch (Exception exc)
{
testOutputHelper.WriteLine(exc.Message);
}

// Then
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckoutFailed(guestStayId, GuestCheckoutFailed.FailureReason.BalanceNotSettled, now));
}

private readonly Database database = new();
private readonly EventBus eventBus = new();
private readonly MessageCatcher publishedMessages = new();
private readonly GuestStayFacade guestStayFacade;
private readonly Faker generate = new();
private readonly DateTimeOffset now = DateTimeOffset.Now;
private readonly ITestOutputHelper testOutputHelper;

public EntityDefinitionTests(ITestOutputHelper testOutputHelper)
{
this.testOutputHelper = testOutputHelper;
guestStayFacade = new GuestStayFacade(database, eventBus);
eventBus.Use(publishedMessages.Catch);
}
}
Loading

0 comments on commit ddd616b

Please sign in to comment.