Skip to content

Commit

Permalink
Merge pull request #67 from meysamhadeli/develop
Browse files Browse the repository at this point in the history
- add end-to-end test base
  • Loading branch information
meysamhadeli authored Dec 9, 2022
2 parents c02824f + 44724d7 commit 66f2813
Show file tree
Hide file tree
Showing 25 changed files with 202 additions and 31 deletions.
8 changes: 4 additions & 4 deletions src/BuildingBlocks/BuildingBlocks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="6.2.1" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="6.2.1" />
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="6.2.1" />
<PackageReference Include="Duende.IdentityServer" Version="6.2.0-rc.1" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.0-rc.1" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.0-rc.1" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.0-rc.1" />
<PackageReference Include="Duende.IdentityServer" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.2.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Testcontainers" Version="2.2.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

Expand All @@ -7,18 +8,18 @@ namespace BuildingBlocks.PersistMessageProcessor;
public class PersistMessageBackgroundService : BackgroundService
{
private readonly ILogger<PersistMessageBackgroundService> _logger;
private readonly IPersistMessageProcessor _persistMessageProcessor;
private readonly IServiceProvider _serviceProvider;
private PersistMessageOptions _options;

private Task? _executingTask;

public PersistMessageBackgroundService(
ILogger<PersistMessageBackgroundService> logger,
IPersistMessageProcessor persistMessageProcessor,
IServiceProvider serviceProvider,
IOptions<PersistMessageOptions> options)
{
_logger = logger;
_persistMessageProcessor = persistMessageProcessor;
_serviceProvider = serviceProvider;
_options = options.Value;
}

Expand All @@ -44,7 +45,11 @@ private async Task ProcessAsync(CancellationToken stoppingToken)
{
try
{
await _persistMessageProcessor.ProcessAllAsync(stoppingToken);
await using (var scope = _serviceProvider.CreateAsyncScope())
{
var service = scope.ServiceProvider.GetRequiredService<IPersistMessageProcessor>();
await service.ProcessAllAsync(stoppingToken);
}

var delay = _options.Interval is { }
? TimeSpan.FromSeconds((int)_options.Interval)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;

namespace BuildingBlocks.TestBase.EndToEndTest.Auth;

//ref: https://blog.joaograssi.com/posts/2021/asp-net-core-testing-permission-protected-api-endpoints/
public static class AuthServiceCollectionExtensions
{
public static AuthenticationBuilder AddTestAuthentication(
this IServiceCollection services)
{
services.AddAuthorization(options =>
{
// AuthConstants.Scheme is just a scheme we define. I called it "TestAuth"
options.DefaultPolicy = new AuthorizationPolicyBuilder("Test")
.RequireAuthenticatedUser()
.Build();
});

// Register our custom authentication handler
return services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });
}
}
9 changes: 9 additions & 0 deletions src/BuildingBlocks/TestBase/EndToEndTest/Auth/MockAuthUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Security.Claims;

namespace BuildingBlocks.TestBase.EndToEndTest.Auth;

public class MockAuthUser
{
public List<Claim> Claims { get; }
public MockAuthUser(params Claim[] claims) => Claims = claims.ToList();
}
41 changes: 41 additions & 0 deletions src/BuildingBlocks/TestBase/EndToEndTest/Auth/TestAuthHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace BuildingBlocks.TestBase.EndToEndTest.Auth;

//ref: https://blog.joaograssi.com/posts/2021/asp-net-core-testing-permission-protected-api-endpoints/
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly MockAuthUser _mockAuthUser;

public TestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
MockAuthUser mockAuthUser)
: base(options, logger, encoder, clock)
{
// 1. We get a "mock" user instance here via DI.
// we'll see how this work later, don't worry
_mockAuthUser = mockAuthUser;
}

protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (_mockAuthUser.Claims.Count == 0)
return Task.FromResult(AuthenticateResult.Fail("Mock auth user not configured."));

