Merge from master
All checks were successful
Unit tests / test (push) Successful in 1m11s

This commit is contained in:
Olga Nemt 2025-01-20 11:50:31 +05:00
commit 182cea2331
184 changed files with 2537 additions and 2536 deletions

View File

@ -0,0 +1,38 @@
name: Unit tests
run-name: ${{ gitea.actor }} is testing
on: push
jobs:
test:
runs-on: ubuntu-latest
container: node
# Service containers to run with `runner-job`
services:
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres
# Provide the password for postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5442:5432
steps:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Check out repository code
uses: actions/checkout@v4
- name: Run integration tests
run: dotnet test DD.Persistence.IntegrationTests

View File

@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Models.Requests;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using DD.Persistence.Repositories;
using System.Net;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
[ApiController]
[Authorize]

View File

@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Repositories;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Работа с временными данными

View File

@ -0,0 +1,51 @@
using System.Net;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using DD.Persistence.Models;
using DD.Persistence.Repositories;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Работа с системами
/// </summary>
[ApiController]
[Authorize]
[Route("api/[controller]")]
public class DataSourceSystemController : ControllerBase
{
private readonly IDataSourceSystemRepository dataSourceSystemRepository;
public DataSourceSystemController(IDataSourceSystemRepository dataSourceSystemRepository)
{
this.dataSourceSystemRepository = dataSourceSystemRepository;
}
/// <summary>
/// Получить системы
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult<DataSourceSystemDto>> Get(CancellationToken token)
{
var result = await dataSourceSystemRepository.Get(token);
return Ok(result);
}
/// <summary>
/// Добавить систему
/// </summary>
/// <param name="dataSourceSystemDto"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpPost]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
public async Task<IActionResult> Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)
{
await dataSourceSystemRepository.Add(dataSourceSystemDto, token);
return CreatedAtAction(nameof(Add), true);
}
}

View File

@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Repositories;
using System.Net;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Работа с уставками

View File

@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Models.Requests;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using DD.Persistence.Repositories;
using System.Net;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Работа с технологическими сообщениями систем автобурения (АБ)
@ -44,17 +44,17 @@ public class TechMessagesController : ControllerBase
return Ok(result);
}
/// <summary>
/// Получить статистику по системам
/// </summary>
/// <param name="autoDrillingSystem"></param>
/// <param name="categoryIds"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("statistics")]
public async Task<ActionResult<IEnumerable<MessagesStatisticDto>>> GetStatistics([FromQuery] IEnumerable<string> autoDrillingSystem, [FromQuery] IEnumerable<int> categoryIds, CancellationToken token)
{
var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token);
/// <summary>
/// Получить статистику по системам
/// </summary>
/// <param name="autoDrillingSystem"></param>
/// <param name="categoryIds"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("statistics")]
public async Task<ActionResult<IEnumerable<MessagesStatisticDto>>> GetStatistics([FromQuery] IEnumerable<Guid> autoDrillingSystem, [FromQuery] IEnumerable<int> categoryIds, CancellationToken token)
{
var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token);
return Ok(result);
}
@ -78,11 +78,11 @@ public class TechMessagesController : ControllerBase
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("range")]
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token)
public async Task<ActionResult<DatesRangeDto?>> GetDatesRangeAsync(CancellationToken token)
{
var result = await techMessagesRepository.GetDatesRangeAsync(token);
return Ok(result);
return result == null ? NoContent() : Ok(result);
}
/// <summary>
@ -100,19 +100,20 @@ public class TechMessagesController : ControllerBase
return Ok(result);
}
/// <summary>
/// Добавить новые технологические сообщения
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpPost]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
public async Task<IActionResult> AddRange([FromBody] IEnumerable<TechMessageDto> dtos, CancellationToken token)
{
var userId = User.GetUserId<Guid>();
/// <summary>
/// Добавить новые технологические сообщения
/// </summary>
/// <param name="systemId"></param>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpPost("{systemId}")]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
public async Task<IActionResult> AddRange([FromRoute] Guid systemId, [FromBody] IEnumerable<TechMessageDto> dtos, CancellationToken token)
{
var userId = User.GetUserId<Guid>();
var result = await techMessagesRepository.AddRange(dtos, userId, token);
var result = await techMessagesRepository.AddRange(systemId, dtos, userId, token);
return CreatedAtAction(nameof(AddRange), result);
}

View File

@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Repositories;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
[ApiController]
[Authorize]

View File

@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Repositories;
using DD.Persistence.Models;
using DD.Persistence.Repositories;
using System.Net;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Хранение наборов данных с отметкой времени.

View File

@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Persistence.Services.Interfaces;
using DD.Persistence.Models;
using DD.Persistence.Services.Interfaces;
using System.Net;
namespace Persistence.API.Controllers;
namespace DD.Persistence.API.Controllers;
/// <summary>
/// Работа с параметрами Wits

View File

@ -1,30 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Persistence.Database.Postgres\Persistence.Database.Postgres.csproj" />
<ProjectReference Include="..\Persistence.Repository\Persistence.Repository.csproj" />
<ProjectReference Include="..\Persistence\Persistence.csproj" />
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
<ProjectReference Include="..\DD.Persistence.Repository\DD.Persistence.Repository.csproj" />
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
</ItemGroup>
</Project>

View File

@ -3,25 +3,19 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Persistence.Database.Entity;
using Persistence.Models;
using Persistence.Models.Configurations;
using Persistence.Services;
using Persistence.Services.Interfaces;
using DD.Persistence.Models;
using DD.Persistence.Models.Configurations;
using DD.Persistence.Services;
using DD.Persistence.Services.Interfaces;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using System.Text.Json.Nodes;
using DD.Persistence.Database.Entity;
namespace Persistence.API;
namespace DD.Persistence.API;
public static class DependencyInjection
{
public static void MapsterSetup()
{
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<TechMessageDto, TechMessage>()
.Ignore(dest => dest.System, dest => dest.SystemId);
}
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
{
services.AddSwaggerGen(c =>
@ -74,15 +68,16 @@ public static class DependencyInjection
private static void AddKeyCloakAuthentication(this IServiceCollection services, IConfiguration configuration)
{
var keyCloakHost = configuration["KeyCloakAuthentication:Host"];
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.Audience = configuration["Authentication:Audience"];
options.MetadataAddress = configuration["Authentication:MetadataAddress"]!;
options.Audience = configuration["KeyCloakAuthentication:Audience"];
options.MetadataAddress = $"{keyCloakHost}/.well-known/openid-configuration";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = configuration["Authentication:ValidIssuer"],
ValidIssuer = keyCloakHost
};
});
}
@ -143,6 +138,8 @@ public static class DependencyInjection
#region Keycloak
private static void AddKeycloakSecurity(this SwaggerGenOptions options, IConfiguration configuration)
{
var keyCloakHost = configuration["KeyCloakAuthentication:Host"];
options.AddSecurityDefinition("Keycloak", new OpenApiSecurityScheme
{
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345token'",
@ -153,7 +150,7 @@ public static class DependencyInjection
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]!),
AuthorizationUrl = new Uri($"{keyCloakHost}/protocol/openid-connect/auth"),
}
}
});

View File

@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Security.Claims;
namespace Persistence.API;
namespace DD.Persistence.API;
public static class Extensions
{

View File

@ -1,8 +1,8 @@
using Persistence.Database.Model;
using Persistence.Database.Postgres;
using Persistence.Repository;
using DD.Persistence.Database.Model;
using DD.Persistence.Database.Postgres;
using DD.Persistence.Repository;
namespace Persistence.API;
namespace DD.Persistence.API;
public class Startup
{
@ -26,8 +26,6 @@ public class Startup
services.AddJWTAuthentication(Configuration);
services.AddMemoryCache();
services.AddServices();
DependencyInjection.MapsterSetup();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -0,0 +1,5 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}

View File

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>8dcdcfed-c959-4eef-9891-ae60b1b136ea</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<_WebToolingArtifacts Remove="Properties\PublishProfiles\LinuxRelease.pubxml" />
<_WebToolingArtifacts Remove="Properties\PublishProfiles\WindowsRelease.pubxml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DD.Persistence.API\DD.Persistence.API.csproj" />
</ItemGroup>
</Project>

View File

@ -4,21 +4,22 @@ FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Persistence.API/Persistence.API.csproj", "Persistence.API/"]
RUN dotnet restore "./Persistence.API/Persistence.API.csproj"
COPY ["DD.Persistence.App/DD.Persistence.App.csproj", "DD.Persistence.App/"]
RUN dotnet restore "./DD.Persistence.App/DD.Persistence.App.csproj"
COPY . .
WORKDIR "/src/Persistence.API"
RUN dotnet build "./Persistence.API.csproj" -c $BUILD_CONFIGURATION -o /app/build
WORKDIR "/src/DD.Persistence.App"
RUN dotnet build "./DD.Persistence.App.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Persistence.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
RUN dotnet publish "./DD.Persistence.App.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Persistence.API.dll"]
ENTRYPOINT ["dotnet", "DD.Persistence.App.dll"]

View File

@ -1,10 +1,15 @@
namespace Persistence.API;
using DD.Persistence.API;
using System.Globalization;
namespace DD.Persistence.App;
public class Program
{
public static void Main(string[] args)
{
CultureInfo uiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-EN");
var host = CreateHostBuilder(args).Build();
Startup.BeforeRunHandler(host);
host.Run();

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<ProjectGuid>063238bf-e982-43fa-9ddb-7d7d279086d8</ProjectGuid>
<SelfContained>true</SelfContained>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>063238bf-e982-43fa-9ddb-7d7d279086d8</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,52 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5266"
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7154;http://localhost:5266"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:54958",
"sslPort": 44352
}
}
}

