From 88ce24b8bb65d7a30edfc34f4e3f247b806470f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 29 Dec 2023 11:46:17 +0500 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Создание инфраструктуры для интегарционных тестов 2. Покрытие контроллера месторождений тестами --- AsbCloud.sln | 6 + .../ApiTokenHelper.cs | 50 ++++ .../AsbCloudWebApi.IntegrationTests.csproj | 25 ++ .../BaseIntegrationTest.cs | 40 +++ .../Clients/IAdminDepositClient.cs | 27 ++ .../AdminDepositControllerTests.cs | 186 ++++++++++++ .../MatchHelper.cs | 31 ++ .../TestFakers/DepositTestFaker.cs | 25 ++ .../WebAppFactoryFixture.cs | 52 ++++ .../AsbCloudWebApi.Tests.csproj | 1 - .../IntegrationTests/BaseIntegrationTest.cs | 47 --- .../AdminDepositControllerTests.cs | 24 -- .../Controllers/CrudControllerTests.cs | 275 ------------------ .../TestWebApplicationFactory.cs | 46 --- docker-compose.yml | 24 -- 15 files changed, 442 insertions(+), 417 deletions(-) create mode 100644 AsbCloudWebApi.IntegrationTests/ApiTokenHelper.cs create mode 100644 AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj create mode 100644 AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs create mode 100644 AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs create mode 100644 AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs create mode 100644 AsbCloudWebApi.IntegrationTests/MatchHelper.cs create mode 100644 AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs create mode 100644 AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs delete mode 100644 AsbCloudWebApi.Tests/IntegrationTests/BaseIntegrationTest.cs delete mode 100644 AsbCloudWebApi.Tests/IntegrationTests/Controllers/AdminDepositControllerTests.cs delete mode 100644 AsbCloudWebApi.Tests/IntegrationTests/Controllers/CrudControllerTests.cs delete mode 100644 AsbCloudWebApi.Tests/IntegrationTests/TestWebApplicationFactory.cs delete mode 100644 docker-compose.yml diff --git a/AsbCloud.sln b/AsbCloud.sln index e4d9f235..a33359b7 100644 --- a/AsbCloud.sln +++ b/AsbCloud.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudWebApi.Tests", "Asb EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SignalRTestClient", "SignalRTestClient\SignalRTestClient.csproj", "{E6B97963-4CEA-47B6-A0C8-625FFA9B7D69}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsbCloudWebApi.IntegrationTests", "AsbCloudWebApi.IntegrationTests\AsbCloudWebApi.IntegrationTests.csproj", "{2A937DFD-8E78-4204-A6B9-F3195EAA5818}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {E6B97963-4CEA-47B6-A0C8-625FFA9B7D69}.Debug|Any CPU.Build.0 = Debug|Any CPU {E6B97963-4CEA-47B6-A0C8-625FFA9B7D69}.Release|Any CPU.ActiveCfg = Release|Any CPU {E6B97963-4CEA-47B6-A0C8-625FFA9B7D69}.Release|Any CPU.Build.0 = Release|Any CPU + {2A937DFD-8E78-4204-A6B9-F3195EAA5818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A937DFD-8E78-4204-A6B9-F3195EAA5818}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A937DFD-8E78-4204-A6B9-F3195EAA5818}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A937DFD-8E78-4204-A6B9-F3195EAA5818}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AsbCloudWebApi.IntegrationTests/ApiTokenHelper.cs b/AsbCloudWebApi.IntegrationTests/ApiTokenHelper.cs new file mode 100644 index 00000000..2e4e5dc0 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/ApiTokenHelper.cs @@ -0,0 +1,50 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using AsbCloudDb.Model; +using Microsoft.IdentityModel.Tokens; + +namespace AsbCloudWebApi.IntegrationTests; + +public static class ApiTokenHelper +{ + public static string GetAdminUserToken() + { + var user = new User() + { + Id = 1, + IdCompany = 1, + Login = "test_user" + }; + var roles = new[] { "root" }; + + return CreateToken(user, roles); + } + + private static string CreateToken(User user, IEnumerable roles) + { + var claims = new List + { + new("id", user.Id.ToString()), + new(ClaimsIdentity.DefaultNameClaimType, user.Login), + new("idCompany", user.IdCompany.ToString()), + }; + + claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role))); + + const string secret = "супер секретный ключ для шифрования"; + + var key = Encoding.ASCII.GetBytes(secret); + var tokenDescriptor = new SecurityTokenDescriptor + { + Issuer = "a", + Audience = "a", + Subject = new ClaimsIdentity(claims), + Expires = DateTime.UtcNow.AddHours(1), + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) + }; + var tokenHandler = new JwtSecurityTokenHandler(); + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj b/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj new file mode 100644 index 00000000..1824d4ce --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs new file mode 100644 index 00000000..7017e79c --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs @@ -0,0 +1,40 @@ +using System.Net.Http.Headers; +using System.Text.Json; +using AsbCloudDb.Model; +using AsbCloudWebApi.IntegrationTests.Clients; +using Microsoft.Extensions.DependencyInjection; +using Refit; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests; + +public abstract class BaseIntegrationTest : IClassFixture +{ + private readonly IServiceScope scope; + private readonly HttpClient httpClient; + + protected readonly IAsbCloudDbContext dbContext; + + protected IAdminDepositClient adminDepositClient; + + protected BaseIntegrationTest(WebAppFactoryFixture factory) + { + scope = factory.Services.CreateScope(); + httpClient = factory.CreateClient(); + + dbContext = scope.ServiceProvider.GetRequiredService(); + + var jwtToken = ApiTokenHelper.GetAdminUserToken(); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + + var jsonSerializerOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true + }; + + var refitSettings = new RefitSettings(new SystemTextJsonContentSerializer(jsonSerializerOptions)); + + adminDepositClient = RestService.For(httpClient, refitSettings); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs new file mode 100644 index 00000000..ddc32005 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs @@ -0,0 +1,27 @@ +using AsbCloudApp.Data; +using Refit; + +namespace AsbCloudWebApi.IntegrationTests.Clients; + +public interface IAdminDepositClient +{ + private const string BaseRoute = "/api/admin/deposit"; + + [Post(BaseRoute)] + Task> InsertAsync([Body] DepositBaseDto deposit); + + [Post($"{BaseRoute}/range")] + Task> InsertRangeAsync([Body] IEnumerable deposits); + + [Put($"{BaseRoute}")] + Task> UpdateAsync([Body] DepositBaseDto deposit); + + [Get(BaseRoute + "/{id}")] + Task> GetOrDefaultAsync(int id); + + [Get(BaseRoute)] + Task>> GetAllAsync(); + + [Delete(BaseRoute + "/{id}")] + Task> DeleteAsync(int id); +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs b/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs new file mode 100644 index 00000000..81c76420 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs @@ -0,0 +1,186 @@ +using System.Net; +using AsbCloudApp.Data; +using AsbCloudWebApi.IntegrationTests.TestFakers; +using Mapster; +using Microsoft.EntityFrameworkCore; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests.Controllers; + +public class AdminDepositControllerTests : BaseIntegrationTest +{ + public AdminDepositControllerTests(WebAppFactoryFixture factory) + : base(factory) + { + } + + [Fact] + public async Task InsertAsync_ReturnsSuccess_WhenNewItemIsValid() + { + //arrange + var expectedDto = DepositTestFaker.GetDeposit().Adapt(); + + //act + var response = await adminDepositClient.InsertAsync(expectedDto); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.Content > 0); + + var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content); + var actualDto = entity?.Adapt(); + + var excludeProps = new[] { nameof(DepositBaseDto.Id) }; + MatchHelper.Match(expectedDto, actualDto, excludeProps); + } + + [Fact] + public async Task InsertRangeAsync_ReturnsSuccess_WhenAllNewItemsIsValid() + { + //arrange + var dto = DepositTestFaker.GetDeposit().Adapt(); + + //act + var responce = await adminDepositClient.InsertRangeAsync(new[] { dto }); + + //assert + Assert.Equal(HttpStatusCode.OK, responce.StatusCode); + Assert.Equal(1, responce.Content); + + var entity = await dbContext.Deposits.OrderBy(d => d.Id).LastOrDefaultAsync(); + var deposit = entity?.Adapt(); + + var excludeProps = new[] { nameof(DepositBaseDto.Id) }; + MatchHelper.Match(dto, deposit, excludeProps); + } + + [Fact] + public async Task UpdateAsync_ReturnsBadRequest_WhenUpdatedItemHasInvalidId() + { + //arrange + var dto = DepositTestFaker.GetDeposit().Adapt(); + + //act + var response = await adminDepositClient.UpdateAsync(dto); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task UpdateAsync_ReturnsSuccess_WhenUpdatedItemIsValid() + { + //arrange + var dto = DepositTestFaker.GetDeposit().Adapt(); + var insertResponse = await adminDepositClient.InsertAsync(dto); + + dto.Id = insertResponse.Content; + dto.Caption = "Test"; + dto.Latitude = 50; + dto.Longitude = 50; + dto.Timezone = new SimpleTimezoneDto + { + IsOverride = true, + Hours = 12 + }; + + //act + var response = await adminDepositClient.UpdateAsync(dto); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.Content > 0); + + var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content); + var deposit = entity?.Adapt(); + + MatchHelper.Match(dto, deposit); + } + + [Fact] + public async Task GetOrDefaultAsync_ReturnsSuccess_WhenIdIsValid() + { + //arrange + var dto = DepositTestFaker.GetDeposit().Adapt(); + var insertResponse = await adminDepositClient.InsertAsync(dto); + var id = insertResponse.Content; + + //act + var response = await adminDepositClient.GetOrDefaultAsync(id); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + + var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content.Id); + var deposit = entity?.Adapt(); + + var excludeProps = new[] { nameof(DepositBaseDto.Id) }; + MatchHelper.Match(dto, deposit, excludeProps); + } + + [Fact] + public async Task GetOrDefaultAsync_ReturnsNoContent_WhenIdIsInvalid() + { + //arrange + const int id = 0; + + //act + var responce = await adminDepositClient.GetOrDefaultAsync(id); + + //assert + Assert.Equal(HttpStatusCode.NoContent, responce.StatusCode); + } + + [Fact] + public async Task GetAllAsync_ReturnsSuccess() + { + //act + var response = await adminDepositClient.GetAllAsync(); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + + var expectedCount = await dbContext.Deposits.CountAsync(); + Assert.Equal(expectedCount, response.Content.Count()); + + + var entity = await dbContext.Deposits.FirstOrDefaultAsync(); + var dto = entity?.Adapt(); + + MatchHelper.Match(dto, response.Content.FirstOrDefault()); + } + + [Fact] + public async Task DeleteAsync_ReturnsSuccess_WhenIdIsValid() + { + //arrange + var dto = DepositTestFaker.GetDeposit().Adapt(); + var insertResponse = await adminDepositClient.InsertAsync(dto); + var id = insertResponse.Content; + + //act + var response = await adminDepositClient.DeleteAsync(id); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.Content > 0); + + var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == dto.Id); + Assert.Null(entity); + } + + [Fact] + public async Task DeleteAsync_ReturnsNoContent_WhenIdIsInvalid() + { + //arrange + const int id = 0; + + //act + var response = await adminDepositClient.DeleteAsync(id); + + //assert + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/MatchHelper.cs b/AsbCloudWebApi.IntegrationTests/MatchHelper.cs new file mode 100644 index 00000000..6a8704f8 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/MatchHelper.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using Xunit.Sdk; + +namespace AsbCloudWebApi.IntegrationTests; + +public static class MatchHelper +{ + public static void Match(T expected, T actual, IEnumerable? excludeProps = null) + { + if (ReferenceEquals(expected, actual)) + throw new EqualException(expected, actual); + + if (expected is null || actual is null) + throw new EqualException(expected, actual); + + var props = typeof(T).GetProperties( + BindingFlags.Public + | BindingFlags.Instance).Where(prop => prop.CanWrite); + + if (excludeProps is not null && excludeProps.Any()) + props = props.Where(prop => !excludeProps.Contains(prop.Name)); + + foreach (var prop in props) + { + var objValue = prop.GetValue(expected); + var anotherValue = prop.GetValue(actual); + if (objValue != null && !objValue.Equals(anotherValue)) + throw new EqualException(expected, actual); + } + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs b/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs new file mode 100644 index 00000000..c2f6e098 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs @@ -0,0 +1,25 @@ +using AsbCloudDb.Model; +using Bogus; + +namespace AsbCloudWebApi.IntegrationTests.TestFakers; + +public static class DepositTestFaker +{ + public static Deposit GetDeposit() => + GetDepositFaker().Generate(); + + public static IEnumerable GetDeposits(int count) => + GetDepositFaker().Generate(count); + + private static Faker GetDepositFaker() => + new Faker() + .RuleFor(d => d.Id, 0) + .RuleFor(d => d.Caption, f => f.Random.String2(1, 50)) + .RuleFor(d => d.Latitude, f => f.Random.Int(-90, 90)) + .RuleFor(d => d.Longitude, f => f.Random.Int(-180, 180)) + .RuleFor(d => d.Timezone, f => new SimpleTimezone + { + Hours = f.Random.Int(1, 12), + IsOverride = f.Random.Bool() + }); +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs new file mode 100644 index 00000000..a6116e5d --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs @@ -0,0 +1,52 @@ +using AsbCloudDb; +using AsbCloudDb.Model; +using AsbCloudWebApi.IntegrationTests.TestFakers; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests; + +public class WebAppFactoryFixture : WebApplicationFactory, + IAsyncLifetime +{ + private const string connectionString = + "Host=localhost;Database=test;Port=5433;Username=postgres;Password=root;Persist Security Info=True;Include Error Detail=True;"; + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + var descriptor = services.FirstOrDefault(d => d.ServiceType == typeof(DbContextOptions)); + + if (descriptor is not null) + services.Remove(descriptor); + + services.AddDbContext(options => + options.UseNpgsql(connectionString)); + }); + } + + public async Task InitializeAsync() + { + using var scope = Services.CreateScope(); + var scopedServices = scope.ServiceProvider; + var dbContext = scopedServices.GetRequiredService(); + + dbContext.Database.EnsureCreatedAndMigrated(); + + dbContext.Deposits.AddRange(DepositTestFaker.GetDeposits(15)); + await dbContext.SaveChangesAsync(); + } + + public new async Task DisposeAsync() + { + using var scope = Services.CreateScope(); + var scopedServices = scope.ServiceProvider; + var dbContext = scopedServices.GetRequiredService(); + + await dbContext.Database.EnsureDeletedAsync(); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj b/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj index 5d42db1b..06d8d055 100644 --- a/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj +++ b/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj @@ -22,7 +22,6 @@ - runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/AsbCloudWebApi.Tests/IntegrationTests/BaseIntegrationTest.cs b/AsbCloudWebApi.Tests/IntegrationTests/BaseIntegrationTest.cs deleted file mode 100644 index 3f047084..00000000 --- a/AsbCloudWebApi.Tests/IntegrationTests/BaseIntegrationTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using AsbCloudApp.Data.User; -using AsbCloudDb; -using AsbCloudDb.Model; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace AsbCloudWebApi.Tests.IntegrationTests; - -public abstract class BaseIntegrationTest : IClassFixture -{ - private readonly IAsbCloudDbContext dbContext; - - protected readonly HttpClient httpClient; - protected readonly IServiceScope scope; - - protected BaseIntegrationTest(TestWebApplicationFactory factory) - { - scope = factory.Services.CreateScope(); - httpClient = factory.CreateClient(); - dbContext = scope.ServiceProvider.GetRequiredService(); - - dbContext.Database.EnsureCreatedAndMigrated(); - } - - protected void SetToken(string token) - { - httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - } - - //TODO: поправить метод регистрации, сделать этот метод следующим образом: - //1. Пройти регистрацию - //2. Залогиниться под новым логином и паролем. Тестить всё под учёткой dev -- это неправильно, но пока так. - // Пока используется jwt токен dev, пока так захардкожено - protected Task RegisterUserAsync() - { - var authToken = new UserTokenDto - { - Token = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE3MDIzNjg3NzksImV4cCI6MTczMzkyNjM3OSwiaXNzIjoiYSIsImF1ZCI6ImEifQ.zMJHgoEkfifR28vIPxtABvznf8NFJjk33E9fxNZTwGM" - }; - - return Task.FromResult(authToken); - } -} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/IntegrationTests/Controllers/AdminDepositControllerTests.cs b/AsbCloudWebApi.Tests/IntegrationTests/Controllers/AdminDepositControllerTests.cs deleted file mode 100644 index 7d9d2f72..00000000 --- a/AsbCloudWebApi.Tests/IntegrationTests/Controllers/AdminDepositControllerTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudApp.Services; - -namespace AsbCloudWebApi.Tests.IntegrationTests.Controllers; - -public class AdminDepositControllerTests : CrudControllerTests> -{ - public AdminDepositControllerTests(TestWebApplicationFactory factory) : base(factory) - { - } - - protected override string Uri => "api/admin/deposit"; - - protected override DepositDto GetFakerData() => new() - { - Caption = "Fake deposit", - Timezone = new SimpleTimezoneDto - { - Hours = 5, - IsOverride = false, - TimezoneId = "Екатеринбург" - } - }; -} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/IntegrationTests/Controllers/CrudControllerTests.cs b/AsbCloudWebApi.Tests/IntegrationTests/Controllers/CrudControllerTests.cs deleted file mode 100644 index 1f274a35..00000000 --- a/AsbCloudWebApi.Tests/IntegrationTests/Controllers/CrudControllerTests.cs +++ /dev/null @@ -1,275 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Json; -using System.Threading.Tasks; -using AsbCloudApp.Data; -using AsbCloudApp.Services; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace AsbCloudWebApi.Tests.IntegrationTests.Controllers; - -public abstract class CrudControllerTests : BaseIntegrationTest - where T : class, IId - where TRepository : ICrudRepository -{ - private readonly TRepository repository; - - protected abstract string Uri { get; } - - protected abstract T GetFakerData(); - - protected CrudControllerTests(TestWebApplicationFactory factory) - : base(factory) - { - repository = scope.ServiceProvider.GetRequiredService(); - } - - [Fact] - public virtual async Task InsertAsync_Should_ReturnsSuccess() - { - //arrange - var fakerData = GetFakerData(); - - var request = new HttpRequestMessage - { - Content = JsonContent.Create(fakerData), - Method = HttpMethod.Post, - RequestUri = new Uri(Uri, UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.True(result > 0); - Assert.True(response.IsSuccessStatusCode); - } - - [Fact] - public virtual async Task InsertRangeAsync_Should_ReturnsSuccess() - { - //arrange - var fakerData = GetFakerData(); - - var request = new HttpRequestMessage - { - Content = JsonContent.Create(new[] { fakerData }), - Method = HttpMethod.Post, - RequestUri = new Uri($"{Uri}/range", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.True(result > 0); - Assert.True(response.IsSuccessStatusCode); - } - - [Fact] - public virtual async Task InsertRangeAsync_Should_ReturnsBadRequest_WhenInputCollectionFakerDataIsEmpty() - { - //arrange - var request = new HttpRequestMessage - { - Content = JsonContent.Create(Enumerable.Empty()), - Method = HttpMethod.Post, - RequestUri = new Uri($"{Uri}/range", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - - //assert - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } - - [Fact] - public virtual async Task UpdateAsync_Should_ReturnsSuccess() - { - //arrange - var fakerData = GetFakerData(); - fakerData.Id = await repository.InsertAsync(fakerData, default); - - var request = new HttpRequestMessage - { - Content = JsonContent.Create(fakerData), - Method = HttpMethod.Put, - RequestUri = new Uri(Uri, UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.Equal(fakerData.Id, result); - Assert.True(response.IsSuccessStatusCode); - } - - [Fact] - public virtual async Task UpdateAsync_Should_ReturnsBadRequest_WhenFakerDataHasInvalidId() - { - //arrange - var fakerData = GetFakerData(); - - var request = new HttpRequestMessage - { - Content = JsonContent.Create(fakerData), - Method = HttpMethod.Put, - RequestUri = new Uri(Uri, UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - - //assert - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } - - [Fact] - public virtual async Task DeleteAsync_Should_ReturnsSuccess() - { - //arrange - var fakerData = GetFakerData(); - fakerData.Id = await repository.InsertAsync(fakerData, default); - - var request = new HttpRequestMessage - { - Method = HttpMethod.Delete, - RequestUri = new Uri($"{Uri}/{fakerData.Id}", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.True(result > 0); - Assert.True(response.IsSuccessStatusCode); - } - - [Fact] - public virtual async Task DeleteAsync_Should_ReturnsNoContent_WhenFakerDataHasInvalidId() - { - //arrange - const int fakerInvalidId = 0; - - var request = new HttpRequestMessage - { - Method = HttpMethod.Delete, - RequestUri = new Uri($"{Uri}/{fakerInvalidId}", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - - //assert - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } - - [Fact] - public virtual async Task GetOrDefaultAsync_Should_ReturnsSuccess() - { - //arrange - var fakerData = GetFakerData(); - fakerData.Id = await repository.InsertAsync(fakerData, default); - - var request = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri($"{Uri}/{fakerData.Id}", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.NotNull(result); - Assert.Equal(fakerData.Id, result.Id); - Assert.True(response.IsSuccessStatusCode); - } - - [Fact] - public virtual async Task GetOrDefaultAsync_Should_ReturnsNoContent_WhenFakerDataHasInvalidId() - { - //arrange - const int fakerInvalidId = 0; - - var request = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri($"{Uri}/{fakerInvalidId}", UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - - //assert - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } - - [Fact] - public virtual async Task GetAllAsync_Should_ReturnsSuccess() - { - //arrange - var existingFakerDataIds = (await repository.GetAllAsync(default)).Select(f => f.Id); - - foreach (var existingFakerDataId in existingFakerDataIds) - await repository.DeleteAsync(existingFakerDataId, default); - - var fakerData = GetFakerData(); - fakerData.Id = await repository.InsertAsync(fakerData, default); - - var request = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri(Uri, UriKind.Relative) - }; - - var user = await RegisterUserAsync(); - SetToken(user.Token); - - //act - var response = await httpClient.SendAsync(request); - var result = await response.Content.ReadFromJsonAsync(); - - //assert - Assert.NotNull(result); - Assert.Single(result); - Assert.True(response.IsSuccessStatusCode); - } -} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/IntegrationTests/TestWebApplicationFactory.cs b/AsbCloudWebApi.Tests/IntegrationTests/TestWebApplicationFactory.cs deleted file mode 100644 index 0e645b8d..00000000 --- a/AsbCloudWebApi.Tests/IntegrationTests/TestWebApplicationFactory.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using AsbCloudDb.Model; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Testcontainers.PostgreSql; -using Xunit; - -namespace AsbCloudWebApi.Tests.IntegrationTests; - -public class TestWebApplicationFactory : WebApplicationFactory, - IAsyncLifetime -{ - private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder() - .WithImage("timescale/timescaledb:latest-pg15") - .WithDatabase("AsbCloud") - .WithUsername("postgres") - .WithPassword("postgres") - .Build(); - - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.ConfigureServices(services => - { - var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); - - if (descriptor is not null) - services.Remove(descriptor); - - services.AddDbContext(options => - options.UseNpgsql(_dbContainer.GetConnectionString())); - }); - } - - public Task InitializeAsync() - { - return _dbContainer.StartAsync(); - } - - public new Task DisposeAsync() - { - return _dbContainer.StopAsync(); - } -} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 45db8475..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3.9' - -services: - - postgres: - container_name: pg_db - image: timescale/timescaledb:latest-pg15 - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: "AsbCloud" - volumes: - - ./timescaledb_data:/var/lib/postgresql/data - ports: - - "5434:5432" - - pgadmin: - container_name: pgadmin - image: dpage/pgadmin4 - environment: - PGADMIN_DEFAULT_EMAIL: noemail@noemail.com - PGADMIN_DEFAULT_PASSWORD: root - ports: - - "5050:80" \ No newline at end of file