Расширить фабрику клиентов Persistance

This commit is contained in:
Roman Efremov 2024-12-09 14:45:35 +05:00
parent 6f93c331a2
commit 36ace4125d
32 changed files with 917 additions and 265 deletions

View File

@ -0,0 +1,62 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Helpers;
using Refit;
namespace Persistence.Client.Clients.Base;
public class BaseClient
{
private readonly ILogger logger;
public BaseClient(ILogger logger)
{
this.logger = logger;
}
public async Task<T> ExecuteGetResponse<T>(Func<Task<IApiResponse<T>>> getMethod, CancellationToken token)
{
var response = await getMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
{
return response.Content;
}
var exception = response.GetPersistenceException();
logger.LogError(exception.Message);
throw exception;
}
public async Task ExecutePostResponse(Func<Task<IApiResponse>> postMethod, CancellationToken token)
{
var response = await postMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
{
return;
}
var exception = response.GetPersistenceException();
logger.LogError(exception.Message);
throw exception;
}
public async Task<int> ExecutePostResponse(Func<Task<IApiResponse<int>>> postMethod, CancellationToken token)
{
var response = await postMethod.Invoke().WaitAsync(token);
if (response.IsSuccessful)
{
return response.Content;
}
var exception = response.GetPersistenceException();
logger.LogError(exception.Message);
throw exception;
}
}

View File

@ -1,30 +0,0 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients;
/// <summary>
/// Интерфейс клиента для работы с уставками
/// </summary>
public interface ISetpointClient
{
private const string BaseRoute = "/api/setpoint";
[Get($"{BaseRoute}/current")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
[Get($"{BaseRoute}/history")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment);
[Get($"{BaseRoute}/log")]
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
[Get($"{BaseRoute}/range")]
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
[Get($"{BaseRoute}/part")]
Task<IApiResponse<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
[Post($"{BaseRoute}/")]
Task<IApiResponse> Add(Guid setpointKey, object newValue);
}

View File

@ -1,31 +0,0 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients
{
/// <summary>
/// Интерфейс клиента для хранения технологических сообщений
/// </summary>
public interface ITechMessagesClient
{
private const string BaseRoute = "/api/techMessages";
[Get($"{BaseRoute}")]
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] RequestDto request, CancellationToken token);
[Post($"{BaseRoute}")]
Task<IApiResponse<int>> AddRange([Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
[Get($"{BaseRoute}/systems")]
Task<IApiResponse<IEnumerable<string>>> 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] string autoDrillingSystem, [Query] int categoryId, CancellationToken token);
}
}

View File

@ -0,0 +1,59 @@
using Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с уставками
/// </summary>
public interface ISetpointClient
{
/// <summary>
/// Добавить уставку
/// </summary>
/// <param name="setpointKey"></param>
/// <param name="newValue"></param>
/// <param name="token"></param>
/// <returns></returns>
Task Add(Guid setpointKey, object newValue, CancellationToken token);
/// <summary>
/// Получить актуальные значения уставок
/// </summary>
/// <param name="setpointKeys"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
/// <summary>
/// Получить диапазон дат, для которых есть данные в репозитории
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
/// <summary>
/// Получить значения уставок за определенный момент времени
/// </summary>
/// <param name="setpointKeys"></param>
/// <param name="historyMoment"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token);
/// <summary>
/// Получить историю изменений значений уставок
/// </summary>
/// <param name="setpointKeys"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
/// <summary>
/// Получить порцию записей, начиная с заданной даты
/// </summary>
/// <param name="dateBegin"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
}

View File

@ -0,0 +1,57 @@
using Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с технологическими сообщениями
/// </summary>
public interface ITechMessagesClient
{
/// <summary>
/// Добавить новые технологические сообщения
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> AddRange(IEnumerable<TechMessageDto> dtos, CancellationToken token);
/// <summary>
/// Получить диапазон дат, для которых есть данные в репозитории
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
/// <summary>
/// Получить список технологических сообщений в виде страницы
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<TechMessageDto>> GetPage(RequestDto request, CancellationToken token);
/// <summary>
/// Получить порцию записей, начиная с заданной даты
/// </summary>
/// <param name="dateBegin"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
/// <summary>
/// Получить статистику по системам
/// </summary>
/// <param name="autoDrillingSystem"></param>
/// <param name="categoryId"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<MessagesStatisticDto>> GetStatistics(string autoDrillingSystem, int categoryId, CancellationToken token);
/// <summary>
/// Получить список всех систем
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<string>> GetSystems(CancellationToken token);
}

View File

