Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marten scalled projections sample #219

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/build.docker.helpdesk.scaled-up.yml
@@ -0,0 +1,43 @@
name: Bulild Helpdesk Docker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: Bulild Helpdesk Docker
name: Build Helpdesk Docker


on:
# run it on push to the default repository branch
push:
branches: [main]
paths:
- "Sample/Helpdesk.ScaledUpProjections/**"
# run it during pull request
pull_request:
paths:
- "Sample/Helpdesk.ScaledUpProjections/**"

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Check Out Repo
uses: actions/checkout@v3

- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2

- name: Build and push
id: docker_build
uses: docker/build-push-action@v4
with:
context: "./Sample/Helpdesk.ScaledUpProjections/Helpdesk.Api"
push: false
tags: oskardudycz/eventsourcing.netcore.helpdesk.scaledup:latest
build-args: |
"project_name=Helpdesk"

- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
6 changes: 6 additions & 0 deletions Sample/Helpdesk.ScaledUpProjections/.dockerignore
@@ -0,0 +1,6 @@
**/bin/
**/obj/
**/out/
**/TestResults/
**/Internal/Generated
Dockerfile
62 changes: 62 additions & 0 deletions Sample/Helpdesk.ScaledUpProjections/Dockerfile
@@ -0,0 +1,62 @@
ARG dotnet_version=7.0
########################################
# First stage of multistage build
########################################
# Use Build image with label `builder
########################################
FROM mcr.microsoft.com/dotnet/sdk:${dotnet_version}-alpine AS builder
# Project file name, mandatory parameter, e.g. Helpdesk.Api
ARG run_codegen=true

# Setup working directory for project
WORKDIR /app

COPY ./Helpdesk/Helpdesk.csproj ./Helpdesk/Helpdesk.csproj
COPY ./Helpdesk.Api/Helpdesk.Api.csproj ./Helpdesk.Api/Helpdesk.Api.csproj

# Restore nuget packages
RUN dotnet restore ./Helpdesk.Api/Helpdesk.Api.csproj

# Copy project files
COPY ./ ./

# Run code generation depending on the build argument
RUN if [ "run_codegen" = true ] ; then dotnet run -- codegen write & dotnet run -- codegen test; else echo "skipping code generation"; fi

# Build project with Release configuration
# and no restore, as we did it already
RUN dotnet build -c Release --no-restore ./Helpdesk.Api/Helpdesk.Api.csproj

## Test project with Release configuration
## and no build, as we did it already
#RUN dotnet test -c Release --no-build ./Sample/Tickets/Tickets.Api/Tickets.Api.csproj

# Publish project to output folder
# and no build, as we did it already
WORKDIR /app/
RUN ls
RUN dotnet publish -c Release --no-build -o out ./Helpdesk.Api/Helpdesk.Api.csproj

########################################
# Second stage of multistage build
########################################
# Use other build image as the final one
# that won't have source codes
########################################
FROM mcr.microsoft.com/dotnet/aspnet:${dotnet_version}-alpine
ARG dotnet_version=7.0

# Setup working directory for project
WORKDIR /app/

# Copy published in previous stage binaries
# from the `builder` image
COPY --from=builder /app/Helpdesk.Api/out .

# Set URL that App will be exposed
ENV ASPNETCORE_URLS="http://*:5000"
ENV PROJECT_DLL="Helpdesk.Api.dll"

# sets entry point command to automatically
# run application on `docker run`
ENTRYPOINT dotnet $PROJECT_DLL
62 changes: 62 additions & 0 deletions Sample/Helpdesk.ScaledUpProjections/Dockerfile.SignalR
@@ -0,0 +1,62 @@
ARG dotnet_version=7.0
########################################
# First stage of multistage build
########################################
# Use Build image with label `builder
########################################
FROM mcr.microsoft.com/dotnet/sdk:${dotnet_version}-alpine AS builder
# Project file name, mandatory parameter, e.g. Helpdesk.SignalR
ARG run_codegen=true

# Setup working directory for project
WORKDIR /app

