Skip to content

Commit

Permalink
Added Alba test scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Feb 5, 2024
1 parent f6216a8 commit c4a665f
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Alba" Version="7.4.1" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
using Alba;
using Bogus;
using Bogus.DataSets;
using FluentAssertions;
using Helpdesk.Api.Incidents;
using Helpdesk.Api.Incidents.GettingDetails;
using Helpdesk.Api.Incidents.Logging;
using Xunit;
using Ogooreck.API;
using Wolverine.Http;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class LogIncidentsTests(ApiSpecification<Program> API):
IClassFixture<ApiSpecification<Program>>
public class LogIncidentsTests(AppFixture fixture): IntegrationContext(fixture)
{
[Fact]
public Task LogIncident_ShouldSucceed() =>
API.Given()
.When(
POST,
URI($"api/customers/{CustomerId}/incidents/"),
BODY(new LogIncident(CustomerId, Contact, IncidentDescription))
)
.Then(CREATED_WITH_DEFAULT_HEADERS(locationHeaderPrefix: "/api/incidents/"))
.And()
.When(GET, URI(ctx => $"/api/incidents/{ctx.GetCreatedId()}"))
.Then(
OK,
RESPONSE_BODY(ctx =>
new IncidentDetails(
ctx.GetCreatedId<Guid>(),
CustomerId,
IncidentStatus.Pending,
Array.Empty<IncidentNote>(),
null,
null,
null,
1
)
)
);
public async Task LogIncident_ShouldSucceed()
{
// POST a CategoriseIncident to the HTTP endpoint, wait until all
// cascading Wolverine processing is complete
var result = await Host.Scenario(x =>
{
x.Post.Json(new LogIncident(CustomerId, Contact, IncidentDescription))
.ToUrl($"/api/customers/{CustomerId}/incidents/");

x.StatusCodeShouldBe(201);
});

var response = await result.ReadAsJsonAsync<CreationResponse>();
response.Should().NotBeNull();
response!.Url.Should().StartWith("/api/incidents/");

result = await Host.Scenario(x =>
{
x.Get.Url(response.Url);

x.StatusCodeShouldBeOk();
});

var incident = await result.ReadAsJsonAsync<IncidentDetails>();
incident.Should().NotBeNull();
incident!.CustomerId.Should().Be(CustomerId);
incident.Status.Should().Be(IncidentStatus.Pending);
incident.Notes.Should().BeEmpty();
incident.Category.Should().BeNull();
incident.Priority.Should().BeNull();
incident.AgentId.Should().BeNull();
incident.Version.Should().Be(1);
}

private readonly Guid CustomerId = Guid.NewGuid();

Expand Down
128 changes: 128 additions & 0 deletions Sample/Helpdesk.Wolverine/Helpdesk.Api.Tests/IntegrationContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using Alba;
using Alba.Security;
using FluentAssertions;
using JasperFx.Core;
using Marten;
using Marten.Schema;
using Microsoft.Extensions.DependencyInjection;
using Oakton;
using Wolverine;
using Wolverine.Tracking;
using Xunit;

namespace Helpdesk.Api.Tests;

public class AppFixture : IAsyncLifetime
{
public IAlbaHost Host { get; private set; } = default!;

// This is a one time initialization of the
// system under test before the first usage
public async Task InitializeAsync()
{
// Sorry folks, but this is absolutely necessary if you
// use Oakton for command line processing and want to
// use WebApplicationFactory and/or Alba for integration testing
OaktonEnvironment.AutoStartHost = true;

// This is bootstrapping the actual application using
// its implied Program.Main() set up
// This is using a library named "Alba". See https://jasperfx.github.io/alba for more information
Host = await AlbaHost.For<Program>(x =>
{
x.ConfigureServices(services =>
{
services.DisableAllExternalWolverineTransports();

// We're going to establish some baseline data
// for testing
// services.InitializeMartenWith<BaselineData>();
});
}, new AuthenticationStub());
}

public Task DisposeAsync()
{
if (Host != null)
{
return Host.DisposeAsync().AsTask();
}

return Task.CompletedTask;
}
}

// public class BaselineData : IInitialData
// {
// public static Guid Customer1Id { get; } = Guid.NewGuid();
//
// public async Task Populate(IDocumentStore store, CancellationToken cancellation)
// {
// await using var session = store.LightweightSession();
// session.Store(new Customer
// {
// Id = Customer1Id,
// Region = "West Cost",
// Duration = new ContractDuration(DateOnly.FromDateTime(DateTime.Today.Subtract(100.Days())), DateOnly.FromDateTime(DateTime.Today.Add(100.Days())))
// });
//
// await session.SaveChangesAsync(cancellation);
// }
// }

// xUnit specific junk
[CollectionDefinition("integration")]
public class IntegrationCollection : ICollectionFixture<AppFixture>
{
}

[Collection("integration")]
public abstract class IntegrationContext(AppFixture fixture): IAsyncLifetime
{
public IAlbaHost Host => fixture.Host;

public IDocumentStore Store => fixture.Host.Services.GetRequiredService<IDocumentStore>();

async Task IAsyncLifetime.InitializeAsync()
{
// Using Marten, wipe out all data and reset the state
// back to exactly what we described in InitialAccountData
await Store.Advanced.ResetAllData();
}

// This is required because of the IAsyncLifetime
// interface. Note that I do *not* tear down database
// state after the test. That's purposeful
public Task DisposeAsync()
{
return Task.CompletedTask;
}

public async Task<IScenarioResult> Scenario(Action<Scenario> configure)
{
return await Host.Scenario(configure);
}

// This method allows us to make HTTP calls into our system
// in memory with Alba, but do so within Wolverine's test support
// for message tracking to both record outgoing messages and to ensure
// that any cascaded work spawned by the initial command is completed
// before passing control back to the calling test
protected async Task<(ITrackedSession, IScenarioResult)> TrackedHttpCall(Action<Scenario> configuration)
{
IScenarioResult? result = null;

// The outer part is tying into Wolverine's test support
// to "wait" for all detected message activity to complete
var tracked = await Host.ExecuteAndWaitAsync(async () =>
{
// The inner part here is actually making an HTTP request
// to the system under test with Alba
result = await Host.Scenario(configuration);
});

result.Should().NotBeNull();

return (tracked, result!);
}
}

0 comments on commit c4a665f

Please sign in to comment.