@ -0,0 +1,44 @@
using Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с временными данными
/// </summary>
/// <typeparam name="TDto"></typeparam>
public interface ITimeSeriesClient<TDto> where TDto : class, new()
{
/// <summary>
/// Добавление записей
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
/// <summary>
/// Получить список объектов, удовлетворяющий диапазону дат
/// </summary>
/// <param name="dateBegin"></param>
/// <param name="dateEnd"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
/// <summary>
/// Получить диапазон дат, для которых есть данные в репозитории
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto?> GetDatesRange(CancellationToken token);
/// <summary>
/// Получить список объектов с прореживанием, удовлетворяющий диапазону дат
/// </summary>
/// <param name="dateBegin"></param>
/// <param name="intervalSec"></param>
/// <param name="approxPointsCount"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default);
}

View File

@ -0,0 +1,56 @@
using Persistence.Models;
namespace Persistence.Client.Clients.Interfaces;
/// <summary>
/// Клиент для работы с данными с отметкой времени
/// </summary>
public interface ITimestampedSetClient
{
/// <summary>
/// Записать новые данные
/// </summary>
/// <param name="idDiscriminator"></param>
/// <param name="sets"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
/// <summary>
/// Количество записей по указанному набору в БД. Для пагинации
/// </summary>
/// <param name="idDiscriminator"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> Count(Guid idDiscriminator, CancellationToken token);
/// <summary>
/// Получение данных с фильтрацией. Значение фильтра null - отключен
/// </summary>
/// <param name="idDiscriminator"></param>
/// <param name="geTimestamp"></param>
/// <param name="columnNames"></param>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TimestampedSetDto>> Get(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
/// <summary>
/// Диапазон дат за которые есть данные
/// </summary>
/// <param name="idDiscriminator"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token);
/// <summary>
///
/// </summary>
/// <param name="idDiscriminator"></param>
/// <param name="columnNames"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TimestampedSetDto>> GetLast(Guid idDiscriminator, IEnumerable<string>? columnNames, int take, CancellationToken token);
}

View File

@ -0,0 +1,30 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit;
/// <summary>
/// Интерфейс клиента для работы с уставками
/// </summary>
public interface IRefitSetpointClient
{
private const string BaseRoute = "/api/setpoint";
[Get($"{BaseRoute}/current")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, CancellationToken token);
[Get($"{BaseRoute}/history")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment, CancellationToken token);
[Get($"{BaseRoute}/log")]
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, CancellationToken token);
[Get($"{BaseRoute}/range")]
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
[Get($"{BaseRoute}/part")]
Task<IApiResponse<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
[Post($"{BaseRoute}/")]
Task<IApiResponse> Add(Guid setpointKey, object newValue, CancellationToken token);
}

View File

@ -0,0 +1,31 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients.Interfaces.Refit
{
/// <summary>
/// Интерфейс клиента для хранения технологических сообщений
/// </summary>
public interface IRefitTechMessagesClient
{
private const string BaseRoute = "/api/techMessages";
[Get($"{BaseRoute}")]
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] RequestDto request, CancellationToken token);
[Post($"{BaseRoute}")]
Task<IApiResponse<int>> AddRange([Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
[Get($"{BaseRoute}/systems")]
Task<IApiResponse<IEnumerable<string>>> 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] string autoDrillingSystem, [Query] int categoryId, CancellationToken token);
}
}

View File

@ -1,21 +1,21 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients;
public interface ITimeSeriesClient<TDto>
namespace Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimeSeriesClient<TDto>
where TDto : class, new()
{
private const string BaseRoute = "/api/dataSaub";
[Post($"{BaseRoute}")]
Task<IApiResponse<int>> AddRange(IEnumerable<TDto> dtos);
Task<IApiResponse<int>> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
[Get($"{BaseRoute}")]
Task<IApiResponse<IEnumerable<TDto>>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd);
Task<IApiResponse<IEnumerable<TDto>>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
[Get($"{BaseRoute}/resampled")]
Task<IApiResponse<IEnumerable<TDto>>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024);
Task<IApiResponse<IEnumerable<TDto>>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default);
[Get($"{BaseRoute}/datesRange")]
Task<IApiResponse<DatesRangeDto?>> GetDatesRange();
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(CancellationToken token);
}

View File