COPY ./Helpdesk/Helpdesk.csproj ./Helpdesk/Helpdesk.csproj
COPY ./Helpdesk.SignalR/Helpdesk.SignalR.csproj ./Helpdesk.SignalR/Helpdesk.SignalR.csproj

# Restore nuget packages
RUN dotnet restore ./Helpdesk.SignalR/Helpdesk.SignalR.csproj

# Copy project files
COPY ./ ./

# Run code generation depending on the build argument
RUN if [ "run_codegen" = true ] ; then dotnet run -- codegen write & dotnet run -- codegen test; else echo "skipping code generation"; fi

# Build project with Release configuration
# and no restore, as we did it already
RUN dotnet build -c Release --no-restore ./Helpdesk.SignalR/Helpdesk.SignalR.csproj

## Test project with Release configuration
## and no build, as we did it already
#RUN dotnet test -c Release --no-build ./Sample/Tickets/Tickets.SignalR/Tickets.SignalR.csproj

# Publish project to output folder
# and no build, as we did it already
WORKDIR /app/
RUN ls
RUN dotnet publish -c Release --no-build -o out ./Helpdesk.SignalR/Helpdesk.SignalR.csproj

########################################
# Second stage of multistage build
########################################
# Use other build image as the final one
# that won't have source codes
########################################
FROM mcr.microsoft.com/dotnet/aspnet:${dotnet_version}-alpine
ARG dotnet_version=7.0

# Setup working directory for project
WORKDIR /app/

# Copy published in previous stage binaries
# from the `builder` image
COPY --from=builder /app/Helpdesk.SignalR/out .

# Set URL that App will be exposed
ENV ASPNETCORE_URLS="http://*:5000"
ENV PROJECT_DLL="Helpdesk.SignalR.dll"

# sets entry point command to automatically
# run application on `docker run`
ENTRYPOINT dotnet $PROJECT_DLL
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="NSubstitute" Version="5.0.0" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.9" />
<PackageReference Include="Ogooreck" Version="0.6.0" />
<PackageReference Include="Bogus" Version="34.0.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

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

<Import Project="..\..\..\Tests.Build.props" />

</Project>
@@ -0,0 +1,40 @@
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Helpdesk.Incidents;
using Xunit;
using static Ogooreck.API.ApiSpecification;

namespace Helpdesk.Api.Tests.Incidents;

public class AcknowledgeResolutionIncidentTests: IClassFixture<ApiWithResolvedIncident>
{
[Fact]
[Trait("Category", "Acceptance")]
public async Task ResolveCommand_Succeeds()
{
await API
.Given(
URI($"/api/customers/{API.Incident.CustomerId}/incidents/{API.Incident.Id}/acknowledge"),
HEADERS(IF_MATCH(2))
)
.When(POST)
.Then(OK);

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

private readonly ApiWithResolvedIncident API;

public AcknowledgeResolutionIncidentTests(ApiWithResolvedIncident api) => API = api;
}
@@ -0,0 +1,40 @@
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(
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/assign"),
HEADERS(IF_MATCH(1))
)
.When(POST)
.Then(OK);

await API
.Given(URI($"/api/incidents/{API.Incident.Id}"))
.When(GET)
.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;
}
@@ -0,0 +1,45 @@
using Bogus;
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Helpdesk.Incidents;
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(
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/category"),
BODY(new CategoriseIncidentRequest(category)),
HEADERS(IF_MATCH(1))
)
.When(POST)
.Then(OK);

await API
.Given(URI($"/api/incidents/{API.Incident.Id}"))
.When(GET)
.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;

}
@@ -0,0 +1,41 @@
using Helpdesk.Api.Tests.Incidents.Fixtures;
using Helpdesk.Incidents;
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(
URI($"/api/agents/{agentId}/incidents/{API.Incident.Id}/close"),
HEADERS(IF_MATCH(3))
)
.When(POST)
.Then(OK);

await API
.Given(URI($"/api/incidents/{API.Incident.Id}"))
.When(GET)
.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;
}
@@ -0,0 +1,18 @@
using Helpdesk.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;
}