-
-
Notifications
You must be signed in to change notification settings - Fork 506
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented Incident Batch Resolution Saga
- Loading branch information
1 parent
cc14f75
commit 0ac4a08
Showing
18 changed files
with
381 additions
and
144 deletions.
There are no files selected for viewing
106 changes: 106 additions & 0 deletions
106
Sample/Helpdesk.Wolverine/Helpdesk.Api.Tests/Incidents/BatchResolutionTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System.Collections.Immutable; | ||
using Alba; | ||
using FluentAssertions; | ||
using Helpdesk.Api.Incidents; | ||
using Helpdesk.Api.Incidents.ResolutionBatch; | ||
using Helpdesk.Api.Tests.Incidents.Fixtures; | ||
using Xunit; | ||
using Wolverine.Http; | ||
using Wolverine.Tracking; | ||
|
||
namespace Helpdesk.Api.Tests.Incidents; | ||
|
||
public class BatchResolutionTests(AppFixture fixture): IntegrationContext(fixture) | ||
{ | ||
[Fact] | ||
public async Task InitiateBatch_ShouldSucceed() | ||
{ | ||
// Given | ||
List<Guid> incidents = | ||
[ | ||
(await Host.LoggedIncident()).Id, | ||
(await Host.LoggedIncident()).Id, | ||
(await Host.LoggedIncident()).Id | ||
]; | ||
|
||
// When | ||
var result = await Host.Scenario(x => | ||
{ | ||
x.Post.Json(new InitiateIncidentsBatchResolution(incidents, agentId, resolution)) | ||
.ToUrl($"/api/agents/{agentId}/incidents/resolve"); | ||
x.StatusCodeShouldBe(201); | ||
}); | ||
|
||
// Then | ||
// Check the HTTP Response | ||
var response = await result.ReadAsJsonAsync<CreationResponse>(); | ||
response.Should().NotBeNull(); | ||
response!.Url.Should().StartWith("/api/incidents/resolution/"); | ||
|
||
// Check if details are available | ||
result = await Host.Scenario(x => | ||
{ | ||
x.Get.Url(response.Url); | ||
x.StatusCodeShouldBeOk(); | ||
}); | ||
|
||
var updated = await result.ReadAsJsonAsync<IncidentsBatchResolution>(); | ||
updated.Should().BeEquivalentTo( | ||
new IncidentsBatchResolution( | ||
response.GetCreatedId("/api/incidents/resolution/"), | ||
incidents.ToImmutableDictionary(ks => ks, _ => ResolutionStatus.Pending), | ||
ResolutionStatus.Pending, | ||
1 | ||
) | ||
); | ||
} | ||
|
||
[Fact] | ||
public async Task Batch_ShouldComplete() | ||
{ | ||
// Given | ||
List<Guid> incidents = | ||
[ | ||
(await Host.LoggedIncident()).Id, | ||
(await Host.LoggedIncident()).Id, | ||
(await Host.LoggedIncident()).Id | ||
]; | ||
|
||
var (session, result) = await TrackedHttpCall(x => | ||
{ | ||
x.Post.Json(new InitiateIncidentsBatchResolution(incidents, agentId, resolution)) | ||
.ToUrl($"/api/agents/{agentId}/incidents/resolve"); | ||
x.StatusCodeShouldBe(201); | ||
}); | ||
var creationResponse = await result.ReadAsJsonAsync<CreationResponse>(); | ||
var batchId = creationResponse!.GetCreatedId("/api/incidents/resolution/"); | ||
|
||
// Then | ||
session.Status.Should().Be(TrackingStatus.Completed); | ||
|
||
// Check if details are available | ||
result = await Host.Scenario(x => | ||
{ | ||
x.Get.Url($"/api/incidents/resolution/{batchId}"); | ||
x.StatusCodeShouldBeOk(); | ||
}); | ||
|
||
var updated = await result.ReadAsJsonAsync<IncidentsBatchResolution>(); | ||
updated.Should().NotBeNull(); | ||
updated.Should().BeEquivalentTo( | ||
new IncidentsBatchResolution( | ||
batchId, | ||
incidents.ToImmutableDictionary(ks => ks, _ => ResolutionStatus.Resolved), | ||
ResolutionStatus.Resolved, | ||
incidents.Count + 2 // for initiated and completed | ||
) | ||
); | ||
} | ||
|
||
private readonly Guid agentId = Guid.NewGuid(); | ||
private readonly ResolutionType resolution = ResolutionType.Permanent; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
Sample/Helpdesk.Wolverine/Helpdesk.Api/Core/Http/AcceptedResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// using System.Reflection; | ||
// using JasperFx.CodeGeneration.Frames; | ||
// using JasperFx.CodeGeneration.Model; | ||
// using Microsoft.AspNetCore.Http.Metadata; | ||
// using Microsoft.Extensions.Primitives; | ||
// using Wolverine.Http; | ||
// | ||
// namespace Helpdesk.Api.Core.Http; | ||
// | ||
// public record AcceptedResponse(string Url) : IHttpAware, IEndpointMetadataProvider | ||
// { | ||
// public static void PopulateMetadata(MethodInfo method, EndpointBuilder builder) | ||
// { | ||
// builder.RemoveStatusCodeResponse(200); | ||
// | ||
// var create = new MethodCall(method.DeclaringType!, method).Creates.FirstOrDefault()?.VariableType; | ||
// var metadata = new WolverineProducesResponseTypeMetadata { Type = create, StatusCode = 201 }; | ||
// builder.Metadata.Add(metadata); | ||
// } | ||
// | ||
// void IHttpAware.Apply(HttpContext context) | ||
// { | ||
// context.Response.Headers.Location = Url; | ||
// context.Response.StatusCode = 201; | ||
// } | ||
// | ||
// public static CreationResponse<T> For<T>(T value, string url) => new CreationResponse<T>(url, value); | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
Sample/Helpdesk.Wolverine/Helpdesk.Api/Incidents/Configuration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using Helpdesk.Api.Incidents.GettingCustomerIncidents; | ||
using Helpdesk.Api.Incidents.GettingCustomerIncidentsSummary; | ||
using Helpdesk.Api.Incidents.GettingDetails; | ||
using Helpdesk.Api.Incidents.GettingHistory; | ||
using Helpdesk.Api.Incidents.ResolutionBatch; | ||
using Helpdesk.Api.Incidents.Resolving; | ||
using Marten; | ||
using Marten.Events.Projections; | ||
using Wolverine; | ||
|
||
namespace Helpdesk.Api.Incidents; | ||
|
||
public static class Configuration | ||
{ | ||
public static StoreOptions ConfigureIncidents(this StoreOptions options) | ||
{ | ||
options.Projections.LiveStreamAggregation<Incident>(); | ||
options.Projections.LiveStreamAggregation<IncidentsBatchResolution>(); | ||
options.Projections.Add<IncidentHistoryTransformation>(ProjectionLifecycle.Inline); | ||
options.Projections.Add<IncidentDetailsProjection>(ProjectionLifecycle.Inline); | ||
options.Projections.Add<IncidentShortInfoProjection>(ProjectionLifecycle.Inline); | ||
options.Projections.Add<CustomerIncidentsSummaryProjection>(ProjectionLifecycle.Async); | ||
|
||
return options; | ||
} | ||
|
||
public static WolverineOptions ConfigureIncidents(this WolverineOptions options) | ||
{ | ||
//Console.WriteLine(options.DescribeHandlerMatch(typeof(ResolveFromBatchHandler))); | ||
options.LocalQueue("incidents_batch_resolution") | ||
.Sequential(); | ||
|
||
options.Publish(rule => | ||
{ | ||
rule.Message<InitiateIncidentsBatchResolution>(); | ||
rule.Message<ResolveIncidentFromBatch>() | ||
.Message<IncidentResolved>() | ||
.Message<IncidentResolutionFailed>(); | ||
rule.MessagesImplementing<IncidentsBatchResolutionEvent>(); | ||
rule | ||
.ToLocalQueue("incidents_batch_resolution") | ||
.UseDurableInbox(); | ||
}); | ||
|
||
return options; | ||
} | ||
} |
17 changes: 4 additions & 13 deletions
17
...ine/Helpdesk.Api/Incidents/GettingCustomerIncidentsSummary/GetCustomerIncidentsSummary.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,14 @@ | ||
using Marten; | ||
using Marten.AspNetCore; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Wolverine.Http; | ||
|
||
namespace Helpdesk.Api.Incidents.GettingCustomerIncidentsSummary; | ||
|
||
public static class GetCustomerIncidentsSummaryEndpoint | ||
{ | ||
// That for some reason doesn't work for me | ||
// [WolverineGet("/api/customers/{customerId:guid}/incidents/incidents-summary")] | ||
// public static Task GetCustomerIncidentsSummary([FromRoute] Guid customerId, HttpContext context, | ||
// IQuerySession querySession) => | ||
// querySession.Json.WriteById<CustomerIncidentsSummary>(customerId, context); | ||
|
||
[WolverineGet("/api/customers/{customerId:guid}/incidents/incidents-summary")] | ||
public static Task<CustomerIncidentsSummary?> GetCustomerIncidentsSummary( | ||
[FromRoute] Guid customerId, | ||
IQuerySession querySession, | ||
CancellationToken ct | ||
) => | ||
querySession.LoadAsync<CustomerIncidentsSummary>(customerId, ct); | ||
|
||
public static Task GetCustomerIncidentsSummary([FromRoute] Guid customerId, HttpContext context, | ||
IQuerySession querySession) => | ||
querySession.Json.WriteById<CustomerIncidentsSummary>(customerId, context); | ||
} |
11 changes: 3 additions & 8 deletions
11
Sample/Helpdesk.Wolverine/Helpdesk.Api/Incidents/GettingDetails/GetIncidentDetails.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,13 @@ | ||
using Marten; | ||
using Marten.AspNetCore; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Wolverine.Http; | ||
|
||
namespace Helpdesk.Api.Incidents.GettingDetails; | ||
|
||
public static class GetDetailsEndpoints | ||
{ | ||
// That for some reason doesn't work for me | ||
// [WolverineGet("/api/incidents/{incidentId:guid}")] | ||
// public static Task GetIncidentById([FromRoute] Guid incidentId, IQuerySession querySession, HttpContext context) => | ||
// querySession.Json.WriteById<IncidentDetails>(incidentId, context); | ||
|
||
[WolverineGet("/api/incidents/{incidentId:guid}")] | ||
public static Task<IncidentDetails?> GetDetails([FromRoute] Guid incidentId, IQuerySession querySession, | ||
CancellationToken ct) => | ||
querySession.LoadAsync<IncidentDetails>(incidentId, ct); | ||
public static Task GetIncidentById([FromRoute] Guid incidentId, IQuerySession querySession, HttpContext context) => | ||
querySession.Json.WriteById<IncidentDetails>(incidentId, context); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
...i/Incidents/ResolutionBatch/GettingIncidentResolutionBatch/GetIncidentsBatchResolution.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Marten; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Wolverine.Http; | ||
|
||
namespace Helpdesk.Api.Incidents.ResolutionBatch.GettingIncidentResolutionBatch; | ||
|
||
public class GetIncidentsBatchResolution | ||
{ | ||
[WolverineGet("/api/incidents/resolution/{batchId:guid}")] | ||
public static Task<IncidentsBatchResolution?> Get([FromRoute] Guid batchId, [FromQuery]long version, IQuerySession querySession, | ||
CancellationToken ct) => | ||
querySession.Events.AggregateStreamAsync<IncidentsBatchResolution>(batchId, version: version, token: ct); | ||
} |
Oops, something went wrong.