using AsbCloudApp.Data; using AsbCloudDb.Model; using AsbCloudInfrastructure; using AsbCloudWebApi.IntegrationTests.Clients; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using System.Net; using Xunit; namespace AsbCloudWebApi.IntegrationTests.Controllers { public abstract class CrudWellRelatedClient : BaseIntegrationTest where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated where TEntity : class, AsbCloudDb.Model.IId, AsbCloudDb.Model.IWellRelated { public abstract IEnumerable ValidDtos { get; } public abstract IEnumerable InvalidDtos { get; } public abstract IEnumerable ForbiddenDtos { get; } protected List ExcludeProps { get; set; } = new() { "Id" }; protected ICrudWellRelatedClient client; public CrudWellRelatedClient(WebAppFactoryFixture factory, string uriSuffix) : base(factory) { client = factory.GetAuthorizedHttpClient>(uriSuffix); } protected async Task> GetCleanDbSet() { var dbset = dbContext.Set(); dbset.RemoveRange(dbset); await dbContext.SaveChangesAsync(CancellationToken.None); return dbset; } [Fact] public async Task Insert_returns_success_for_validDtos() { foreach (var validDto in ValidDtos) await Insert_returns_success(validDto); } private async Task Insert_returns_success(TDto validDto) { var dbset = await GetCleanDbSet(); //act var response = await client.InsertAsync(validDto); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.True(response.Content > 0); var entity = dbset.First(); var fromDbDto = Convert(entity); MatchHelper.Match(validDto, fromDbDto, ExcludeProps); } [Fact] public async Task Insert_returns_badRequest_for_invalidDtos() { foreach (var inValidDto in InvalidDtos) await Insert_returns_badRequest(inValidDto); } private async Task Insert_returns_badRequest(TDto invalidDto) { await GetCleanDbSet(); //act var response = await client.InsertAsync(invalidDto); //assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task Insert_returns_forbidden_for_forbiddenDtos() { foreach (var forbiddenDto in ForbiddenDtos) await Insert_returns_forbidden(forbiddenDto); } private async Task Insert_returns_forbidden(TDto forbiddenDto) { await GetCleanDbSet(); //act var response = await client.InsertAsync(forbiddenDto); //assert Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); } [Fact] public async Task GetAllAsync_returns_data() { //arrange var dbset = await GetCleanDbSet(); var entries = new List<(EntityEntry, TDto)>(); foreach (var dto in ValidDtos) { var entity = Convert(dto); entity.Id = 0; var entry = dbset.Add(entity); entries.Add((entry, dto)); } dbContext.SaveChanges(); //act var response = await client.GetAllAsync(); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(response.Content); Assert.Equal(entries.Count, response.Content.Count()); foreach (var item in response.Content) { var entry = entries.First(e => e.Item1.Entity.Id == item.Id); MatchHelper.Match(entry.Item2, item, ExcludeProps); } } protected virtual TDto Convert(TEntity entity) { var dto = entity.Adapt(); return dto; } protected virtual TEntity Convert(TDto dto) { var entity = dto.Adapt(); return entity; } } public class ScheduleControllerTest : CrudWellRelatedClient { static Driller driller = Data.Defaults.Drillers.First(); static DrillerDto drillerDto = driller.Adapt(); static Well well = Data.Defaults.Wells.First(); public override IEnumerable ValidDtos { get; } = new ScheduleDto[] { new() { Id = 1, IdWell = well.Id, Driller = drillerDto, IdDriller = driller.Id, DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified), ShiftStart = new TimeDto(8, 0, 0), ShiftEnd = new TimeDto(20, 0, 0), }, new() { Id = 1, IdWell = well.Id, Driller = drillerDto, IdDriller = driller.Id, DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified), ShiftStart = new TimeDto(20, 0, 0), ShiftEnd = new TimeDto(8, 0, 0), } }; public override IEnumerable InvalidDtos { get; } = new ScheduleDto[] { new() { IdWell = well.Id, Driller = drillerDto, IdDriller = driller.Id, DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), DrillEnd = new DateTime(2022, 1, 2, 0, 0, 0, DateTimeKind.Unspecified), ShiftStart = new TimeDto(8, 0, 0), ShiftEnd = new TimeDto(20, 0, 0), }, new() { IdWell = well.Id, Driller = drillerDto, IdDriller = int.MaxValue - 1, DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified), ShiftStart = new TimeDto(8, 0, 0), ShiftEnd = new TimeDto(20, 0, 0), } }; public override IEnumerable ForbiddenDtos { get; } = new ScheduleDto[] { new() { IdWell = int.MaxValue - 1, Driller = drillerDto, IdDriller = driller.Id, DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), DrillEnd = new DateTime(2022, 1, 2, 0, 0, 0, DateTimeKind.Unspecified), ShiftStart = new TimeDto(8, 0, 0), ShiftEnd = new TimeDto(20, 0, 0), } }; public ScheduleControllerTest(WebAppFactoryFixture factory) : base(factory, "api/schedule") { ExcludeProps.Add(nameof(ScheduleDto.Driller)); } protected override ScheduleDto Convert(Schedule entity) { var dto = base.Convert(entity); dto.DrillStart = entity.DrillStart.ToRemoteDateTime(well.Timezone.Hours); dto.DrillEnd = entity.DrillEnd.ToRemoteDateTime(well.Timezone.Hours); return dto; } protected override Schedule Convert(ScheduleDto dto) { var entity = base.Convert(dto); entity.DrillStart = dto.DrillStart.FromTimeZoneOffsetHours(well.Timezone.Hours); entity.DrillEnd = dto.DrillEnd.FromTimeZoneOffsetHours(well.Timezone.Hours); return entity; } } }