using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using MySql.Data.MySqlClient;
using System.Collections.Generic;
using System.Data.Common;
using System.Threading.Tasks;
using Ucas.Authorisation.Api;
using Ucas.Authorisation.Application.Common.Interfaces;
using Ucas.Authorisation.Application.Models.Account;
using Ucas.Authorisation.Domain.Entities;
using Ucas.Authorisation.Infrastructure;
namespace Ucas.Authorisation.IntegrationTests
public class InvalidIdentityService : IIdentityService
public Task<IdentityUser> LookupByUcasAccountId(string id)
public class StubIdentityService : IIdentityService
public static string UcasAccountId = Guid.NewGuid().ToString();
public static string PermissionsId = Guid.NewGuid().ToString();
public static string Email = "email@email.com";
public Task<IdentityUser> LookupByUcasAccountId(string id)
UcasAccountId = UcasAccountId,
ProfileData = new ProfileData
public class StubProfileService : IProfileService
public static string Uid = "RandomGigyaId";
public static Dictionary<string, bool> IsVerified = new Dictionary<string, bool>()
{"UnverifiedEmail", false},
public static string FirstName = "Teresa";
public static string LastName = "Green";
public static string Name = "Teresa Green";
public Task<Result<Account>> GetUserProfileByEmail(string email)
IsVerified = IsVerified[email],
public class TestAuthorisationWebApplicationFactory : WebApplicationFactory<Startup>, IAsyncLifetime
public Respawner Respawner => _respawner;
private readonly MySqlTestcontainer _mySqlContainer =
new TestcontainersBuilder<MySqlTestcontainer>()
.WithDatabase(new MySqlTestcontainerConfiguration
Database = "ucaspermissions",
.WithImage("mysql:5.7.38")
private IConfiguration _configuration;
private Respawner? _respawner;
private DbConnection? _dbConnection;
public DbConnection DbConnection => _dbConnection;
protected override void ConfigureWebHost(IWebHostBuilder builder)
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
var apiUserConnection = new MySqlConnectionStringBuilder(_mySqlContainer.ConnectionString)
Database = "ucaspermissions"
var migratorConnection = new MySqlConnectionStringBuilder(_mySqlContainer.ConnectionString);
builder.ConfigureAppConfiguration(config =>
config.AddInMemoryCollection(new Dictionary<string, string>
{"UseInMemoryDatabase", "false"},
config.AddInMemoryCollection(new Dictionary<string, string>
["ConnectionStrings:db"] = apiUserConnection.ConnectionString,
["ConnectionStrings:db_Migrator"] = migratorConnection.ConnectionString
_configuration = config.Build();
builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureTestServices(services =>
services.RemoveAll<IIdentityService>();
services.RemoveAll<IProfileService>();
services.AddTransient<IIdentityService, StubIdentityService>();
services.AddTransient<IProfileService, StubProfileService>();
public async Task InitializeAsync()
await _mySqlContainer.StartAsync();
_dbConnection = new MySqlConnection(_mySqlContainer.ConnectionString);
await InitializeRespawner();
private async Task InitializeRespawner()
await DbConnection.OpenAsync();
_respawner = await Respawner.CreateAsync(DbConnection, new RespawnerOptions
new Table("__EFMigrationsHistory"),
new Table("outbox_message_registry"),
new Table("outbox_message_type")
DbAdapter = DbAdapter.MySql,
SchemasToInclude = new[] { "ucaspermissions" }
public async Task ResetDatabaseAsync()
await _respawner.ResetAsync(DbConnection);
public IApplicationDbContext DbContext
using var scope = Services.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
public async Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)
using var scope = Services.CreateScope();
var mediator = scope.ServiceProvider.GetService<ISender>();
return await mediator.Send(request);
public async Task AddAsync<TEntity>(TEntity entity)
using var scope = Services.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
await context.SaveChangesAsync(CancellationToken.None);
public async Task<TEntity> FindAsync<TEntity>(params object[] keyValues) where TEntity : class
using var scope = Services.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
return await context.FindAsync<TEntity>(keyValues);
public async Task<IEnumerable<Policy<string>>> FindPolicies(string userId)
using var scope = Services.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
return await context.Policies.Where(p => p.UserId == userId).ToListAsync();
public async Task<IEnumerable<OutboxRow>> QueryOutbox()
using var scope = Services.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
var connectionString = context.Database.GetConnectionString();
await using var conn = new MySqlConnection(connectionString);
return await conn.QueryAsync<OutboxRow>("SELECT message_id AS MessageId, message_registry_id AS RegistryId, message AS Message FROM outbox");
public new async Task DisposeAsync()
await _mySqlContainer.StopAsync();
private void EnsureDatabase()
using var scope = Services.CreateScope();
public Guid MessageId { get; set; }
public Guid RegistryId { get; set; }
public string Message { get; set; }