@ -1,7 +1,7 @@
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients;
namespace Persistence.Client.Clients.Interfaces.Refit;
/// <summary>
/// Клиент для работы с репозиторием для хранения разных наборов данных рядов.
@ -9,7 +9,7 @@ namespace Persistence.Client.Clients;
/// idDiscriminator формируют клиенты и только им известно что они обозначают.
/// Так как данные приходят редко, то их прореживания для построения графиков не предусмотрено.
/// </summary>
public interface ITimestampedSetClient
public interface IRefitTimestampedSetClient
{
private const string baseUrl = "/api/TimestampedSet/{idDiscriminator}";
@ -20,7 +20,7 @@ public interface ITimestampedSetClient
/// <param name="sets"></param>
/// <returns></returns>
[Post(baseUrl)]
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets);
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
/// <summary>
/// Получение данных с фильтрацией. Значение фильтра null - отключен
@ -32,7 +32,7 @@ public interface ITimestampedSetClient
/// <param name="take"></param>
/// <returns></returns>
[Get(baseUrl)]
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> Get(Guid idDiscriminator, [Query] DateTimeOffset? geTimestamp, [Query] IEnumerable<string>? columnNames, int skip, int take);
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> Get(Guid idDiscriminator, [Query] DateTimeOffset? geTimestamp, [Query] IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
/// <summary>
/// Получить последние данные
@ -42,7 +42,7 @@ public interface ITimestampedSetClient
/// <param name="take"></param>
/// <returns></returns>
[Get($"{baseUrl}/last")]
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> GetLast(Guid idDiscriminator, [Query] IEnumerable<string>? columnNames, int take);
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> GetLast(Guid idDiscriminator, [Query] IEnumerable<string>? columnNames, int take, CancellationToken token);
/// <summary>
/// Количество записей по указанному набору в БД. Для пагинации.
@ -50,7 +50,7 @@ public interface ITimestampedSetClient
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
/// <returns></returns>
[Get($"{baseUrl}/count")]
Task<IApiResponse<int>> Count(Guid idDiscriminator);
Task<IApiResponse<int>> Count(Guid idDiscriminator, CancellationToken token);
/// <summary>
/// Диапазон дат за которые есть данные
@ -58,5 +58,5 @@ public interface ITimestampedSetClient
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
/// <returns></returns>
[Get($"{baseUrl}/datesRange")]
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid idDiscriminator);
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid idDiscriminator, CancellationToken token);
}

View File

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

View File

@ -0,0 +1,65 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
namespace Persistence.Client.Clients;
public class TechMessagesClient : BaseClient, ITechMessagesClient
{
private readonly IRefitTechMessagesClient refitTechMessagesClient;
public TechMessagesClient(IRefitTechMessagesClient refitTechMessagesClient, ILogger logger) : base(logger)
{
this.refitTechMessagesClient = refitTechMessagesClient;
}
public async Task<PaginationContainer<TechMessageDto>> GetPage(RequestDto request, CancellationToken token)
{
var result = await ExecuteGetResponse<PaginationContainer<TechMessageDto>>(
async () => await refitTechMessagesClient.GetPage(request, token), token);
return result;
}
public async Task<int> AddRange(IEnumerable<TechMessageDto> dtos, CancellationToken token)
{
var result = await ExecutePostResponse(
async () => await refitTechMessagesClient.AddRange(dtos, token), token);
return result;
}
public async Task<IEnumerable<string>> GetSystems(CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<string>>(
async () => await refitTechMessagesClient.GetSystems(token), token);
return result;
}
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto>(
async () => await refitTechMessagesClient.GetDatesRangeAsync(token), token);
return result;
}
public async Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TechMessageDto>>(
async () => await refitTechMessagesClient.GetPart(dateBegin, take, token), token);
return result;
}
public async Task<IEnumerable<MessagesStatisticDto>> GetStatistics(string autoDrillingSystem, int categoryId, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<MessagesStatisticDto>>(
async () => await refitTechMessagesClient.GetStatistics(autoDrillingSystem, categoryId, token), token);
return result;
}
}

View File

@ -0,0 +1,48 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
namespace Persistence.Client.Clients;
public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, new()
{
private readonly IRefitTimeSeriesClient<TDto> timeSeriesClient;
public TimeSeriesClient(IRefitTimeSeriesClient<TDto> refitTechMessagesClient, ILogger logger) : base(logger)
{
this.timeSeriesClient = refitTechMessagesClient;
}
public async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
{
var result = await ExecutePostResponse(
async () => await timeSeriesClient.AddRange(dtos, token), token);
return result;
}
public async Task<IEnumerable<TDto>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TDto>>(
async () => await timeSeriesClient.Get(dateBegin, dateEnd, token), token);
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>>(
async () => await timeSeriesClient.GetResampledData(dateBegin, intervalSec, approxPointsCount, token), token);
return result;
}
public async Task<DatesRangeDto?> GetDatesRange(CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto?>(
async () => await timeSeriesClient.GetDatesRange(token), token);
return result;
}
}

