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

added api tests for the v4 trust endpoint #434

Merged
merged 23 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1e3e21e
added test coverage for trust v4 endpoints
mikestock-nimble Dec 6, 2023
e361347
fixed v4 tests so that they are reliable
mikestock-nimble Dec 6, 2023
4565344
made the tests more dynamic so they can run multiple times
mikestock-nimble Dec 7, 2023
20dcc91
removing comment
mikestock-nimble Dec 7, 2023
3392b5e
updated the test seed and cleanup so it runs once per test set
mikestock-nimble Dec 7, 2023
cba9034
added docker compose that creates a separate database for the tests o…
mikestock-nimble Dec 7, 2023
be79555
renamed foreign keys to follow the entity framework naming standard
mikestock-nimble Dec 7, 2023
20ac99f
change microsoft log to warning, to reduce the level of logs
mikestock-nimble Dec 7, 2023
f463800
get serilog to read from the configuration
mikestock-nimble Dec 7, 2023
3aa7483
handle the case where trust type is null
mikestock-nimble Dec 8, 2023
dfcecd0
started writing api tests for establishment
mikestock-nimble Dec 11, 2023
cf9e409
fixed issue with test database not being in sync
mikestock-nimble Dec 14, 2023
d86d906
added working test for get establishment by ukprn
mikestock-nimble Dec 14, 2023
9becb3b
added tests for the the get establishments for trust api
mikestock-nimble Dec 15, 2023
9ee7db3
added tests for the search establishments api
mikestock-nimble Dec 15, 2023
ec6b163
tidy up of the establishment repository to remove the unused methods
mikestock-nimble Dec 15, 2023
57faafc
reverted changes to the db fixture
mikestock-nimble Dec 15, 2023
bf57222
added a test to check the api can handle data that only has the minim…
mikestock-nimble Dec 18, 2023
47100eb
removed commented code
mikestock-nimble Dec 18, 2023
53b9d6e
moved files around to simplify the structure
mikestock-nimble Dec 18, 2023
c844689
moved the integration tests v3 to a v3 folder
mikestock-nimble Dec 18, 2023
36a66a2
renamed the properties to follow entity framework conventions
mikestock-nimble Dec 18, 2023
a74ae5b
updated the readme with the V4 testing strategy
mikestock-nimble Dec 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@
<ProjectReference Include="..\Dfe.Academies.Domain\Dfe.Academies.Domain.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>

</Project>

Large diffs are not rendered by default.

360 changes: 360 additions & 0 deletions Dfe.Academies.Api.Infrastructure/Migrations/20231218095513_Initial.cs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

92 changes: 55 additions & 37 deletions Dfe.Academies.Api.Infrastructure/MstrContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
using Dfe.Academies.Domain.Trust;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace Dfe.Academies.Academisation.Data;

public class MstrContext : DbContext
{
const string DEFAULT_SCHEMA = "mstr";

public MstrContext()
{

}

public MstrContext(DbContextOptions<MstrContext> options) : base(options)
{

Expand All @@ -24,6 +29,14 @@ public MstrContext(DbContextOptions<MstrContext> options) : base(options)

public DbSet<IfdPipeline> IfdPipelines { get; set; } = null!;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=localhost;Database=sip;Integrated Security=true;TrustServerCertificate=True");
}
}


protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Expand All @@ -41,7 +54,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