// 2. Create the principal and the ticket
var identity = new ClaimsIdentity(_mockAuthUser.Claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");

// 3. Authenticate the request
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
46 changes: 46 additions & 0 deletions src/BuildingBlocks/TestBase/EndToEndTest/EndToEndTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Net.Http.Json;
using BuildingBlocks.Mongo;
using BuildingBlocks.TestBase.IntegrationTest;
using BuildingBlocks.Web;
using Microsoft.EntityFrameworkCore;
using Xunit.Abstractions;

namespace BuildingBlocks.TestBase.EndToEndTest;

public class EndToEndTestBase<TEntryPoint, TWContext, TRContext> :
IntegrationTestBase<TEntryPoint, TWContext, TRContext>
where TWContext : DbContext
where TRContext : MongoDbContext
where TEntryPoint : class
{
public EndToEndTestBase(
IntegrationTestFactory<TEntryPoint, TWContext, TRContext> sharedFixture,
ITestOutputHelper outputHelper = null)
: base(sharedFixture, outputHelper)
{
}

public async Task<TResponse> GetAsync<TResponse>(string requestUrl, CancellationToken cancellationToken = default)
{
return await Fixture.HttpClient.GetFromJsonAsync<TResponse>(requestUrl, cancellationToken: cancellationToken);
}

public async Task<TResponse> PostAsync<TRequest, TResponse>(string requestUrl, TRequest request,
CancellationToken cancellationToken = default)
{
return await Fixture.HttpClient.PostAsJsonAsync<TRequest, TResponse>(requestUrl, request, cancellationToken);
}

public async Task<TResponse> PutAsync<TRequest, TResponse>(
string requestUrl,
TRequest request,
CancellationToken cancellationToken = default)
{
return await Fixture.HttpClient.PutAsJsonAsync<TRequest, TResponse>(requestUrl, request, cancellationToken);
}

public async Task Delete(string requestUrl, CancellationToken cancellationToken = default)
{
await Fixture.HttpClient.DeleteAsync(requestUrl, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Ardalis.GuardClauses;
using System.Security.Claims;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.Event;
using BuildingBlocks.Core.Model;
using BuildingBlocks.EFCore;
using BuildingBlocks.MassTransit;
using BuildingBlocks.Mongo;
using BuildingBlocks.PersistMessageProcessor;
using BuildingBlocks.TestBase.EndToEndTest.Auth;
using BuildingBlocks.Web;
using DotNet.Testcontainers.Containers;
using EasyNetQ.Management.Client;
Expand All @@ -27,8 +29,9 @@
using Serilog;
using Xunit;
using Xunit.Abstractions;
using ILogger = Serilog.ILogger;

namespace BuildingBlocks.TestBase;
namespace BuildingBlocks.TestBase.IntegrationTest;

public class IntegrationTestFactory<TEntryPoint> : IAsyncLifetime
where TEntryPoint : class
Expand All @@ -43,9 +46,7 @@ public class IntegrationTestFactory<TEntryPoint> : IAsyncLifetime

private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
public HttpClient HttpClient => _factory?.CreateClient();

public GrpcChannel Channel => GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });

public Action<IServiceCollection> TestRegistrationServices { get; set; }
public IServiceProvider ServiceProvider => _factory?.Services;
public IConfiguration Configuration => _factory?.Services.GetRequiredService<IConfiguration>();
Expand All @@ -63,6 +64,11 @@ public IntegrationTestFactory()
{
TestRegistrationServices?.Invoke(services);
services.ReplaceSingleton(AddHttpContextAccessorMock);
// Add our custom handler
services.AddTestAuthentication();

// Register a default user, so all requests have it by default
services.AddScoped(_ => GetMockUser());
});
});
}
Expand Down Expand Up @@ -255,6 +261,10 @@ private IHttpContextAccessor AddHttpContextAccessorMock(IServiceProvider service

return httpContextAccessorMock;
}

private MockAuthUser GetMockUser() =>
new MockAuthUser(new Claim("sub", Guid.NewGuid().ToString()),
new Claim("email", "[email protected]"));
}

public class IntegrationTestFactory<TEntryPoint, TWContext> : IntegrationTestFactory<TEntryPoint>
Expand Down Expand Up @@ -514,4 +524,3 @@ protected IntegrationTestBase(

public IntegrationTestFactory<TEntryPoint, TWContext, TRContext> Fixture { get; }
}

36 changes: 36 additions & 0 deletions src/BuildingBlocks/Web/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Net.Http.Json;

namespace BuildingBlocks.Web;

public static class HttpClientExtensions
{
public static async Task<TResponse>
PostAsJsonAsync<TRequest, TResponse>(
this HttpClient httpClient,
string requestUri,
TRequest request,
CancellationToken cancellationToken = default)
{
var responseMessage =
await httpClient.PostAsJsonAsync(requestUri, request, cancellationToken: cancellationToken);

var result = await responseMessage.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken);

return result;
}

public static async Task<TResponse?>
PutAsJsonAsync<TRequest, TResponse>(
this HttpClient httpClient,
string requestUri,
TRequest request,
CancellationToken cancellationToken = default)
{
var responseMessage =
await httpClient.PutAsJsonAsync(requestUri, request, cancellationToken: cancellationToken);

var result = await responseMessage.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken);

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Booking.Data;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.PersistMessageProcessor.Data;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight;
using FluentAssertions;
using Grpc.Core;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Booking.Api;
using Booking.Data;
using BuildingBlocks.PersistMessageProcessor.Data;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Xunit;

namespace Integration.Test;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Aircrafts.Features.CreateAircraft.Commands.V1.Reads;
using Flight.Api;
using Flight.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Airports.Features.CreateAirport.Commands.V1.Reads;
using Flight.Api;
using Flight.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Api;
using Flight.Data;
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Api;
using Flight.Data;
using Flight.Flights.Features.DeleteFlight.Commands.V1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Api;
using Flight.Data;
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Threading.Tasks;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight;
using Flight.Api;
using Flight.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Api;
using Flight.Data;
using Flight.Flights.Features.UpdateFlight.Commands.V1.Reads;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight.Api;
using Flight.Data;
using Xunit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Threading.Tasks;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight;
using Flight.Api;
using Flight.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Threading.Tasks;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Flight;
using Flight.Api;
using Flight.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using FluentAssertions;
using Identity.Api;
using Identity.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using Identity.Api;
using Identity.Data;
using Xunit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase;
using BuildingBlocks.TestBase.IntegrationTest;
using FluentAssertions;
using Integration.Test.Fakes;
using Passenger.Api;
Expand Down
Loading

0 comments on commit 66f2813

Please sign in to comment.