View File

@ -0,0 +1,56 @@
using Microsoft.Extensions.Logging;
using Persistence.Client.Clients.Base;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients.Interfaces.Refit;
using Persistence.Models;
namespace Persistence.Client.Clients;
public class TimestampedSetClient : BaseClient, ITimestampedSetClient
{
private readonly IRefitTimestampedSetClient refitTimestampedSetClient;
public TimestampedSetClient(IRefitTimestampedSetClient refitTimestampedSetClient, ILogger logger) : base(logger)
{
this.refitTimestampedSetClient = refitTimestampedSetClient;
}
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)
{
var result = await ExecutePostResponse(
async () => await refitTimestampedSetClient.AddRange(idDiscriminator, sets, token), token);
return result;
}
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>>(
async () => await refitTimestampedSetClient.Get(idDiscriminator, geTimestamp, columnNames, skip, take, token), token);
return result;
}
public async Task<IEnumerable<TimestampedSetDto>> GetLast(Guid idDiscriminator, IEnumerable<string>? columnNames, int take, CancellationToken token)
{
var result = await ExecuteGetResponse<IEnumerable<TimestampedSetDto>>(
async () => await refitTimestampedSetClient.GetLast(idDiscriminator, columnNames, take, token), token);
return result;
}
public async Task<int> Count(Guid idDiscriminator, CancellationToken token)
{
var result = await ExecuteGetResponse<int>(
async () => await refitTimestampedSetClient.Count(idDiscriminator, token), token);
return result;
}
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
{
var result = await ExecuteGetResponse<DatesRangeDto?>(
async () => await refitTimestampedSetClient.GetDatesRange(idDiscriminator, token), token);
return result;
}
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Not Acceptable (406)
/// </summary>
public class AcceptableException : Exception
{
public AcceptableException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Bad gateway (502)
/// </summary>
public class BadGatewayException : Exception
{
public BadGatewayException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Forbidden (403)
/// </summary>
public class ForbiddenException : Exception
{
public ForbiddenException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Internal Server Error (500)
/// </summary>
public class InternalServerException : Exception
{
public InternalServerException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Locked (423)
/// </summary>
public class LockedException : Exception
{
public LockedException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Service Unavailable Error (503)
/// </summary>
public class ServiceUnavailableException : Exception
{
public ServiceUnavailableException(string message)
: base(message) { }
}

View File

@ -0,0 +1,10 @@
namespace Persistence.Client.CustomExceptions;
/// <summary>
/// Too Many Requests (429)
/// </summary>
public class TooManyRequestsException : Exception
{
public TooManyRequestsException(string message)
: base(message) { }
}

View File

@ -27,6 +27,11 @@ public static class ApiTokenHelper
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
}
public static void Authorize(this HttpClient httpClient, string jwtToken)
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
}
private static string CreateDefaultJwtToken(this AuthUser authUser)
{
var nameIdetifier = Guid.NewGuid().ToString();

View File

@ -0,0 +1,33 @@
using System.ComponentModel.DataAnnotations;
using Persistence.Client.CustomExceptions;
using Refit;
namespace Persistence.Client.Helpers;
public static class ExceptionsHelper
{
private static readonly Dictionary<System.Net.HttpStatusCode, Exception> ExceptionsDictionary = new Dictionary<System.Net.HttpStatusCode, Exception>()
{
{ System.Net.HttpStatusCode.BadRequest, new ValidationException("Ошибка валидации, формата или маршрутизации запроса") },
{ System.Net.HttpStatusCode.Unauthorized, new UnauthorizedAccessException("Ошибка авторизации, клиент должен аутентифицировать себя, чтобы получить запрошенный ответ") },
{ System.Net.HttpStatusCode.Forbidden, new ForbiddenException("Клиент известен серверу, но он неавторизован") },
{ System.Net.HttpStatusCode.NotFound, new EntryPointNotFoundException("Сервер не может найти запрошенный ресурс") },
{ System.Net.HttpStatusCode.MethodNotAllowed, new MethodAccessException("Обращение запрещено") },
{ System.Net.HttpStatusCode.NotAcceptable, new AcceptableException("После выполнения согласования контента не найдено содержимого, соответствующего заданным критериям") },
{ System.Net.HttpStatusCode.RequestTimeout, new TimeoutException("Время ожидания истекло") },
{ System.Net.HttpStatusCode.Locked, new LockedException("Запрашиваемый ресурс заблокирован") },
{ System.Net.HttpStatusCode.TooManyRequests, new TooManyRequestsException("Пользователь отправил слишком много запросов в определённый промежуток времени") },
{ System.Net.HttpStatusCode.InternalServerError, new InternalServerException("На сервере произошла ошибка, в результате которой он не может успешно обработать запрос") },
{ System.Net.HttpStatusCode.NotImplemented, new NotImplementedException("Метод запроса не поддерживается сервером") },
{ System.Net.HttpStatusCode.BadGateway, new BadGatewayException("В процессе обработки запроса полуен недопустимый ответ от целевого сервера") },
{ System.Net.HttpStatusCode.ServiceUnavailable, new ServiceUnavailableException("В процессе обработки запроса полуен недопустимый ответ от целевого сервера") },
{ System.Net.HttpStatusCode.GatewayTimeout, new TimeoutException("Время ожидания целевого сервера истекло") }
};
public static Exception GetPersistenceException(this IApiResponse response)
{
var exception = ExceptionsDictionary
.FirstOrDefault(e => e.Key == response.StatusCode).Value ?? new Exception("Неопознанная ошибка");
return exception;
}
}

View File

@ -18,8 +18,4 @@
<ProjectReference Include="..\Persistence\Persistence.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,12 @@
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using Persistence.Client.Clients.Interfaces;
using Persistence.Client.Clients;
using Persistence.Client.Helpers;
using Refit;
using Persistence.Factories;
using Persistence.Client.Clients.Interfaces.Refit;
using Microsoft.Extensions.Logging;
namespace Persistence.Client
{
@ -16,17 +21,75 @@ namespace Persistence.Client
PropertyNameCaseInsensitive = true
};
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
private readonly ILogger logger;
private HttpClient httpClient;
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IConfiguration configuration)
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, ILogger<PersistenceClientFactory> logger, IConfiguration configuration)
{
this.httpClient = httpClientFactory.CreateClient();
this.logger = logger;
httpClient = httpClientFactory.CreateClient();
httpClient.Authorize(configuration);
}
public T GetClient<T>()
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IAuthTokenFactory authTokenFactory, ILogger logger, IConfiguration configuration)
{
return RestService.For<T>(httpClient, RefitSettings);
this.logger = logger;
httpClient = httpClientFactory.CreateClient();
var token = authTokenFactory.GetToken();
httpClient.Authorize(token);
}
/// <summary>
/// Получить клиент для работы с уставками
/// </summary>
/// <returns></returns>
public ISetpointClient GetSetpointClient()
{
var restClient = RestService.For<IRefitSetpointClient>(httpClient, RefitSettings);
var client = new SetpointClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с технологическими сообщениями
/// </summary>
/// <returns></returns>
public ITechMessagesClient GetTechMessagesClient()
{
var restClient = RestService.For<IRefitTechMessagesClient>(httpClient, RefitSettings);
var client = new TechMessagesClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с временными данными
/// </summary>
/// <typeparam name="TDto"></typeparam>
/// <returns></returns>
public ITimeSeriesClient<TDto> GetTimeSeriesClient<TDto>()
where TDto : class, new()
{
var restClient = RestService.For<IRefitTimeSeriesClient<TDto>>(httpClient, RefitSettings);
var client = new TimeSeriesClient<TDto>(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с данными с отметкой времени
/// </summary>
/// <returns></returns>
public ITimestampedSetClient GetTimestampedSetClient()
{
var restClient = RestService.For<IRefitTimestampedSetClient>(httpClient, RefitSettings);
var client = new TimestampedSetClient(restClient, logger);
return client;
}
}
}

View File

@ -1,8 +1,6 @@
using System.Net;
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Model;
using Xunit;
@ -22,7 +20,7 @@ namespace Persistence.IntegrationTests.Controllers
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
setpointClient = persistenceClientFactory.GetClient<ISetpointClient>();
setpointClient = persistenceClientFactory.GetSetpointClient();
}
[Fact]
@ -36,12 +34,11 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await setpointClient.GetCurrent(setpointKeys);
var response = await setpointClient.GetCurrent(setpointKeys, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -51,13 +48,12 @@ namespace Persistence.IntegrationTests.Controllers
var setpointKey = await Add();
//act
var response = await setpointClient.GetCurrent([setpointKey]);
var response = await setpointClient.GetCurrent([setpointKey], new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
}
[Fact]
@ -72,12 +68,11 @@ namespace Persistence.IntegrationTests.Controllers
var historyMoment = DateTimeOffset.UtcNow;
//act
var response = await setpointClient.GetHistory(setpointKeys, historyMoment);
var response = await setpointClient.GetHistory(setpointKeys, historyMoment, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -89,13 +84,12 @@ namespace Persistence.IntegrationTests.Controllers
historyMoment = historyMoment.AddDays(1);
//act
var response = await setpointClient.GetHistory([setpointKey], historyMoment);
var response = await setpointClient.GetHistory([setpointKey], historyMoment, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
}
[Fact]
@ -109,12 +103,11 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await setpointClient.GetLog(setpointKeys);
var response = await setpointClient.GetLog(setpointKeys, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -124,13 +117,12 @@ namespace Persistence.IntegrationTests.Controllers
var setpointKey = await Add();
//act
var response = await setpointClient.GetLog([setpointKey]);
var response = await setpointClient.GetLog([setpointKey], new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.Equal(setpointKey, response.Content.FirstOrDefault().Key);
Assert.NotNull(response);
Assert.NotEmpty(response);
Assert.Equal(setpointKey, response.FirstOrDefault().Key);
}
[Fact]
@ -143,10 +135,9 @@ namespace Persistence.IntegrationTests.Controllers
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Equal(DateTimeOffset.MinValue, response.Content!.From);
Assert.Equal(DateTimeOffset.MaxValue, response.Content!.To);
Assert.NotNull(response);
Assert.Equal(DateTimeOffset.MinValue, response!.From);
Assert.Equal(DateTimeOffset.MaxValue, response!.To);
}
[Fact]
@ -165,17 +156,16 @@ namespace Persistence.IntegrationTests.Controllers
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotNull(response);
var expectedValue = part.Content!
var expectedValue = part!
.FirstOrDefault()!.Created
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualValueFrom = response.Content.From
var actualValueFrom = response.From
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedValue, actualValueFrom);
var actualValueTo = response.Content.To
var actualValueTo = response.To
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedValue, actualValueTo);
}
@ -191,9 +181,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -208,9 +197,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.NotNull(response);
Assert.NotEmpty(response);
}
[Fact]
@ -230,10 +218,7 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await setpointClient.Add(setpointKey, setpointValue);
//assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
await setpointClient.Add(setpointKey, setpointValue, new CancellationToken());
return setpointKey;
}

