From 4a29291dc22dcfdaab4cf19c758888b1ae612ac7 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:41:37 +0100 Subject: [PATCH 01/13] Add Project models --- .../Models/ConversionProject.cs | 16 ++++++++++++++++ Dfe.Identifiers.Domain/Models/FormAMatProject.cs | 8 ++++++++ Dfe.Identifiers.Domain/Models/TransferProject.cs | 9 +++++++++ 3 files changed, 33 insertions(+) create mode 100644 Dfe.Identifiers.Domain/Models/ConversionProject.cs create mode 100644 Dfe.Identifiers.Domain/Models/FormAMatProject.cs create mode 100644 Dfe.Identifiers.Domain/Models/TransferProject.cs diff --git a/Dfe.Identifiers.Domain/Models/ConversionProject.cs b/Dfe.Identifiers.Domain/Models/ConversionProject.cs new file mode 100644 index 0000000..eb30433 --- /dev/null +++ b/Dfe.Identifiers.Domain/Models/ConversionProject.cs @@ -0,0 +1,16 @@ +namespace Dfe.Identifiers.Domain.Models; + +public class ConversionProject +{ + public int? Id { get; set; } + public int URN { get; set; } + public string? SchoolName { get; set; } + public string? ApplicationReferenceNumber { get; set; } + public string? TrustReferenceNumber { get; set; } + public string? SponsorReferenceNumber { get; set; } + + // Foreign Key + public int? FormAMatProjectId { get; set; } + + public FormAMatProject? FormAMatProject { get; set; } +} \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Models/FormAMatProject.cs b/Dfe.Identifiers.Domain/Models/FormAMatProject.cs new file mode 100644 index 0000000..c9e995d --- /dev/null +++ b/Dfe.Identifiers.Domain/Models/FormAMatProject.cs @@ -0,0 +1,8 @@ +namespace Dfe.Identifiers.Domain.Models; + +public class FormAMatProject +{ + public int? Id { get; set; } + public string? ApplicationReference { get; set; } + public string? ReferenceNumber { get; set; } +} \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Models/TransferProject.cs b/Dfe.Identifiers.Domain/Models/TransferProject.cs new file mode 100644 index 0000000..e358e5e --- /dev/null +++ b/Dfe.Identifiers.Domain/Models/TransferProject.cs @@ -0,0 +1,9 @@ +namespace Dfe.Identifiers.Domain.Models; + +public class TransferProject +{ + public int? Id { get; set; } + public int URN { get; set; } + public string? ProjectReference { get; set; } + public long? OutgoingTrustUKPRN { get; set; } +} \ No newline at end of file From 0f84bbc0d25226b8bb4eda4d303a0b419e8de4aa Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:42:00 +0100 Subject: [PATCH 02/13] Add academisation context --- .../Context/AcademisationContext.cs | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Dfe.Identifiers.Infrastructure/Context/AcademisationContext.cs diff --git a/Dfe.Identifiers.Infrastructure/Context/AcademisationContext.cs b/Dfe.Identifiers.Infrastructure/Context/AcademisationContext.cs new file mode 100644 index 0000000..de82e2f --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Context/AcademisationContext.cs @@ -0,0 +1,85 @@ +using Dfe.Identifiers.Domain.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Dfe.Identifiers.Infrastructure.Context; + +public class AcademisationContext : DbContext +{ + const string DEFAULT_SCHEMA = "academisation"; + + public AcademisationContext() + { + + } + + public AcademisationContext(DbContextOptions options) : base(options) + { + + } + + public DbSet ConversionProjects { get; set; } = null!; + public DbSet TransferProjects { get; set; } = null!; + public DbSet FormAMatProjects { get; set; } = null!; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlServer("Server=localhost;Database=sip;Integrated Security=true;TrustServerCertificate=True"); + } + optionsBuilder.LogTo(Console.WriteLine); + } + + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(ConfigureConversionProjects); + modelBuilder.Entity(ConfigureTransferProject); + modelBuilder.Entity(ConfigureFormAMatProject); + + base.OnModelCreating(modelBuilder); + } + + private void ConfigureFormAMatProject(EntityTypeBuilder projectConfiguration) + { + projectConfiguration.HasKey(e => e.Id); + + projectConfiguration.ToTable("FormAMatProject", DEFAULT_SCHEMA); + + projectConfiguration.Property(e => e.ApplicationReference).HasColumnName("ApplicationReference"); + projectConfiguration.Property(e => e.ReferenceNumber).HasColumnName("ReferenceNumber"); + } + + private void ConfigureTransferProject(EntityTypeBuilder projectConfiguration) + { + projectConfiguration.HasKey(e => e.Id); + + projectConfiguration.ToTable("TransferProject", DEFAULT_SCHEMA); + + projectConfiguration.Property(e => e.URN).HasColumnName("Urn"); + projectConfiguration.Property(e => e.ProjectReference).HasColumnName("ProjectReference"); + projectConfiguration.Property(e => e.OutgoingTrustUKPRN).HasColumnName("OutgoingTrustUkprn"); + } + + private void ConfigureConversionProjects(EntityTypeBuilder projectConfiguration) + { + projectConfiguration.HasKey(e => e.Id); + + projectConfiguration.ToTable("Project", DEFAULT_SCHEMA); + + projectConfiguration.Property(e => e.ApplicationReferenceNumber).HasColumnName("ApplicationReferenceNumber"); + projectConfiguration.Property(e => e.URN).HasColumnName("Urn"); + projectConfiguration.Property(e => e.SchoolName).HasColumnName("SchoolName"); + projectConfiguration.Property(e => e.FormAMatProjectId).HasColumnName("FormAMatProjectId"); + projectConfiguration.Property(e => e.TrustReferenceNumber).HasColumnName("TrustReferenceNumber"); + projectConfiguration.Property(e => e.SponsorReferenceNumber).HasColumnName("SponsorReferenceNumber"); + + projectConfiguration + .HasOne(x => x.FormAMatProject) + .WithMany() + .HasForeignKey(x => x.FormAMatProjectId) + .IsRequired(false); + + } +} From 90928b43de79cb45accbb623ed4d8fab80b1b096 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:42:41 +0100 Subject: [PATCH 03/13] Create the project repository --- .../Interfaces/IProjectsRepository.cs | 15 +++++++ .../Repositories/ProjectsRepository.cs | 39 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 Dfe.Identifiers.Infrastructure/Interfaces/IProjectsRepository.cs create mode 100644 Dfe.Identifiers.Infrastructure/Repositories/ProjectsRepository.cs diff --git a/Dfe.Identifiers.Infrastructure/Interfaces/IProjectsRepository.cs b/Dfe.Identifiers.Infrastructure/Interfaces/IProjectsRepository.cs new file mode 100644 index 0000000..b0cce45 --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Interfaces/IProjectsRepository.cs @@ -0,0 +1,15 @@ +using Dfe.Identifiers.Domain.Models; + +namespace Dfe.Identifiers.Infrastructure.Interfaces; + +public interface IProjectsRepository +{ + Task> GetConversionProjectsByIdentifier(string identifier, + CancellationToken cancellationToken); + + Task> GetTransfersProjectsByIdentifier(string identifier, + CancellationToken cancellationToken); + + Task> GetFormAMatProjectsByIdentifier(string identifier, + CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/Dfe.Identifiers.Infrastructure/Repositories/ProjectsRepository.cs b/Dfe.Identifiers.Infrastructure/Repositories/ProjectsRepository.cs new file mode 100644 index 0000000..e2cbd3c --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Repositories/ProjectsRepository.cs @@ -0,0 +1,39 @@ +using Dfe.Identifiers.Domain.Models; +using Dfe.Identifiers.Infrastructure.Context; +using Dfe.Identifiers.Infrastructure.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace Dfe.Identifiers.Infrastructure.Repositories; + +public class ProjectsRepository(AcademisationContext context) : IProjectsRepository +{ + public async Task> GetConversionProjectsByIdentifier(string identifier, + CancellationToken cancellationToken) + { + var query = await context.ConversionProjects.Where(project => + project.ApplicationReferenceNumber == identifier || + project.TrustReferenceNumber == identifier || + project.SponsorReferenceNumber == identifier + ).ToListAsync(cancellationToken); + return query; + } + + public async Task> GetTransfersProjectsByIdentifier(string identifier, + CancellationToken cancellationToken) + { + var query = await context.TransferProjects.Where(project => + project.ProjectReference == identifier + ).ToListAsync(cancellationToken); + return query; + } + + public async Task> GetFormAMatProjectsByIdentifier(string identifier, + CancellationToken cancellationToken) + { + var query = await context.FormAMatProjects.Where(project => + project.ApplicationReference == identifier || + project.ReferenceNumber == identifier + ).ToListAsync(cancellationToken); + return query; + } +} \ No newline at end of file From 672905a532356488d4b81e91fa9ebb1ba2ee56ad Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:44:12 +0100 Subject: [PATCH 04/13] Add projects to the identifiers query --- .../IdentifiersQuery.cs | 24 +++++++++++++------ .../Helpers/IdentifierMapping.cs | 16 +++++++++++++ .../ConversionProjectIdentifiers.cs | 6 +++++ .../Identifiers/FormAMatProjectIdentifiers.cs | 3 +++ .../Identifiers/IdentifiersCollection.cs | 7 +++++- .../Identifiers/TransferProjectIdentifiers.cs | 3 +++ 6 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 Dfe.Identifiers.Domain/Identifiers/ConversionProjectIdentifiers.cs create mode 100644 Dfe.Identifiers.Domain/Identifiers/FormAMatProjectIdentifiers.cs create mode 100644 Dfe.Identifiers.Domain/Identifiers/TransferProjectIdentifiers.cs diff --git a/Dfe.Identifiers.Application/IdentifiersQuery.cs b/Dfe.Identifiers.Application/IdentifiersQuery.cs index c7eaad9..55a7fcf 100644 --- a/Dfe.Identifiers.Application/IdentifiersQuery.cs +++ b/Dfe.Identifiers.Application/IdentifiersQuery.cs @@ -4,18 +4,28 @@ namespace Dfe.Identifiers.Application; -public class IdentifiersQuery(ITrustRepository trustRepository, IEstablishmentRepository establishmentRepository) : IIdentifiersQuery +public class IdentifiersQuery( + ITrustRepository trustRepository, + IEstablishmentRepository establishmentRepository, + IProjectsRepository projectsRepository) : IIdentifiersQuery { - private ITrustRepository _trustRepository { get; } = trustRepository; - private IEstablishmentRepository _establishmentRepository { get; } = establishmentRepository; - public async Task GetIdentifiers(string identifier, CancellationToken cancellationToken) { - var trusts = await _trustRepository.GetTrustsByIdentifier(identifier, cancellationToken).ConfigureAwait(false); - var establishments = await _establishmentRepository.GetEstablishmentsByIdentifier(identifier, cancellationToken) + var trusts = await trustRepository.GetTrustsByIdentifier(identifier, cancellationToken).ConfigureAwait(false); + var establishments = await establishmentRepository.GetEstablishmentsByIdentifier(identifier, cancellationToken) + .ConfigureAwait(false); + var transfers = await projectsRepository.GetTransfersProjectsByIdentifier(identifier, cancellationToken) + .ConfigureAwait(false); + var conversions = await projectsRepository.GetConversionProjectsByIdentifier(identifier, cancellationToken) .ConfigureAwait(false); + var formAMats = await projectsRepository.GetFormAMatProjectsByIdentifier(identifier, cancellationToken) + .ConfigureAwait(false); + var results = new IdentifiersCollection(trusts.Select(MapTrustToIdentifiers).ToArray(), - establishments.Select(MapEstablishmentToIdentifiers).ToArray()); + establishments.Select(MapEstablishmentToIdentifiers).ToArray(), + conversions.Select(MapConversionProjectToIdentifiers).ToArray(), + transfers.Select(MapTransferProjectToIdentifiers).ToArray(), + formAMats.Select(MapFormAMatProjectToIdentifiers).ToArray()); return results; } } \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Helpers/IdentifierMapping.cs b/Dfe.Identifiers.Domain/Helpers/IdentifierMapping.cs index be761f3..6476107 100644 --- a/Dfe.Identifiers.Domain/Helpers/IdentifierMapping.cs +++ b/Dfe.Identifiers.Domain/Helpers/IdentifierMapping.cs @@ -15,4 +15,20 @@ public static TrustIdentifiers MapTrustToIdentifiers(Trust trust) { return new TrustIdentifiers(UID: trust.GroupUID, UKPRN: trust.UKPRN, TrustReference: trust.GroupID); } + + public static ConversionProjectIdentifiers MapConversionProjectToIdentifiers(ConversionProject project) + { + return new ConversionProjectIdentifiers(ApplicationReferenceNumber: project.ApplicationReferenceNumber, + TrustReferenceNumber: project.TrustReferenceNumber, SponsorReferenceNumber: project.SponsorReferenceNumber); + } + + public static TransferProjectIdentifiers MapTransferProjectToIdentifiers(TransferProject project) + { + return new TransferProjectIdentifiers(ProjectReference: project.ProjectReference); + } + + public static FormAMatProjectIdentifiers MapFormAMatProjectToIdentifiers(FormAMatProject project) + { + return new FormAMatProjectIdentifiers(ReferenceNumber: project.ReferenceNumber, ApplicationReference: project.ApplicationReference); + } } \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Identifiers/ConversionProjectIdentifiers.cs b/Dfe.Identifiers.Domain/Identifiers/ConversionProjectIdentifiers.cs new file mode 100644 index 0000000..9efc2cf --- /dev/null +++ b/Dfe.Identifiers.Domain/Identifiers/ConversionProjectIdentifiers.cs @@ -0,0 +1,6 @@ +namespace Dfe.Identifiers.Domain.Identifiers; + +public record ConversionProjectIdentifiers( + string? ApplicationReferenceNumber, + string? TrustReferenceNumber, + string? SponsorReferenceNumber); \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Identifiers/FormAMatProjectIdentifiers.cs b/Dfe.Identifiers.Domain/Identifiers/FormAMatProjectIdentifiers.cs new file mode 100644 index 0000000..59604c7 --- /dev/null +++ b/Dfe.Identifiers.Domain/Identifiers/FormAMatProjectIdentifiers.cs @@ -0,0 +1,3 @@ +namespace Dfe.Identifiers.Domain.Identifiers; + +public record FormAMatProjectIdentifiers(string? ReferenceNumber, string? ApplicationReference); \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Identifiers/IdentifiersCollection.cs b/Dfe.Identifiers.Domain/Identifiers/IdentifiersCollection.cs index bf5cf15..5123b8f 100644 --- a/Dfe.Identifiers.Domain/Identifiers/IdentifiersCollection.cs +++ b/Dfe.Identifiers.Domain/Identifiers/IdentifiersCollection.cs @@ -1,3 +1,8 @@ namespace Dfe.Identifiers.Domain.Identifiers; -public record IdentifiersCollection(TrustIdentifiers[] Trusts, EstablishmentIdentifiers[] Establishments); \ No newline at end of file +public record IdentifiersCollection( + TrustIdentifiers[] Trusts, + EstablishmentIdentifiers[] Establishments, + ConversionProjectIdentifiers[] ConversionProjects, + TransferProjectIdentifiers[] TransferProjects, + FormAMatProjectIdentifiers[] FormAMatProjects); \ No newline at end of file diff --git a/Dfe.Identifiers.Domain/Identifiers/TransferProjectIdentifiers.cs b/Dfe.Identifiers.Domain/Identifiers/TransferProjectIdentifiers.cs new file mode 100644 index 0000000..74bafa3 --- /dev/null +++ b/Dfe.Identifiers.Domain/Identifiers/TransferProjectIdentifiers.cs @@ -0,0 +1,3 @@ +namespace Dfe.Identifiers.Domain.Identifiers; + +public record TransferProjectIdentifiers( string? ProjectReference ); \ No newline at end of file From 64a29afeb22c043cf51a56b8af8cb1125ba93b82 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:45:04 +0100 Subject: [PATCH 05/13] Remove unused fields from mstr context --- Dfe.Identifiers.Domain/Models/Establishment.cs | 5 ----- Dfe.Identifiers.Domain/Models/Trust.cs | 2 -- Dfe.Identifiers.Infrastructure/Context/MstrContext.cs | 4 ---- 3 files changed, 11 deletions(-) diff --git a/Dfe.Identifiers.Domain/Models/Establishment.cs b/Dfe.Identifiers.Domain/Models/Establishment.cs index c3d42a7..8d90b53 100644 --- a/Dfe.Identifiers.Domain/Models/Establishment.cs +++ b/Dfe.Identifiers.Domain/Models/Establishment.cs @@ -16,12 +16,7 @@ public class Establishment public long? RegionId { get; set; } public int? EstablishmentNumber { get; set; } public string? EstablishmentName { get; set; } - - public DateTime? Modified { get; set; } - public string? ModifiedBy { get; set; } - public string? UKPRN { get; set; } - public int? URNAtCurrentFullInspection { get; set; } public int? URNAtPreviousFullInspection { get; set; } public int? URNAtSection8Inspection { get; set; } diff --git a/Dfe.Identifiers.Domain/Models/Trust.cs b/Dfe.Identifiers.Domain/Models/Trust.cs index 9cbc9d0..5c54e2c 100644 --- a/Dfe.Identifiers.Domain/Models/Trust.cs +++ b/Dfe.Identifiers.Domain/Models/Trust.cs @@ -14,8 +14,6 @@ public class Trust public string? Name { get; set; } public string? CompaniesHouseNumber { get; set; } public string? TrustStatus { get; set; } - public DateTime? Modified { get; set; } - public string? ModifiedBy { get; set; } public string? UKPRN { get; set; } public string? UPIN { get; set; } public TrustType? TrustType { get; set; } diff --git a/Dfe.Identifiers.Infrastructure/Context/MstrContext.cs b/Dfe.Identifiers.Infrastructure/Context/MstrContext.cs index f659fc6..886060f 100644 --- a/Dfe.Identifiers.Infrastructure/Context/MstrContext.cs +++ b/Dfe.Identifiers.Infrastructure/Context/MstrContext.cs @@ -63,8 +63,6 @@ private void ConfigureEstablishment(EntityTypeBuilder establishme 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.Modified).HasColumnName("Modified"); - establishmentConfiguration.Property(e => e.ModifiedBy).HasColumnName("Modified By"); establishmentConfiguration.Property(e => e.PK_CDM_ID).HasColumnName("PK_CDM_ID"); establishmentConfiguration.Property(e => e.PK_GIAS_URN).HasColumnName("PK_GIAS_URN").HasConversion(); establishmentConfiguration.Property(e => e.UKPRN).HasColumnName("UKPRN"); @@ -103,8 +101,6 @@ void ConfigureTrust(EntityTypeBuilder trustConfiguration) trustConfiguration.Property(e => e.Name).HasColumnName("Name").IsRequired(); trustConfiguration.Property(e => e.CompaniesHouseNumber).HasColumnName("Companies House Number"); trustConfiguration.Property(e => e.TrustStatus).HasColumnName("Trust Status"); - trustConfiguration.Property(e => e.Modified).HasColumnName("Modified"); - trustConfiguration.Property(e => e.ModifiedBy).HasColumnName("Modified By"); trustConfiguration.Property(e => e.UKPRN).HasColumnName("UKPRN"); trustConfiguration.Property(e => e.UPIN).HasColumnName("UPIN"); From 7a6c7fed084d0b34da0c958d5216c19cb875f974 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:45:32 +0100 Subject: [PATCH 06/13] Add academisation migrations for tests --- .../20240422140157_InitialCreate.Designer.cs | 124 ++++++++++++++++++ .../20240422140157_InitialCreate.cs | 95 ++++++++++++++ .../AcademisationContextModelSnapshot.cs | 121 +++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs create mode 100644 Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs create mode 100644 Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs new file mode 100644 index 0000000..c545b4b --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs @@ -0,0 +1,124 @@ +// +using System; +using Dfe.Identifiers.Infrastructure.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Dfe.Identifiers.Infrastructure.Migrations.Academisation +{ + [DbContext(typeof(AcademisationContext))] + [Migration("20240422140157_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApplicationReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("ApplicationReferenceNumber"); + + b.Property("FormAMatProjectId") + .HasColumnType("bigint") + .HasColumnName("FormAMatProjectId"); + + b.Property("SchoolName") + .HasColumnType("nvarchar(max)") + .HasColumnName("SchoolName"); + + b.Property("SponsorReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("SponsorReferenceNumber"); + + b.Property("TrustReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("TrustReferenceNumber"); + + b.Property("URN") + .HasColumnType("bigint") + .HasColumnName("Urn"); + + b.HasKey("Id"); + + b.HasIndex("FormAMatProjectId"); + + b.ToTable("Project", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.FormAMatProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApplicationReference") + .HasColumnType("nvarchar(max)") + .HasColumnName("ApplicationReference"); + + b.Property("ReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("ReferenceNumber"); + + b.HasKey("Id"); + + b.ToTable("FormAMatProject", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.TransferProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("OutgoingTrustUKPRN") + .HasColumnType("bigint") + .HasColumnName("OutgoingTrustUkprn"); + + b.Property("ProjectReference") + .HasColumnType("nvarchar(max)") + .HasColumnName("ProjectReference"); + + b.Property("URN") + .HasColumnType("bigint") + .HasColumnName("Urn"); + + b.HasKey("Id"); + + b.ToTable("TransferProject", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => + { + b.HasOne("Dfe.Identifiers.Domain.Models.FormAMatProject", "FormAMatProject") + .WithMany() + .HasForeignKey("FormAMatProjectId"); + + b.Navigation("FormAMatProject"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs new file mode 100644 index 0000000..8baa4bc --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs @@ -0,0 +1,95 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Dfe.Identifiers.Infrastructure.Migrations.Academisation +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "academisation"); + + migrationBuilder.CreateTable( + name: "FormAMatProject", + schema: "academisation", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ApplicationReference = table.Column(type: "nvarchar(max)", nullable: true), + ReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_FormAMatProject", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TransferProject", + schema: "academisation", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Urn = table.Column(type: "bigint", nullable: false), + ProjectReference = table.Column(type: "nvarchar(max)", nullable: true), + OutgoingTrustUkprn = table.Column(type: "bigint", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TransferProject", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Project", + schema: "academisation", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Urn = table.Column(type: "bigint", nullable: false), + SchoolName = table.Column(type: "nvarchar(max)", nullable: true), + ApplicationReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), + TrustReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), + SponsorReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), + FormAMatProjectId = table.Column(type: "bigint", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Project", x => x.Id); + table.ForeignKey( + name: "FK_Project_FormAMatProject_FormAMatProjectId", + column: x => x.FormAMatProjectId, + principalSchema: "academisation", + principalTable: "FormAMatProject", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Project_FormAMatProjectId", + schema: "academisation", + table: "Project", + column: "FormAMatProjectId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Project", + schema: "academisation"); + + migrationBuilder.DropTable( + name: "TransferProject", + schema: "academisation"); + + migrationBuilder.DropTable( + name: "FormAMatProject", + schema: "academisation"); + } + } +} diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs new file mode 100644 index 0000000..93464a5 --- /dev/null +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs @@ -0,0 +1,121 @@ +// +using System; +using Dfe.Identifiers.Infrastructure.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Dfe.Identifiers.Infrastructure.Migrations.Academisation +{ + [DbContext(typeof(AcademisationContext))] + partial class AcademisationContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApplicationReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("ApplicationReferenceNumber"); + + b.Property("FormAMatProjectId") + .HasColumnType("bigint") + .HasColumnName("FormAMatProjectId"); + + b.Property("SchoolName") + .HasColumnType("nvarchar(max)") + .HasColumnName("SchoolName"); + + b.Property("SponsorReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("SponsorReferenceNumber"); + + b.Property("TrustReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("TrustReferenceNumber"); + + b.Property("URN") + .HasColumnType("bigint") + .HasColumnName("Urn"); + + b.HasKey("Id"); + + b.HasIndex("FormAMatProjectId"); + + b.ToTable("Project", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.FormAMatProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApplicationReference") + .HasColumnType("nvarchar(max)") + .HasColumnName("ApplicationReference"); + + b.Property("ReferenceNumber") + .HasColumnType("nvarchar(max)") + .HasColumnName("ReferenceNumber"); + + b.HasKey("Id"); + + b.ToTable("FormAMatProject", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.TransferProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("OutgoingTrustUKPRN") + .HasColumnType("bigint") + .HasColumnName("OutgoingTrustUkprn"); + + b.Property("ProjectReference") + .HasColumnType("nvarchar(max)") + .HasColumnName("ProjectReference"); + + b.Property("URN") + .HasColumnType("bigint") + .HasColumnName("Urn"); + + b.HasKey("Id"); + + b.ToTable("TransferProject", "academisation"); + }); + + modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => + { + b.HasOne("Dfe.Identifiers.Domain.Models.FormAMatProject", "FormAMatProject") + .WithMany() + .HasForeignKey("FormAMatProjectId"); + + b.Navigation("FormAMatProject"); + }); +#pragma warning restore 612, 618 + } + } +} From 21f9f2a63912aa0f606b1d1c5b699f8244a48428 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:49:25 +0100 Subject: [PATCH 07/13] Update test database model builder --- .../DatabaseModelBuilder.cs | 39 --- .../Helpers/DatabaseModelBuilder.cs | 262 ++++++++++++++++++ Dfe.Identifiers.Api.Test/Helpers/IdTypes.cs | 28 ++ .../Helpers/TrustEstablishmentDataSet.cs | 8 + 4 files changed, 298 insertions(+), 39 deletions(-) delete mode 100644 Dfe.Identifiers.Api.Test/DatabaseModelBuilder.cs create mode 100644 Dfe.Identifiers.Api.Test/Helpers/DatabaseModelBuilder.cs create mode 100644 Dfe.Identifiers.Api.Test/Helpers/IdTypes.cs create mode 100644 Dfe.Identifiers.Api.Test/Helpers/TrustEstablishmentDataSet.cs diff --git a/Dfe.Identifiers.Api.Test/DatabaseModelBuilder.cs b/Dfe.Identifiers.Api.Test/DatabaseModelBuilder.cs deleted file mode 100644 index 3084772..0000000 --- a/Dfe.Identifiers.Api.Test/DatabaseModelBuilder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using AutoFixture; -using Dfe.Identifiers.Domain.Models; - -namespace Dfe.Identifiers.Api.Test -{ - public static class DatabaseModelBuilder - { - private static readonly Fixture _fixture = new(); - - public static Trust BuildTrust() - { - var result = _fixture.Create(); - result.SK = null; - result.TrustStatus = "Open"; - result.TrustTypeId = 30; - result.TrustType = null; - result.TrustStatusId = null; - result.RegionId = null; - result.TrustBandingId = null; - result.RID = result.RID.Substring(0, 10); - - return result; - } - - public static Establishment BuildEstablishment() - { - var result = _fixture.Create(); - result.SK = null; - result.LocalAuthority = null; - result.EstablishmentType = null; - result.PK_GIAS_URN = _fixture.Create().ToString(); - // Only 224 or 228 are valid in this subset of test data used (see mstr context) - result.EstablishmentTypeId = 224; - result.LocalAuthorityId = 1; - - return result; - } - } -} \ No newline at end of file diff --git a/Dfe.Identifiers.Api.Test/Helpers/DatabaseModelBuilder.cs b/Dfe.Identifiers.Api.Test/Helpers/DatabaseModelBuilder.cs new file mode 100644 index 0000000..5830d77 --- /dev/null +++ b/Dfe.Identifiers.Api.Test/Helpers/DatabaseModelBuilder.cs @@ -0,0 +1,262 @@ +using AutoFixture; +using Dfe.Identifiers.Api.Test.Constants; +using Dfe.Identifiers.Api.Test.Extensions; +using Dfe.Identifiers.Domain.Models; +using Dfe.Identifiers.Infrastructure.Context; + +namespace Dfe.Identifiers.Api.Test.Helpers; + +public static class DatabaseModelBuilder +{ + private static readonly Fixture _fixture = new(); + + public static Trust BuildTrust() + { + var result = _fixture.Create(); + result.SK = null; + result.TrustStatus = "Open"; + result.TrustTypeId = 30; + result.TrustType = null; + result.TrustStatusId = null; + result.RegionId = null; + result.TrustBandingId = null; + result.RID = result.RID.Substring(0, 10); + + return result; + } + + public static Establishment BuildEstablishment() + { + var result = _fixture.Create(); + result.SK = null; + result.LocalAuthority = null; + result.EstablishmentType = null; + result.PK_GIAS_URN = _fixture.Create().ToString(); + // Only 224 or 228 are valid in this subset of test data used (see mstr context) + result.EstablishmentTypeId = 224; + result.LocalAuthorityId = 1; + + return result; + } + + public static ConversionProject BuildConversionProject() + { + var result = _fixture.Create(); + result.Id = null; + result.FormAMatProjectId = null; + result.FormAMatProject = null; + return result; + } + + public static TransferProject BuildTransferProject() + { + var result = _fixture.Create(); + result.Id = null; + return result; + } + + public static FormAMatProject BuildFormAMatProject() + { + var result = _fixture.Create(); + result.Id = null; + return result; + } + + public static async Task> BuildTrustSet(MstrContext context) + { + var trusts = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var trust = BuildTrust(); + trusts.Add(trust); + } + + context.Trusts.AddRange(trusts); + await context.SaveChangesAsync(); + return trusts; + } + + public static async Task> CreateDuplicateTrustSet(MstrContext context, TrustIdTypes trustId) + { + var trusts = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var trust = BuildTrust(); + switch (trustId) + { + case TrustIdTypes.GroupID: + trust.GroupID = "GroupID"; + break; + case TrustIdTypes.UKPRN: + trust.UKPRN = "UKPRN"; + break; + case TrustIdTypes.GroupUID: + trust.GroupUID = "GroupUID"; + break; + } + + trusts.Add(trust); + } + + context.Trusts.AddRange(trusts); + await context.SaveChangesAsync(); + return trusts; + } + + public static async Task> CreateTrustSetWithEmptyData(MstrContext context, + TrustIdTypes trustIdTypeToKeep) + { + var trusts = await BuildTrustSet(context); + foreach (var trust in trusts) + { + switch (trustIdTypeToKeep) + { + case TrustIdTypes.GroupID: + trust.UKPRN = null; + break; + case TrustIdTypes.UKPRN: + trust.GroupID = null; + break; + case TrustIdTypes.GroupUID: + trust.GroupID = null; + trust.UKPRN = null; + break; + default: + throw new ArgumentOutOfRangeException(nameof(trustIdTypeToKeep), trustIdTypeToKeep, null); + } + } + + context.Trusts.UpdateRange(trusts); + await context.SaveChangesAsync(); + return trusts; + } + + public static TrustEstablishmentDataSet CreateEstablishmentSet(MstrContext context) + { + var trust = BuildTrust(); + context.Add(trust); + context.SaveChanges(); + + var establishments = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var localAuthority = context.LocalAuthorities.First(la => la.SK % 3 == idx); + var establishment = BuildEstablishment().LinkLocalAuthorityToEstablishment(localAuthority); + + context.Establishments.Add(establishment); + + establishments.Add(establishment); + } + + context.SaveChanges(); + + var trustToEstablishmentLinks = + LinkTrustToEstablishments(trust, establishments); + + context.EducationEstablishmentTrusts.AddRange(trustToEstablishmentLinks); + + context.SaveChanges(); + + var result = new TrustEstablishmentDataSet(Trust: trust, Establishments: establishments); + + return result; + } + + public static TrustEstablishmentDataSet CreateSameUKPRNDataSet(MstrContext context) + { + var trust = BuildTrust(); + trust.UKPRN = IdentifierConstants.MixedSameUkprn; + context.Add(trust); + context.SaveChanges(); + + //Establishment + var establishments = new List(); + + var establishment = BuildEstablishment().LinkLocalAuthorityToEstablishment(context.LocalAuthorities.First()); + establishment.UKPRN = IdentifierConstants.MixedSameUkprn; + + context.Establishments.Add(establishment); + + establishments.Add(establishment); + + context.SaveChanges(); + + var trustToEstablishmentLinks = + LinkTrustToEstablishments(trust, establishments); + + context.EducationEstablishmentTrusts.AddRange(trustToEstablishmentLinks); + + context.SaveChanges(); + + var result = new TrustEstablishmentDataSet(Trust: trust, Establishments: establishments); + + return result; + } + + private static List LinkTrustToEstablishments(Trust trust, + List establishments) + { + var result = new List(); + + establishments.ForEach(establishment => + { + var educationEstablishmentTrust = new EducationEstablishmentTrust() + { + TrustId = (int)trust.SK, + EducationEstablishmentId = (int)establishment.SK + }; + + result.Add(educationEstablishmentTrust); + }); + + return result; + } + + public static async Task> CreateConversionProjectsSet(AcademisationContext context) + { + var projects = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var project = BuildConversionProject(); + projects.Add(project); + } + + context.ConversionProjects.AddRange(projects); + await context.SaveChangesAsync(); + return projects; + } + + public static async Task> CreateTransferProjectsSet(AcademisationContext context) + { + var projects = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var project = BuildTransferProject(); + projects.Add(project); + } + + context.TransferProjects.AddRange(projects); + await context.SaveChangesAsync(); + return projects; + } + + public static async Task> CreateFormAMatProjectsSet(AcademisationContext context) + { + var projects = new List(); + + for (var idx = 0; idx < 3; idx++) + { + var project = BuildFormAMatProject(); + projects.Add(project); + } + + context.FormAMatProjects.AddRange(projects); + await context.SaveChangesAsync(); + return projects; + } +} \ No newline at end of file diff --git a/Dfe.Identifiers.Api.Test/Helpers/IdTypes.cs b/Dfe.Identifiers.Api.Test/Helpers/IdTypes.cs new file mode 100644 index 0000000..2b8c4b2 --- /dev/null +++ b/Dfe.Identifiers.Api.Test/Helpers/IdTypes.cs @@ -0,0 +1,28 @@ +namespace Dfe.Identifiers.Api.Test.Helpers; + +public enum TrustIdTypes +{ + GroupID, + UKPRN, + GroupUID +} + +public enum EstablishmentsIdTypes +{ + URN, + UKPRN, + LAESTAB +} + +public enum ConversionProjectIdTypes +{ + ApplicationReferenceNumber, + TrustReferenceNumber, + SponsorReferenceNumber +} + +public enum FormAMatProjectIdTypes +{ + ApplicationReference, + ReferenceNumber +} \ No newline at end of file diff --git a/Dfe.Identifiers.Api.Test/Helpers/TrustEstablishmentDataSet.cs b/Dfe.Identifiers.Api.Test/Helpers/TrustEstablishmentDataSet.cs new file mode 100644 index 0000000..c8679d0 --- /dev/null +++ b/Dfe.Identifiers.Api.Test/Helpers/TrustEstablishmentDataSet.cs @@ -0,0 +1,8 @@ +using Dfe.Identifiers.Domain.Models; + +namespace Dfe.Identifiers.Api.Test.Helpers; + +public record TrustEstablishmentDataSet( + Trust Trust, + List Establishments +); \ No newline at end of file From 132ae0424eedb8d1d1731ea0a5f2ae099079fe6e Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:50:35 +0100 Subject: [PATCH 08/13] Add Academisation context to api test fixture --- Dfe.Identifiers.Api.Test/ApiTestFixture.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs index 82ab873..636e895 100644 --- a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs +++ b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs @@ -7,7 +7,9 @@ namespace Dfe.Identifiers.Api.Test public class ApiTestFixture : IDisposable { private const string connectionStringKey = "ConnectionStrings:DefaultConnection"; - private DbContextOptions _dbContextOptions { get; init; } + private DbContextOptions _mstrContextOptions { get; init; } + + private DbContextOptions _academisationContextOptions { get; init; } public ApiTestFixture() { @@ -17,17 +19,24 @@ public ApiTestFixture() .AddUserSecrets(); Configuration = builder.Build(); - _dbContextOptions = new DbContextOptionsBuilder() + _mstrContextOptions = new DbContextOptionsBuilder() .UseSqlServer(Configuration[connectionStringKey]) .Options; - using var context = GetMstrContext(); - context.Database.EnsureDeleted(); - context.Database.Migrate(); + _academisationContextOptions = new DbContextOptionsBuilder() + .UseSqlServer(Configuration[connectionStringKey]) + .Options; + using var mstrContext = GetMstrContext(); + using var academisationContext = GetAcademisationContext(); + mstrContext.Database.EnsureDeleted(); + academisationContext.Database.EnsureDeleted(); + mstrContext.Database.Migrate(); + academisationContext.Database.Migrate(); } private IConfigurationRoot Configuration { get; init; } - public MstrContext GetMstrContext() => new(_dbContextOptions); + public MstrContext GetMstrContext() => new(_mstrContextOptions); + public AcademisationContext GetAcademisationContext() => new(_academisationContextOptions); public void Dispose() { From d5bf9667ab2206e28bace3fcb4616485ff2d7635 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:50:56 +0100 Subject: [PATCH 09/13] Add projects tests --- .../Api/IdentifiersEndpointTests.cs | 262 +++++++----------- .../Constants/IdentifierConstants.cs | 6 + .../Extensions/EstablishmentExtensions.cs | 13 + 3 files changed, 114 insertions(+), 167 deletions(-) create mode 100644 Dfe.Identifiers.Api.Test/Constants/IdentifierConstants.cs create mode 100644 Dfe.Identifiers.Api.Test/Extensions/EstablishmentExtensions.cs diff --git a/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs b/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs index 4e201c3..9f87945 100644 --- a/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs +++ b/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs @@ -1,6 +1,8 @@ using System.Net; using Dfe.Identifiers.Api.Controllers; +using Dfe.Identifiers.Api.Test.Constants; using Dfe.Identifiers.Api.Test.Extensions; +using Dfe.Identifiers.Api.Test.Helpers; using Dfe.Identifiers.Application; using Dfe.Identifiers.Domain.Identifiers; using Dfe.Identifiers.Domain.Models; @@ -18,15 +20,14 @@ public class IdentifiersEndpointTests : IClassFixture private ApiTestFixture Fixture { get; } private IdentifiersController Sut { get; } - private const string MixedSameUkprn = "SameUKPRN"; - public IdentifiersEndpointTests(ApiTestFixture fixture) { Fixture = fixture; var logger = new Mock>(); - var context = fixture.GetMstrContext(); - Sut = new IdentifiersController(logger.Object, new IdentifiersQuery(new TrustRepository(context), - new EstablishmentRepository(context))); + var mstrContext = fixture.GetMstrContext(); + var academistationContext = fixture.GetAcademisationContext(); + Sut = new IdentifiersController(logger.Object, new IdentifiersQuery(new TrustRepository(mstrContext), + new EstablishmentRepository(mstrContext), new ProjectsRepository(academistationContext))); } // TRUSTS @@ -39,7 +40,7 @@ public async Task Get_TrustIdentifiers_AndTrustExists_Returns_Ok(TrustIdTypes tr { using var context = Fixture.GetMstrContext(); - var trustData = await BuildTrustSet(context); + var trustData = await DatabaseModelBuilder.BuildTrustSet(context); var selectedTrust = trustData.First(); @@ -73,7 +74,7 @@ public async Task Get_TrustIdentifiers_AndDuplicateTrustsExists_Returns_Ok(Trust { using var context = Fixture.GetMstrContext(); - var trustData = await BuildDuplicateTrustSet(context, trustIdType); + var trustData = await DatabaseModelBuilder.CreateDuplicateTrustSet(context, trustIdType); var identifier = trustIdType switch { @@ -107,7 +108,7 @@ public async Task Get_TrustIdentifiers_AndNoOtherIdentifiersExist_Returns_Ok(Tru { using var context = Fixture.GetMstrContext(); - var trustData = await BuildTrustSetWithEmptyData(context, trustIdType); + var trustData = await DatabaseModelBuilder.CreateTrustSetWithEmptyData(context, trustIdType); var selectedTrust = trustData.First(); var identifier = trustIdType switch { @@ -136,7 +137,7 @@ public async Task Get_TrustIdentifiers_AndTrustDoesNotExist_Returns_EmptyList() { using var context = Fixture.GetMstrContext(); - await BuildTrustSet(context); + await DatabaseModelBuilder.BuildTrustSet(context); var cancellationToken = new CancellationToken(); var response = await Sut.GetIdentifiers("NoTrustExists", cancellationToken); @@ -161,7 +162,7 @@ public async Task Get_EstablishmentIdentifiers_AndEstablishmentExists_Returns_Ok { using var context = Fixture.GetMstrContext(); - var trustData = CreateEstablishmentSet(context); + var trustData = DatabaseModelBuilder.CreateEstablishmentSet(context); var selectedEstablishment = trustData.Establishments.First(); var identifier = idType switch @@ -193,13 +194,13 @@ public async Task Get_Identifiers_AndEstablishmentAndTrustExists_Returns_Ok() { using var context = Fixture.GetMstrContext(); - var mixedData = CreateSameUKPRNDataSet(context); + var mixedData = DatabaseModelBuilder.CreateSameUKPRNDataSet(context); var selectedEstablishment = mixedData.Establishments.First(); var selectedTrust = mixedData.Trust; var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(MixedSameUkprn, cancellationToken); + var response = await Sut.GetIdentifiers(IdentifierConstants.MixedSameUkprn, cancellationToken); response.Result.Should().NotBeNull(); response.Result.Should().BeOfType(typeof(OkObjectResult)); @@ -215,166 +216,94 @@ public async Task Get_Identifiers_AndEstablishmentAndTrustExists_Returns_Ok() AssertTrustIdentifierResponse(trusts.First(), selectedTrust); } - private static async Task> BuildTrustSet(MstrContext context) + // PROJECTS + + [Theory] + [InlineData(ConversionProjectIdTypes.ApplicationReferenceNumber)] + [InlineData(ConversionProjectIdTypes.SponsorReferenceNumber)] + [InlineData(ConversionProjectIdTypes.TrustReferenceNumber)] + public async Task Get_ConversionProjectIdentifier_AndProjectExistsExists_Returns_Ok(ConversionProjectIdTypes idType) { - var trusts = new List(); + using var context = Fixture.GetAcademisationContext(); - for (var idx = 0; idx < 3; idx++) - { - var trust = DatabaseModelBuilder.BuildTrust(); - trusts.Add(trust); - } + var projectData = await DatabaseModelBuilder.CreateConversionProjectsSet(context); - context.Trusts.AddRange(trusts); - await context.SaveChangesAsync(); - return trusts; - } + var selectedProject = projectData.First(); + var identifier = idType switch + { + ConversionProjectIdTypes.ApplicationReferenceNumber => selectedProject.ApplicationReferenceNumber, + ConversionProjectIdTypes.SponsorReferenceNumber => selectedProject.SponsorReferenceNumber, + ConversionProjectIdTypes.TrustReferenceNumber => selectedProject.TrustReferenceNumber, + _ => throw new ArgumentOutOfRangeException(nameof(idType), idType, null) + }; - private static async Task> BuildDuplicateTrustSet(MstrContext context, TrustIdTypes trustId) - { - var trusts = new List(); + var cancellationToken = new CancellationToken(); + var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - for (var idx = 0; idx < 3; idx++) - { - var trust = DatabaseModelBuilder.BuildTrust(); - switch (trustId) - { - case TrustIdTypes.GroupID: - trust.GroupID = "GroupID"; - break; - case TrustIdTypes.UKPRN: - trust.UKPRN = "UKPRN"; - break; - case TrustIdTypes.GroupUID: - trust.GroupUID = "GroupUID"; - break; - } - - trusts.Add(trust); - } - - context.Trusts.AddRange(trusts); - await context.SaveChangesAsync(); - return trusts; - } + response.Result.Should().NotBeNull(); + response.Result.Should().BeOfType(typeof(OkObjectResult)); + response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - private static async Task> BuildTrustSetWithEmptyData(MstrContext context, - TrustIdTypes trustIdTypeToKeep) - { - var trusts = await BuildTrustSet(context); - foreach (var trust in trusts) - { - switch (trustIdTypeToKeep) - { - case TrustIdTypes.GroupID: - trust.UKPRN = null; - break; - case TrustIdTypes.UKPRN: - trust.GroupID = null; - break; - case TrustIdTypes.GroupUID: - trust.GroupID = null; - trust.UKPRN = null; - break; - default: - throw new ArgumentOutOfRangeException(nameof(trustIdTypeToKeep), trustIdTypeToKeep, null); - } - } - - context.Trusts.UpdateRange(trusts); - await context.SaveChangesAsync(); - return trusts; + var content = response.GetIdentifiers(); + content.Should().NotBeNull(); + var conversionProjects = content!.ConversionProjects; + conversionProjects.Length.Should().Be(1); + AssertConversionProjectIdentifierResponse(conversionProjects.First(), selectedProject); } - - private static TrustDataSet CreateEstablishmentSet(MstrContext context) + + [Fact] + public async Task Get_TransferProjectIdentifier_AndProjectExistsExists_Returns_Ok() { - var trust = DatabaseModelBuilder.BuildTrust(); - context.Add(trust); - context.SaveChanges(); - - var establishments = new List(); - - for (var idx = 0; idx < 3; idx++) - { - var localAuthority = context.LocalAuthorities.First(la => la.SK % 3 == idx); - var establishmentDataSet = CreateEstablishment(localAuthority); - - context.Establishments.Add(establishmentDataSet); - - establishments.Add(establishmentDataSet); - } + using var context = Fixture.GetAcademisationContext(); - context.SaveChanges(); + var projectData = await DatabaseModelBuilder.CreateTransferProjectsSet(context); - var trustToEstablishmentLinks = - LinkTrustToEstablishments(trust, establishments); + var selectedProject = projectData.First(); + var identifier = selectedProject.ProjectReference; - context.EducationEstablishmentTrusts.AddRange(trustToEstablishmentLinks); - - context.SaveChanges(); - - var result = new TrustDataSet(Trust: trust, Establishments: establishments); - - return result; - } - - private static List LinkTrustToEstablishments(Trust trust, - List establishments) - { - var result = new List(); - - establishments.ForEach(establishment => - { - var educationEstablishmentTrust = new EducationEstablishmentTrust() - { - TrustId = (int)trust.SK, - EducationEstablishmentId = (int)establishment.SK - }; + var cancellationToken = new CancellationToken(); + var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - result.Add(educationEstablishmentTrust); - }); + response.Result.Should().NotBeNull(); + response.Result.Should().BeOfType(typeof(OkObjectResult)); + response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - return result; + var content = response.GetIdentifiers(); + content.Should().NotBeNull(); + var transferProjects = content!.TransferProjects; + transferProjects.Length.Should().Be(1); + AssertTransferProjectIdentifierResponse(transferProjects.First(), selectedProject); } - - private static TrustDataSet CreateSameUKPRNDataSet(MstrContext context) + + [Theory] + [InlineData(FormAMatProjectIdTypes.ApplicationReference)] + [InlineData(FormAMatProjectIdTypes.ReferenceNumber)] + public async Task Get_FormAMatProjectIdentifier_AndProjectExistsExists_Returns_Ok(FormAMatProjectIdTypes idType) { - var trust = DatabaseModelBuilder.BuildTrust(); - trust.UKPRN = MixedSameUkprn; - context.Add(trust); - context.SaveChanges(); + using var context = Fixture.GetAcademisationContext(); - //Establishment - var establishments = new List(); + var projectData = await DatabaseModelBuilder.CreateFormAMatProjectsSet(context); - var establishment = CreateEstablishment(context.LocalAuthorities.First()); - establishment.UKPRN = MixedSameUkprn; - - context.Establishments.Add(establishment); - - establishments.Add(establishment); - - context.SaveChanges(); - - var trustToEstablishmentLinks = - LinkTrustToEstablishments(trust, establishments); - - context.EducationEstablishmentTrusts.AddRange(trustToEstablishmentLinks); - - context.SaveChanges(); - - var result = new TrustDataSet(Trust: trust, Establishments: establishments); - - return result; - } + var selectedProject = projectData.First(); + var identifier = idType switch + { + FormAMatProjectIdTypes.ApplicationReference => selectedProject.ApplicationReference, + FormAMatProjectIdTypes.ReferenceNumber => selectedProject.ReferenceNumber, + _ => throw new ArgumentOutOfRangeException(nameof(idType), idType, null) + }; - private static Establishment CreateEstablishment(LocalAuthority la) - { - var establishment = DatabaseModelBuilder.BuildEstablishment(); + var cancellationToken = new CancellationToken(); + var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - establishment.LocalAuthority = la; + response.Result.Should().NotBeNull(); + response.Result.Should().BeOfType(typeof(OkObjectResult)); + response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - return establishment; + var content = response.GetIdentifiers(); + content.Should().NotBeNull(); + var formAMatProjects = content!.FormAMatProjects; + formAMatProjects.Length.Should().Be(1); + AssertFormAMatProjectIdentifierResponse(formAMatProjects.First(), selectedProject); } private static void AssertTrustIdentifierResponse(TrustIdentifiers actual, Trust expected) @@ -390,23 +319,22 @@ private static void AssertEstablishmentsIdentifierResponse(EstablishmentIdentifi actual.UKPRN.Should().Be(expected.UKPRN); actual.LAESTAB.Should().Be($"{expected.LocalAuthority.Code}/{expected.EstablishmentNumber}"); } - - public enum TrustIdTypes + + private static void AssertConversionProjectIdentifierResponse(ConversionProjectIdentifiers actual, ConversionProject expected) { - GroupID, - UKPRN, - GroupUID + actual.ApplicationReferenceNumber.Should().Be(expected.ApplicationReferenceNumber); + actual.SponsorReferenceNumber.Should().Be(expected.SponsorReferenceNumber); + actual.TrustReferenceNumber.Should().Be(expected.TrustReferenceNumber); } - - public enum EstablishmentsIdTypes + + private static void AssertTransferProjectIdentifierResponse(TransferProjectIdentifiers actual, TransferProject expected) { - URN, - UKPRN, - LAESTAB + actual.ProjectReference.Should().Be(expected.ProjectReference); + } + + private static void AssertFormAMatProjectIdentifierResponse(FormAMatProjectIdentifiers actual, FormAMatProject expected) + { + actual.ApplicationReference.Should().Be(expected.ApplicationReference); + actual.ReferenceNumber.Should().Be(expected.ReferenceNumber); } - - private record TrustDataSet( - Trust Trust, - List Establishments - ); } \ No newline at end of file diff --git a/Dfe.Identifiers.Api.Test/Constants/IdentifierConstants.cs b/Dfe.Identifiers.Api.Test/Constants/IdentifierConstants.cs new file mode 100644 index 0000000..e878b91 --- /dev/null +++ b/Dfe.Identifiers.Api.Test/Constants/IdentifierConstants.cs @@ -0,0 +1,6 @@ +namespace Dfe.Identifiers.Api.Test.Constants; + +public static class IdentifierConstants +{ + public static readonly string MixedSameUkprn = "SameUKPRN"; +} \ No newline at end of file diff --git a/Dfe.Identifiers.Api.Test/Extensions/EstablishmentExtensions.cs b/Dfe.Identifiers.Api.Test/Extensions/EstablishmentExtensions.cs new file mode 100644 index 0000000..2d76850 --- /dev/null +++ b/Dfe.Identifiers.Api.Test/Extensions/EstablishmentExtensions.cs @@ -0,0 +1,13 @@ +using Dfe.Identifiers.Domain.Models; + +namespace Dfe.Identifiers.Api.Test.Extensions; + +public static class EstablishmentExtensions +{ + public static Establishment LinkLocalAuthorityToEstablishment(this Establishment establishment, + LocalAuthority localAuthority) + { + establishment.LocalAuthority = localAuthority; + return establishment; + } +} \ No newline at end of file From 5f1968eff9bbf2bdffb7e3aebbd8b9481a5f7e05 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 10:52:00 +0100 Subject: [PATCH 10/13] Add project and academisation dependency injection --- Dfe.Identifiers.Api/Startup.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dfe.Identifiers.Api/Startup.cs b/Dfe.Identifiers.Api/Startup.cs index befc6c7..f9e718d 100644 --- a/Dfe.Identifiers.Api/Startup.cs +++ b/Dfe.Identifiers.Api/Startup.cs @@ -39,7 +39,10 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddDbContext(options => - options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); + options.UseSqlServer(configuration.GetConnectionString("MstrConnection") ?? configuration.GetConnectionString("DefaultConnection"))); + services.AddDbContext(options => + options.UseSqlServer(configuration.GetConnectionString("AcademisationConnection") ?? configuration.GetConnectionString("DefaultConnection"))); } } \ No newline at end of file From 3a0d1317300271a39cad7f4054fa82bd97ebb149 Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Tue, 23 Apr 2024 15:31:27 +0100 Subject: [PATCH 11/13] Remake migration with updated field types --- ... 20240423142452_InitialCreate.Designer.cs} | 32 +++++++++---------- ...ate.cs => 20240423142452_InitialCreate.cs} | 12 +++---- .../AcademisationContextModelSnapshot.cs | 30 ++++++++--------- 3 files changed, 37 insertions(+), 37 deletions(-) rename Dfe.Identifiers.Infrastructure/Migrations/Academisation/{20240422140157_InitialCreate.Designer.cs => 20240423142452_InitialCreate.Designer.cs} (84%) rename Dfe.Identifiers.Infrastructure/Migrations/Academisation/{20240422140157_InitialCreate.cs => 20240423142452_InitialCreate.cs} (87%) diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.Designer.cs similarity index 84% rename from Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs rename to Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.Designer.cs index c545b4b..b344af6 100644 --- a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.Designer.cs +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ namespace Dfe.Identifiers.Infrastructure.Migrations.Academisation { [DbContext(typeof(AcademisationContext))] - [Migration("20240422140157_InitialCreate")] + [Migration("20240423142452_InitialCreate")] partial class InitialCreate { /// @@ -27,18 +27,18 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ApplicationReferenceNumber") .HasColumnType("nvarchar(max)") .HasColumnName("ApplicationReferenceNumber"); - b.Property("FormAMatProjectId") - .HasColumnType("bigint") + b.Property("FormAMatProjectId") + .HasColumnType("int") .HasColumnName("FormAMatProjectId"); b.Property("SchoolName") @@ -53,8 +53,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasColumnName("TrustReferenceNumber"); - b.Property("URN") - .HasColumnType("bigint") + b.Property("URN") + .HasColumnType("int") .HasColumnName("Urn"); b.HasKey("Id"); @@ -66,11 +66,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.FormAMatProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ApplicationReference") .HasColumnType("nvarchar(max)") @@ -87,11 +87,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.TransferProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("OutgoingTrustUKPRN") .HasColumnType("bigint") @@ -101,8 +101,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasColumnName("ProjectReference"); - b.Property("URN") - .HasColumnType("bigint") + b.Property("URN") + .HasColumnType("int") .HasColumnName("Urn"); b.HasKey("Id"); diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.cs similarity index 87% rename from Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs rename to Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.cs index 8baa4bc..eda31ba 100644 --- a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240422140157_InitialCreate.cs +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/20240423142452_InitialCreate.cs @@ -18,7 +18,7 @@ protected override void Up(MigrationBuilder migrationBuilder) schema: "academisation", columns: table => new { - Id = table.Column(type: "bigint", nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), ApplicationReference = table.Column(type: "nvarchar(max)", nullable: true), ReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true) @@ -33,9 +33,9 @@ protected override void Up(MigrationBuilder migrationBuilder) schema: "academisation", columns: table => new { - Id = table.Column(type: "bigint", nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Urn = table.Column(type: "bigint", nullable: false), + Urn = table.Column(type: "int", nullable: false), ProjectReference = table.Column(type: "nvarchar(max)", nullable: true), OutgoingTrustUkprn = table.Column(type: "bigint", nullable: true) }, @@ -49,14 +49,14 @@ protected override void Up(MigrationBuilder migrationBuilder) schema: "academisation", columns: table => new { - Id = table.Column(type: "bigint", nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Urn = table.Column(type: "bigint", nullable: false), + Urn = table.Column(type: "int", nullable: false), SchoolName = table.Column(type: "nvarchar(max)", nullable: true), ApplicationReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), TrustReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), SponsorReferenceNumber = table.Column(type: "nvarchar(max)", nullable: true), - FormAMatProjectId = table.Column(type: "bigint", nullable: true) + FormAMatProjectId = table.Column(type: "int", nullable: true) }, constraints: table => { diff --git a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs index 93464a5..2190930 100644 --- a/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs +++ b/Dfe.Identifiers.Infrastructure/Migrations/Academisation/AcademisationContextModelSnapshot.cs @@ -24,18 +24,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.ConversionProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ApplicationReferenceNumber") .HasColumnType("nvarchar(max)") .HasColumnName("ApplicationReferenceNumber"); - b.Property("FormAMatProjectId") - .HasColumnType("bigint") + b.Property("FormAMatProjectId") + .HasColumnType("int") .HasColumnName("FormAMatProjectId"); b.Property("SchoolName") @@ -50,8 +50,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasColumnName("TrustReferenceNumber"); - b.Property("URN") - .HasColumnType("bigint") + b.Property("URN") + .HasColumnType("int") .HasColumnName("Urn"); b.HasKey("Id"); @@ -63,11 +63,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.FormAMatProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ApplicationReference") .HasColumnType("nvarchar(max)") @@ -84,11 +84,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Dfe.Identifiers.Domain.Models.TransferProject", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint"); + .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("OutgoingTrustUKPRN") .HasColumnType("bigint") @@ -98,8 +98,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasColumnName("ProjectReference"); - b.Property("URN") - .HasColumnType("bigint") + b.Property("URN") + .HasColumnType("int") .HasColumnName("Urn"); b.HasKey("Id"); From e2d1bc6a6601c6e2c360ddc9f1dd5d1c41dacbba Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Fri, 26 Apr 2024 14:40:53 +0100 Subject: [PATCH 12/13] Switch api tests to running the web application properly using the web application factory --- .../Api/IdentifiersEndpointTests.cs | 103 ++++++------------ Dfe.Identifiers.Api.Test/ApiTestFixture.cs | 75 +++++++++---- 2 files changed, 86 insertions(+), 92 deletions(-) diff --git a/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs b/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs index 9f87945..c99d178 100644 --- a/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs +++ b/Dfe.Identifiers.Api.Test/Api/IdentifiersEndpointTests.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Http.Json; using Dfe.Identifiers.Api.Controllers; using Dfe.Identifiers.Api.Test.Constants; using Dfe.Identifiers.Api.Test.Extensions; @@ -18,16 +19,14 @@ namespace Dfe.Identifiers.Api.Test.Api; public class IdentifiersEndpointTests : IClassFixture { private ApiTestFixture Fixture { get; } - private IdentifiersController Sut { get; } + + private readonly HttpClient _client; + private const string ApiUrlPrefix = "/api/identifier"; public IdentifiersEndpointTests(ApiTestFixture fixture) { Fixture = fixture; - var logger = new Mock>(); - var mstrContext = fixture.GetMstrContext(); - var academistationContext = fixture.GetAcademisationContext(); - Sut = new IdentifiersController(logger.Object, new IdentifiersQuery(new TrustRepository(mstrContext), - new EstablishmentRepository(mstrContext), new ProjectsRepository(academistationContext))); + _client = fixture.Client; } // TRUSTS @@ -52,14 +51,10 @@ public async Task Get_TrustIdentifiers_AndTrustExists_Returns_Ok(TrustIdTypes tr _ => throw new ArgumentOutOfRangeException(nameof(trustIdType), trustIdType, null) }; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var trusts = content!.Trusts; trusts.Length.Should().Be(1); @@ -84,14 +79,10 @@ public async Task Get_TrustIdentifiers_AndDuplicateTrustsExists_Returns_Ok(Trust _ => throw new ArgumentOutOfRangeException(nameof(trustIdType), trustIdType, null) }; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var trusts = content!.Trusts; trusts.Length.Should().Be(3); @@ -117,15 +108,11 @@ public async Task Get_TrustIdentifiers_AndNoOtherIdentifiersExist_Returns_Ok(Tru TrustIdTypes.GroupUID => selectedTrust.GroupUID, _ => throw new ArgumentOutOfRangeException(nameof(trustIdType), trustIdType, null) }; + + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var trusts = content!.Trusts; trusts.Length.Should().Be(1); @@ -139,14 +126,10 @@ public async Task Get_TrustIdentifiers_AndTrustDoesNotExist_Returns_EmptyList() await DatabaseModelBuilder.BuildTrustSet(context); - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers("NoTrustExists", cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/noIdentifier"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var trusts = content!.Trusts; trusts.Length.Should().Be(0); @@ -174,14 +157,10 @@ public async Task Get_EstablishmentIdentifiers_AndEstablishmentExists_Returns_Ok _ => throw new ArgumentOutOfRangeException(nameof(idType), idType, null) }; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var establishments = content!.Establishments; establishments.Length.Should().Be(1); @@ -199,14 +178,10 @@ public async Task Get_Identifiers_AndEstablishmentAndTrustExists_Returns_Ok() var selectedEstablishment = mixedData.Establishments.First(); var selectedTrust = mixedData.Trust; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(IdentifierConstants.MixedSameUkprn, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{IdentifierConstants.MixedSameUkprn}"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var establishments = content!.Establishments; establishments.Length.Should().Be(1); @@ -237,14 +212,10 @@ public async Task Get_ConversionProjectIdentifier_AndProjectExistsExists_Returns _ => throw new ArgumentOutOfRangeException(nameof(idType), idType, null) }; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var conversionProjects = content!.ConversionProjects; conversionProjects.Length.Should().Be(1); @@ -261,14 +232,10 @@ public async Task Get_TransferProjectIdentifier_AndProjectExistsExists_Returns_O var selectedProject = projectData.First(); var identifier = selectedProject.ProjectReference; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); - - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var transferProjects = content!.TransferProjects; transferProjects.Length.Should().Be(1); @@ -292,14 +259,10 @@ public async Task Get_FormAMatProjectIdentifier_AndProjectExistsExists_Returns_O _ => throw new ArgumentOutOfRangeException(nameof(idType), idType, null) }; - var cancellationToken = new CancellationToken(); - var response = await Sut.GetIdentifiers(identifier!, cancellationToken); - - response.Result.Should().NotBeNull(); - response.Result.Should().BeOfType(typeof(OkObjectResult)); - response.GetStatusCode().Should().Be((int)HttpStatusCode.OK); + var response = await _client.GetAsync($"{ApiUrlPrefix}/{identifier}"); - var content = response.GetIdentifiers(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var content = await response.Content.ReadFromJsonAsync(); content.Should().NotBeNull(); var formAMatProjects = content!.FormAMatProjects; formAMatProjects.Length.Should().Be(1); diff --git a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs index 636e895..387cf5e 100644 --- a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs +++ b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs @@ -1,4 +1,6 @@ -using Dfe.Identifiers.Infrastructure.Context; +using System.Net.Mime; +using Dfe.Identifiers.Infrastructure.Context; +using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -8,38 +10,67 @@ public class ApiTestFixture : IDisposable { private const string connectionStringKey = "ConnectionStrings:DefaultConnection"; private DbContextOptions _mstrContextOptions { get; init; } - private DbContextOptions _academisationContextOptions { get; init; } + private static readonly object _lock = new(); + private static bool isInitalised = false; + public HttpClient Client { get; init; } + + private readonly WebApplicationFactory _application; public ApiTestFixture() { - var builder = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .AddEnvironmentVariables() - .AddUserSecrets(); - - Configuration = builder.Build(); - _mstrContextOptions = new DbContextOptionsBuilder() - .UseSqlServer(Configuration[connectionStringKey]) - .Options; - _academisationContextOptions = new DbContextOptionsBuilder() - .UseSqlServer(Configuration[connectionStringKey]) - .Options; - using var mstrContext = GetMstrContext(); - using var academisationContext = GetAcademisationContext(); - mstrContext.Database.EnsureDeleted(); - academisationContext.Database.EnsureDeleted(); - mstrContext.Database.Migrate(); - academisationContext.Database.Migrate(); + lock (_lock) + { + if (!isInitalised) + { + string? connectionString = null; + _application = new WebApplicationFactory() + .WithWebHostBuilder(builder => + { + builder.ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .AddUserSecrets(); + var configuration = config.Build(); + connectionString = configuration[connectionStringKey]; + }); + }); + + Client = _application.CreateClient(); + Client.DefaultRequestHeaders.Add("ApiKey", "app-key"); + Client.DefaultRequestHeaders.Add("ContentType", MediaTypeNames.Application.Json); + Client.BaseAddress = new Uri("https://identifiers-api.com"); + + _mstrContextOptions = new DbContextOptionsBuilder() + .UseSqlServer(connectionString) + .EnableSensitiveDataLogging() + .Options; + _academisationContextOptions = new DbContextOptionsBuilder() + .UseSqlServer(connectionString) + .EnableSensitiveDataLogging() + .Options; + } + SetupDatabase(); + } + } - private IConfigurationRoot Configuration { get; init; } - public MstrContext GetMstrContext() => new(_mstrContextOptions); public AcademisationContext GetAcademisationContext() => new(_academisationContextOptions); public void Dispose() { } + + private void SetupDatabase() + { + using var mstrContext = GetMstrContext(); + using var academisationContext = GetAcademisationContext(); + mstrContext.Database.EnsureDeleted(); + academisationContext.Database.EnsureDeleted(); + mstrContext.Database.Migrate(); + academisationContext.Database.Migrate(); + } } } \ No newline at end of file From 736c337584379cfc0335964ba61022206edb97ed Mon Sep 17 00:00:00 2001 From: Nick Warms Date: Fri, 26 Apr 2024 14:42:05 +0100 Subject: [PATCH 13/13] Remove sensitive logging - no longer needed for debugging --- Dfe.Identifiers.Api.Test/ApiTestFixture.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs index 387cf5e..078877b 100644 --- a/Dfe.Identifiers.Api.Test/ApiTestFixture.cs +++ b/Dfe.Identifiers.Api.Test/ApiTestFixture.cs @@ -44,11 +44,9 @@ public ApiTestFixture() _mstrContextOptions = new DbContextOptionsBuilder() .UseSqlServer(connectionString) - .EnableSensitiveDataLogging() .Options; _academisationContextOptions = new DbContextOptionsBuilder() .UseSqlServer(connectionString) - .EnableSensitiveDataLogging() .Options; } SetupDatabase();