lab4-preready

This commit is contained in:
2025-04-09 01:46:17 +04:00
parent cec7b9240e
commit f649754da7
73 changed files with 3664 additions and 71 deletions

View File

@@ -9,6 +9,29 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Contracts\BindingModels\IngredientBindingModel.cs" />
<Compile Include="Contracts\BindingModels\OrderBindingModel.cs" />
<Compile Include="Contracts\BindingModels\PekarBindingModel.cs" />
<Compile Include="Contracts\BindingModels\PekarHistoryBindingModel.cs" />
<Compile Include="Contracts\BindingModels\PositionBindingModel.cs" />
<Compile Include="Contracts\BindingModels\ProductBindingModel.cs" />
<Compile Include="Contracts\BindingModels\RecipeBindingModel.cs" />
<Compile Include="Contracts\BindingModels\SalaryBindingModel.cs" />
<Compile Include="Contracts\OperationResponses\IngredientOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\OrderOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\PekarHistoryOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\PekarOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\PositionOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\ProductOperationResponse.cs" />
<Compile Include="Contracts\OperationResponses\SalaryOperationResponse.cs" />
<Compile Include="Contracts\ViewModels\IngredientViewModel.cs" />
<Compile Include="Contracts\ViewModels\OrderViewModel.cs" />
<Compile Include="Contracts\ViewModels\PekarHistoryViewModel.cs" />
<Compile Include="Contracts\ViewModels\PekarViewModel.cs" />
<Compile Include="Contracts\ViewModels\PositionViewModel.cs" />
<Compile Include="Contracts\ViewModels\ProductViewModel.cs" />
<Compile Include="Contracts\ViewModels\RecipeViewModel.cs" />
<Compile Include="Contracts\ViewModels\SalaryViewModel.cs" />
<Compile Include="DataModels\IngredientDataModel.cs" />
<Compile Include="DataModels\OrderDataModel.cs" />
<Compile Include="DataModels\PekarDataModel.cs" />
@@ -36,6 +59,14 @@
<Compile Include="Implementations\SalaryBusinessLogicContract.cs" />
<Compile Include="Infrastructure\Infrastructure.cs" />
<Compile Include="Infrastructure\IValidation.cs" />
<Compile Include="Infrastructure\OperationResponse.cs" />
<Compile Include="Interfaces\Adapters\IIngredientAdapter.cs" />
<Compile Include="Interfaces\Adapters\IOrderAdapter.cs" />
<Compile Include="Interfaces\Adapters\IPekarAdapter.cs" />
<Compile Include="Interfaces\Adapters\IPekarHistoryAdapter.cs" />
<Compile Include="Interfaces\Adapters\IPositionAdapter.cs" />
<Compile Include="Interfaces\Adapters\IProductAdapter.cs" />
<Compile Include="Interfaces\Adapters\ISalaryAdapter.cs" />
<Compile Include="Interfaces\BusinessLogicsContracts\IIngredientBusinessLogicContact.cs" />
<Compile Include="Interfaces\BusinessLogicsContracts\IOrderBusinessLogicContact.cs" />
<Compile Include="Interfaces\BusinessLogicsContracts\IPekarBusinessLogicContact.cs" />
@@ -51,6 +82,7 @@
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="CatHasPawsTests" />
<InternalsVisibleTo Include="CandyHouseWebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup>
@@ -66,7 +98,10 @@
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-preview.1.25080.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.8" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class IngredientBindingModel
{
public string? Id { get; set; }
public string? Name { get; set; }
public string? Unit { get; set; }
public double Cost { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class OrderBindingModel
{
public string? Id { get; set; }
public string? ProductId { get; set; }
public object Count { get; set; }
public object Status { get; set; }
public object DateCreate { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class PekarBindingModel
{
public string? Id { get; set; }
public object FIO { get; set; }
public object PhoneNumber { get; set; }
public object Login { get; set; }
public object Password { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class PekarHistoryBindingModel
{
public string? Id { get; set; }
public string? PekarId { get; set; }
public string? PositionId { get; set; }
public object DateStart { get; set; }
public object DateEnd { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class PositionBindingModel
{
public string? Id { get; set; }
public object Name { get; set; }
public object SalaryRate { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class ProductBindingModel
{
public string? Id { get; set; }
public object Name { get; set; }
public object Price { get; set; }
public object StorageCount { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class RecipeBindingModel
{
public string? ProductId { get; set; }
public string? IngredientId { get; set; }
public int Quantity { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace CandyHouseBase.Contracts.BindingModels;
public class SalaryBindingModel
{
public string? Id { get; set; }
public string? PekarId { get; set; }
public object Amount { get; set; }
public object DateIssue { get; set; }
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class IngredientOperationResponse : OperationResponse
{
public static IngredientOperationResponse OK(List<IngredientViewModel> data) =>
OK<IngredientOperationResponse, List<IngredientViewModel>>(data);
public static IngredientOperationResponse OK(IngredientViewModel data) =>
OK<IngredientOperationResponse, IngredientViewModel>(data);
public static IngredientOperationResponse NoContent() =>
NoContent<IngredientOperationResponse>();
public static IngredientOperationResponse NotFound(string message) =>
NotFound<IngredientOperationResponse>(message);
public static IngredientOperationResponse BadRequest(string message) =>
BadRequest<IngredientOperationResponse>(message);
public static IngredientOperationResponse InternalServerError(string message) =>
InternalServerError<IngredientOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class OrderOperationResponse : OperationResponse
{
public static OrderOperationResponse OK(List<OrderViewModel> data) =>
OK<OrderOperationResponse, List<OrderViewModel>>(data);
public static OrderOperationResponse OK(OrderViewModel data) =>
OK<OrderOperationResponse, OrderViewModel>(data);
public static OrderOperationResponse NoContent() =>
NoContent<OrderOperationResponse>();
public static OrderOperationResponse NotFound(string message) =>
NotFound<OrderOperationResponse>(message);
public static OrderOperationResponse BadRequest(string message) =>
BadRequest<OrderOperationResponse>(message);
public static OrderOperationResponse InternalServerError(string message) =>
InternalServerError<OrderOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class PekarHistoryOperationResponse : OperationResponse
{
public static PekarHistoryOperationResponse OK(List<PekarHistoryViewModel> data) =>
OK<PekarHistoryOperationResponse, List<PekarHistoryViewModel>>(data);
public static PekarHistoryOperationResponse OK(PekarHistoryViewModel data) =>
OK<PekarHistoryOperationResponse, PekarHistoryViewModel>(data);
public static PekarHistoryOperationResponse NoContent() =>
NoContent<PekarHistoryOperationResponse>();
public static PekarHistoryOperationResponse NotFound(string message) =>
NotFound<PekarHistoryOperationResponse>(message);
public static PekarHistoryOperationResponse BadRequest(string message) =>
BadRequest<PekarHistoryOperationResponse>(message);
public static PekarHistoryOperationResponse InternalServerError(string message) =>
InternalServerError<PekarHistoryOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class PekarOperationResponse : OperationResponse
{
public static PekarOperationResponse OK(List<PekarViewModel> data) =>
OK<PekarOperationResponse, List<PekarViewModel>>(data);
public static PekarOperationResponse OK(PekarViewModel data) =>
OK<PekarOperationResponse, PekarViewModel>(data);
public static PekarOperationResponse NoContent() =>
NoContent<PekarOperationResponse>();
public static PekarOperationResponse NotFound(string message) =>
NotFound<PekarOperationResponse>(message);
public static PekarOperationResponse BadRequest(string message) =>
BadRequest<PekarOperationResponse>(message);
public static PekarOperationResponse InternalServerError(string message) =>
InternalServerError<PekarOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class PositionOperationResponse : OperationResponse
{
public static PositionOperationResponse OK(List<PositionViewModel> data) =>
OK<PositionOperationResponse, List<PositionViewModel>>(data);
public static PositionOperationResponse OK(PositionViewModel data) =>
OK<PositionOperationResponse, PositionViewModel>(data);
public static PositionOperationResponse NoContent() =>
NoContent<PositionOperationResponse>();
public static PositionOperationResponse NotFound(string message) =>
NotFound<PositionOperationResponse>(message);
public static PositionOperationResponse BadRequest(string message) =>
BadRequest<PositionOperationResponse>(message);
public static PositionOperationResponse InternalServerError(string message) =>
InternalServerError<PositionOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class ProductOperationResponse : OperationResponse
{
public static ProductOperationResponse OK(List<ProductViewModel> data) =>
OK<ProductOperationResponse, List<ProductViewModel>>(data);
public static ProductOperationResponse OK(ProductViewModel data) =>
OK<ProductOperationResponse, ProductViewModel>(data);
public static ProductOperationResponse NoContent() =>
NoContent<ProductOperationResponse>();
public static ProductOperationResponse NotFound(string message) =>
NotFound<ProductOperationResponse>(message);
public static ProductOperationResponse BadRequest(string message) =>
BadRequest<ProductOperationResponse>(message);
public static ProductOperationResponse InternalServerError(string message) =>
InternalServerError<ProductOperationResponse>(message);
}

View File

@@ -0,0 +1,25 @@
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.Contracts.OperationResponses;
public class SalaryOperationResponse : OperationResponse
{
public static SalaryOperationResponse OK(List<SalaryViewModel> data) =>
OK<SalaryOperationResponse, List<SalaryViewModel>>(data);
public static SalaryOperationResponse OK(SalaryViewModel data) =>
OK<SalaryOperationResponse, SalaryViewModel>(data);
public static SalaryOperationResponse NoContent() =>
NoContent<SalaryOperationResponse>();
public static SalaryOperationResponse NotFound(string message) =>
NotFound<SalaryOperationResponse>(message);
public static SalaryOperationResponse BadRequest(string message) =>
BadRequest<SalaryOperationResponse>(message);
public static SalaryOperationResponse InternalServerError(string message) =>
InternalServerError<SalaryOperationResponse>(message);
}

View File

@@ -0,0 +1,9 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class IngredientViewModel
{
public required string Id { get; set; }
public required string Name { get; set; }
public required string Unit { get; set; }
public double Cost { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class OrderViewModel
{
public required string Id { get; set; }
public required string ProductId { get; set; }
public object Count { get; set; }
public object Status { get; set; }
public object DateCreate { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class PekarHistoryViewModel
{
public required string Id { get; set; }
public required string PekarId { get; set; }
public required string PositionId { get; set; }
public object DateStart { get; set; }
public object DateEnd { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class PekarViewModel
{
public required string Id { get; set; }
public object FIO { get; set; }
public object PhoneNumber { get; set; }
public object Login { get; set; }
public object Password { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class PositionViewModel
{
public required string Id { get; set; }
public object Name { get; set; }
public object SalaryRate { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class ProductViewModel
{
public required string Id { get; set; }
public object Name { get; set; }
public object Price { get; set; }
public object StorageCount { get; set; }
}

View File

@@ -0,0 +1,13 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class RecipeViewModel
{
public string? ProductId { get; set; }
public string? ProductName { get; set; }
public string? IngredientId { get; set; }
public string? IngredientName { get; set; }
public string? Unit { get; set; }
public int Quantity { get; set; }
public decimal Cost { get; set; }
public decimal TotalCost { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CandyHouseBase.Contracts.ViewModels;
public class SalaryViewModel
{
public required string Id { get; set; }
public required string PekarId { get; set; }
public string? PekarFIO { get; set; }
public object Amount { get; set; }
public object DateIssue { get; set; }
}

View File

@@ -4,20 +4,13 @@ using CandyHouseBase.Infrastructure;
namespace CandyHouseBase.DataModels
{
public class IngredientDataModel : IValidation
public class IngredientDataModel(string id, string name, string unit, decimal cost)
: IValidation
{
public string Id { get; private set; }
public string Name { get; private set; }
public string Unit { get; private set; }
public decimal Cost { get; private set; }
public IngredientDataModel(string id, string name, string unit, decimal cost)
{
Id = id;
Name = name;
Unit = unit;
Cost = cost;
}
public string Id { get; private set; } = id;
public string Name { get; private set; } = name;
public string Unit { get; private set; } = unit;
public decimal Cost { get; private set; } = cost;
public void Validate()
{

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IIngredientAdapter
{
IngredientOperationResponse GetList();
IngredientOperationResponse GetElement(string data);
IngredientOperationResponse Register(IngredientBindingModel model);
IngredientOperationResponse Update(IngredientBindingModel model);
IngredientOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IOrderAdapter
{
OrderOperationResponse GetList();
OrderOperationResponse GetElement(string data);
OrderOperationResponse Register(OrderBindingModel model);
OrderOperationResponse Update(OrderBindingModel model);
OrderOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IPekarAdapter
{
PekarOperationResponse GetList();
PekarOperationResponse GetElement(string data);
PekarOperationResponse Register(PekarBindingModel model);
PekarOperationResponse Update(PekarBindingModel model);
PekarOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IPekarHistoryAdapter
{
PekarHistoryOperationResponse GetList();
PekarHistoryOperationResponse GetElement(string data);
PekarHistoryOperationResponse Register(PekarHistoryBindingModel model);
PekarHistoryOperationResponse Update(PekarHistoryBindingModel model);
PekarHistoryOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IPositionAdapter
{
PositionOperationResponse GetList();
PositionOperationResponse GetElement(string data);
PositionOperationResponse Register(PositionBindingModel model);
PositionOperationResponse Update(PositionBindingModel model);
PositionOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface IProductAdapter
{
ProductOperationResponse GetList();
ProductOperationResponse GetElement(string data);
ProductOperationResponse Register(ProductBindingModel model);
ProductOperationResponse Update(ProductBindingModel model);
ProductOperationResponse Delete(string id);
}

View File

@@ -0,0 +1,14 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
namespace CandyHouseBase.Interfaces.Adapters;
public interface ISalaryAdapter
{
SalaryOperationResponse GetList();
SalaryOperationResponse GetElement(string data);
SalaryOperationResponse Register(SalaryBindingModel model);
SalaryOperationResponse Update(SalaryBindingModel model);
SalaryOperationResponse Delete(string id);
}

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using CandyHouseBase.DataModels;
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts

View File

@@ -4,10 +4,15 @@ using Microsoft.EntityFrameworkCore;
namespace CandyHouseDataBase;
public class CandyHouseDbContext(IConfigurationDatabase configurationDatabase) : DbContext
public class CandyHouseDbContext : DbContext
{
private readonly IConfigurationDatabase? _configurationDatabase = configurationDatabase;
private readonly IConfigurationDatabase? _configurationDatabase;
public CandyHouseDbContext(IConfigurationDatabase configurationDatabase)
{
_configurationDatabase = configurationDatabase;
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(_configurationDatabase?.ConnectionString);

View File

@@ -18,6 +18,7 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
</AssemblyAttribute>
<InternalsVisibleTo Include="CandyHouseWebApi" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />

View File

@@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CandyHouseTests", "CandyHou
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CandyHouseDataBase", "CandyHouseDataBase\CandyHouseDataBase.csproj", "{54F7ED2D-9E96-4546-BA6B-B65140E1F602}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CandyHouseWebApi", "CandyHouseWebApi\CandyHouseWebApi.csproj", "{4D0A5083-2F58-470C-8591-11EC2CE3B71B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +26,9 @@ Global
{54F7ED2D-9E96-4546-BA6B-B65140E1F602}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54F7ED2D-9E96-4546-BA6B-B65140E1F602}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54F7ED2D-9E96-4546-BA6B-B65140E1F602}.Release|Any CPU.Build.0 = Release|Any CPU
{4D0A5083-2F58-470C-8591-11EC2CE3B71B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D0A5083-2F58-470C-8591-11EC2CE3B71B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D0A5083-2F58-470C-8591-11EC2CE3B71B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D0A5083-2F58-470C-8591-11EC2CE3B71B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
@@ -9,25 +9,30 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-preview.1.25080.5" />
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="NUnit" Version="3.14.0" /> <!-- Updated to a recent version -->
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> <!-- Added test adapter -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" /> <!-- Added test SDK -->
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit.Analyzers" Version="4.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Serilog" Version="4.2.1-dev-02352" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CandyHouseBase\CandyHouseBase.csproj">
<Project>{5df70b46-31f7-4d15-8c60-52c0a0a364f0}</Project>
<Name>CandyHouseBase</Name>
</ProjectReference>
<ProjectReference Include="..\CandyHouseBase\CandyHouseBase.csproj"/>
<ProjectReference Include="..\CandyHouseDataBase\CandyHouseDataBase.csproj" />
<ProjectReference Include="..\CandyHouseWebApi\CandyHouseWebApi.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using NUnit.Framework;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using System;
using NUnit.Framework;
namespace CandyHouseTests.DataModelsTests
{
@@ -18,10 +18,10 @@ namespace CandyHouseTests.DataModelsTests
var ingredient = new IngredientDataModel(id, name, unit, cost);
Assert.AreEqual(id, ingredient.Id);
Assert.AreEqual(name, ingredient.Name);
Assert.AreEqual(unit, ingredient.Unit);
Assert.AreEqual(cost, ingredient.Cost);
Assert.That(id, Is.EqualTo(ingredient.Id));
Assert.That(name, Is.EqualTo(ingredient.Name));
Assert.That(unit, Is.EqualTo(ingredient.Unit));
Assert.That(cost, Is.EqualTo(ingredient.Cost));
}
[Test]

View File

@@ -24,14 +24,14 @@ namespace CandyHouseTests.DataModelsTests
var order = new OrderDataModel(id, customerName, orderDate, totalAmount, discountAmount, productId, pekarId,
statusType);
Assert.AreEqual(id, order.Id);
Assert.AreEqual(customerName, order.CustomerName);
Assert.AreEqual(orderDate, order.OrderDate);
Assert.AreEqual(totalAmount, order.TotalAmount);
Assert.AreEqual(discountAmount, order.DiscountAmount);
Assert.AreEqual(productId, order.ProductId);
Assert.AreEqual(pekarId, order.PekarId);
Assert.AreEqual(statusType, order.StatusType);
Assert.That(id, Is.EqualTo(order.Id));
Assert.That(customerName, Is.EqualTo(order.CustomerName));
Assert.That(orderDate, Is.EqualTo(order.OrderDate));
Assert.That(totalAmount, Is.EqualTo(order.TotalAmount));
Assert.That(discountAmount, Is.EqualTo(order.DiscountAmount));
Assert.That(productId, Is.EqualTo(order.ProductId));
Assert.That(pekarId, Is.EqualTo(order.PekarId));
Assert.That(statusType, Is.EqualTo(order.StatusType));
}
[Test]

View File

@@ -18,9 +18,9 @@ namespace CandyHouseTests.DataModelsTests
var pekar = new PekarDataModel(id, name, experience, 0, new List<ProductDataModel>());
Assert.AreEqual(id, pekar.Id);
Assert.AreEqual(name, pekar.FIO);
Assert.AreEqual(experience, pekar.Position);
Assert.That(id, Is.EqualTo(pekar.Id));
Assert.That(name, Is.EqualTo(pekar.FIO));
Assert.That(experience, Is.EqualTo(pekar.Position));
}
[Test]

View File

@@ -18,11 +18,11 @@ namespace CandyHouseTests.DataModelsTests
var peKarHistory = new PekarHistoryDataModel(peKarId, fio, positionId, bonusCoefficient, dateTime);
Assert.AreEqual(peKarId, peKarHistory.PekarId);
Assert.AreEqual(fio, peKarHistory.FIO);
Assert.AreEqual(positionId, peKarHistory.PositionId);
Assert.AreEqual(bonusCoefficient, peKarHistory.BonusCoefficient);
Assert.AreEqual(dateTime, peKarHistory.Date);
Assert.That(peKarId, Is.EqualTo(peKarHistory.PekarId));
Assert.That(fio, Is.EqualTo(peKarHistory.FIO));
Assert.That(positionId, Is.EqualTo(peKarHistory.PositionId));
Assert.That(bonusCoefficient, Is.EqualTo(peKarHistory.BonusCoefficient));
Assert.That(dateTime, Is.EqualTo(peKarHistory.Date));
}
}
}

View File

@@ -18,9 +18,9 @@ namespace CandyHouseTests.DataModelsTests
var position = new PositionDataModel(id, type, title);
Assert.AreEqual(id, position.Id);
Assert.AreEqual(type, position.Type);
Assert.AreEqual(title, position.Title);
Assert.That(id, Is.EqualTo(position.Id));
Assert.That(type, Is.EqualTo(position.Type));
Assert.That(title, Is.EqualTo(position.Title));
}
[Test]

View File

@@ -19,10 +19,10 @@ namespace CandyHouseTests.DataModelsTests
{ new IngredientDataModel(Guid.NewGuid().ToString(), "sugar", "Sugar", 10) };
var product = new ProductDataModel(id, name, description, ingredients);
Assert.AreEqual(id, product.Id);
Assert.AreEqual(name, product.Name);
Assert.AreEqual(description, product.Description);
Assert.AreEqual(ingredients, product.IngredientsItems);
Assert.That(id, Is.EqualTo(product.Id));
Assert.That(name, Is.EqualTo(product.Name));
Assert.That(description, Is.EqualTo(product.Description));
Assert.That(ingredients, Is.EqualTo(product.IngredientsItems));
}
[Test]

View File

@@ -17,9 +17,9 @@ namespace CandyHouseTests.DataModelsTests
var recipe = new RecipeDataModel(productId, ingredientId, quantity);
Assert.AreEqual(productId, recipe.ProductId);
Assert.AreEqual(ingredientId, recipe.IngredientId);
Assert.AreEqual(quantity, recipe.Quantity);
Assert.That(productId, Is.EqualTo(recipe.ProductId));
Assert.That(ingredientId, Is.EqualTo(recipe.IngredientId));
Assert.That(quantity, Is.EqualTo(recipe.Quantity));
}
[Test]

View File

@@ -19,12 +19,12 @@ namespace CandyHouseTests.DataModelsTests
var salaryData = new SalaryDataModel(id, pekarId, period, baseRate, bonusRate, totalSalary);
Assert.AreEqual(id, salaryData.Id);
Assert.AreEqual(pekarId, salaryData.PekarId);
Assert.AreEqual(period, salaryData.Period);
Assert.AreEqual(baseRate, salaryData.BaseRate);
Assert.AreEqual(bonusRate, salaryData.BonusRate);
Assert.AreEqual(totalSalary, salaryData.TotalSalary);
Assert.That(id, Is.EqualTo(salaryData.Id));
Assert.That(pekarId, Is.EqualTo(salaryData.PekarId));
Assert.That(period, Is.EqualTo(salaryData.Period));
Assert.That(baseRate, Is.EqualTo(salaryData.BaseRate));
Assert.That(bonusRate, Is.EqualTo(salaryData.BonusRate));
Assert.That(totalSalary, Is.EqualTo(salaryData.TotalSalary));
}
[Test]

View File

@@ -0,0 +1,106 @@
using CandyHouseDataBase;
using CandyHouseDataBase.Models;
using Microsoft.EntityFrameworkCore;
namespace CandyHouseTests.Infrastructure;
internal static class CandyHouseDbContextExtensions
{
public static Ingredient InsertIngredientToDatabaseAndReturn(this CandyHouseDbContext db, string? id = null, string name = "Flour", string unit = "kg", decimal cost = 1.0m)
{
var model = new Ingredient { Id = id ?? Guid.NewGuid().ToString(), Name = name, Unit = unit, Cost = cost };
db.Ingredients.Add(model);
db.SaveChanges();
return model;
}
public static Order InsertOrderToDatabaseAndReturn(this CandyHouseDbContext db, string productId, string pekarId, string? id = null)
{
var model = new Order
{
Id = id ?? Guid.NewGuid().ToString(),
ProductId = productId,
PekarId = pekarId,
OrderDate = DateTime.UtcNow,
TotalAmount = 100,
DiscountAmount = 10,
StatusType = CandyHouseBase.Enums.StatusType.Pending
};
db.Orders.Add(model);
db.SaveChanges();
return model;
}
public static Pekar InsertPekarToDatabaseAndReturn(this CandyHouseDbContext db, string? id = null, string fio = "Pekar", string positionId = "default", decimal bonus = 1)
{
var model = new Pekar { Id = id ?? Guid.NewGuid().ToString(), FIO = fio, PositionId = positionId, BonusCoefficient = bonus };
db.Pekars.Add(model);
db.SaveChanges();
return model;
}
public static Position InsertPositionToDatabaseAndReturn(this CandyHouseDbContext db, string? id = null, string title = "Baker")
{
var model = new Position { Id = id ?? Guid.NewGuid().ToString(), Title = title, IsActual = true };
db.Positions.Add(model);
db.SaveChanges();
return model;
}
public static Product InsertProductToDatabaseAndReturn(this CandyHouseDbContext db, string? id = null, string name = "Cake")
{
var model = new Product { Id = id ?? Guid.NewGuid().ToString(), Name = name, Description = "Delicious cake" };
db.Products.Add(model);
db.SaveChanges();
return model;
}
public static Salary InsertSalaryToDatabaseAndReturn(this CandyHouseDbContext db, string pekarId, DateTime? period = null)
{
var model = new Salary
{
Id = Guid.NewGuid().ToString(),
PekarId = pekarId,
Period = period ?? DateTime.UtcNow,
BaseRate = 1000,
BonusRate = 200,
TotalSalary = 1200
};
db.Salaries.Add(model);
db.SaveChanges();
return model;
}
public static PekarHistory InsertPekarHistoryToDatabaseAndReturn(this CandyHouseDbContext db, string pekarId, string positionId)
{
var model = new PekarHistory
{
Id = Guid.NewGuid().ToString(),
PekarId = pekarId,
PositionId = positionId,
FIO = "Pekar Hist",
Date = DateTime.UtcNow,
BonusCoefficient = 1.2m
};
db.PekarHistories.Add(model);
db.SaveChanges();
return model;
}
public static Recipe InsertRecipeToDatabaseAndReturn(this CandyHouseDbContext db, string productId, string ingredientId)
{
var model = new Recipe { ProductId = productId, IngredientId = ingredientId, Quantity = 1 };
db.Recipes.Add(model);
db.SaveChanges();
return model;
}
public static void RemoveIngredientsFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Ingredients\" CASCADE;");
public static void RemoveOrdersFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Orders\" CASCADE;");
public static void RemovePekarsFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Pekars\" CASCADE;");
public static void RemovePositionsFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Positions\" CASCADE;");
public static void RemoveProductsFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Products\" CASCADE;");
public static void RemoveSalariesFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Salaries\" CASCADE;");
public static void RemovePekarHistoriesFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"PekarHistories\" CASCADE;");
public static void RemoveRecipesFromDatabase(this CandyHouseDbContext db) => db.Database.ExecuteSqlRaw("TRUNCATE \"Recipes\" CASCADE;");
}

View File

@@ -0,0 +1,86 @@
using CandyHouseBase.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Diagnostics;
using CandyHouseWebApi;
namespace CandyHouseTests.Infrastructure;
internal class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram>
where TProgram : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Replace database configuration for tests
var databaseConfig = services.SingleOrDefault(x => x.ServiceType == typeof(IConfigurationDatabase));
if (databaseConfig is not null)
services.Remove(databaseConfig);
services.AddSingleton<IConfigurationDatabase, ConfigurationDatabaseTest>();
// Replace logger if needed
var loggerFactory = services.SingleOrDefault(x => x.ServiceType == typeof(LoggerFactory));
if (loggerFactory is not null)
services.Remove(loggerFactory);
// IMPORTANT: Don't remove or replace authentication services
// Just configure them for testing
// Configure JWT for testing
services.PostConfigure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
// For testing purposes, make validation less strict
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = AuthOptions.ISSUER,
ValidateAudience = true,
ValidAudience = AuthOptions.AUDIENCE,
ValidateLifetime = false, // Don't validate lifetime for tests
IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
ValidateIssuerSigningKey = true,
RequireExpirationTime = false,
ClockSkew = TimeSpan.FromMinutes(5)
};
// Log authentication events
options.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
Console.WriteLine("Token validated successfully!");
return System.Threading.Tasks.Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
Console.WriteLine($"Authentication failed: {context.Exception}");
return System.Threading.Tasks.Task.CompletedTask;
},
OnMessageReceived = context =>
{
var token = context.Token;
Console.WriteLine($"Token received: {token?.Substring(0, Math.Min(50, token?.Length ?? 0))}...");
return System.Threading.Tasks.Task.CompletedTask;
},
OnChallenge = context =>
{
Console.WriteLine($"Challenge: {context.Error}, {context.ErrorDescription}");
return System.Threading.Tasks.Task.CompletedTask;
}
};
});
});
// Use Development environment for testing
builder.UseEnvironment("Development");
base.ConfigureWebHost(builder);
}
}

View File

@@ -21,6 +21,7 @@ public class BaseStorageContractTest
[OneTimeTearDown]
public void OneTimeTearDown()
{
CandyHouseDbContext.Database.EnsureDeleted();
CandyHouseDbContext.Dispose();
}

View File

@@ -0,0 +1,127 @@
using System.Text;
using System.Text.Json;
using CandyHouseDataBase;
using CandyHouseTests.Infrastructure;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using CandyHouseBase.Infrastructure;
using System.Net.Http.Headers;
using CandyHouseWebApi;
namespace CandyHouseTests.WebApiControllersTests;
internal class BaseWebApiControllerTest
{
private WebApplicationFactory<Program> _webApplication;
protected HttpClient HttpClient { get; private set; }
protected CandyHouseDbContext CandyHouseDbContext { get; private set; }
protected static readonly JsonSerializerOptions JsonSerializerOptions = new() { PropertyNameCaseInsensitive = true };
[OneTimeSetUp]
public void OneTimeSetUp()
{
_webApplication = new CustomWebApplicationFactory<Program>();
HttpClient = _webApplication
.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
using var loggerFactory = new LoggerFactory();
loggerFactory.AddSerilog(new LoggerConfiguration()
.ReadFrom.Configuration(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build())
.CreateLogger());
services.AddSingleton(loggerFactory);
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
// Initialize database first
CandyHouseDbContext = _webApplication.Services.GetRequiredService<CandyHouseDbContext>();
CandyHouseDbContext.Database.EnsureDeleted();
CandyHouseDbContext.Database.EnsureCreated();
// IMPORTANT: Don't use the login endpoint - generate a token directly
// The error suggests there's an issue with the token format from the endpoint
var token = GenerateTestToken("user");
Console.WriteLine($"Generated token manually: {token.Substring(0, Math.Min(50, token.Length))}...");
// Set the token with proper Bearer format - using AuthenticationHeaderValue
HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// Let's make sure our auth header looks correct
var authHeader = HttpClient.DefaultRequestHeaders.Authorization;
Console.WriteLine($"Authorization header set: {authHeader?.Scheme} {authHeader?.Parameter?.Substring(0, Math.Min(50, authHeader?.Parameter?.Length ?? 0))}...");
// OPTIONAL: Add a delay to ensure any async setup completes
// System.Threading.Thread.Sleep(1000);
}
// Generate a token manually to avoid any issues with the login endpoint
private string GenerateTestToken(string username)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username),
new Claim(JwtRegisteredClaimNames.Sub, username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = AuthOptions.GetSymmetricSecurityKey();
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: AuthOptions.ISSUER,
audience: AuthOptions.AUDIENCE,
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
[OneTimeTearDown]
public void OneTimeTearDown()
{
CandyHouseDbContext?.Database.EnsureDeleted();
CandyHouseDbContext?.Dispose();
HttpClient?.Dispose();
_webApplication?.Dispose();
}
protected static async Task<T?> GetModelFromResponseAsync<T>(HttpResponseMessage response) =>
JsonSerializer.Deserialize<T>(await response.Content.ReadAsStringAsync(), JsonSerializerOptions);
protected static StringContent MakeContent(object model) =>
new(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json");
protected static void AssertElement(object actual, object expected)
{
foreach (var property in expected.GetType().GetProperties())
{
var actualValue = actual.GetType().GetProperty(property.Name)?.GetValue(actual);
var expectedValue = property.GetValue(expected);
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
continue;
Assert.That(actualValue, Is.EqualTo(expectedValue), $"Property {property.Name} does not match. Expected: {expectedValue}, Actual: {actualValue}");
}
}
}

View File

@@ -0,0 +1,118 @@
using CandyHouseBase.Contracts;
using CandyHouseTests.Infrastructure;
using System.Net;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using NUnit.Framework;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class IngredientControllerTests : BaseWebApiControllerTest
{
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemoveIngredientsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var ingredient = CandyHouseDbContext.InsertIngredientToDatabaseAndReturn(name: "Sugar");
CandyHouseDbContext.InsertIngredientToDatabaseAndReturn(name: "Salt");
//Act
var response = await HttpClient.GetAsync("/api/ingredients");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<IngredientViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
});
AssertElement(data.First(x => x.Id == ingredient.Id), ingredient);
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
var response = await HttpClient.GetAsync("/api/ingredients");
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<IngredientViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
var ingredient = CandyHouseDbContext.InsertIngredientToDatabaseAndReturn();
var response = await HttpClient.GetAsync($"/api/ingredients/{ingredient.Id}");
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
AssertElement(await GetModelFromResponseAsync<IngredientViewModel>(response), ingredient);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
CandyHouseDbContext.InsertIngredientToDatabaseAndReturn();
var response = await HttpClient.GetAsync($"/api/ingredients/{Guid.NewGuid()}");
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
var model = new IngredientBindingModel
{
Id = Guid.NewGuid().ToString(),
Name = "Cocoa",
Unit = "g",
Cost = 100
};
var response = await HttpClient.PostAsync("/api/ingredients", MakeContent(model));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
AssertElement(CandyHouseDbContext.Ingredients.First(x => x.Id == model.Id), model);
}
[Test]
public async Task Post_WhenDataIsIncorrect_ShouldBadRequest_Test()
{
var modelWithEmptyName = new IngredientBindingModel
{
Id = Guid.NewGuid().ToString(),
Name = "",
Unit = "g",
Cost = 1
};
var modelWithNegativeCost = new IngredientBindingModel
{
Id = Guid.NewGuid().ToString(),
Name = "Invalid",
Unit = "g",
Cost = -10
};
var response1 = await HttpClient.PostAsync("/api/ingredients", MakeContent(modelWithEmptyName));
var response2 = await HttpClient.PostAsync("/api/ingredients", MakeContent(modelWithNegativeCost));
Assert.Multiple(() =>
{
Assert.That(response1.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
Assert.That(response2.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
});
}
[Test]
public async Task Post_WhenSendEmptyData_ShouldBadRequest_Test()
{
var response = await HttpClient.PostAsync("/api/ingredients", MakeContent(string.Empty));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
}

View File

@@ -0,0 +1,245 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Enums;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class OrderControllerTests : BaseWebApiControllerTest
{
private string _pekarId;
private string _productId;
[SetUp]
public void SetUp()
{
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: position.Id);
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
_pekarId = pekar.Id;
_productId = product.Id;
}
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemoveOrdersFromDatabase();
CandyHouseDbContext.RemovePekarsFromDatabase();
CandyHouseDbContext.RemovePositionsFromDatabase();
CandyHouseDbContext.RemoveProductsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var order = CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
//Act
var response = await HttpClient.GetAsync($"/api/orders?fromDate={DateTime.UtcNow.AddDays(-1):yyyy-MM-dd}&toDate={DateTime.UtcNow.AddDays(1):yyyy-MM-dd}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<OrderViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
});
AssertElement(data.First(x => x.Id == order.Id), order);
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync($"/api/orders?fromDate={DateTime.UtcNow.AddDays(-1):yyyy-MM-dd}&toDate={DateTime.UtcNow.AddDays(1):yyyy-MM-dd}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<OrderViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_ByDateRange_ShouldSuccess_Test()
{
//Arrange
var yesterday = DateTime.UtcNow.AddDays(-1);
var tomorrow = DateTime.UtcNow.AddDays(1);
// Orders outside the range we'll query
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
var pastOrder = CandyHouseDbContext.Orders.First();
pastOrder.OrderDate = yesterday.AddDays(-1);
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
var futureOrder = CandyHouseDbContext.Orders.Skip(1).First();
futureOrder.OrderDate = tomorrow.AddDays(1);
// Orders within the range
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
var inRangeOrder = CandyHouseDbContext.Orders.Skip(2).First();
inRangeOrder.OrderDate = yesterday.AddHours(12);
CandyHouseDbContext.SaveChanges();
//Act
var response = await HttpClient.GetAsync($"/api/orders?fromDate={yesterday:yyyy-MM-dd}&toDate={tomorrow:yyyy-MM-dd}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<OrderViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(1));
}
[Test]
public async Task GetList_ByPekarId_ShouldSuccess_Test()
{
//Arrange
var anotherPekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Another Baker");
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, anotherPekar.Id);
//Act
var response = await HttpClient.GetAsync($"/api/orders/pekar/{_pekarId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<OrderViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(1));
Assert.That(data[0].ProductId, Is.EqualTo(_productId));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var order = CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
//Act
var response = await HttpClient.GetAsync($"/api/orders/{order.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<OrderViewModel>(response);
AssertElement(result, order);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Arrange
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
//Act
var response = await HttpClient.GetAsync($"/api/orders/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var orderModel = CreateModel(_productId, _pekarId);
//Act
var response = await HttpClient.PostAsync($"/api/orders", MakeContent(orderModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedOrder = CandyHouseDbContext.Orders.FirstOrDefault(x => x.Id == orderModel.Id);
Assert.That(savedOrder, Is.Not.Null);
Assert.That(savedOrder.ProductId, Is.EqualTo(orderModel.ProductId));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var orderModel = CreateModel(_productId, _pekarId);
CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId, orderModel.Id);
//Act
var response = await HttpClient.PostAsync($"/api/orders", MakeContent(orderModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
var order = CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
var orderModel = new OrderBindingModel
{
Id = order.Id,
ProductId = _productId,
Count = 5,
Status = StatusType.Completed,
DateCreate = DateTime.UtcNow
};
//Act
var response = await HttpClient.PutAsync($"/api/orders", MakeContent(orderModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedOrder = CandyHouseDbContext.Orders.FirstOrDefault(x => x.Id == order.Id);
Assert.That(updatedOrder, Is.Not.Null);
Assert.That(updatedOrder.StatusType, Is.EqualTo(StatusType.Completed));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var orderModel = CreateModel(_productId, _pekarId);
//Act
var response = await HttpClient.PutAsync($"/api/orders", MakeContent(orderModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var order = CandyHouseDbContext.InsertOrderToDatabaseAndReturn(_productId, _pekarId);
//Act
var response = await HttpClient.DeleteAsync($"/api/orders/{order.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedOrder = CandyHouseDbContext.Orders.FirstOrDefault(x => x.Id == order.Id);
// Check that the order is completely deleted or marked as canceled in some way
Assert.That(deletedOrder, Is.Null);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/orders/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static OrderBindingModel CreateModel(string productId, string pekarId, string? id = null)
{
return new OrderBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
ProductId = productId,
Count = 1,
Status = StatusType.Pending,
DateCreate = DateTime.UtcNow
};
}
}

View File

@@ -0,0 +1,259 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class PekarControllerTests : BaseWebApiControllerTest
{
private Position _position;
[SetUp]
public void SetUp()
{
_position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
}
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemovePekarsFromDatabase();
CandyHouseDbContext.RemovePositionsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Ivan Petrov", positionId: _position.Id);
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Maria Ivanova", positionId: _position.Id);
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Alex Smith", positionId: _position.Id);
//Act
var response = await HttpClient.GetAsync("/api/pekars");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(3));
});
AssertElement(data.First(x => x.Id == pekar.Id), pekar);
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync("/api/pekars");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_OnlyActive_ShouldSuccess_Test()
{
//Arrange
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Inactive Baker", positionId: _position.Id);
var inactivePekar = CandyHouseDbContext.Pekars.First(x => x.FIO == "Inactive Baker");
inactivePekar.IsDeleted = true;
CandyHouseDbContext.SaveChanges();
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Active Baker", positionId: _position.Id);
//Act
var response = await HttpClient.GetAsync("/api/pekars?onlyActive=true");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(1));
Assert.That(data[0].FIO, Is.EqualTo("Active Baker"));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: _position.Id);
//Act
var response = await HttpClient.GetAsync($"/api/pekars/{pekar.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<PekarViewModel>(response);
AssertElement(result, pekar);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Arrange
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: _position.Id);
//Act
var response = await HttpClient.GetAsync($"/api/pekars/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ById_WhenRecordWasDeleted_ShouldNotFound_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: _position.Id);
pekar.IsDeleted = true;
CandyHouseDbContext.SaveChanges();
//Act
var response = await HttpClient.GetAsync($"/api/pekars/{pekar.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ByFIO_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Unique Baker", positionId: _position.Id);
//Act
var response = await HttpClient.GetAsync($"/api/pekars/fio/{pekar.FIO}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<PekarViewModel>(response);
AssertElement(result, pekar);
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var pekarModel = CreateModel(_position.Id);
//Act
var response = await HttpClient.PostAsync($"/api/pekars", MakeContent(pekarModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedPekar = CandyHouseDbContext.Pekars.FirstOrDefault(x => x.Id == pekarModel.Id);
Assert.That(savedPekar, Is.Not.Null);
Assert.That(savedPekar.FIO, Is.EqualTo(pekarModel.FIO.ToString()));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var pekarModel = CreateModel(_position.Id);
CandyHouseDbContext.InsertPekarToDatabaseAndReturn(pekarModel.Id, positionId: _position.Id);
//Act
var response = await HttpClient.PostAsync($"/api/pekars", MakeContent(pekarModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenDataIsIncorrect_ShouldBadRequest_Test()
{
//Arrange
var pekarModelWithInvalidFIO = new PekarBindingModel
{
Id = Guid.NewGuid().ToString(), FIO = "", PhoneNumber = "+7-123-456-7890", Login = "baker1",
Password = "password"
};
var pekarModelWithInvalidPhone = new PekarBindingModel
{
Id = Guid.NewGuid().ToString(), FIO = "Valid Name", PhoneNumber = "invalid", Login = "baker1",
Password = "password"
};
//Act
var responseWithInvalidFIO = await HttpClient.PostAsync($"/api/pekars", MakeContent(pekarModelWithInvalidFIO));
var responseWithInvalidPhone =
await HttpClient.PostAsync($"/api/pekars", MakeContent(pekarModelWithInvalidPhone));
//Assert
Assert.Multiple(() =>
{
Assert.That(responseWithInvalidFIO.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "FIO is invalid");
Assert.That(responseWithInvalidPhone.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest),
"Phone number is invalid");
});
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: _position.Id);
var pekarModel = new PekarBindingModel
{
Id = pekar.Id,
FIO = "Updated Baker",
PhoneNumber = "+7-999-888-7777",
Login = "updated_login",
Password = "updated_password"
};
//Act
var response = await HttpClient.PutAsync($"/api/pekars", MakeContent(pekarModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedPekar = CandyHouseDbContext.Pekars.FirstOrDefault(x => x.Id == pekar.Id);
Assert.That(updatedPekar, Is.Not.Null);
Assert.That(updatedPekar.FIO, Is.EqualTo(pekarModel.FIO.ToString()));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var pekarModel = CreateModel(_position.Id);
//Act
var response = await HttpClient.PutAsync($"/api/pekars", MakeContent(pekarModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: _position.Id);
//Act
var response = await HttpClient.DeleteAsync($"/api/pekars/{pekar.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedPekar = CandyHouseDbContext.Pekars.FirstOrDefault(x => x.Id == pekar.Id);
Assert.That(deletedPekar.IsDeleted, Is.True);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/pekars/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static PekarBindingModel CreateModel(string positionId, string? id = null, string fio = "Test Baker")
{
return new PekarBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
FIO = fio,
PhoneNumber = "+7-123-456-7890",
Login = "baker1",
Password = "password"
};
}
}

View File

@@ -0,0 +1,207 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class PekarHistoryControllerTests : BaseWebApiControllerTest
{
private string _pekarId;
private string _positionId;
[SetUp]
public void SetUp()
{
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: position.Id);
_pekarId = pekar.Id;
_positionId = position.Id;
}
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemovePekarHistoriesFromDatabase();
CandyHouseDbContext.RemovePekarsFromDatabase();
CandyHouseDbContext.RemovePositionsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var history = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
//Act
var response = await HttpClient.GetAsync("/api/pekarhistory");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarHistoryViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
});
Assert.That(data.Any(x => x.Id == history.Id));
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync("/api/pekarhistory");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarHistoryViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_ByPekarId_ShouldSuccess_Test()
{
//Arrange
var anotherPekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Another Baker");
CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(anotherPekar.Id, _positionId);
//Act
var response = await HttpClient.GetAsync($"/api/pekarhistory/pekar/{_pekarId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarHistoryViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(2));
Assert.That(data.All(x => x.PekarId == _pekarId));
});
}
[Test]
public async Task GetList_ByPeriod_ShouldSuccess_Test()
{
//Arrange
var yesterday = DateTime.UtcNow.AddDays(-1);
var tomorrow = DateTime.UtcNow.AddDays(1);
var lastWeek = DateTime.UtcNow.AddDays(-7);
var nextWeek = DateTime.UtcNow.AddDays(7);
var h1 = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
h1.Date = yesterday;
var h2 = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
h2.Date = lastWeek;
var h3 = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
h3.Date = nextWeek;
CandyHouseDbContext.SaveChanges();
//Act
var response = await HttpClient.GetAsync($"/api/pekarhistory/period?fromDate={yesterday.AddHours(-1):yyyy-MM-dd HH:mm:ss}&toDate={tomorrow:yyyy-MM-dd HH:mm:ss}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PekarHistoryViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(1));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var history = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
//Act
var response = await HttpClient.GetAsync($"/api/pekarhistory/{history.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<PekarHistoryViewModel>(response);
AssertElement(result, history);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Act
var response = await HttpClient.GetAsync($"/api/pekarhistory/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var historyModel = CreateModel(_pekarId, _positionId);
//Act
var response = await HttpClient.PostAsync($"/api/pekarhistory", MakeContent(historyModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedHistory = CandyHouseDbContext.PekarHistories.FirstOrDefault(x => x.Id == historyModel.Id);
Assert.That(savedHistory, Is.Not.Null);
Assert.That(savedHistory.PekarId, Is.EqualTo(historyModel.PekarId));
Assert.That(savedHistory.PositionId, Is.EqualTo(historyModel.PositionId));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var historyModel = CreateModel(_pekarId, _positionId);
var existingHistory = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
historyModel.Id = existingHistory.Id;
//Act
var response = await HttpClient.PostAsync($"/api/pekarhistory", MakeContent(historyModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var history = CandyHouseDbContext.InsertPekarHistoryToDatabaseAndReturn(_pekarId, _positionId);
//Act
var response = await HttpClient.DeleteAsync($"/api/pekarhistory/{history.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedHistory = CandyHouseDbContext.PekarHistories.FirstOrDefault(x => x.Id == history.Id);
Assert.That(deletedHistory, Is.Null);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/pekarhistory/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static PekarHistoryBindingModel CreateModel(string pekarId, string positionId, string? id = null)
{
return new PekarHistoryBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
PekarId = pekarId,
PositionId = positionId,
DateStart = DateTime.UtcNow.AddDays(-30),
DateEnd = DateTime.UtcNow
};
}
}

View File

@@ -0,0 +1,249 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class PositionControllerTests : BaseWebApiControllerTest
{
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemovePekarsFromDatabase();
CandyHouseDbContext.RemovePositionsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Head Baker");
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Pastry Chef");
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Assistant");
//Act
var response = await HttpClient.GetAsync("/api/positions");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PositionViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(3));
});
AssertElement(data.First(x => x.Id == position.Id), position);
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync("/api/positions");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PositionViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_OnlyActual_ShouldSuccess_Test()
{
//Arrange
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Obsolete Position");
var positionToUpdate = CandyHouseDbContext.Positions.First(x => x.Title == "Obsolete Position");
positionToUpdate.IsActual = false;
CandyHouseDbContext.SaveChanges();
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Current Position");
//Act
var response = await HttpClient.GetAsync("/api/positions?onlyActual=true");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<PositionViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(1));
Assert.That(data[0].Name, Is.EqualTo("Current Position"));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/positions/{position.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<PositionViewModel>(response);
AssertElement(result, position);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Arrange
CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/positions/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ById_WhenRecordWasDeleted_ShouldNotFound_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
position.IsActual = false;
CandyHouseDbContext.SaveChanges();
//Act
var response = await HttpClient.GetAsync($"/api/positions/{position.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ByTitle_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: "Master Baker");
//Act
var response = await HttpClient.GetAsync($"/api/positions/title/{position.Title}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<PositionViewModel>(response);
AssertElement(result, position);
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var positionModel = CreateModel();
//Act
var response = await HttpClient.PostAsync($"/api/positions", MakeContent(positionModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedPosition = CandyHouseDbContext.Positions.FirstOrDefault(x => x.Id == positionModel.Id);
Assert.That(savedPosition, Is.Not.Null);
Assert.That(savedPosition.Title, Is.EqualTo(positionModel.Name.ToString()));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var positionModel = CreateModel();
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(positionModel.Id);
//Act
var response = await HttpClient.PostAsync($"/api/positions", MakeContent(positionModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenHaveRecordWithSameTitle_ShouldBadRequest_Test()
{
//Arrange
var positionModel = CreateModel(name: "Unique Position");
CandyHouseDbContext.InsertPositionToDatabaseAndReturn(title: positionModel.Name.ToString());
//Act
var response = await HttpClient.PostAsync($"/api/positions", MakeContent(positionModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenDataIsIncorrect_ShouldBadRequest_Test()
{
//Arrange
var positionModelWithInvalidName = new PositionBindingModel { Id = Guid.NewGuid().ToString(), Name = "", SalaryRate = 1000 };
var positionModelWithInvalidSalary = new PositionBindingModel { Id = Guid.NewGuid().ToString(), Name = "Valid Name", SalaryRate = -100 };
//Act
var responseWithInvalidName = await HttpClient.PostAsync($"/api/positions", MakeContent(positionModelWithInvalidName));
var responseWithInvalidSalary = await HttpClient.PostAsync($"/api/positions", MakeContent(positionModelWithInvalidSalary));
//Assert
Assert.Multiple(() =>
{
Assert.That(responseWithInvalidName.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Name is invalid");
Assert.That(responseWithInvalidSalary.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Salary is invalid");
});
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
var positionModel = new PositionBindingModel
{
Id = position.Id,
Name = "Updated Position",
SalaryRate = 2500
};
//Act
var response = await HttpClient.PutAsync($"/api/positions", MakeContent(positionModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedPosition = CandyHouseDbContext.Positions.FirstOrDefault(x => x.Id == position.Id);
Assert.That(updatedPosition, Is.Not.Null);
Assert.That(updatedPosition.Title, Is.EqualTo(positionModel.Name.ToString()));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var positionModel = CreateModel();
//Act
var response = await HttpClient.PutAsync($"/api/positions", MakeContent(positionModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
//Act
var response = await HttpClient.DeleteAsync($"/api/positions/{position.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedPosition = CandyHouseDbContext.Positions.FirstOrDefault(x => x.Id == position.Id);
Assert.That(deletedPosition.IsActual, Is.False);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/positions/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static PositionBindingModel CreateModel(string? id = null, string name = "Baker Position")
{
return new PositionBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
Name = name,
SalaryRate = 2000
};
}
}

View File

@@ -0,0 +1,239 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class ProductControllerTests : BaseWebApiControllerTest
{
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemoveRecipesFromDatabase();
CandyHouseDbContext.RemoveProductsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: "Donut");
CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: "Cupcake");
CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: "Cookie");
//Act
var response = await HttpClient.GetAsync("/api/products");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<ProductViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(3));
});
AssertElement(data.First(x => x.Id == product.Id), product);
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync("/api/products");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<ProductViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/products/{product.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<ProductViewModel>(response);
AssertElement(result, product);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Arrange
CandyHouseDbContext.InsertProductToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/products/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ById_WhenRecordWasDeleted_ShouldNotFound_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
product.IsDeleted = true;
CandyHouseDbContext.SaveChanges();
//Act
var response = await HttpClient.GetAsync($"/api/products/{product.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task GetElement_ByName_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/products/name/{product.Name}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<ProductViewModel>(response);
AssertElement(result, product);
}
[Test]
public async Task GetElement_ByName_WhenNoRecord_ShouldNotFound_Test()
{
//Arrange
CandyHouseDbContext.InsertProductToDatabaseAndReturn();
//Act
var response = await HttpClient.GetAsync($"/api/products/name/NonExistentProduct");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var productModel = CreateModel();
//Act
var response = await HttpClient.PostAsync($"/api/products", MakeContent(productModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedProduct = CandyHouseDbContext.Products.FirstOrDefault(x => x.Id == productModel.Id);
Assert.That(savedProduct, Is.Not.Null);
Assert.That(savedProduct.Name, Is.EqualTo(productModel.Name.ToString()));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var productModel = CreateModel();
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn(productModel.Id);
//Act
var response = await HttpClient.PostAsync($"/api/products", MakeContent(productModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenHaveRecordWithSameName_ShouldBadRequest_Test()
{
//Arrange
var productModel = CreateModel();
CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: productModel.Name.ToString());
//Act
var response = await HttpClient.PostAsync($"/api/products", MakeContent(productModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenDataIsIncorrect_ShouldBadRequest_Test()
{
//Arrange
var productModelWithInvalidName = new ProductBindingModel { Id = Guid.NewGuid().ToString(), Name = "", Price = 10, StorageCount = 5 };
var productModelWithInvalidPrice = new ProductBindingModel { Id = Guid.NewGuid().ToString(), Name = "Valid Name", Price = -10, StorageCount = 5 };
//Act
var responseWithInvalidName = await HttpClient.PostAsync($"/api/products", MakeContent(productModelWithInvalidName));
var responseWithInvalidPrice = await HttpClient.PostAsync($"/api/products", MakeContent(productModelWithInvalidPrice));
//Assert
Assert.Multiple(() =>
{
Assert.That(responseWithInvalidName.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Name is invalid");
Assert.That(responseWithInvalidPrice.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Price is invalid");
});
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
var productModel = new ProductBindingModel
{
Id = product.Id,
Name = "Updated Product",
Price = 15.99,
StorageCount = 50
};
//Act
var response = await HttpClient.PutAsync($"/api/products", MakeContent(productModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedProduct = CandyHouseDbContext.Products.FirstOrDefault(x => x.Id == product.Id);
Assert.That(updatedProduct, Is.Not.Null);
Assert.That(updatedProduct.Name, Is.EqualTo(productModel.Name.ToString()));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var productModel = CreateModel();
//Act
var response = await HttpClient.PutAsync($"/api/products", MakeContent(productModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
//Act
var response = await HttpClient.DeleteAsync($"/api/products/{product.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedProduct = CandyHouseDbContext.Products.FirstOrDefault(x => x.Id == product.Id);
Assert.That(deletedProduct.IsDeleted, Is.True);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/products/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static ProductBindingModel CreateModel(string? id = null, string name = "Test Product")
{
return new ProductBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
Name = name,
Price = 9.99,
StorageCount = 10
};
}
}

View File

@@ -0,0 +1,212 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class RecipeControllerTests : BaseWebApiControllerTest
{
private string _productId;
private string _ingredientId;
[SetUp]
public void SetUp()
{
var product = CandyHouseDbContext.InsertProductToDatabaseAndReturn();
var ingredient = CandyHouseDbContext.InsertIngredientToDatabaseAndReturn();
_productId = product.Id;
_ingredientId = ingredient.Id;
}
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemoveRecipesFromDatabase();
CandyHouseDbContext.RemoveProductsFromDatabase();
CandyHouseDbContext.RemoveIngredientsFromDatabase();
}
[Test]
public async Task GetList_ByProduct_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var recipe = CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
var secondIngredient = CandyHouseDbContext.InsertIngredientToDatabaseAndReturn(name: "Sugar");
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, secondIngredient.Id);
//Act
var response = await HttpClient.GetAsync($"/api/recipes/product/{_productId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<RecipeViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
Assert.That(data.All(x => x.ProductId == _productId));
});
}
[Test]
public async Task GetList_ByProduct_WhenNoRecords_ShouldSuccess_Test()
{
//Arrange
var anotherProduct = CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: "Another Product");
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(anotherProduct.Id, _ingredientId);
//Act
var response = await HttpClient.GetAsync($"/api/recipes/product/{_productId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<RecipeViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_ByIngredient_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var recipe = CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
var secondProduct = CandyHouseDbContext.InsertProductToDatabaseAndReturn(name: "Muffin");
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(secondProduct.Id, _ingredientId);
//Act
var response = await HttpClient.GetAsync($"/api/recipes/ingredient/{_ingredientId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<RecipeViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
Assert.That(data.All(x => x.IngredientId == _ingredientId));
});
}
[Test]
public async Task GetElement_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
//Act
var response = await HttpClient.GetAsync($"/api/recipes/{_productId}/{_ingredientId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<RecipeViewModel>(response);
Assert.That(result, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(result.ProductId, Is.EqualTo(_productId));
Assert.That(result.IngredientId, Is.EqualTo(_ingredientId));
});
}
[Test]
public async Task GetElement_WhenNoRecord_ShouldNotFound_Test()
{
//Act
var response = await HttpClient.GetAsync($"/api/recipes/{_productId}/{_ingredientId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var recipeModel = CreateModel(_productId, _ingredientId);
//Act
var response = await HttpClient.PostAsync($"/api/recipes", MakeContent(recipeModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedRecipe = CandyHouseDbContext.Recipes.FirstOrDefault(x =>
x.ProductId == recipeModel.ProductId && x.IngredientId == recipeModel.IngredientId);
Assert.That(savedRecipe, Is.Not.Null);
Assert.That(savedRecipe.Quantity, Is.EqualTo(recipeModel.Quantity));
}
[Test]
public async Task Post_WhenRecordAlreadyExists_ShouldBadRequest_Test()
{
//Arrange
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
var recipeModel = CreateModel(_productId, _ingredientId);
//Act
var response = await HttpClient.PostAsync($"/api/recipes", MakeContent(recipeModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
var recipeModel = CreateModel(_productId, _ingredientId, 5);
//Act
var response = await HttpClient.PutAsync($"/api/recipes", MakeContent(recipeModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedRecipe = CandyHouseDbContext.Recipes.FirstOrDefault(x =>
x.ProductId == recipeModel.ProductId && x.IngredientId == recipeModel.IngredientId);
Assert.That(updatedRecipe, Is.Not.Null);
Assert.That(updatedRecipe.Quantity, Is.EqualTo(recipeModel.Quantity));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var recipeModel = CreateModel(_productId, _ingredientId);
//Act
var response = await HttpClient.PutAsync($"/api/recipes", MakeContent(recipeModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
CandyHouseDbContext.InsertRecipeToDatabaseAndReturn(_productId, _ingredientId);
//Act
var response = await HttpClient.DeleteAsync($"/api/recipes/{_productId}/{_ingredientId}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedRecipe = CandyHouseDbContext.Recipes.FirstOrDefault(x =>
x.ProductId == _productId && x.IngredientId == _ingredientId);
Assert.That(deletedRecipe, Is.Null);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/recipes/{_productId}/{_ingredientId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
private static RecipeBindingModel CreateModel(string productId, string ingredientId, int quantity = 2)
{
return new RecipeBindingModel
{
ProductId = productId,
IngredientId = ingredientId,
Quantity = quantity
};
}
}

View File

@@ -0,0 +1,367 @@
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseDataBase.Models;
using CandyHouseTests.Infrastructure;
using System.Net;
namespace CandyHouseTests.WebApiControllersTests;
[TestFixture]
internal class SalaryControllerTests : BaseWebApiControllerTest
{
private string _pekarId;
[SetUp]
public void SetUp()
{
var position = CandyHouseDbContext.InsertPositionToDatabaseAndReturn();
var pekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(positionId: position.Id);
_pekarId = pekar.Id;
}
[TearDown]
public void TearDown()
{
CandyHouseDbContext.RemoveSalariesFromDatabase();
CandyHouseDbContext.RemovePekarsFromDatabase();
CandyHouseDbContext.RemovePositionsFromDatabase();
}
[Test]
public async Task GetList_WhenHaveRecords_ShouldSuccess_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, DateTime.UtcNow.AddMonths(-1));
//Act
var response = await HttpClient.GetAsync("/api/salaries");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<SalaryViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(2));
});
Assert.That(data.Any(x => x.Id == salary.Id));
}
[Test]
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
{
//Act
var response = await HttpClient.GetAsync("/api/salaries");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<SalaryViewModel>>(response);
Assert.Multiple(() =>
{
Assert.That(data, Is.Not.Null);
Assert.That(data, Has.Count.EqualTo(0));
});
}
[Test]
public async Task GetList_ByPekarId_ShouldSuccess_Test()
{
//Arrange
var anotherPekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Another Baker");
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, DateTime.UtcNow.AddMonths(-1));
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(anotherPekar.Id);
//Act
var response = await HttpClient.GetAsync($"/api/salaries/pekar/{_pekarId}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<SalaryViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(2));
Assert.That(data.All(x => x.PekarId == _pekarId));
});
}
[Test]
public async Task GetList_ByPeriod_ShouldSuccess_Test()
{
//Arrange
var currentMonth = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1);
var lastMonth = currentMonth.AddMonths(-1);
var twoMonthsAgo = currentMonth.AddMonths(-2);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, currentMonth);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, lastMonth);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, twoMonthsAgo);
//Act
var response = await HttpClient.GetAsync($"/api/salaries/period?fromDate={lastMonth:yyyy-MM-dd}&toDate={currentMonth.AddDays(28):yyyy-MM-dd}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<SalaryViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(2));
});
}
[Test]
public async Task GetList_ByPekarIdAndPeriod_ShouldSuccess_Test()
{
//Arrange
var anotherPekar = CandyHouseDbContext.InsertPekarToDatabaseAndReturn(fio: "Another Baker");
var currentMonth = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1);
var lastMonth = currentMonth.AddMonths(-1);
// Create salary records for both pekars in different periods
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, currentMonth);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId, lastMonth);
CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(anotherPekar.Id, currentMonth);
//Act
var response = await HttpClient.GetAsync($"/api/salaries/pekar/{_pekarId}/period?fromDate={lastMonth:yyyy-MM-dd}&toDate={currentMonth.AddDays(28):yyyy-MM-dd}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var data = await GetModelFromResponseAsync<List<SalaryViewModel>>(response);
Assert.That(data, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(data, Has.Count.EqualTo(2));
Assert.That(data.All(x => x.PekarId == _pekarId));
});
}
[Test]
public async Task GetElement_ById_WhenHaveRecord_ShouldSuccess_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
//Act
var response = await HttpClient.GetAsync($"/api/salaries/{salary.Id}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var result = await GetModelFromResponseAsync<SalaryViewModel>(response);
AssertElement(result, salary);
}
[Test]
public async Task GetElement_ById_WhenNoRecord_ShouldNotFound_Test()
{
//Act
var response = await HttpClient.GetAsync($"/api/salaries/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
[Test]
public async Task Post_ShouldSuccess_Test()
{
//Arrange
var salaryModel = CreateModel(_pekarId);
//Act
var response = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
var savedSalary = CandyHouseDbContext.Salaries.FirstOrDefault(x => x.Id == salaryModel.Id);
Assert.That(savedSalary, Is.Not.Null);
Assert.That(savedSalary.PekarId, Is.EqualTo(salaryModel.PekarId));
}
[Test]
public async Task Post_WhenHaveRecordWithSameId_ShouldBadRequest_Test()
{
//Arrange
var salaryModel = CreateModel(_pekarId);
var existingSalary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
salaryModel.Id = existingSalary.Id;
//Act
var response = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WhenPekarDoesNotExist_ShouldBadRequest_Test()
{
//Arrange
var salaryModel = new SalaryBindingModel
{
Id = Guid.NewGuid().ToString(),
PekarId = Guid.NewGuid().ToString(), // Non-existent pekar ID
Amount = 1000,
DateIssue = DateTime.UtcNow
};
//Act
var response = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Post_WithInvalidData_ShouldBadRequest_Test()
{
//Arrange
var salaryModelWithNegativeAmount = new SalaryBindingModel
{
Id = Guid.NewGuid().ToString(),
PekarId = _pekarId,
Amount = -500,
DateIssue = DateTime.UtcNow
};
var salaryModelWithoutPekarId = new SalaryBindingModel
{
Id = Guid.NewGuid().ToString(),
PekarId = null,
Amount = 500,
DateIssue = DateTime.UtcNow
};
var salaryModelWithFutureDate = new SalaryBindingModel
{
Id = Guid.NewGuid().ToString(),
PekarId = _pekarId,
Amount = 500,
DateIssue = DateTime.UtcNow.AddMonths(1) // Future date
};
//Act
var responseWithNegativeAmount = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModelWithNegativeAmount));
var responseWithoutPekarId = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModelWithoutPekarId));
var responseWithFutureDate = await HttpClient.PostAsync($"/api/salaries", MakeContent(salaryModelWithFutureDate));
//Assert
Assert.Multiple(() =>
{
Assert.That(responseWithNegativeAmount.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Amount is negative");
Assert.That(responseWithoutPekarId.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "PekarId is missing");
Assert.That(responseWithFutureDate.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Date is in the future");
});
}
[Test]
public async Task Put_ShouldSuccess_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
var salaryModel = new SalaryBindingModel
{
Id = salary.Id,
PekarId = _pekarId,
Amount = 1500, // Updated amount
DateIssue = DateTime.UtcNow
};
//Act
var response = await HttpClient.PutAsync($"/api/salaries", MakeContent(salaryModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var updatedSalary = CandyHouseDbContext.Salaries.FirstOrDefault(x => x.Id == salary.Id);
Assert.That(updatedSalary, Is.Not.Null);
Assert.That(updatedSalary.TotalSalary, Is.EqualTo(1500));
}
[Test]
public async Task Put_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Arrange
var salaryModel = CreateModel(_pekarId);
//Act
var response = await HttpClient.PutAsync($"/api/salaries", MakeContent(salaryModel));
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Put_WithInvalidData_ShouldBadRequest_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
var salaryModelWithNegativeAmount = new SalaryBindingModel
{
Id = salary.Id,
PekarId = _pekarId,
Amount = -500,
DateIssue = DateTime.UtcNow
};
//Act
var responseWithNegativeAmount = await HttpClient.PutAsync($"/api/salaries", MakeContent(salaryModelWithNegativeAmount));
//Assert
Assert.That(responseWithNegativeAmount.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest), "Amount is negative");
}
[Test]
public async Task Delete_ShouldSuccess_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
//Act
var response = await HttpClient.DeleteAsync($"/api/salaries/{salary.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
var deletedSalary = CandyHouseDbContext.Salaries.FirstOrDefault(x => x.Id == salary.Id);
Assert.That(deletedSalary, Is.Null);
});
}
[Test]
public async Task Delete_WhenNoFoundRecord_ShouldBadRequest_Test()
{
//Act
var response = await HttpClient.DeleteAsync($"/api/salaries/{Guid.NewGuid()}");
//Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task Delete_ShouldUpdateRelatedEntities_Test()
{
//Arrange
var salary = CandyHouseDbContext.InsertSalaryToDatabaseAndReturn(_pekarId);
// Create a reference to this salary in another entity if needed
// For example, if there's a bonus record linked to this salary
//Act
var response = await HttpClient.DeleteAsync($"/api/salaries/{salary.Id}");
//Assert
Assert.Multiple(() =>
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
CandyHouseDbContext.ChangeTracker.Clear();
// Check that the salary was deleted
var deletedSalary = CandyHouseDbContext.Salaries.FirstOrDefault(x => x.Id == salary.Id);
Assert.That(deletedSalary, Is.Null);
// Check that the pekar still exists and is not affected
var pekar = CandyHouseDbContext.Pekars.FirstOrDefault(x => x.Id == _pekarId);
Assert.That(pekar, Is.Not.Null);
});
}
private static SalaryBindingModel CreateModel(string pekarId, string? id = null)
{
return new SalaryBindingModel
{
Id = id ?? Guid.NewGuid().ToString(),
PekarId = pekarId,
Amount = 1000,
DateIssue = DateTime.UtcNow
};
}
}

View File

@@ -0,0 +1,28 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information"
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "../logs/cathaspaws-.log",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj}{Exception}{NewLine}"
}
}
]
},
"AllowedHosts": "*",
"DataBaseSettings": {
"ConnectionString": "Host=127.0.0.1;Port=5432;Database=CandyHouseTest;Username=postgres;Password=postgres;"
}
}

View File

@@ -0,0 +1,105 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces.Adapters;
namespace CandyHouseWebApi.Adapters;
public class IngredientAdapter : IIngredientAdapter
{
private readonly IIngredientBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public IngredientAdapter(IIngredientBusinessLogicContact logic, ILogger<IngredientAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<IngredientBindingModel, IngredientDataModel>();
cfg.CreateMap<IngredientDataModel, IngredientViewModel>();
});
_mapper = new Mapper(config);
}
public IngredientOperationResponse GetList()
{
try
{
return IngredientOperationResponse.OK(_logic.GetAllIngredients().Select(x => _mapper.Map<IngredientViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return IngredientOperationResponse.InternalServerError(ex.Message);
}
}
public IngredientOperationResponse GetElement(string data)
{
try
{
return IngredientOperationResponse.OK(_mapper.Map<IngredientViewModel>(_logic.GetIngredientByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return IngredientOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return IngredientOperationResponse.InternalServerError(ex.Message);
}
}
public IngredientOperationResponse Register(IngredientBindingModel model)
{
try
{
_logic.InsertIngredient(_mapper.Map<IngredientDataModel>(model));
return IngredientOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return IngredientOperationResponse.BadRequest(ex.Message);
}
}
public IngredientOperationResponse Update(IngredientBindingModel model)
{
try
{
_logic.UpdateIngredient(_mapper.Map<IngredientDataModel>(model));
return IngredientOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return IngredientOperationResponse.BadRequest(ex.Message);
}
}
public IngredientOperationResponse Delete(string id)
{
try
{
_logic.DeleteIngredient(id);
return IngredientOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return IngredientOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,105 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces.Adapters;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
namespace CandyHouseWebApi.Adapters;
public class OrderAdapter : IOrderAdapter
{
private readonly IOrderBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public OrderAdapter(IOrderBusinessLogicContact logic, ILogger<OrderAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<OrderBindingModel, OrderDataModel>();
cfg.CreateMap<OrderDataModel, OrderViewModel>();
});
_mapper = new Mapper(config);
}
public OrderOperationResponse GetList()
{
try
{
return OrderOperationResponse.OK(_logic.GetAllOrders().Select(x => _mapper.Map<OrderViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return OrderOperationResponse.InternalServerError(ex.Message);
}
}
public OrderOperationResponse GetElement(string data)
{
try
{
return OrderOperationResponse.OK(_mapper.Map<OrderViewModel>(_logic.GetOrderByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return OrderOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return OrderOperationResponse.InternalServerError(ex.Message);
}
}
public OrderOperationResponse Register(OrderBindingModel model)
{
try
{
_logic.InsertOrder(_mapper.Map<OrderDataModel>(model));
return OrderOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return OrderOperationResponse.BadRequest(ex.Message);
}
}
public OrderOperationResponse Update(OrderBindingModel model)
{
try
{
_logic.UpdateOrder(_mapper.Map<OrderDataModel>(model));
return OrderOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return OrderOperationResponse.BadRequest(ex.Message);
}
}
public OrderOperationResponse Delete(string id)
{
try
{
_logic.DeleteOrder(id);
return OrderOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return OrderOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,107 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces;
using CandyHouseBase.Interfaces.Adapters;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace CandyHouseWebApi.Adapters;
public class PekarAdapter : IPekarAdapter
{
private readonly IPekarBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public PekarAdapter(IPekarBusinessLogicContact logic, ILogger<PekarAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PekarBindingModel, PekarDataModel>();
cfg.CreateMap<PekarDataModel, PekarViewModel>();
});
_mapper = new Mapper(config);
}
public PekarOperationResponse GetList()
{
try
{
return PekarOperationResponse.OK(_logic.GetAllPekars().Select(x => _mapper.Map<PekarViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return PekarOperationResponse.InternalServerError(ex.Message);
}
}
public PekarOperationResponse GetElement(string data)
{
try
{
return PekarOperationResponse.OK(_mapper.Map<PekarViewModel>(_logic.GetPekarByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return PekarOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return PekarOperationResponse.InternalServerError(ex.Message);
}
}
public PekarOperationResponse Register(PekarBindingModel model)
{
try
{
_logic.InsertPekar(_mapper.Map<PekarDataModel>(model));
return PekarOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return PekarOperationResponse.BadRequest(ex.Message);
}
}
public PekarOperationResponse Update(PekarBindingModel model)
{
try
{
_logic.UpdatePekar(_mapper.Map<PekarDataModel>(model));
return PekarOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return PekarOperationResponse.BadRequest(ex.Message);
}
}
public PekarOperationResponse Delete(string id)
{
try
{
_logic.DeletePekar(id);
return PekarOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return PekarOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,107 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces;
using CandyHouseBase.Interfaces.Adapters;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace CandyHouseWebApi.Adapters;
public class PositionAdapter : IPositionAdapter
{
private readonly IPositionBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public PositionAdapter(IPositionBusinessLogicContact logic, ILogger<PositionAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PositionBindingModel, PositionDataModel>();
cfg.CreateMap<PositionDataModel, PositionViewModel>();
});
_mapper = new Mapper(config);
}
public PositionOperationResponse GetList()
{
try
{
return PositionOperationResponse.OK(_logic.GetAllPositions().Select(x => _mapper.Map<PositionViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return PositionOperationResponse.InternalServerError(ex.Message);
}
}
public PositionOperationResponse GetElement(string data)
{
try
{
return PositionOperationResponse.OK(_mapper.Map<PositionViewModel>(_logic.GetPositionByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return PositionOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return PositionOperationResponse.InternalServerError(ex.Message);
}
}
public PositionOperationResponse Register(PositionBindingModel model)
{
try
{
_logic.InsertPosition(_mapper.Map<PositionDataModel>(model));
return PositionOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return PositionOperationResponse.BadRequest(ex.Message);
}
}
public PositionOperationResponse Update(PositionBindingModel model)
{
try
{
_logic.UpdatePosition(_mapper.Map<PositionDataModel>(model));
return PositionOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return PositionOperationResponse.BadRequest(ex.Message);
}
}
public PositionOperationResponse Delete(string id)
{
try
{
_logic.DeletePosition(id);
return PositionOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return PositionOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,107 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces;
using CandyHouseBase.Interfaces.Adapters;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace CandyHouseWebApi.Adapters;
public class ProductAdapter : IProductAdapter
{
private readonly IProductBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductAdapter(IProductBusinessLogicContact logic, ILogger<ProductAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductBindingModel, ProductDataModel>();
cfg.CreateMap<ProductDataModel, ProductViewModel>();
});
_mapper = new Mapper(config);
}
public ProductOperationResponse GetList()
{
try
{
return ProductOperationResponse.OK(_logic.GetAllProducts().Select(x => _mapper.Map<ProductViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return ProductOperationResponse.InternalServerError(ex.Message);
}
}
public ProductOperationResponse GetElement(string data)
{
try
{
return ProductOperationResponse.OK(_mapper.Map<ProductViewModel>(_logic.GetProductByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return ProductOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return ProductOperationResponse.InternalServerError(ex.Message);
}
}
public ProductOperationResponse Register(ProductBindingModel model)
{
try
{
_logic.InsertProduct(_mapper.Map<ProductDataModel>(model));
return ProductOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return ProductOperationResponse.BadRequest(ex.Message);
}
}
public ProductOperationResponse Update(ProductBindingModel model)
{
try
{
_logic.UpdateProduct(_mapper.Map<ProductDataModel>(model));
return ProductOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return ProductOperationResponse.BadRequest(ex.Message);
}
}
public ProductOperationResponse Delete(string id)
{
try
{
_logic.DeleteProduct(id);
return ProductOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return ProductOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,107 @@
using AutoMapper;
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Contracts.OperationResponses;
using CandyHouseBase.Contracts.ViewModels;
using CandyHouseBase.DataModels;
using CandyHouseBase.Exceptions;
using CandyHouseBase.Interfaces;
using CandyHouseBase.Interfaces.Adapters;
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
using Microsoft.Extensions.Logging;
namespace CandyHouseWebApi.Adapters;
public class SalaryAdapter : ISalaryAdapter
{
private readonly ISalaryBusinessLogicContact _logic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public SalaryAdapter(ISalaryBusinessLogicContact logic, ILogger<SalaryAdapter> logger)
{
_logic = logic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SalaryBindingModel, SalaryDataModel>();
cfg.CreateMap<SalaryDataModel, SalaryViewModel>();
});
_mapper = new Mapper(config);
}
public SalaryOperationResponse GetList()
{
try
{
return SalaryOperationResponse.OK(_logic.GetAllSalaries().Select(x => _mapper.Map<SalaryViewModel>(x)).ToList());
}
catch (Exception ex)
{
_logger.LogError(ex, "GetList failed");
return SalaryOperationResponse.InternalServerError(ex.Message);
}
}
public SalaryOperationResponse GetElement(string data)
{
try
{
return SalaryOperationResponse.OK(_mapper.Map<SalaryViewModel>(_logic.GetSalaryByData(data)));
}
catch (ElementNotFoundException ex)
{
_logger.LogError(ex, "Not found");
return SalaryOperationResponse.NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error");
return SalaryOperationResponse.InternalServerError(ex.Message);
}
}
public SalaryOperationResponse Register(SalaryBindingModel model)
{
try
{
_logic.InsertSalary(_mapper.Map<SalaryDataModel>(model));
return SalaryOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Register error");
return SalaryOperationResponse.BadRequest(ex.Message);
}
}
public SalaryOperationResponse Update(SalaryBindingModel model)
{
try
{
_logic.UpdateSalary(_mapper.Map<SalaryDataModel>(model));
return SalaryOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Update error");
return SalaryOperationResponse.BadRequest(ex.Message);
}
}
public SalaryOperationResponse Delete(string id)
{
try
{
_logic.DeleteSalary(id);
return SalaryOperationResponse.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Delete error");
return SalaryOperationResponse.BadRequest(ex.Message);
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace CandyHouseWebApi
{
// Make sure this class is public and accessible to your tests
public class AuthOptions
{
public const string ISSUER = "CandyHouseWebApi";
public const string AUDIENCE = "CandyHouseClient";
const string KEY = "candy_house_secret_key_for_jwt_auth_please_change_in_production";
public static SymmetricSecurityKey GetSymmetricSecurityKey() =>
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(KEY));
}
}
// In your test project, if you need a reference to this
// Make sure you're using the exact same values in both places!

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class IngredientsController(IIngredientAdapter adapter) : ControllerBase
{
private readonly IIngredientAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] IngredientBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] IngredientBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class OrdersController(IOrderAdapter adapter) : ControllerBase
{
private readonly IOrderAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] OrderBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] OrderBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class PekarsController(IPekarAdapter adapter) : ControllerBase
{
private readonly IPekarAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] PekarBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] PekarBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class PositionsController(IPositionAdapter adapter) : ControllerBase
{
private readonly IPositionAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] PositionBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] PositionBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class ProductsController(IProductAdapter adapter) : ControllerBase
{
private readonly IProductAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] ProductBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] ProductBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,34 @@
using CandyHouseBase.Contracts;
using CandyHouseBase.Contracts.BindingModels;
using CandyHouseBase.Interfaces.Adapters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CandyHouseWebApi.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class SalarysController(ISalaryAdapter adapter) : ControllerBase
{
private readonly ISalaryAdapter _adapter = adapter;
[HttpGet]
public IActionResult Get() => _adapter.GetList().GetResponse(Request, Response);
[HttpGet("{data}")]
public IActionResult Get(string data) => _adapter.GetElement(data).GetResponse(Request, Response);
[HttpPost]
public IActionResult Post([FromBody] SalaryBindingModel model) =>
_adapter.Register(model).GetResponse(Request, Response);
[HttpPut]
public IActionResult Put([FromBody] SalaryBindingModel model) =>
_adapter.Update(model).GetResponse(Request, Response);
[HttpDelete("{id}")]
public IActionResult Delete(string id) =>
_adapter.Delete(id).GetResponse(Request, Response);
}

View File

@@ -0,0 +1,13 @@
using CandyHouseBase.Infrastructure;
namespace CandyHouseWebApi.Infrastructure;
internal class ConfigurationDatabase(IConfiguration configuration) : IConfigurationDatabase
{
private readonly Lazy<DataBaseSettings> _dataBaseSettings = new(() =>
{
return configuration.GetValue<DataBaseSettings>("DataBaseSettings") ?? throw new InvalidDataException(nameof(DataBaseSettings));
});
public string ConnectionString => _dataBaseSettings.Value.ConnectionString;
}

View File

@@ -0,0 +1,6 @@
namespace CandyHouseWebApi.Infrastructure;
public class DataBaseSettings
{
public required string ConnectionString { get; set; }
}