View File

@ -1,8 +1,7 @@
using System.Net;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Entity;
using Persistence.Models;
using Xunit;
@ -20,7 +19,7 @@ namespace Persistence.IntegrationTests.Controllers
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
techMessagesClient = persistenceClientFactory.GetClient<ITechMessagesClient>();
techMessagesClient = persistenceClientFactory.GetTechMessagesClient();
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
}
@ -43,11 +42,10 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content.Items);
Assert.Equal(requestDto.Skip, response.Content.Skip);
Assert.Equal(requestDto.Take, response.Content.Take);
Assert.NotNull(response);
Assert.Empty(response.Items);
Assert.Equal(requestDto.Skip, response.Skip);
Assert.Equal(requestDto.Take, response.Take);
}
[Fact]
@ -67,9 +65,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Equal(dtosCount, response.Content.Count);
Assert.NotNull(response);
Assert.Equal(dtosCount, response.Count);
}
[Fact]
@ -82,6 +79,7 @@ namespace Persistence.IntegrationTests.Controllers
public async Task InsertRange_returns_BadRequest()
{
//arrange
var exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
var dtos = new List<TechMessageDto>()
{
new TechMessageDto()
@ -96,11 +94,16 @@ namespace Persistence.IntegrationTests.Controllers
}
};
//act
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
try
{
//act
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
}
catch (Exception ex)
{
//assert
Assert.Equal(exceptionMessage, ex.Message);
}
}
[Fact]
@ -115,9 +118,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetSystems(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -134,9 +136,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetSystems(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
string?[]? content = response.Content?.ToArray();
Assert.NotNull(response);
string?[]? content = response?.ToArray();
Assert.Equal(systems, content);
}
@ -155,9 +156,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -173,9 +173,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var categories = response.Content
Assert.NotNull(response);
var categories = response
.FirstOrDefault()?.Categories
.FirstOrDefault(e => e.Key == 0).Value;
Assert.Equal(filteredDtos.Count(), categories);
@ -184,14 +183,18 @@ namespace Persistence.IntegrationTests.Controllers
[Fact]
public async Task GetDatesRange_returns_success()
{
//arrange
memoryCache.Remove(SystemCacheKey);
dbContext.CleanupDbSet<TechMessage>();
dbContext.CleanupDbSet<DrillingSystem>();
//act
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
//Assert.Equal(DateTimeOffset.MinValue, response.Content?.From);
//Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To);
Assert.NotNull(response);
Assert.Equal(DateTimeOffset.MinValue, response?.From);
Assert.Equal(DateTimeOffset.MaxValue, response?.To);
}
[Fact]
@ -204,10 +207,9 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotNull(response.Content?.From);
Assert.NotNull(response.Content?.To);
Assert.NotNull(response);
Assert.NotNull(response?.From);
Assert.NotNull(response?.To);
}
[Fact]
@ -221,9 +223,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
Assert.NotNull(response);
Assert.Empty(response);
}
[Fact]
@ -238,9 +239,8 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.NotNull(response);
Assert.NotEmpty(response);
}
private async Task<IEnumerable<TechMessageDto>> InsertRange()
@ -279,8 +279,7 @@ namespace Persistence.IntegrationTests.Controllers
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Equal(dtos.Count, response.Content);
Assert.Equal(dtos.Count, response);
return dtos;
}