View File

@ -0,0 +1,29 @@
# DD.Persistence.App Readme
## Краткое описание DD.Persistence.App сервиса
DD.Persistence.App - проект исполняемого файла микросервиса
## Настройка DD.Persistence.App (файл appsettings.json)
- `appsettings.json` - файл с настройками проекта.
### Подключение к БД
- Настройки подключения к базе хранятся в свойстве `DefaultConnection` секции `ConnectionStrings`
файла `appsettings.json`, где:
- Host - название или ip хоста;
- Database - название базы данных;
- Username - пользователь базы данных;
- Password - пароль базы данных;
- Больше информации о настройке подключения к postgreSQL можно прочесть по [ссылке](https://www.npgsql.org/doc/connection-string-parameters.html)
### Авторизация
1. В проекте предусмотрены 2 типа авторизации:
- Авторизация через KeyCloak. Используется в продакшен версии.
- Авторизация через Jwt-токен. Используется для разработки и тестирования.
2. Для включения авторизации через KeyCloak необходимо:
- Установить секцию `NeedUseKeyCloak` файла `appsettings.json` в `true`
- По необходимости настроить свойства секции `Authentication` файла `appsettings.json`
### defaultsettings.json
Копия файла `appsettings.json` хранится в файле `defaultsettings.json`

View File

@ -0,0 +1,17 @@
{
"DbConnection": {
"Host": "postgres",
"Port": 5432,
"Database": "persistence",
"Username": "postgres",
"Password": "postgres"
},
"NeedUseKeyCloak": false,
"AuthUser": {
"username": "myuser",
"password": 12345,
"clientId": "webapi",
"grantType": "password"
},
"KeycloakGetTokenUrl": "http://192.168.0.10:8321/realms/Persistence/protocol/openid-connect/token"
}

View File

@ -0,0 +1,25 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=persistence;Username=postgres;Password=postgres;Persist Security Info=True"
},
"AllowedHosts": "*",
"NeedUseKeyCloak": false,
"KeyCloakAuthentication": {
"Audience": "account",
"Host": "http://192.168.0.10:8321/realms/Persistence"
},
"AuthUser": {
"username": "myuser",
"password": 12345,
"clientId": "webapi",
"grantType": "password",
"http://schemas.xmlsoap.org/ws/2005/05/identity /claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6"
},
"ClientUrl": "http://localhost:5000/"
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"NeedUseKeyCloak": false
}

View File

@ -6,16 +6,14 @@
}
},
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=persistence;Username=postgres;Password=q;Persist Security Info=True"
"DefaultConnection": "Host=localhost;Port=5432;Database=persistence;Username=postgres;Password=q;Persist Security Info=True"
},
"AllowedHosts": "*",
"Authentication": {
"MetadataAddress": "http://192.168.0.10:8321/realms/Persistence/.well-known/openid-configuration",
"Audience": "account",
"ValidIssuer": "http://192.168.0.10:8321/realms/Persistence",
"AuthorizationUrl": "http://192.168.0.10:8321/realms/Persistence/protocol/openid-connect/auth"
},
"NeedUseKeyCloak": false,
"KeyCloakAuthentication": {
"Audience": "account",
"Host": "http://192.168.0.10:8321/realms/Persistence"
},
"AuthUser": {
"username": "myuser",
"password": 12345,

View File

@ -1,8 +1,8 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Helpers;
using DD.Persistence.Client.Helpers;
using Microsoft.Extensions.Logging;
using Refit;
namespace Persistence.Client.Clients.Base;
namespace DD.Persistence.Client.Clients.Base;
public abstract class BaseClient
{
private readonly ILogger logger;
@ -12,11 +12,11 @@ public abstract class BaseClient
this.logger = logger;
}
public async Task<T> ExecuteGetResponse<T>(Func<Task<IApiResponse<T>>> getMethod, CancellationToken token)
public async Task<T?> ExecuteGetResponse<T>(Func<Task<IApiResponse<T>>> getMethod, CancellationToken token)
{
var response = await getMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
if (response.IsSuccessStatusCode)
{
return response.Content;
}
@ -32,7 +32,7 @@ public abstract class BaseClient
{
var response = await postMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
if (response.IsSuccessStatusCode)
{
return;
}
@ -48,7 +48,7 @@ public abstract class BaseClient
{
var response = await postMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
if (response.IsSuccessStatusCode)
{
return response.Content;
}

View File

@ -1,22 +1,23 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Models;
using Persistence.Models.Requests;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using DD.Persistence.Client.Clients.Interfaces.Refit;
namespace Persistence.Client.Clients;
namespace DD.Persistence.Client.Clients;
public class ChangeLogClient : BaseClient, IChangeLogClient
{
private readonly Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient;
private readonly IRefitChangeLogClient refitChangeLogClient;
public ChangeLogClient(Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient, ILogger<ChangeLogClient> logger) : base(logger)
public ChangeLogClient(IRefitClientFactory<IRefitChangeLogClient> refitClientFactory, ILogger<ChangeLogClient> logger) : base(logger)
{
this.refitChangeLogClient = refitChangeLogClient;
}
this.refitChangeLogClient = refitClientFactory.Create();
}
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
{
var result = await ExecuteGetResponse<int>(
var result = await ExecuteGetResponse(
async () => await refitChangeLogClient.ClearAndAddRange(idDiscriminator, dtos, token), token);
return result;
@ -25,7 +26,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
public async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment,
SectionPartRequest filterRequest, PaginationRequest paginationRequest, CancellationToken token)
{
var result = await ExecuteGetResponse<PaginationContainer<DataWithWellDepthAndSectionDto>>(
var result = await ExecuteGetResponse(
async () => await refitChangeLogClient.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token), token);
return result;
@ -33,10 +34,10 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<ChangeLogDto>>(
var result = await ExecuteGetResponse(
async () => await refitChangeLogClient.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token), token);
return result;
return result!;
}
public async Task<int> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token)
@ -89,7 +90,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto?>(
var result = await ExecuteGetResponse(
async () => await refitChangeLogClient.GetDatesRange(idDiscriminator, token), token);
return result;
@ -98,5 +99,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
public void Dispose()
{
refitChangeLogClient.Dispose();
}
GC.SuppressFinalize(this);
}
}

View File

@ -0,0 +1,37 @@
using Microsoft.Extensions.Logging;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
namespace DD.Persistence.Client.Clients;
public class DataSourceSystemClient : BaseClient, IDataSourceSystemClient
{
private readonly IRefitDataSourceSystemClient dataSourceSystemClient;
public DataSourceSystemClient(IRefitClientFactory<IRefitDataSourceSystemClient> dataSourceSystemClientFactory, ILogger<DataSourceSystemClient> logger) : base(logger)
{
this.dataSourceSystemClient = dataSourceSystemClientFactory.Create();
}
public async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)
{
await ExecutePostResponse(
async () => await dataSourceSystemClient.Add(dataSourceSystemDto, token), token);
}
public async Task<IEnumerable<DataSourceSystemDto>> Get(CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await dataSourceSystemClient.Get(token), token);
return result!;
}
public void Dispose()
{
dataSourceSystemClient.Dispose();
GC.SuppressFinalize(this);
}
}

View File

@ -1,7 +1,7 @@
using Persistence.Models;
using Persistence.Models.Requests;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с записями ChangeLog

View File

@ -0,0 +1,25 @@
using DD.Persistence.Models;
using Refit;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с системами
/// </summary>
public interface IDataSourceSystemClient : IDisposable
{
/// <summary>
/// Получить системы
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DataSourceSystemDto>> Get(CancellationToken token);
/// <summary>
/// Добавить систему
/// </summary>
/// <param name="dataSourceSystemDto"></param>
/// <param name="token"></param>
/// <returns></returns>
Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token);
}

View File

@ -1,6 +1,6 @@
using Persistence.Models;
using DD.Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с уставками

View File

@ -1,7 +1,7 @@
using Persistence.Models;
using Persistence.Models.Requests;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с технологическими сообщениями
@ -14,14 +14,14 @@ public interface ITechMessagesClient : IDisposable
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> AddRange(IEnumerable<TechMessageDto> dtos, CancellationToken token);
Task<int> AddRange(Guid systemId, IEnumerable<TechMessageDto> dtos, CancellationToken token);
/// <summary>
/// Получить диапазон дат, для которых есть данные в репозитории
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
Task<DatesRangeDto?> GetDatesRangeAsync(CancellationToken token);
/// <summary>
/// Получить список технологических сообщений в виде страницы
@ -43,16 +43,16 @@ public interface ITechMessagesClient : IDisposable
/// <summary>
/// Получить статистику по системам
/// </summary>
/// <param name="autoDrillingSystem"></param>
/// <param name="categoryId"></param>
/// <param name="systemIds"></param>
/// <param name="categoryIds"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<MessagesStatisticDto>> GetStatistics(string autoDrillingSystem, int categoryId, CancellationToken token);
Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<Guid> systemIds, IEnumerable<int> categoryIds, CancellationToken token);
/// <summary>
/// Получить список всех систем
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<string>> GetSystems(CancellationToken token);
Task<IEnumerable<DataSourceSystemDto>> GetSystems(CancellationToken token);
}

View File

