Skip to content

Commit

Permalink
Added Helpdesk sample from EventSourcing.NET repo
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Dec 20, 2023
1 parent f5085ef commit 0f96981
Show file tree
Hide file tree
Showing 37 changed files with 2,043 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/Marten.sln
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marten.CommandLine.Tests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqTests", "LinqTests\LinqTests.csproj", "{94EF979D-F2C0-4479-9D1D-63647042E915}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Helpdesk", "Helpdesk", "{F3DADE49-9C89-4F74-BCCE-7DAFD35675E9}"
ProjectSection(SolutionItems) = preProject
samples\Helpdesk\README.md = samples\Helpdesk\README.md
samples\Helpdesk\docker-compose.yml = samples\Helpdesk\docker-compose.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helpdesk.Api", "samples\Helpdesk\Helpdesk.Api\Helpdesk.Api.csproj", "{5E18DEBD-C768-4636-B167-7DA2A4954F43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helpdesk.Api.Tests", "samples\Helpdesk\Helpdesk.Api.Tests\Helpdesk.Api.Tests.csproj", "{B0629D41-CA4E-4123-BC98-79A04D708A3E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -201,6 +211,14 @@ Global
{94EF979D-F2C0-4479-9D1D-63647042E915}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94EF979D-F2C0-4479-9D1D-63647042E915}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94EF979D-F2C0-4479-9D1D-63647042E915}.Release|Any CPU.Build.0 = Release|Any CPU
{5E18DEBD-C768-4636-B167-7DA2A4954F43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E18DEBD-C768-4636-B167-7DA2A4954F43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E18DEBD-C768-4636-B167-7DA2A4954F43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E18DEBD-C768-4636-B167-7DA2A4954F43}.Release|Any CPU.Build.0 = Release|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -234,5 +252,8 @@ Global
{7B710A53-373B-4A7D-B49E-53C15E6A8CA8} = {79961196-DB50-4AD3-B749-D231799BCF2E}
{0962E83F-482B-4316-A8AB-3B714EEEC3AA} = {DA7EC300-12F5-4B80-B5DF-B7B71E344E24}
{94EF979D-F2C0-4479-9D1D-63647042E915} = {91D87D73-EC07-4067-8A64-26A2E4F6BC83}
{F3DADE49-9C89-4F74-BCCE-7DAFD35675E9} = {79961196-DB50-4AD3-B749-D231799BCF2E}
{5E18DEBD-C768-4636-B167-7DA2A4954F43} = {F3DADE49-9C89-4F74-BCCE-7DAFD35675E9}
{B0629D41-CA4E-4123-BC98-79A04D708A3E} = {F3DADE49-9C89-4F74-BCCE-7DAFD35675E9}
EndGlobalSection
EndGlobal
28 changes: 28 additions & 0 deletions src/samples/Helpdesk/Helpdesk.Api.Tests/Helpdesk.Api.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<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"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="NSubstitute" Version="5.1.0"/>
<PackageReference Include="xunit" Version="2.6.3"/>
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="8.0.0"/>
<PackageReference Include="Ogooreck" Version="0.8.0"/>
<PackageReference Include="Bogus" Version="35.0.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Helpdesk.Api\Helpdesk.Api.csproj"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Threading.Tasks;
using Helpdesk.Api.Incidents;
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Xunit;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class AcknowledgeResolutionIncidentTests: IClassFixture<ApiWithResolvedIncident>
{
[Fact]
[Trait("Category", "Acceptance")]
public Task ResolveCommand_Succeeds() =>
API
.Given()
.When(
POST,
URI($"/api/customers/{API.Incident.CustomerId}/incidents/{API.Incident.Id}/acknowledge"),
HEADERS(IF_MATCH(2))
)
.Then(OK)
.And()
.When(GET, URI($"/api/incidents/{API.Incident.Id}"))
.Then(
OK,
RESPONSE_BODY(
API.Incident with { Status = IncidentStatus.ResolutionAcknowledgedByCustomer, Version = 3 }
)
);

private readonly ApiWithResolvedIncident API;

public AcknowledgeResolutionIncidentTests(ApiWithResolvedIncident api) => API = api;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Threading.Tasks;
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Xunit;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class AssignAgentToIncidentTests: IClassFixture<ApiWithLoggedIncident>
{
[Fact]
[Trait("Category", "Acceptance")]
public async Task AssignAgentCommand_ChangesIncidentCategory()
{
await API
.Given()
.When(
POST,
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/assign"),
HEADERS(IF_MATCH(1))
)
.Then(OK)
.And()
.When(GET, URI($"/api/incidents/{API.Incident.Id}"))
.Then(
OK,
RESPONSE_BODY(
API.Incident with { AgentId = agentId, Version = 2 }
)
);
}

private readonly Guid agentId = Guid.NewGuid();
private readonly ApiWithLoggedIncident API;

public AssignAgentToIncidentTests(ApiWithLoggedIncident api) => API = api;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Threading.Tasks;
using Bogus;
using Helpdesk.Api.Incidents;
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Xunit;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class CategoriseIncidentTests: IClassFixture<ApiWithLoggedIncident>
{
[Fact]
[Trait("Category", "Acceptance")]
public async Task CategoriseCommand_ChangesIncidentCategory()
{
await API
.Given()
.When(
POST,
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/category"),
BODY(new CategoriseIncidentRequest(category)),
HEADERS(IF_MATCH(1))
)
.Then(OK);

await API
.Given()
.When(GET, URI($"/api/incidents/{API.Incident.Id}"))
.Then(
OK,
RESPONSE_BODY(
API.Incident with { Category = category, Version = 2 }
)
);
}

private readonly Guid agentId = Guid.NewGuid();
private readonly IncidentCategory category = new Faker().PickRandom<IncidentCategory>();
private readonly ApiWithLoggedIncident API;

public CategoriseIncidentTests(ApiWithLoggedIncident api) => API = api;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using Helpdesk.Api.Incidents;
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Xunit;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class CloseIncidentTests: IClassFixture<ApiWithAcknowledgedIncident>
{
[Fact]
[Trait("Category", "Acceptance")]
public async Task ResolveCommand_Succeeds()
{
await API
.Given()
.When(
POST,
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/close"),
HEADERS(IF_MATCH(3))
)
.Then(OK);

await API
.Given()
.When(GET, URI($"/api/incidents/{API.Incident.Id}"))
.Then(
OK,
RESPONSE_BODY(
API.Incident with { Status = IncidentStatus.Closed, Version = 4 }
)
);
}

private readonly ApiWithAcknowledgedIncident API;
private Guid agentId = Guid.NewGuid();

public CloseIncidentTests(ApiWithAcknowledgedIncident api) => API = api;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Helpdesk.Api.Incidents.GetIncidentDetails;
using Ogooreck.API;
using Xunit;

namespace Helpdesk.Api.Tests.Incidents.Fixtures;

public class ApiWithAcknowledgedIncident: ApiSpecification<Program>, IAsyncLifetime
{
public async Task InitializeAsync()
{
Incident = await this.AcknowledgedIncident();
}

public IncidentDetails Incident { get; set; } = default!;

public Task DisposeAsync() => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Threading.Tasks;
using Helpdesk.Api.Incidents.GetIncidentDetails;
using Ogooreck.API;
using Xunit;

namespace Helpdesk.Api.Tests.Incidents.Fixtures;

public class ApiWithLoggedIncident: ApiSpecification<Program>, IAsyncLifetime
{
public async Task InitializeAsync()
{
Incident = await this.LoggedIncident();
}

public IncidentDetails Incident { get; protected set; } = default!;
public Task DisposeAsync() => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Helpdesk.Api.Incidents.GetIncidentDetails;
using Ogooreck.API;
using Xunit;

namespace Helpdesk.Api.Tests.Incidents.Fixtures;

public class ApiWithResolvedIncident: ApiSpecification<Program>, IAsyncLifetime
{
public async Task InitializeAsync()
{
Incident = await this.ResolvedIncident();
}

public IncidentDetails Incident { get; set; } = default!;

public Task DisposeAsync() => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Threading.Tasks;
using Bogus;
using Bogus.DataSets;
using Helpdesk.Api.Incidents;
using Helpdesk.Api.Incidents.GetIncidentDetails;
using Ogooreck.API;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents.Fixtures;

public static class Scenarios
{
private static readonly Faker faker = new();
private static readonly Lorem loremIpsum = new();

public static async Task<IncidentDetails> LoggedIncident(
this ApiSpecification<Program> api
)
{
var customerId = Guid.NewGuid();

var contact = new Contact(
faker.PickRandom<ContactChannel>(),
faker.Name.FirstName(),
faker.Name.LastName(),
faker.Internet.Email(),
faker.Phone.PhoneNumber()
);
var incidentDescription = loremIpsum.Sentence();

var response = await api.Scenario(
api.LogIncident(customerId, contact, incidentDescription),
r => api.GetIncidentDetails(r.GetCreatedId<Guid>())
);

return await response.GetResultFromJson<IncidentDetails>();
}

public static async Task<IncidentDetails> ResolvedIncident(
this ApiSpecification<Program> api
)
{
var agentId = Guid.NewGuid();
var resolvedType = faker.PickRandom<ResolutionType>();
var incident = await api.LoggedIncident();

return await api.Scenario(
api.ResolveIncident(incident.Id, agentId, resolvedType),
_ => api.GetIncidentDetails(incident.Id)
).GetResponseBody<IncidentDetails>();
}

public static async Task<IncidentDetails> AcknowledgedIncident(
this ApiSpecification<Program> api
)
{
var incident = await api.ResolvedIncident();

return await api.Scenario(
api.AcknowledgeIncident(incident.Id, incident.CustomerId),
_ => api.GetIncidentDetails(incident.Id)
).GetResponseBody<IncidentDetails>();
}

private static Task<Result> LogIncident(
this ApiSpecification<Program> api,
Guid customerId,
Contact contact,
string incidentDescription
) =>
api.Given()
.When(POST, URI($"api/customers/{customerId}/incidents/"),
BODY(new LogIncidentRequest(contact, incidentDescription)))
.Then(CREATED_WITH_DEFAULT_HEADERS(locationHeaderPrefix: "/api/incidents/"));

private static Task<Result> ResolveIncident<T>(
this ApiSpecification<T> api,
Guid incidentId,
Guid agentId,
ResolutionType resolutionType
) where T : class =>
api.Given()
.When(
POST,
URI($"/api/agents/{agentId}/incidents/{incidentId}/resolve"),
BODY(new ResolveIncidentRequest(resolutionType)),
HEADERS(IF_MATCH(1))
)
.Then(OK);

private static Task<Result> AcknowledgeIncident<T>(
this ApiSpecification<T> api,
Guid incidentId,
Guid customerId
) where T : class =>
api.Given()
.When(
POST,
URI($"/api/customers/{customerId}/incidents/{incidentId}/acknowledge"),
HEADERS(IF_MATCH(2))
)
.Then(OK);

private static Task<Result> GetIncidentDetails(
this ApiSpecification<Program> api,
Guid incidentId
) =>
api.Given()
.When(GET, URI($"/api/incidents/{incidentId}"))
.Then(OK);
}
Loading

0 comments on commit 0f96981

Please sign in to comment.