View File

@ -2,7 +2,7 @@ using System.Net;
using Mapster;
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Model;
using Xunit;
@ -21,7 +21,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
timeSeriesClient = persistenceClientFactory.GetClient<ITimeSeriesClient<TDto>>();
timeSeriesClient = persistenceClientFactory.GetTimeSeriesClient<TDto>();
}
public async Task InsertRangeSuccess(TDto dto)
@ -30,11 +30,10 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
var expected = dto.Adapt<TDto>();
//act
var response = await timeSeriesClient.AddRange(new TDto[] { expected });
var response = await timeSeriesClient.AddRange(new TDto[] { expected }, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(1, response.Content);
Assert.Equal(1, response);
}
public async Task GetSuccess(DateTimeOffset beginDate, DateTimeOffset endDate, TEntity entity)
@ -46,12 +45,11 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
dbContext.SaveChanges();
var response = await timeSeriesClient.Get(beginDate, endDate);
var response = await timeSeriesClient.Get(beginDate, endDate, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Single(response.Content);
Assert.NotNull(response);
Assert.Single(response);
}
public async Task GetDatesRangeSuccess(TEntity entity)
@ -68,13 +66,12 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
dbContext.SaveChanges();
var response = await timeSeriesClient.GetDatesRange();
var response = await timeSeriesClient.GetDatesRange(new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotNull(response);
var datesRangeActual = (response.Content.To - response.Content.From).Days;
var datesRangeActual = (response.To - response.From).Days;
Assert.Equal(datesRangeExpected, datesRangeActual);
}
@ -98,11 +95,10 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
dbContext.SaveChanges();
var response = await timeSeriesClient.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount);
var response = await timeSeriesClient.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount, new CancellationToken());
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotNull(response);
var ratio = entities.Count() / approxPointsCount;
if (ratio > 1)
@ -111,15 +107,11 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
.Where((_, index) => index % ratio == 0)
.Count();
Assert.Equal(expectedResampledCount, response.Content.Count());
Assert.Equal(expectedResampledCount, response.Count());
}
else
{
Assert.Equal(entities.Count(), response.Content.Count());
Assert.Equal(entities.Count(), response.Count());
}
}
}