@ -1,12 +1,12 @@
using Persistence.Models;
using DD.Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с временными данными
/// </summary>
/// <typeparam name="TDto"></typeparam>
public interface ITimeSeriesClient<TDto> : IDisposable where TDto : class, new()
public interface ITimeSeriesClient<TDto> : IDisposable where TDto : class, ITimeSeriesAbstractDto
{
/// <summary>
/// Добавление записей

View File

@ -1,6 +1,6 @@
using Persistence.Models;
using DD.Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с репозиторием для хранения разных наборов данных рядов.

View File

@ -1,7 +1,7 @@
using Persistence.Models;
using DD.Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces;
namespace DD.Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с параметрами Wits

View File

@ -1,10 +1,10 @@
using Persistence.Models;
using Persistence.Models.Requests;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitChangeLogClient : IDisposable
public interface IRefitChangeLogClient : IRefitClient, IDisposable
{
private const string BaseRoute = "/api/ChangeLog";

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitClient
{
}

View File

@ -0,0 +1,14 @@
using DD.Persistence.Models;
using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitDataSourceSystemClient : IRefitClient, IDisposable
{
private const string BaseRoute = "/api/dataSourceSystem";
[Get($"{BaseRoute}")]
Task<IApiResponse<IEnumerable<DataSourceSystemDto>>> Get(CancellationToken token);
[Post($"{BaseRoute}")]
Task<IApiResponse> Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token);
}

View File

@ -1,9 +1,9 @@
using Persistence.Models;
using DD.Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitSetpointClient : IDisposable
public interface IRefitSetpointClient : IRefitClient, IDisposable
{
private const string BaseRoute = "/api/setpoint";

View File

@ -0,0 +1,29 @@
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit
{
public interface IRefitTechMessagesClient : IRefitClient, IDisposable
{
private const string BaseRoute = "/api/techMessages";
[Get($"{BaseRoute}")]
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] PaginationRequest request, CancellationToken token);
[Post($"{BaseRoute}/{{systemId}}")]
Task<IApiResponse<int>> AddRange(Guid systemId, [Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
[Get($"{BaseRoute}/systems")]
Task<IApiResponse<IEnumerable<DataSourceSystemDto>>> GetSystems(CancellationToken token);
[Get($"{BaseRoute}/range")]
Task<IApiResponse<DatesRangeDto?>> GetDatesRangeAsync(CancellationToken token);
[Get($"{BaseRoute}/part")]
Task<IApiResponse<IEnumerable<TechMessageDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
[Get($"{BaseRoute}/statistics")]
Task<IApiResponse<IEnumerable<MessagesStatisticDto>>> GetStatistics([Query(CollectionFormat.Multi)] IEnumerable<Guid> systemIds, [Query(CollectionFormat.Multi)] IEnumerable<int> categoryIds, CancellationToken token);
}
}

View File

@ -1,9 +1,9 @@
using Persistence.Models;
using DD.Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimeSeriesClient<TDto> : IDisposable
where TDto : class, new()
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimeSeriesClient<TDto> : IRefitClient, IDisposable
where TDto : class, ITimeSeriesAbstractDto
{
private const string BaseRoute = "/api/dataSaub";

View File

@ -1,9 +1,9 @@
using Persistence.Models;
using DD.Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimestampedSetClient : IDisposable
public interface IRefitTimestampedSetClient : IRefitClient, IDisposable
{
private const string baseUrl = "/api/TimestampedSet/{idDiscriminator}";

View File

@ -1,9 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using DD.Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitWitsDataClient : IDisposable
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitWitsDataClient : IRefitClient, IDisposable
{
private const string BaseRoute = "/api/witsData";

View File

@ -1,58 +1,58 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
namespace Persistence.Client.Clients;
namespace DD.Persistence.Client.Clients;
public class SetpointClient : BaseClient, ISetpointClient
{
private readonly IRefitSetpointClient refitSetpointClient;
public SetpointClient(IRefitSetpointClient refitSetpointClient, ILogger<SetpointClient> logger) : base(logger)
public SetpointClient(IRefitClientFactory<IRefitSetpointClient> refitSetpointClientFactory, ILogger<SetpointClient> logger) : base(logger)
{
this.refitSetpointClient = refitSetpointClient;
this.refitSetpointClient = refitSetpointClientFactory.Create();
}
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<SetpointValueDto>>(
var result = await ExecuteGetResponse(
async () => await refitSetpointClient.GetCurrent(setpointKeys, token), token);
return result;
return result!;
}
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<SetpointValueDto>>(
var result = await ExecuteGetResponse(
async () => await refitSetpointClient.GetHistory(setpointKeys, historyMoment, token), token);
return result;
return result!;
}
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
{
var result = await ExecuteGetResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>(
var result = await ExecuteGetResponse(
async () => await refitSetpointClient.GetLog(setpointKeys, token), token);
return result;
return result!;
}
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto>(
var result = await ExecuteGetResponse(
async () => await refitSetpointClient.GetDatesRangeAsync(token), token);
return result;
return result!;
}
public async Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<SetpointLogDto>>(
var result = await ExecuteGetResponse(
async () => await refitSetpointClient.GetPart(dateBegin, take, token), token);
return result;
return result!;
}
public async Task Add(Guid setpointKey, object newValue, CancellationToken token)
@ -64,5 +64,7 @@ public class SetpointClient : BaseClient, ISetpointClient
public void Dispose()
{
refitSetpointClient.Dispose();
}
GC.SuppressFinalize(this);
}
}

View File

@ -0,0 +1,73 @@
using Microsoft.Extensions.Logging;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
namespace DD.Persistence.Client.Clients;
public class TechMessagesClient : BaseClient, ITechMessagesClient
{
private readonly IRefitTechMessagesClient refitTechMessagesClient;
public TechMessagesClient(IRefitClientFactory<IRefitTechMessagesClient> refitTechMessagesClientFactory, ILogger<TechMessagesClient> logger) : base(logger)
{
this.refitTechMessagesClient = refitTechMessagesClientFactory.Create();
}
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await refitTechMessagesClient.GetPage(request, token), token);
return result!;
}
public async Task<int> AddRange(Guid systemId, IEnumerable<TechMessageDto> dtos, CancellationToken token)
{
var result = await ExecutePostResponse(
async () => await refitTechMessagesClient.AddRange(systemId, dtos, token), token);
return result;
}
public async Task<IEnumerable<DataSourceSystemDto>> GetSystems(CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await refitTechMessagesClient.GetSystems(token), token);
return result!;
}
public async Task<DatesRangeDto?> GetDatesRangeAsync(CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await refitTechMessagesClient.GetDatesRangeAsync(token), token);
return result;
}
public async Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await refitTechMessagesClient.GetPart(dateBegin, take, token), token);
return result!;
}
public async Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<Guid> systemIds, IEnumerable<int> categoryIds, CancellationToken token)
{
var result = await ExecuteGetResponse(
async () => await refitTechMessagesClient.GetStatistics(systemIds, categoryIds, token), token);
return result!;
}
public void Dispose()
{
refitTechMessagesClient.Dispose();
GC.SuppressFinalize(this);
}
}

View File