private void ConfigureEstablishment(EntityTypeBuilder<Establishment> establishmentConfiguration)
{
establishmentConfiguration.HasKey(e => e.SK).HasName("SK");
establishmentConfiguration.HasKey(e => e.SK);

establishmentConfiguration.ToTable("EducationEstablishment", DEFAULT_SCHEMA);

Expand All @@ -64,11 +77,11 @@ private void ConfigureEstablishment(EntityTypeBuilder<Establishment> establishme
establishmentConfiguration.Property(e => e.Email).HasColumnName("Email");
establishmentConfiguration.Property(e => e.EstablishmentName).HasColumnName("EstablishmentName");
establishmentConfiguration.Property(e => e.EstablishmentNumber).HasColumnName("EstablishmentNumber");
establishmentConfiguration.Property(e => e.FK_EstablishmentGroupType).HasColumnName("FK_EstablishmentGroupType");
establishmentConfiguration.Property(e => e.FK_EstablishmentStatus).HasColumnName("FK_EstablishmentStatus");
establishmentConfiguration.Property(e => e.FK_EstablishmentType).HasColumnName("FK_EstablishmentType");
establishmentConfiguration.Property(e => e.FK_LocalAuthority).HasColumnName("FK_LocalAuthority");
establishmentConfiguration.Property(e => e.FK_Region).HasColumnName("FK_Region");
establishmentConfiguration.Property(e => e.EstablishmentGroupTypeId).HasColumnName("FK_EstablishmentGroupType");
establishmentConfiguration.Property(e => e.EstablishmentStatusId).HasColumnName("FK_EstablishmentStatus");
establishmentConfiguration.Property(e => e.EstablishmentTypeId).HasColumnName("FK_EstablishmentType");
establishmentConfiguration.Property(e => e.LocalAuthorityId).HasColumnName("FK_LocalAuthority");
establishmentConfiguration.Property(e => e.RegionId).HasColumnName("FK_Region");
establishmentConfiguration.Property(e => e.GORregion).HasColumnName("GORregion");
establishmentConfiguration.Property(e => e.HeadFirstName).HasColumnName("HeadFirstName");
establishmentConfiguration.Property(e => e.HeadLastName).HasColumnName("HeadLastName");
Expand Down Expand Up @@ -135,21 +148,14 @@ private void ConfigureEstablishment(EntityTypeBuilder<Establishment> establishme

establishmentConfiguration
.HasOne(x => x.EstablishmentType)
.WithOne()
.HasForeignKey<Establishment>(x => x.FK_EstablishmentType)
.WithMany()
.HasForeignKey(x => x.EstablishmentTypeId)
.IsRequired(false);

establishmentConfiguration
.HasOne(x => x.LocalAuthority)
.WithOne()
.HasForeignKey<Establishment>(x => x.FK_LocalAuthority)
.IsRequired(false);

establishmentConfiguration
.HasOne(x => x.IfdPipeline)
.WithOne()
.HasForeignKey<Establishment>(x => x.PK_GIAS_URN)
.HasPrincipalKey<IfdPipeline>(x => x.GeneralDetailsUrn)
.WithMany()
.HasForeignKey(x => x.LocalAuthorityId)
.IsRequired(false);
}

Expand All @@ -160,14 +166,14 @@ private void ConfigureEstablishment(EntityTypeBuilder<Establishment> establishme

void ConfigureTrust(EntityTypeBuilder<Trust> trustConfiguration)
{
trustConfiguration.HasKey(e => e.SK).HasName("SK");

trustConfiguration.HasKey(e => e.SK);
trustConfiguration.ToTable("Trust", DEFAULT_SCHEMA);

trustConfiguration.Property(e => e.TrustsTrustType).HasColumnName("FK_TrustType");
trustConfiguration.Property(e => e.Region).HasColumnName("FK_Region");
trustConfiguration.Property(e => e.TrustBanding).HasColumnName("FK_TrustBanding");
trustConfiguration.Property(e => e.FK_TrustStatus).HasColumnName("FK_TrustStatus");
trustConfiguration.Property(e => e.TrustTypeId).HasColumnName("FK_TrustType");
trustConfiguration.Property(e => e.RegionId).HasColumnName("FK_Region");
trustConfiguration.Property(e => e.TrustBandingId).HasColumnName("FK_TrustBanding");
trustConfiguration.Property(e => e.TrustStatusId).HasColumnName("FK_TrustStatus");
trustConfiguration.Property(e => e.GroupUID).HasColumnName("Group UID").IsRequired();
trustConfiguration.Property(e => e.GroupID).HasColumnName("Group ID");
trustConfiguration.Property(e => e.RID).HasColumnName("RID");
Expand Down Expand Up @@ -207,39 +213,51 @@ void ConfigureTrust(EntityTypeBuilder<Trust> trustConfiguration)
trustConfiguration.Property(e => e.IncorporatedOnOpenDate).HasColumnName("Incorporated on (open date)");

trustConfiguration
.HasOne(x => x.TrustType)
.WithOne()
.HasForeignKey<Trust>(x => x.TrustsTrustType)
.IsRequired(true);
.HasOne(x => x.TrustType)
.WithMany()
.HasForeignKey(x => x.TrustTypeId);
}

void ConfigureTrustType(EntityTypeBuilder<TrustType> trustTypeConfiguration)
private void ConfigureTrustType(EntityTypeBuilder<TrustType> trustTypeConfiguration)
{
trustTypeConfiguration.HasKey(e => e.SK).HasName("SK");
trustTypeConfiguration.HasKey(e => e.SK);

trustTypeConfiguration.ToTable("Ref_TrustType", DEFAULT_SCHEMA);

trustTypeConfiguration.HasData(new TrustType() { SK = 30, Code = "06", Name = "Multi-academy trust" });
trustTypeConfiguration.HasData(new TrustType() { SK = 32, Code = "10", Name = "Single-academy trust" });
}
private void ConfigureEducationEstablishmentTrust(EntityTypeBuilder<EducationEstablishmentTrust> entityBuilder)
{
entityBuilder.HasKey(e => e.SK);
entityBuilder.ToTable("EducationEstablishmentTrust", DEFAULT_SCHEMA);

entityBuilder.ToTable("EducationEstablishmentTrust", DEFAULT_SCHEMA);

entityBuilder.Property(e => e.EducationEstablishmentId).HasColumnName("FK_EducationEstablishment");
entityBuilder.Property(e => e.TrustId).HasColumnName("FK_Trust");
}
void ConfigureLocalAuthority(EntityTypeBuilder<LocalAuthority> localAuthorityConfiguration)

private void ConfigureLocalAuthority(EntityTypeBuilder<LocalAuthority> localAuthorityConfiguration)
{
localAuthorityConfiguration.HasKey(e => e.SK).HasName("SK");
localAuthorityConfiguration.HasKey(e => e.SK);
localAuthorityConfiguration.ToTable("Ref_LocalAuthority", DEFAULT_SCHEMA);

localAuthorityConfiguration.HasData(new LocalAuthority() { SK = 1, Code = "202", Name = "Barnsley" });
localAuthorityConfiguration.HasData(new LocalAuthority() { SK = 2, Code = "203", Name = "Birmingham" });
localAuthorityConfiguration.HasData(new LocalAuthority() { SK = 3, Code = "204", Name = "Bradford" });
}

void ConfigureEstablishmentType(EntityTypeBuilder<EstablishmentType> establishmentTypeConfiguration)
private void ConfigureEstablishmentType(EntityTypeBuilder<EstablishmentType> establishmentTypeConfiguration)
{
establishmentTypeConfiguration.HasKey(e => e.SK).HasName("SK");
establishmentTypeConfiguration.HasKey(e => e.SK);
establishmentTypeConfiguration.ToTable("Ref_EducationEstablishmentType", DEFAULT_SCHEMA);

establishmentTypeConfiguration.HasData(new EstablishmentType() { SK = 224, Code = "35", Name = "Free schools" });
establishmentTypeConfiguration.HasData(new EstablishmentType() { SK = 228, Code = "18", Name = "Further education" });
}

private void ConfigureIfdPipeline(EntityTypeBuilder<IfdPipeline> ifdPipelineConfiguration)
{
ifdPipelineConfiguration.HasKey(e => e.SK).HasName("SK");
ifdPipelineConfiguration.HasKey(e => e.SK);

ifdPipelineConfiguration.ToTable("IfdPipeline", DEFAULT_SCHEMA);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,99 +1,140 @@
using Dfe.Academies.Academisation.Data;
using Dfe.Academies.Academisation.Data.Repositories;
using Dfe.Academies.Domain.Establishment;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
using static System.Net.Mime.MediaTypeNames;

namespace Dfe.Academies.Infrastructure.Repositories
{
public class EstablishmentRepository : GenericRepository<Establishment>, IEstablishmentRepository
public class EstablishmentRepository : IEstablishmentRepository
{
public EstablishmentRepository(MstrContext context) : base(context)
private MstrContext _context;

public EstablishmentRepository(MstrContext context)
{
_context = context;
}

public async Task<Establishment?> GetEstablishmentByUkprn(string ukprn, CancellationToken cancellationToken)
{
var Establishment = await DefaultIncludes().SingleOrDefaultAsync(x => x.UKPRN == ukprn).ConfigureAwait(false);
var queryResult = await BaseQuery().SingleOrDefaultAsync(r => r.Establishment.UKPRN == ukprn);

if (queryResult == null)
{
return null;
}

return Establishment;
var result = ToEstablishment(queryResult);

return result;
}

public async Task<Establishment?> GetEstablishmentByUrn(string urn, CancellationToken cancellationToken)
{
var establishment = await DefaultIncludes().SingleOrDefaultAsync(x => x.URN.ToString() == urn).ConfigureAwait(false);
var queryResult = await BaseQuery().SingleOrDefaultAsync(r => r.Establishment.URN.ToString() == urn);

return establishment;
if (queryResult == null)
{
return null;
}

var result = ToEstablishment(queryResult);

return result;
}

public async Task<List<Establishment>> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken)
{
IQueryable<Establishment> query = DefaultIncludes().AsNoTracking();
IQueryable<EstablishmentQueryResult> query = BaseQuery();

if (!string.IsNullOrEmpty(name))
{
query = query.Where(e => e.EstablishmentName.Contains(name));
query = query.Where(r => r.Establishment.EstablishmentName.Contains(name));
}
if (!string.IsNullOrEmpty(ukPrn))
{
query = query.Where(e => e.UKPRN == ukPrn);
query = query.Where(r => r.Establishment.UKPRN == ukPrn);
}
if (!string.IsNullOrEmpty(urn))
{
if (int.TryParse(urn, out var urnAsNumber))
{
query = query.Where(e => e.URN == urnAsNumber);
}
}
return await query.Take(100).ToListAsync(cancellationToken);
query = query.Where(r => r.Establishment.URN == urnAsNumber);
}
}
var queryResult = await query.Take(100).ToListAsync(cancellationToken);

var result = queryResult.Select(ToEstablishment).ToList();

return result;
}

public async Task<IEnumerable<int>> GetURNsByRegion(string[] regions, CancellationToken cancellationToken)
{
return await DefaultIncludes() //Adding Explicit cast because the Domain entity has the URN as nullable
{
return await _context.Establishments
.AsNoTracking()
.Where(p => regions.Contains(p!.GORregion.ToLower()) && p.URN.HasValue)
.Where(p => regions.Contains(p.GORregion) && p.URN.HasValue)
.Select(e => e.URN.Value)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
.ToListAsync(cancellationToken);
}

public async Task<List<Establishment>> GetByUrns(int[] urns, CancellationToken cancellationToken)
{
var urnsList = urns.ToList();
return await DefaultIncludes()
.AsNoTracking()
.Where(e => urnsList.Contains((int)e.URN))
var queryResult = await BaseQuery()
.Where(r => urnsList.Contains((int)r.Establishment.URN))
.ToListAsync(cancellationToken);

var result = queryResult.Select(ToEstablishment).ToList();

return result;
}

public async Task<List<Establishment>> GetByTrust(long? trustId, CancellationToken cancellationToken)
{
var establishmentIds = await context.EducationEstablishmentTrusts
.Where(eet => eet.FK_Trust == Convert.ToInt32(trustId))
.Select(eet => (long)eet.FK_EducationEstablishment)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

var establishments = await DefaultIncludes().AsNoTracking()
.Where(e => establishmentIds.Contains(e.SK))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);


return establishments;
}
{
var establishmentIds =
await _context.EducationEstablishmentTrusts
.AsNoTracking()
.Where(eet => eet.TrustId == Convert.ToInt32(trustId))
.Select(eet => (long)eet.EducationEstablishmentId)
.ToListAsync(cancellationToken);

var establishments =
await BaseQuery()
.Where(r => establishmentIds.Contains(r.Establishment.SK.Value))
.ToListAsync(cancellationToken);

var result = establishments.Select(ToEstablishment).ToList();

return result;
}

private IQueryable<Establishment> DefaultIncludes()
private IQueryable<EstablishmentQueryResult> BaseQuery()
{
var x = dbSet
.Include(x => x.EstablishmentType)
.Include(x => x.LocalAuthority)
.Include(x => x.IfdPipeline)
.AsQueryable();
var result =
from establishment in _context.Establishments
from ifdPipeline in _context.IfdPipelines.Where(i => i.GeneralDetailsUrn == establishment.PK_GIAS_URN).DefaultIfEmpty()
from establishmentType in _context.EstablishmentTypes.Where(e => e.SK == establishment.EstablishmentTypeId).DefaultIfEmpty()
from localAuthority in _context.LocalAuthorities.Where(l => l.SK == establishment.LocalAuthorityId).DefaultIfEmpty()
select new EstablishmentQueryResult { Establishment = establishment, IfdPipeline = ifdPipeline, LocalAuthority = localAuthority, EstablishmentType = establishmentType };

return x;
return result;
}

private static Establishment ToEstablishment(EstablishmentQueryResult queryResult)
{
var result = queryResult.Establishment;
result.IfdPipeline = queryResult.IfdPipeline;
result.LocalAuthority = queryResult.LocalAuthority;
result.EstablishmentType = queryResult.EstablishmentType;

return result;
}
}

internal record EstablishmentQueryResult
{
public Establishment Establishment { get; set; }
public IfdPipeline IfdPipeline { get; set; }
public LocalAuthority LocalAuthority { get; set; }
public EstablishmentType EstablishmentType { get; set; }
}
}
Loading
Loading