View File

@ -1,6 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients;
using Persistence.Client.Clients.Interfaces;
using Persistence.Models;
using Xunit;
@ -14,7 +14,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<PersistenceClientFactory>();
client = persistenceClientFactory.GetClient<ITimestampedSetClient>();
client = persistenceClientFactory.GetTimestampedSetClient();
}
[Fact]
@ -25,11 +25,10 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
IEnumerable<TimestampedSetDto> testSets = Generate(10, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
// act
var response = await client.AddRange(idDiscriminator, testSets);
var response = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.Equal(testSets.Count(), response.Content);
Assert.Equal(testSets.Count(), response);
}
[Fact]
@ -39,16 +38,14 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
Guid idDiscriminator = Guid.NewGuid();
int count = 10;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
// act
var response = await client.Get(idDiscriminator, null, null, 0, int.MaxValue);
var response = await client.Get(idDiscriminator, null, null, 0, int.MaxValue, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(count, items.Count());
Assert.NotNull(response);
Assert.Equal(count, response.Count());
}
[Fact]
@ -58,26 +55,24 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
Guid idDiscriminator = Guid.NewGuid();
int count = 10;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
string[] props = ["A"];
// act
var response = await client.Get(idDiscriminator, null, props, 0, int.MaxValue);
var response = await client.Get(idDiscriminator, null, props, 0, int.MaxValue, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(count, items.Count());
foreach ( var item in items )
{
Assert.Single(item.Set);
var kv = item.Set.First();
Assert.Equal("A", kv.Key);
}
}
Assert.NotNull(response);
Assert.Equal(count, response.Count());
foreach ( var item in response )
{
Assert.Single(item.Set);
var kv = item.Set.First();
Assert.Equal("A", kv.Key);
}
}
[Fact]
[Fact]
public async Task Get_geDate()
{
// arrange
@ -86,21 +81,19 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
var dateMin = DateTimeOffset.Now;
var dateMax = DateTimeOffset.Now.AddSeconds(count);
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
var tail = testSets.OrderBy(t => t.Timestamp).Skip(count / 2).Take(int.MaxValue);
var geDate = tail.First().Timestamp;
var tolerance = TimeSpan.FromSeconds(1);
var expectedCount = tail.Count();
// act
var response = await client.Get(idDiscriminator, geDate, null, 0, int.MaxValue);
var response = await client.Get(idDiscriminator, geDate, null, 0, int.MaxValue, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(expectedCount, items.Count());
var minDate = items.Min(t => t.Timestamp);
Assert.NotNull(response);
Assert.Equal(expectedCount, response.Count());
var minDate = response.Min(t => t.Timestamp);
Assert.Equal(geDate, geDate, tolerance);
}
@ -111,21 +104,19 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
Guid idDiscriminator = Guid.NewGuid();
int count = 10;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
var expectedCount = count / 2;
// act
var response = await client.Get(idDiscriminator, null, null, 2, expectedCount);
var response = await client.Get(idDiscriminator, null, null, 2, expectedCount, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(expectedCount, items.Count());
}
Assert.NotNull(response);
Assert.Equal(expectedCount, response.Count());
}
[Fact]
[Fact]
public async Task Get_with_big_skip_take()
{
// arrange
@ -133,16 +124,14 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
var expectedCount = 1;
int count = 10 + expectedCount;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
// act
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count);
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(expectedCount, items.Count());
Assert.NotNull(response);
Assert.Equal(expectedCount, response.Count());
}
[Fact]
@ -152,17 +141,15 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
Guid idDiscriminator = Guid.NewGuid();
int count = 10;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
var expectedCount = 8;
// act
var response = await client.GetLast(idDiscriminator, null, expectedCount);
var response = await client.GetLast(idDiscriminator, null, expectedCount, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var items = response.Content!;
Assert.Equal(expectedCount, items.Count());
Assert.NotNull(response);
Assert.Equal(expectedCount, response.Count());
}
[Fact]
@ -174,18 +161,16 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
var dateMin = DateTimeOffset.Now;
var dateMax = DateTimeOffset.Now.AddSeconds(count-1);
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
var tolerance = TimeSpan.FromSeconds(1);
// act
var response = await client.GetDatesRange(idDiscriminator);
var response = await client.GetDatesRange(idDiscriminator, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
var range = response.Content!;
Assert.Equal(dateMin, range.From, tolerance);
Assert.Equal(dateMax, range.To, tolerance);
Assert.NotNull(response);
Assert.Equal(dateMin, response.From, tolerance);
Assert.Equal(dateMax, response.To, tolerance);
}
[Fact]
@ -195,14 +180,13 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
Guid idDiscriminator = Guid.NewGuid();
int count = 144;
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
var insertResponse = await client.AddRange(idDiscriminator, testSets);
var insertResponse = await client.AddRange(idDiscriminator, testSets, new CancellationToken());
// act
var response = await client.Count(idDiscriminator);
var response = await client.Count(idDiscriminator, new CancellationToken());
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
Assert.Equal(count, response.Content);
Assert.Equal(count, response);
}
private static IEnumerable<TimestampedSetDto> Generate(int n, DateTimeOffset from)

View File

@ -4,8 +4,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Persistence.API;
using Persistence.Database;
using Persistence.Client;
using Persistence.Database.Model;
using Persistence.Database.Postgres;
@ -34,6 +34,8 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
services.AddDbContext<PersistenceDbContext>(options =>
options.UseNpgsql(connectionString));
services.AddLogging(builder => builder.AddConsole());
services.RemoveAll<IHttpClientFactory>();
services.AddSingleton<IHttpClientFactory>(provider =>
{

View File

@ -0,0 +1,13 @@
namespace Persistence.Factories;
/// <summary>
/// Фабрика токенов аутентификации
/// </summary>
public interface IAuthTokenFactory
{
/// <summary>
/// Получить токен
/// </summary>
/// <returns></returns>
public string GetToken();
}