@ -1,17 +1,17 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
namespace Persistence.Client.Clients;
public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, new()
namespace DD.Persistence.Client.Clients;
public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, ITimeSeriesAbstractDto
{
private readonly IRefitTimeSeriesClient<TDto> timeSeriesClient;
public TimeSeriesClient(IRefitTimeSeriesClient<TDto> refitTechMessagesClient, ILogger<TimeSeriesClient<TDto>> logger) : base(logger)
public TimeSeriesClient(IRefitClientFactory<IRefitTimeSeriesClient<TDto>> refitTechMessagesClientFactory, ILogger<TimeSeriesClient<TDto>> logger) : base(logger)
{
this.timeSeriesClient = refitTechMessagesClient;
this.timeSeriesClient = refitTechMessagesClientFactory.Create();
}
public async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
@ -24,23 +24,23 @@ public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where
public async Task<IEnumerable<TDto>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TDto>>(
var result = await ExecuteGetResponse(
async () => await timeSeriesClient.Get(dateBegin, dateEnd, token), token);
return result;
return result!;
}
public async Task<IEnumerable<TDto>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
{
var result = await ExecuteGetResponse<IEnumerable<TDto>>(
var result = await ExecuteGetResponse(
async () => await timeSeriesClient.GetResampledData(dateBegin, intervalSec, approxPointsCount, token), token);
return result;
return result!;
}
public async Task<DatesRangeDto?> GetDatesRange(CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto?>(
var result = await ExecuteGetResponse(
async () => await timeSeriesClient.GetDatesRange(token), token);
return result;
@ -49,5 +49,7 @@ public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where
public void Dispose()
{
timeSeriesClient.Dispose();
}
GC.SuppressFinalize(this);
}
}

View File

@ -1,17 +1,17 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
namespace Persistence.Client.Clients;
namespace DD.Persistence.Client.Clients;
public class TimestampedSetClient : BaseClient, ITimestampedSetClient
{
private readonly IRefitTimestampedSetClient refitTimestampedSetClient;
public TimestampedSetClient(IRefitTimestampedSetClient refitTimestampedSetClient, ILogger<TimestampedSetClient> logger) : base(logger)
public TimestampedSetClient(IRefitClientFactory<IRefitTimestampedSetClient> refitTimestampedSetClientFactory, ILogger<TimestampedSetClient> logger) : base(logger)
{
this.refitTimestampedSetClient = refitTimestampedSetClient;
this.refitTimestampedSetClient = refitTimestampedSetClientFactory.Create();
}
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)
@ -24,23 +24,23 @@ public class TimestampedSetClient : BaseClient, ITimestampedSetClient
public async Task<IEnumerable<TimestampedSetDto>> Get(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TimestampedSetDto>>(
var result = await ExecuteGetResponse(
async () => await refitTimestampedSetClient.Get(idDiscriminator, geTimestamp, columnNames, skip, take, token), token);
return result;
return result!;
}
public async Task<IEnumerable<TimestampedSetDto>> GetLast(Guid idDiscriminator, IEnumerable<string>? columnNames, int take, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TimestampedSetDto>>(
var result = await ExecuteGetResponse(
async () => await refitTimestampedSetClient.GetLast(idDiscriminator, columnNames, take, token), token);
return result;
return result!;
}
public async Task<int> Count(Guid idDiscriminator, CancellationToken token)
{
var result = await ExecuteGetResponse<int>(
var result = await ExecuteGetResponse(
async () => await refitTimestampedSetClient.Count(idDiscriminator, token), token);
return result;
@ -48,7 +48,7 @@ public class TimestampedSetClient : BaseClient, ITimestampedSetClient
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto?>(
var result = await ExecuteGetResponse(
async () => await refitTimestampedSetClient.GetDatesRange(idDiscriminator, token), token);
return result;
@ -57,5 +57,7 @@ public class TimestampedSetClient : BaseClient, ITimestampedSetClient
public void Dispose()
{
refitTimestampedSetClient.Dispose();
}
GC.SuppressFinalize(this);
}
}

View File

@ -1,17 +1,17 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models;
namespace Persistence.Client.Clients;
namespace DD.Persistence.Client.Clients;
public class WitsDataClient : BaseClient, IWitsDataClient
{
private readonly IRefitWitsDataClient refitWitsDataClient;
public WitsDataClient(IRefitWitsDataClient refitWitsDataClient, ILogger<WitsDataClient> logger) : base(logger)
public WitsDataClient(IRefitClientFactory<IRefitWitsDataClient> refitWitsDataClientFactory, ILogger<WitsDataClient> logger) : base(logger)
{
this.refitWitsDataClient = refitWitsDataClient;
this.refitWitsDataClient = refitWitsDataClientFactory.Create();
}
public async Task<int> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token)
@ -24,30 +24,32 @@ public class WitsDataClient : BaseClient, IWitsDataClient
public async Task<DatesRangeDto> GetDatesRangeAsync(Guid discriminatorId, CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto>(
var result = await ExecuteGetResponse(
async () => await refitWitsDataClient.GetDatesRangeAsync(discriminatorId, token), token);
return result;
return result!;
}
public async Task<IEnumerable<WitsDataDto>> GetPart(Guid discriminatorId, DateTimeOffset dateBegin, int take = 86400, CancellationToken token = default)
{
var result = await ExecuteGetResponse<IEnumerable<WitsDataDto>>(
var result = await ExecuteGetResponse(
async () => await refitWitsDataClient.GetPart(discriminatorId, dateBegin, take, token), token);
return result;
return result!;
}
public async Task<IEnumerable<WitsDataDto>> GetValuesForGraph(Guid discriminatorId, DateTimeOffset dateFrom, DateTimeOffset dateTo, int approxPointsCount, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<WitsDataDto>>(
var result = await ExecuteGetResponse(
async () => await refitWitsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointsCount, token), token);
return result;
return result!;
}
public void Dispose()
{
refitWitsDataClient.Dispose();
}
GC.SuppressFinalize(this);
}
}

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Not Acceptable (406)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Bad gateway (502)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Forbidden (403)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Internal Server Error (500)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Locked (423)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Service Unavailable Error (503)

View File

@ -1,4 +1,4 @@
namespace Persistence.Client.CustomExceptions;
namespace DD.Persistence.Client.CustomExceptions;
/// <summary>
/// Too Many Requests (429)

View File

@ -0,0 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--Генерация NuGet пакета при сборке-->
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<!--Наименование-->
<Title>DD.Persistence.Client</Title>
<!--Версия пакета-->
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
<!--Версия сборки-->
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
<!--Id пакета-->
<PackageId>DD.Persistence.Client</PackageId>
<!--Автор-->
<Authors>Digital Drilling</Authors>
<!--Компания-->
<Company>Digital Drilling</Company>
<!--Описание-->
<Description>Пакет для получения клиентов для работы с Persistence сервисом</Description>
<!--Url репозитория-->
<RepositoryUrl>https://git.ddrilling.ru/on.nemtina/persistence.git</RepositoryUrl>
<!--тип репозитория-->
<RepositoryType>git</RepositoryType>
<!--Символы отладки-->
<IncludeSymbols>true</IncludeSymbols>
<!--Формат пакета с символами-->
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<!--Путь к пакету-->
<PackageOutputPath>C:\Projects\Nuget\Persistence\Client</PackageOutputPath>
<!--Readme-->
<PackageReadmeFile>Readme.md</PackageReadmeFile>
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
<None Include="Readme.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
<PackageReference Include="Refit" Version="8.0.0" />
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DD.Persistence.Models\DD.Persistence.Models.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,30 @@
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models;
using Microsoft.Extensions.DependencyInjection;
namespace DD.Persistence.Client;
/// <summary>
///
/// </summary>
public static class DependencyInjection
{
/// <summary>
///
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddPersistenceClients(this IServiceCollection services)
{
services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>));
services.AddTransient<IChangeLogClient, ChangeLogClient>();
services.AddTransient<IDataSourceSystemClient, DataSourceSystemClient>();
services.AddTransient<ISetpointClient, SetpointClient>();
services.AddTransient<ITechMessagesClient, TechMessagesClient>();
services.AddTransient<ITimeSeriesClient<DataSaubDto>, TimeSeriesClient<DataSaubDto>>();
services.AddTransient<ITimestampedSetClient, TimestampedSetClient>();
services.AddTransient<IWitsDataClient, WitsDataClient>();
return services;
}
}

View File

@ -1,13 +1,13 @@
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Persistence.Models.Configurations;
using DD.Persistence.Models.Configurations;
using RestSharp;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Json;
namespace Persistence.Client.Helpers;
namespace DD.Persistence.Client.Helpers;
public static class ApiTokenHelper
{
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)

View File

@ -1,8 +1,8 @@
using System.ComponentModel.DataAnnotations;
using Persistence.Client.CustomExceptions;
using DD.Persistence.Client.CustomExceptions;
using Refit;
using System.ComponentModel.DataAnnotations;
namespace Persistence.Client.Helpers;
namespace DD.Persistence.Client.Helpers;
public static class ExceptionsHelper
{
private static readonly Dictionary<System.Net.HttpStatusCode, Exception> ExceptionsDictionary = new Dictionary<System.Net.HttpStatusCode, Exception>()
@ -30,6 +30,6 @@ public static class ExceptionsHelper
var result = exception ?? new Exception("Неопознанная ошибка");
return result;
return result;
}
}

View File

@ -0,0 +1,16 @@
using DD.Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client;
/// <summary>
/// Интерфейс для фабрики, которая создает refit-клиентов
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRefitClientFactory<T> where T : IRefitClient
{
/// <summary>
/// Создание refit-клиента
/// </summary>
/// <returns></returns>
public T Create();
}

View File

@ -6,7 +6,7 @@ Persistence сервис отвечает за работу с хранимым
## Описание пакета
Данный пакет предоставляет возможность взаимодействия с
Persistence сервисом посредством обращения к конкретному
клиенту, ответсвенному за работу с одной из областей сервиса.
клиенту, ответственному за работу с одной из областей сервиса.
## Список предоставляемых клиентов
- `ISetpointClient` - Клиент для работы с уставками
@ -15,6 +15,7 @@ Persistence сервисом посредством обращения к кон
- `ITimestampedSetClient` - Клиент для работы с данными с отметкой времени
- `IChangeLogClient` - Клиент для работы с записями ChangeLog
- `IWitsDataClient` - Клиент для работы с параметрами Wits
- `IDataSourceSystemClient` - Клиент для работы с системами
## Использование
Для получения того или иного Persistence - клиента нужно
@ -30,7 +31,7 @@ Persistence сервисом посредством обращения к кон
4. Обратиться к фабрике Persistence - клиентов и получить требуемого клиента.
## xunit тестирование
При написании интеграционных тестов с ипользованием Persistence - клиентов
При написании интеграционных тестов с использованием Persistence - клиентов
Http - клиент не обязан быть авторизован через передачу токена в `PersistenceClientFactory`.
Для осуществления тестовой авторизации достаточно добавить в `appsettings.Tests.json` :
```json

View File

@ -0,0 +1,52 @@
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Helpers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Refit;
using System.Configuration;
using System.Text.Json;
namespace DD.Persistence.Client;
/// <summary>
/// Фабрика, которая создает refit-клиентов
/// </summary>
/// <typeparam name="T"></typeparam>
public class RefitClientFactory<T> : IRefitClientFactory<T> where T : IRefitClient
{
private HttpClient client;
private RefitSettings refitSettings;
/// <inheritdoc/>
public RefitClientFactory(IConfiguration configuration, ILogger<IRefitClientFactory<T>> logger, HttpClient client)
{
//this.client = factory.CreateClient();
this.client = client;
var baseUrl = configuration.GetSection("ClientUrl").Get<string>();
if (String.IsNullOrEmpty(baseUrl))
{
var exception = new SettingsPropertyNotFoundException("В настройках конфигурации не указан адрес Persistence сервиса.");
logger.LogError(exception.Message);
throw exception;
}
client.BaseAddress = new Uri(baseUrl);
JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
};
refitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
}
/// <summary>
/// создание клиента
/// </summary>
/// <returns></returns>
public T Create()
{
return RestService.For<T>(client, refitSettings);
}
}

View File

@ -1,25 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Persistence.Database\Persistence.Database.csproj" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
public static class DependencyInjection
{

View File

@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Npgsql;
using Persistence.Database.Model;
using DD.Persistence.Database.Model;
namespace Persistence.Database.Postgres;
namespace DD.Persistence.Database.Postgres;
/// <summary>
/// Фабрика контекста для dotnet ef миграций

View File

@ -2,7 +2,7 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using System.Diagnostics;
namespace Persistence.Database.Postgres;
namespace DD.Persistence.Database.Postgres;
public static class EFExtensionsInitialization
{
public static void EnsureCreatedAndMigrated(this DatabaseFacade db)

View File

@ -1,57 +1,55 @@
// <auto-generated />
using System;
using DD.Persistence.Database.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Persistence.Database.Model;
#nullable disable
namespace Persistence.Database.Postgres.Migrations
namespace DD.Persistence.Database.Postgres.Migrations
{
[DbContext(typeof(PersistenceDbContext))]
[Migration("20241203120141_ParameterDataMigration")]
partial class ParameterDataMigration
[DbContext(typeof(PersistencePostgresContext))]
[Migration("20241220062251_Init")]
partial class Init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.UseCollation("Russian_Russia.1251")
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Persistence.Database.Entity.DrillingSystem", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
{
b.Property<Guid>("SystemId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("Id системы автобурения");
.HasComment("Id системы - источника данных");
b.Property<string>("Description")
.HasColumnType("text")
.HasComment("Описание системы автобурения");
.HasComment("Описание системы - источника данных");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(256)")
.HasComment("Наименование системы автобурения");
.HasComment("Наименование системы - источника данных");
b.HasKey("SystemId");
b.ToTable("DrillingSystem");
b.ToTable("DataSourceSystem");
});
modelBuilder.Entity("Persistence.Database.Entity.ParameterData", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.ParameterData", b =>
{
b.Property<int>("DiscriminatorId")
.HasColumnType("integer")
b.Property<Guid>("DiscriminatorId")
.HasColumnType("uuid")
.HasComment("Дискриминатор системы");
b.Property<int>("ParameterId")
@ -72,7 +70,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("ParameterData");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
{
b.Property<Guid>("EventId")
.ValueGeneratedOnAdd()
@ -83,27 +81,23 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("integer")
.HasComment("Id Категории важности");
b.Property<double?>("Depth")
.HasColumnType("double precision")
.HasComment("Глубина забоя");
b.Property<int>("EventState")
.HasColumnType("integer")
.HasComment("Статус события");
b.Property<string>("MessageText")
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы, к которой относится сообщение");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("varchar(512)")
.HasComment("Текст сообщения");
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы автобурения, к которой относится сообщение");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone")
.HasComment("Дата возникновения");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasComment("Id пользователя за пультом бурильщика");
b.HasKey("EventId");
b.HasIndex("SystemId");
@ -111,7 +105,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("TechMessage");
});
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedSet", b =>
{
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
@ -134,7 +128,60 @@ namespace Persistence.Database.Postgres.Migrations
});
});
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("Ключ записи");
b.Property<DateTimeOffset>("Creation")
.HasColumnType("timestamp with time zone")
.HasComment("Дата создания записи");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
.HasComment("Глубина забоя на дату окончания интервала");
b.Property<double>("DepthStart")
.HasColumnType("double precision")
.HasComment("Глубина забоя на дату начала интервала");
b.Property<Guid>("IdAuthor")
.HasColumnType("uuid")
.HasComment("Автор изменения");
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
.HasComment("Дискриминатор таблицы");
b.Property<Guid?>("IdEditor")
.HasColumnType("uuid")
.HasComment("Редактор");
b.Property<Guid?>("IdNext")
.HasColumnType("uuid")
.HasComment("Id заменяющей записи");
b.Property<Guid>("IdSection")
.HasColumnType("uuid")
.HasComment("Ключ секции");
b.Property<DateTimeOffset?>("Obsolete")
.HasColumnType("timestamp with time zone")
.HasComment("Дата устаревания (например при удалении)");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("jsonb")
.HasComment("Значение");
b.HasKey("Id");
b.ToTable("ChangeLog");
});
modelBuilder.Entity("DD.Persistence.Database.Model.DataSaub", b =>
{
b.Property<DateTimeOffset>("Date")
.HasColumnType("timestamp with time zone")
@ -217,7 +264,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("DataSaub");
});
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
{
b.Property<Guid>("Key")
.HasColumnType("uuid")
@ -241,9 +288,9 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("Setpoint");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
{
b.HasOne("Persistence.Database.Entity.DrillingSystem", "System")
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
.WithMany()
.HasForeignKey("SystemId")
.OnDelete(DeleteBehavior.Cascade)

View File

@ -0,0 +1,172 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DD.Persistence.Database.Postgres.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ChangeLog",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ записи"),
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
IdAuthor = table.Column<Guid>(type: "uuid", nullable: false, comment: "Автор изменения"),
IdEditor = table.Column<Guid>(type: "uuid", nullable: true, comment: "Редактор"),
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
IdNext = table.Column<Guid>(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
DepthStart = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя на дату начала интервала"),
DepthEnd = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя на дату окончания интервала"),
IdSection = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ секции"),
Value = table.Column<string>(type: "jsonb", nullable: false, comment: "Значение")
},
constraints: table =>
{
table.PrimaryKey("PK_ChangeLog", x => x.Id);
});
migrationBuilder.CreateTable(
name: "DataSaub",
columns: table => new
{
date = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
mode = table.Column<int>(type: "integer", nullable: true),
user = table.Column<string>(type: "text", nullable: true),
wellDepth = table.Column<double>(type: "double precision", nullable: true),
bitDepth = table.Column<double>(type: "double precision", nullable: true),
blockPosition = table.Column<double>(type: "double precision", nullable: true),
blockSpeed = table.Column<double>(type: "double precision", nullable: true),
pressure = table.Column<double>(type: "double precision", nullable: true),
axialLoad = table.Column<double>(type: "double precision", nullable: true),
hookWeight = table.Column<double>(type: "double precision", nullable: true),
rotorTorque = table.Column<double>(type: "double precision", nullable: true),
rotorSpeed = table.Column<double>(type: "double precision", nullable: true),
flow = table.Column<double>(type: "double precision", nullable: true),
mseState = table.Column<short>(type: "smallint", nullable: false),
idFeedRegulator = table.Column<int>(type: "integer", nullable: false),
mse = table.Column<double>(type: "double precision", nullable: true),
pump0Flow = table.Column<double>(type: "double precision", nullable: true),
pump1Flow = table.Column<double>(type: "double precision", nullable: true),
pump2Flow = table.Column<double>(type: "double precision", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_DataSaub", x => x.date);
});
migrationBuilder.CreateTable(
name: "DataSourceSystem",
columns: table => new
{
SystemId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id системы - источника данных"),
Name = table.Column<string>(type: "varchar(256)", nullable: false, comment: "Наименование системы - источника данных"),
Description = table.Column<string>(type: "text", nullable: true, comment: "Описание системы - источника данных")
},
constraints: table =>
{
table.PrimaryKey("PK_DataSourceSystem", x => x.SystemId);
});
migrationBuilder.CreateTable(
name: "ParameterData",
columns: table => new
{
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор системы"),
ParameterId = table.Column<int>(type: "integer", nullable: false, comment: "Id параметра"),
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Временная отметка"),
Value = table.Column<string>(type: "varchar(256)", nullable: false, comment: "Значение параметра в виде строки")
},
constraints: table =>
{
table.PrimaryKey("PK_ParameterData", x => new { x.DiscriminatorId, x.ParameterId, x.Timestamp });
});
migrationBuilder.CreateTable(
name: "Setpoint",
columns: table => new
{
Key = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ"),
Created = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания уставки"),
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
IdUser = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id автора последнего изменения")
},
constraints: table =>
{
table.PrimaryKey("PK_Setpoint", x => new { x.Key, x.Created });
});
migrationBuilder.CreateTable(
name: "TimestampedSets",
columns: table => new
{
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор ссылка на тип сохраняемых данных"),
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Отметка времени, строго в UTC"),
Set = table.Column<string>(type: "jsonb", nullable: false, comment: "Набор сохраняемых данных")
},
constraints: table =>
{
table.PrimaryKey("PK_TimestampedSets", x => new { x.IdDiscriminator, x.Timestamp });
},
comment: "Общая таблица данных временных рядов");
migrationBuilder.CreateTable(
name: "TechMessage",
columns: table => new
{
EventId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id события"),
CategoryId = table.Column<int>(type: "integer", nullable: false, comment: "Id Категории важности"),
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"),
Text = table.Column<string>(type: "varchar(512)", nullable: false, comment: "Текст сообщения"),
SystemId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id системы, к которой относится сообщение"),
EventState = table.Column<int>(type: "integer", nullable: false, comment: "Статус события")
},
constraints: table =>
{
table.PrimaryKey("PK_TechMessage", x => x.EventId);
table.ForeignKey(
name: "FK_TechMessage_DataSourceSystem_SystemId",
column: x => x.SystemId,
principalTable: "DataSourceSystem",
principalColumn: "SystemId",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_TechMessage_SystemId",
table: "TechMessage",
column: "SystemId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ChangeLog");
migrationBuilder.DropTable(
name: "DataSaub");
migrationBuilder.DropTable(
name: "ParameterData");
migrationBuilder.DropTable(
name: "Setpoint");
migrationBuilder.DropTable(
name: "TechMessage");
migrationBuilder.DropTable(
name: "TimestampedSets");
migrationBuilder.DropTable(
name: "DataSourceSystem");
}
}
}

View File

@ -1,15 +1,14 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using DD.Persistence.Database.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Persistence.Database.Model;
#nullable disable
namespace Persistence.Database.Postgres.Migrations
namespace DD.Persistence.Database.Postgres.Migrations
{
[DbContext(typeof(PersistencePostgresContext))]
partial class PersistencePostgresContextModelSnapshot : ModelSnapshot
@ -18,38 +17,36 @@ namespace Persistence.Database.Postgres.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.UseCollation("Russian_Russia.1251")
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Persistence.Database.Entity.DrillingSystem", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
{
b.Property<Guid>("SystemId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("Id системы автобурения");
.HasComment("Id системы - источника данных");
b.Property<string>("Description")
.HasColumnType("text")
.HasComment("Описание системы автобурения");
.HasComment("Описание системы - источника данных");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(256)")
.HasComment("Наименование системы автобурения");
.HasComment("Наименование системы - источника данных");
b.HasKey("SystemId");
b.ToTable("DrillingSystem");
b.ToTable("DataSourceSystem");
});
modelBuilder.Entity("Persistence.Database.Entity.ParameterData", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.ParameterData", b =>
{
b.Property<int>("DiscriminatorId")
.HasColumnType("integer")
b.Property<Guid>("DiscriminatorId")
.HasColumnType("uuid")
.HasComment("Дискриминатор системы");
b.Property<int>("ParameterId")
@ -70,7 +67,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("ParameterData");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
{
b.Property<Guid>("EventId")
.ValueGeneratedOnAdd()
@ -81,27 +78,23 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("integer")
.HasComment("Id Категории важности");
b.Property<double?>("Depth")
.HasColumnType("double precision")
.HasComment("Глубина забоя");
b.Property<int>("EventState")
.HasColumnType("integer")
.HasComment("Статус события");
b.Property<string>("MessageText")
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы, к которой относится сообщение");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("varchar(512)")
.HasComment("Текст сообщения");
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы автобурения, к которой относится сообщение");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone")
.HasComment("Дата возникновения");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasComment("Id пользователя за пультом бурильщика");
b.HasKey("EventId");
b.HasIndex("SystemId");
@ -109,7 +102,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("TechMessage");
});
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedSet", b =>
{
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
@ -132,60 +125,60 @@ namespace Persistence.Database.Postgres.Migrations
});
});
modelBuilder.Entity("Persistence.Database.Model.ChangeLog", b =>
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasColumnName("Id");
.HasComment("Ключ записи");
b.Property<DateTimeOffset>("Creation")
.HasColumnType("timestamp with time zone")
.HasColumnName("Creation");
.HasComment("Дата создания записи");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
.HasColumnName("DepthEnd");
.HasComment("Глубина забоя на дату окончания интервала");
b.Property<double>("DepthStart")
.HasColumnType("double precision")
.HasColumnName("DepthStart");
.HasComment("Глубина забоя на дату начала интервала");
b.Property<Guid>("IdAuthor")
.HasColumnType("uuid")
.HasColumnName("IdAuthor");
.HasComment("Автор изменения");
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
.HasColumnName("IdDiscriminator");
.HasComment("Дискриминатор таблицы");
b.Property<Guid?>("IdEditor")
.HasColumnType("uuid")
.HasColumnName("IdEditor");
.HasComment("Редактор");
b.Property<Guid?>("IdNext")
.HasColumnType("uuid")
.HasColumnName("IdNext");
.HasComment("Id заменяющей записи");
b.Property<Guid>("IdSection")
.HasColumnType("uuid")
.HasColumnName("IdSection");
.HasComment("Ключ секции");
b.Property<DateTimeOffset?>("Obsolete")
.HasColumnType("timestamp with time zone")
.HasColumnName("Obsolete");
.HasComment("Дата устаревания (например при удалении)");
b.Property<IDictionary<string, object>>("Value")
b.Property<string>("Value")
.IsRequired()
.HasColumnType("jsonb")
.HasColumnName("Value");
.HasComment("Значение");
b.HasKey("Id");
b.ToTable("ChangeLog");
});
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
modelBuilder.Entity("DD.Persistence.Database.Model.DataSaub", b =>
{
b.Property<DateTimeOffset>("Date")
.HasColumnType("timestamp with time zone")
@ -268,7 +261,7 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("DataSaub");
});
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
{
b.Property<Guid>("Key")
.HasColumnType("uuid")
@ -292,9 +285,9 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("Setpoint");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
{
b.HasOne("Persistence.Database.Entity.DrillingSystem", "System")
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
.WithMany()
.HasForeignKey("SystemId")
.OnDelete(DeleteBehavior.Cascade)

View File

@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
/// <summary>
/// EF êîíòåêñò äëÿ ÁÄ Postgres
@ -13,10 +13,6 @@ public partial class PersistencePostgresContext : PersistenceDbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("adminpack")
.HasAnnotation("Relational:Collation", "Russian_Russia.1251");
base.OnModelCreating(modelBuilder);
}
}

View File

@ -1,11 +1,11 @@
## Создать миграцию
```
dotnet ef migrations add <MigrationName> --project Persistence.Database.Postgres
dotnet ef migrations add <MigrationName> --project DD.Persistence.Database.Postgres
```
## Откатить миграцию
```
dotnet ef migrations remove --project Persistence.Database.Postgres
dotnet ef migrations remove --project DD.Persistence.Database.Postgres
```
Удаляется последняя созданная миграция.

View File

@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Persistence\Persistence.csproj" />
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Persistence.Database;
namespace DD.Persistence.Database;
public static class EFExtensions
{

View File

@ -1,10 +1,10 @@

using Microsoft.EntityFrameworkCore;
using Persistence.Models;
using DD.Persistence.Models;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
/// <summary>
/// Часть записи, описывающая изменение

View File

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
public class DataSaub : ITimestampedData
{
[Key, Column("date")]

View File

@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DD.Persistence.Database.Entity;
public class DataSourceSystem
{
[Key, Comment("Id системы - источника данных")]
public Guid SystemId { get; set; }
[Required, Column(TypeName = "varchar(256)"), Comment("Наименование системы - источника данных")]
public required string Name { get; set; }
[Comment("Описание системы - источника данных")]
public string? Description { get; set; }
}

View File

@ -1,5 +1,5 @@

namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
/// <summary>
/// Часть записи, описывающая изменение

View File

@ -1,4 +1,4 @@
namespace Persistence.Database.Model;
namespace DD.Persistence.Database.Model;
public interface ITimestampedData
{
/// <summary>

View File

@ -2,7 +2,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Persistence.Database.Entity;
namespace DD.Persistence.Database.Entity;
[PrimaryKey(nameof(DiscriminatorId), nameof(ParameterId), nameof(Timestamp))]
public class ParameterData

View File

@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace Persistence.Database.Model
namespace DD.Persistence.Database.Model
{
[PrimaryKey(nameof(Key), nameof(Created))]
public class Setpoint

View File

@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DD.Persistence.Database.Entity
{
public class TechMessage
{
[Key, Comment("Id события")]
public Guid EventId { get; set; }
[Comment("Id Категории важности")]
public int CategoryId { get; set; }
[Comment("Дата возникновения")]
public DateTimeOffset Timestamp { get; set; }
[Column(TypeName = "varchar(512)"), Comment("Текст сообщения")]
public required string Text { get; set; }
[Required, Comment("Id системы, к которой относится сообщение")]
public required Guid SystemId { get; set; }
[Required, ForeignKey(nameof(SystemId)), Comment("Система, к которой относится сообщение")]
public virtual required DataSourceSystem System { get; set; }
[Comment("Статус события")]
public int EventState { get; set; }
}
}

View File

@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace Persistence.Database.Entity;
namespace DD.Persistence.Database.Entity;
[Comment("Общая таблица данных временных рядов")]
[PrimaryKey(nameof(IdDiscriminator), nameof(Timestamp))]

View File

@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Persistence.Database.Entity;
using Persistence.Database.Model;
using DD.Persistence.Database.Entity;
using DD.Persistence.Database.Model;
namespace Persistence.Database;
namespace DD.Persistence.Database;
/// <summary>
/// EF контекст для любых БД поддерживаемых в EF
@ -21,7 +21,9 @@ public class PersistenceDbContext : DbContext
public DbSet<ParameterData> ParameterData => Set<ParameterData>();
public PersistenceDbContext(DbContextOptions options)
public DbSet<DataSourceSystem> DataSourceSystem => Set<DataSourceSystem>();
public PersistenceDbContext(DbContextOptions options)
: base(options)
{

View File

@ -1,9 +1,9 @@
using Microsoft.Extensions.DependencyInjection;
using Persistence.Database;
using Persistence.Database.Model;
using DD.Persistence.Database;
using DD.Persistence.Database.Model;
using Xunit;
namespace Persistence.IntegrationTests;
namespace DD.Persistence.IntegrationTests;
public abstract class BaseIntegrationTest : IClassFixture<WebAppFactoryFixture>, IDisposable
{
protected readonly IServiceScope scope;

View File

@ -1,15 +1,19 @@
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Entity;
using Persistence.Database.Model;
using Persistence.Models;
using Persistence.Models.Requests;
using DD.Persistence.Database.Model;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using Xunit;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
using Refit;
using System.Net.Http;
namespace Persistence.IntegrationTests.Controllers;
namespace DD.Persistence.IntegrationTests.Controllers;
public class ChangeLogControllerTest : BaseIntegrationTest
{
private readonly IChangeLogClient client;
@ -17,10 +21,12 @@ public class ChangeLogControllerTest : BaseIntegrationTest
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitChangeLogClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ChangeLogClient>>();
client = persistenceClientFactory.GetChangeLogClient();
client = scope.ServiceProvider
.GetRequiredService<IChangeLogClient>();
}
[Fact]
@ -52,7 +58,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken());
// assert
Assert.Equal(insertedCount*2, result);
Assert.Equal(insertedCount * 2, result);
}
[Fact]
@ -116,11 +122,11 @@ public class ChangeLogControllerTest : BaseIntegrationTest
Assert.NotNull(changeLogResult);
var obsoleteDto = changeLogResult
.Where(e => e.Obsolete.HasValue)
.Where(e => e.Obsolete.HasValue)
.FirstOrDefault();
var activeDto = changeLogResult
.Where(e => !e.Obsolete.HasValue)
.Where(e => !e.Obsolete.HasValue)
.FirstOrDefault();
if (obsoleteDto == null || activeDto == null)

View File

@ -1,8 +1,8 @@
using Persistence.Database.Model;
using Persistence.Models;
using DD.Persistence.Database.Model;
using DD.Persistence.Models;
using Xunit;
namespace Persistence.IntegrationTests.Controllers;
namespace DD.Persistence.IntegrationTests.Controllers;
public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaub, DataSaubDto>
{
private readonly DataSaubDto dto = new()

View File

@ -0,0 +1,85 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using DD.Persistence.Client;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Database.Entity;
using DD.Persistence.Models;
using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using Microsoft.Extensions.Logging;
namespace DD.Persistence.IntegrationTests.Controllers
{
public class DataSourceSystemControllerTest : BaseIntegrationTest
{
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DataSourceSystem).FullName}CacheKey";
private readonly IDataSourceSystemClient dataSourceSystemClient;
private readonly IMemoryCache memoryCache;
public DataSourceSystemControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitDataSourceSystemClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<DataSourceSystemClient>>();
dataSourceSystemClient = scope.ServiceProvider
.GetRequiredService<IDataSourceSystemClient>();
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
}
[Fact]
public async Task Get_returns_success()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<DataSourceSystem>();
//act
var response = await dataSourceSystemClient.Get(CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task Get_AfterSave_returns_success()
{
//arrange
await Add();
//act
var response = await dataSourceSystemClient.Get(CancellationToken.None);
//assert
Assert.NotNull(response);
var expectedSystemCount = 1;
var actualSystemCount = response!.Count();
Assert.Equal(expectedSystemCount, actualSystemCount);
}
[Fact]
public async Task Add_returns_success()
{
await Add();
}
private async Task Add()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<DataSourceSystem>();
var dto = new DataSourceSystemDto()
{
SystemId = Guid.NewGuid(),
Name = "Test",
Description = "Test"
};
//act
await dataSourceSystemClient.Add(dto, CancellationToken.None);
}
}
}

View File

@ -0,0 +1,231 @@
using Microsoft.Extensions.DependencyInjection;
using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Database.Model;
using System.Net;
using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
namespace DD.Persistence.IntegrationTests.Controllers
{
public class SetpointControllerTest : BaseIntegrationTest
{
private readonly ISetpointClient setpointClient;
private class TestObject
{
public string? Value1 { get; set; }
public int? Value2 { get; set; }
}
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitSetpointClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<SetpointClient>>();
setpointClient = scope.ServiceProvider
.GetRequiredService<ISetpointClient>();
}
[Fact]
public async Task GetCurrent_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
{
Guid.NewGuid(),
Guid.NewGuid()
};
//act
var response = await setpointClient.GetCurrent(setpointKeys, new CancellationToken());
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetCurrent_AfterSave_returns_success()
{
//arrange
var setpointKey = await Add();
//act
var response = await setpointClient.GetCurrent([setpointKey], new CancellationToken());
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
}
[Fact]
public async Task GetHistory_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
{
Guid.NewGuid(),
Guid.NewGuid()
};
var historyMoment = DateTimeOffset.UtcNow;
//act
var response = await setpointClient.GetHistory(setpointKeys, historyMoment, new CancellationToken());
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetHistory_AfterSave_returns_success()
{
//arrange
var setpointKey = await Add();
var historyMoment = DateTimeOffset.UtcNow;
historyMoment = historyMoment.AddDays(1);
//act
var response = await setpointClient.GetHistory([setpointKey], historyMoment, new CancellationToken());
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
}
[Fact]
public async Task GetLog_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
{
Guid.NewGuid(),
Guid.NewGuid()
};
//act
var response = await setpointClient.GetLog(setpointKeys, new CancellationToken());
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetLog_AfterSave_returns_success()
{
//arrange
var setpointKey = await Add();
//act
var response = await setpointClient.GetLog([setpointKey], new CancellationToken());
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault().Key);
}
[Fact]
public async Task GetDatesRange_returns_success()
{
//arrange
dbContext.CleanupDbSet<Setpoint>();
//act
var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Equal(DateTimeOffset.MinValue, response!.From);
Assert.Equal(DateTimeOffset.MaxValue, response!.To);
}
[Fact]
public async Task GetDatesRange_AfterSave_returns_success()
{
//arrange
dbContext.CleanupDbSet<Setpoint>();
await Add();
var dateBegin = DateTimeOffset.MinValue;
var take = 1;
var part = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//act
var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.NotNull(response);
var expectedValue = part!
.FirstOrDefault()!.Created
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualValueFrom = response.From
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedValue, actualValueFrom);
var actualValueTo = response.To
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedValue, actualValueTo);
}
[Fact]
public async Task GetPart_returns_success()
{
//arrange
var dateBegin = DateTimeOffset.UtcNow;
var take = 2;
//act
var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetPart_AfterSave_returns_success()
{
//arrange
var dateBegin = DateTimeOffset.UtcNow;
var take = 1;
await Add();
//act
var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
}
[Fact]
public async Task Save_returns_success()
{
await Add();
}
private async Task<Guid> Add()
{
//arrange
var setpointKey = Guid.NewGuid();
var setpointValue = new TestObject()
{
Value1 = "1",
Value2 = 2
};
//act
await setpointClient.Add(setpointKey, setpointValue, new CancellationToken());
return setpointKey;
}
}
}

View File

@ -0,0 +1,283 @@
using DD.Persistence.Client;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Entity;
using DD.Persistence.Models;
using DD.Persistence.Models.Enumerations;
using DD.Persistence.Models.Requests;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit;
namespace DD.Persistence.IntegrationTests.Controllers
{
public class TechMessagesControllerTest : BaseIntegrationTest
{
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DataSourceSystem).FullName}CacheKey";
private readonly ITechMessagesClient techMessagesClient;
private readonly IMemoryCache memoryCache;
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitTechMessagesClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TechMessagesClient>>();
techMessagesClient = scope.ServiceProvider
.GetRequiredService<ITechMessagesClient>();
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
}
[Fact]
public async Task GetPage_returns_success()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DataSourceSystem>();
var requestDto = new PaginationRequest()
{
Skip = 1,
Take = 2,
SortSettings = nameof(TechMessage.CategoryId)
};
//act
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response.Items);
Assert.Equal(requestDto.Skip, response.Skip);
Assert.Equal(requestDto.Take, response.Take);
}
[Fact]
public async Task GetPage_AfterSave_returns_success()
{
//arrange
var dtos = await InsertRange(Guid.NewGuid());
var dtosCount = dtos.Count();
var requestDto = new PaginationRequest()
{
Skip = 0,
Take = 2,
SortSettings = nameof(TechMessage.CategoryId)
};
//act
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Equal(dtosCount, response.Count);
}
[Fact]
public async Task InsertRange_returns_success()
{
await InsertRange(Guid.NewGuid());
}
[Fact]
public async Task InsertRange_returns_BadRequest()
{
//arrange
const string exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
var systemId = Guid.NewGuid();
var dtos = new List<TechMessageDto>()
{
new TechMessageDto()
{
EventId = Guid.NewGuid(),
CategoryId = -1, // < 0
Timestamp = DateTimeOffset.UtcNow,
Text = string.Empty, // length < 0
EventState = EventState.Triggered
}
};
try
{
//act
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
}
catch (Exception ex)
{
//assert
Assert.Equal(exceptionMessage, ex.Message);
}
}
[Fact]
public async Task GetSystems_returns_success()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DataSourceSystem>();
//act
var response = await techMessagesClient.GetSystems(CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetSystems_AfterSave_returns_success()
{
//arrange
await InsertRange(Guid.NewGuid());
//act
var response = await techMessagesClient.GetSystems(CancellationToken.None);
//assert
Assert.NotNull(response);
var expectedSystemCount = 1;
Assert.Equal(expectedSystemCount, response!.Count());
}
[Fact]
public async Task GetStatistics_returns_success()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DataSourceSystem>();
var categoryIds = new[] { 1, 2 };
var systemIds = new[] { Guid.NewGuid() };
//act
var response = await techMessagesClient.GetStatistics(systemIds, categoryIds, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetStatistics_AfterSave_returns_success()
{
//arrange
var categoryIds = new[] { 1 };
var systemId = Guid.NewGuid();
var dtos = await InsertRange(systemId);
var filteredDtos = dtos.Where(e => categoryIds.Contains(e.CategoryId));
//act
var response = await techMessagesClient.GetStatistics([systemId], categoryIds, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
var categories = response
.FirstOrDefault()!.Categories
.Count();
Assert.Equal(filteredDtos.Count(), categories);
}
[Fact]
public async Task GetDatesRange_returns_NoContent()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DataSourceSystem>();
//act
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.Null(response);
}
[Fact]
public async Task GetDatesRange_AfterSave_returns_success()
{
//arrange
await InsertRange(Guid.NewGuid());
//act
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.NotNull(response?.From);
Assert.NotNull(response?.To);
}
// [Fact]
// public async Task GetPart_returns_success()
// {
// //arrange
// var dateBegin = DateTimeOffset.UtcNow;
// var take = 2;
// //act
// var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
// //assert
// Assert.NotNull(response);
// Assert.Empty(response);
//}
[Fact]
public async Task GetPart_AfterSave_returns_success()
{
//arrange
var dateBegin = DateTimeOffset.UtcNow;
var take = 1;
await InsertRange(Guid.NewGuid());
//act
var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
}
private async Task<IEnumerable<TechMessageDto>> InsertRange(Guid systemId)
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DataSourceSystem>();
var dtos = new List<TechMessageDto>()
{
new TechMessageDto()
{
EventId = Guid.NewGuid(),
CategoryId = 1,
Timestamp = DateTimeOffset.UtcNow,
Text = nameof(TechMessageDto.Text),
EventState = Models.Enumerations.EventState.Triggered
},
new TechMessageDto()
{
EventId = Guid.NewGuid(),
CategoryId = 2,
Timestamp = DateTimeOffset.UtcNow,
Text = nameof(TechMessageDto.Text),
EventState = Models.Enumerations.EventState.Triggered
}
};
//act
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
//assert
Assert.Equal(dtos.Count, response);
return dtos;
}
}
}

View File

@ -1,16 +1,19 @@
using DD.Persistence.Client;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Model;
using DD.Persistence.Models;
using Mapster;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Model;
using System.Net;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Persistence.IntegrationTests.Controllers;
namespace DD.Persistence.IntegrationTests.Controllers;
public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrationTest
where TEntity : class, ITimestampedData, new()
where TDto : class, new()
where TDto : class, ITimeSeriesAbstractDto, new()
{
private readonly ITimeSeriesClient<TDto> timeSeriesClient;
@ -18,11 +21,12 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
{
dbContext.CleanupDbSet<TEntity>();
var scope = factory.Services.CreateScope();
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitTimeSeriesClient<TDto>>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TimeSeriesClient<TDto>>>();
timeSeriesClient = persistenceClientFactory.GetTimeSeriesClient<TDto>();
timeSeriesClient = scope.ServiceProvider
.GetRequiredService<ITimeSeriesClient<TDto>>();
}
public async Task InsertRangeSuccess(TDto dto)

View File

@ -1,20 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients.Interfaces;
using Persistence.Models;
using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models;
using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
namespace Persistence.IntegrationTests.Controllers;
namespace DD.Persistence.IntegrationTests.Controllers;
public class TimestampedSetControllerTest : BaseIntegrationTest
{
private readonly ITimestampedSetClient client;
public TimestampedSetControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitTimestampedSetClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TimestampedSetClient>>();
client = persistenceClientFactory.GetTimestampedSetClient();
client = scope.ServiceProvider
.GetRequiredService<ITimestampedSetClient>();
}
[Fact]
@ -72,7 +77,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
}
}
[Fact]
[Fact]
public async Task Get_geDate()
{
// arrange
@ -112,11 +117,11 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
// assert
Assert.NotNull(response);
Assert.Equal(expectedCount, response.Count());
}
Assert.Equal(expectedCount, response.Count());
}
[Fact]
[Fact]
public async Task Get_with_big_skip_take()
{
// arrange

View File

@ -1,25 +1,27 @@
using DD.Persistence.Client;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Entity;
using DD.Persistence.Models;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Entity;
using Persistence.Models;
using System.Net;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Persistence.IntegrationTests.Controllers;
namespace DD.Persistence.IntegrationTests.Controllers;
public class WitsDataControllerTest : BaseIntegrationTest
{
private IWitsDataClient witsDataClient;
public WitsDataControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var scope = factory.Services.CreateScope();
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitWitsDataClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<WitsDataClient>>();
witsDataClient = persistenceClientFactory.GetWitsDataClient();
}
witsDataClient = scope.ServiceProvider
.GetRequiredService<IWitsDataClient>();
}
[Fact]
public async Task GetDatesRangeAsync_returns_success()
@ -32,9 +34,9 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, CancellationToken.None);
//assert
Assert.NotNull(response);
}
//assert
Assert.NotNull(response);
}
[Fact]
public async Task GetPart_returns_success()
@ -49,10 +51,10 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task InsertRange_returns_success()
@ -78,10 +80,10 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
//assert
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
public async Task GetDatesRangeAsync_AfterSave_returns_success()
@ -95,25 +97,25 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, CancellationToken.None);
//assert
Assert.NotNull(response);
//assert
Assert.NotNull(response);
var expectedDateFrom = dtos
.Select(e => e.Timestamped)
.Min()
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualDateFrom = response.From.DateTime
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedDateFrom, actualDateFrom);
var expectedDateFrom = dtos
.Select(e => e.Timestamped)
.Min()
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualDateFrom = response.From.DateTime
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedDateFrom, actualDateFrom);
var expectedDateTo = dtos
.Select(e => e.Timestamped)
.Max()
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualDateTo = response.To.DateTime
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedDateTo, actualDateTo);
}
var expectedDateTo = dtos
.Select(e => e.Timestamped)
.Max()
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualDateTo = response.To.DateTime
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedDateTo, actualDateTo);
}
[Fact]
public async Task GetPart_AfterSave_returns_success()
@ -129,14 +131,14 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(take, response.Count());
//assert
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(take, response.Count());
var expectedDto = dtos.FirstOrDefault();
var actualDto = response.FirstOrDefault();
Assert.Equal(expectedDto?.DiscriminatorId, actualDto?.DiscriminatorId);
var expectedDto = dtos.FirstOrDefault();
var actualDto = response.FirstOrDefault();
Assert.Equal(expectedDto?.DiscriminatorId, actualDto?.DiscriminatorId);
var expectedValueDto = expectedDto?.Values.FirstOrDefault();
var actualValueDto = actualDto?.Values.FirstOrDefault();
@ -159,27 +161,27 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, CancellationToken.None);
//assert
Assert.NotNull(response);
Assert.Equal(approxPointCount, response.Count());
}
//assert
Assert.NotNull(response);
Assert.Equal(approxPointCount, response.Count());
}
[Fact]
public async Task AddRange_returns_BadRequest()
{
//arrange
const string exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
var dtos = new List<WitsDataDto>()
{
new WitsDataDto()
{
DiscriminatorId = Guid.NewGuid(),
Timestamped = DateTimeOffset.UtcNow,
Values = new List<WitsValueDto>()
{
new WitsValueDto()
{
RecordId = -1, // < 0
[Fact]
public async Task AddRange_returns_BadRequest()
{
//arrange
const string exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
var dtos = new List<WitsDataDto>()
{
new WitsDataDto()
{
DiscriminatorId = Guid.NewGuid(),
Timestamped = DateTimeOffset.UtcNow,
Values = new List<WitsValueDto>()
{
new WitsValueDto()
{
RecordId = -1, // < 0
ItemId = 101, // > 100
Value = string.Empty
}
@ -187,17 +189,17 @@ public class WitsDataControllerTest : BaseIntegrationTest
}
};
try
{
//act
var response = await witsDataClient.AddRange(dtos, CancellationToken.None);
}
catch (Exception ex)
{
//assert
Assert.Equal(exceptionMessage, ex.Message);
}
}
try
{
//act
var response = await witsDataClient.AddRange(dtos, CancellationToken.None);
}
catch (Exception ex)
{
//assert
Assert.Equal(exceptionMessage, ex.Message);
}
}
private async Task<IEnumerable<WitsDataDto>> AddRange(int countToCreate = 10)
{
@ -226,9 +228,9 @@ public class WitsDataControllerTest : BaseIntegrationTest
//act
var response = await witsDataClient.AddRange(dtos, CancellationToken.None);
//assert
var count = dtos.SelectMany(e => e.Values).Count();
Assert.Equal(count, response);
//assert
var count = dtos.SelectMany(e => e.Values).Count();
Assert.Equal(count, response);
return dtos;
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
@ -10,23 +10,27 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.10" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Refit" Version="8.0.0" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Persistence.API\Persistence.API.csproj" />
<ProjectReference Include="..\Persistence.Client\Persistence.Client.csproj" />
<ProjectReference Include="..\Persistence.Database.Postgres\Persistence.Database.Postgres.csproj" />
<ProjectReference Include="..\DD.Persistence.App\DD.Persistence.App.csproj" />
<ProjectReference Include="..\DD.Persistence.Client\DD.Persistence.Client.csproj" />
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,4 @@
namespace Persistence.IntegrationTests;
namespace DD.Persistence.IntegrationTests;
public class DbConnection
{
public string Host { get; set; } = null!;

View File

@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
namespace Persistence.IntegrationTests;
namespace DD.Persistence.IntegrationTests;
public static class EFCoreExtensions
{
public static void CleanupDbSet<T>(this DbContext dbContext)

View File

@ -1,4 +1,7 @@
namespace Persistence.IntegrationTests
using DD.Persistence.Client.Helpers;
using Microsoft.Extensions.Configuration;
namespace DD.Persistence.IntegrationTests
{
/// <summary>
/// Фабрика HTTP клиентов для интеграционных тестов
@ -6,14 +9,19 @@
public class TestHttpClientFactory : IHttpClientFactory
{
private readonly WebAppFactoryFixture factory;
private readonly IConfiguration configuration;
public TestHttpClientFactory(WebAppFactoryFixture factory)
public TestHttpClientFactory(WebAppFactoryFixture factory, IConfiguration configuration)
{
this.factory = factory;
this.configuration = configuration;
}
public HttpClient CreateClient(string name)
{
return factory.CreateClient();
var client = factory.CreateClient();
client.Authorize(configuration);
return client;
}
}
}

Some files were not shown because too many files have changed in this diff Show More