Setpoint API #1

Merged
on.nemtina merged 10 commits from Setpoint into master 2024-11-25 10:33:36 +05:00
8 changed files with 138 additions and 54 deletions
Showing only changes of commit 9e375b4831 - Show all commits

View File

@ -16,31 +16,33 @@ namespace Persistence.API.Controllers
}
[HttpPost("current")]

Здесь метод [HttpGet]

Здесь метод [HttpGet]
public Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrentAsync(IEnumerable<Guid> setpointKeys, CancellationToken token)
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
{
throw new NotImplementedException();
var result = await setpointRepository.GetCurrent(setpointKeys, token);
return Ok(result);
}
[HttpPost("history")]

Здесь метод [HttpGet]

Здесь метод [HttpGet]
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistoryAsync(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
{
var result = await setpointRepository.GetHistoryAsync(setpointKeys, historyMoment, token);
var result = await setpointRepository.GetHistory(setpointKeys, historyMoment, token);
return Ok(result);
}
[HttpPost("log")]

Здесь метод [HttpGet]

Здесь метод [HttpGet]
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLogAsync([FromBody] IEnumerable<Guid> setpointKeys, CancellationToken token)
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([FromBody] IEnumerable<Guid> setpointKeys, CancellationToken token)
{
var result = await setpointRepository.GetLogAsync(setpointKeys, token);
var result = await setpointRepository.GetLog(setpointKeys, token);
return Ok(result);
}
[HttpPost("save")]

Здесь можно просто [HttpPost]

Здесь можно просто [HttpPost]
public async Task<ActionResult<int>> SaveAsync(Guid setpointKey, object newValue, CancellationToken token)
public async Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token)
{
var result = await setpointRepository.SaveAsync(setpointKey, newValue, token);
var result = await setpointRepository.Save(setpointKey, newValue, 0, token);

Добавить todo, что необходимо решить вопрос с получением пользователя и авторизацией

Добавить todo, что необходимо решить вопрос с получением пользователя и авторизацией
return Ok(result);
}

View File

@ -1,10 +0,0 @@
namespace Persistence.Database.Model
{
public interface ISetpointData
{
public Guid Key { get; set; }
public object Value { get; set; }
public DateTimeOffset Created { get; set; }
public int IdUser { get; set; }
}
}

View File

@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Persistence.Database.Model
{
[PrimaryKey(nameof(Key), nameof(Created))]
public class Setpoint : ISetpointData
public class Setpoint
{
[Comment("Ключ")]
public Guid Key { get; set; }

View File

@ -5,13 +5,16 @@ namespace Persistence.IntegrationTests.Clients
{
public interface ISetpointClient
{
[Post("/api/Setpoint/history")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistoryAsync(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment);
[Post("/current")]

Заголовки методов запроса должны соответствовать тем, что в контроллере (там часть нужно поменять с post на get)

Заголовки методов запроса должны соответствовать тем, что в контроллере (там часть нужно поменять с post на get)
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpointKeys);
[Post("/api/Setpoint/log")]
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLogAsync(IEnumerable<Guid> setpoitKeys);
[Post("/history")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment);
[Post("/api/Setpoint/save")]
Task<IApiResponse<int>> SaveAsync(Guid setpointKey, object newValue);
[Post("/log")]
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog(IEnumerable<Guid> setpoitKeys);
[Post("/save")]
Task<IApiResponse<int>> Save(Guid setpointKey, object newValue);
}
}

View File

@ -1,4 +1,6 @@
using System.Net;
using System.Text.Json;
using Mapster;
using Persistence.IntegrationTests.Clients;
using Xunit;
@ -10,16 +12,36 @@ namespace Persistence.IntegrationTests.Controllers
private class TestObject
{
public string? value1 { get; set; }
public int value2 { get; set; }
public double value3 { get; set; }
public int? value2 { get; set; }
}
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
{
factory.ClientOptions.BaseAddress = new Uri($"http://localhost/api/Setpoint");

Эту строчку лучше убрать, а в интерфейсе ISetpointClient прописать так:

private const string BaseRoute = "/api/setpoint";

 [Post($"{BaseRoute}/current")]
	Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpointKeys);```
Эту строчку лучше убрать, а в интерфейсе ISetpointClient прописать так: ``` private const string BaseRoute = "/api/setpoint"; [Post($"{BaseRoute}/current")] Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpointKeys);```
client = factory.GetHttpClient<ISetpointClient>(string.Empty);
}
[Fact]
public async Task GetHistoryAsync_returns_success()
public async Task GetCurrent_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
{
Guid.NewGuid(),
Guid.NewGuid()
};
//act
var response = await client.GetCurrent(setpointKeys);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
}
[Fact]
public async Task GetHistory_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
@ -30,14 +52,16 @@ namespace Persistence.IntegrationTests.Controllers
var historyMoment = DateTimeOffset.Now.ToUniversalTime();
//act
var response = await client.GetHistoryAsync(setpointKeys, historyMoment);
var response = await client.GetHistory(setpointKeys, historyMoment);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
}
[Fact]
public async Task GetLogAsync_returns_success()
public async Task GetLog_returns_success()
{
//arrange
var setpointKeys = new List<Guid>()
@ -47,30 +71,77 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await client.GetLogAsync(setpointKeys);
var response = await client.GetLog(setpointKeys);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Empty(response.Content);
}
[Fact]
public async Task SaveAsync_returns_success()
public async Task Save_returns_success()
{
//arrange
var setpointKey = Guid.NewGuid();
var setpointValue = new TestObject()
{
value1 = "1",
value2 = 2,
value3 = 3.3
value2 = 2
};
//act
var response = await client.SaveAsync(setpointKey, setpointValue);
var response = await client.Save(setpointKey, setpointValue);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(1, response.Content);
}
[Fact]
public async Task General_test_success()

General_test_success не нужен, вместо него нужно для каждого кейса написать свой тест.
Данные тесты должны быть аналогичны GetCurrent_returns_success, GetHistory_returns_success, GetLog_returns_success, только внутри блока //arrange вызвать метод Save.
Метод Save сделать отдельным приватным методом.

General_test_success не нужен, вместо него нужно для каждого кейса написать свой тест. Данные тесты должны быть аналогичны GetCurrent_returns_success, GetHistory_returns_success, GetLog_returns_success, только внутри блока //arrange вызвать метод Save. Метод Save сделать отдельным приватным методом.
{
//save
var setpointKey = Guid.NewGuid();
var setpointValue = new TestObject()
{
value1 = "1",
value2 = 2
};
var saveResponse = await client.Save(setpointKey, setpointValue);
Assert.Equal(HttpStatusCode.OK, saveResponse.StatusCode);
Assert.Equal(1, saveResponse.Content);
//current
var currentResponse = await client.GetCurrent([setpointKey]);
Assert.Equal(HttpStatusCode.OK, currentResponse.StatusCode);
var currentContent = currentResponse.Content;
Assert.NotNull(currentContent);
Assert.NotEmpty(currentContent);
var currentContentValue = currentContent.FirstOrDefault()?.Value?.ToString();
Assert.NotNull(currentContentValue);

Assert.Equal(expected, actual)

Assert.Equal(expected, actual)
Assert.NotEmpty(currentContentValue);
var testObjectValue = JsonSerializer.Deserialize<TestObject>(currentContentValue);
Assert.NotNull(testObjectValue);
Assert.Equal(setpointValue.value1, testObjectValue.value1);
Assert.Equal(setpointValue.value2, testObjectValue.value2);
//history
var historyMoment = DateTimeOffset.Now.ToUniversalTime();
var historyResponse = await client.GetHistory([setpointKey], historyMoment);
Assert.Equal(HttpStatusCode.OK, historyResponse.StatusCode);
Assert.NotNull(historyResponse.Content);
Assert.NotEmpty(historyResponse.Content);
//log
var logResponse = await client.GetLog([setpointKey]);
Assert.Equal(HttpStatusCode.OK, logResponse.StatusCode);
Assert.NotNull(logResponse.Content);
Assert.NotEmpty(logResponse.Content);
}
}
}

View File

@ -16,7 +16,18 @@ namespace Persistence.Repository.Repositories
protected virtual IQueryable<Setpoint> GetQueryReadOnly() => db.Set<Setpoint>();
public async Task<IEnumerable<SetpointValueDto>> GetHistoryAsync(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
{
var query = GetQueryReadOnly();
var entities = await query
.Where(e => setpointKeys.Contains(e.Key))
.ToArrayAsync(token);
var dtos = entities.Select(e => e.Adapt<SetpointValueDto>());
return dtos;
}
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
{
var query = GetQueryReadOnly();
var entities = await query
@ -27,7 +38,7 @@ namespace Persistence.Repository.Repositories
return dtos;

Здесь нужно еще просортировать, чтобы гарантированно взять нужную близлежайшую к historyMoment уставку

Здесь нужно еще просортировать, чтобы гарантированно взять нужную близлежайшую к historyMoment уставку
}
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLogAsync(IEnumerable<Guid> setpointKeys, CancellationToken token)
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
{
var query = GetQueryReadOnly();
var entities = await query
@ -43,7 +54,7 @@ namespace Persistence.Repository.Repositories
return dtos;
}
public async Task<int> SaveAsync(Guid setpointKey, object newValue, CancellationToken token)
public async Task<int> Save(Guid setpointKey, object newValue, int idUser, CancellationToken token)
{
try
{
@ -51,7 +62,7 @@ namespace Persistence.Repository.Repositories
{
Key = setpointKey,
Value = newValue,
IdUser = 0, // ToDo: откуда тянуть?
IdUser = idUser,
Created = DateTimeOffset.Now.ToUniversalTime()

Можно так: Created = DateTimeOffset.UtcNow

Можно так: Created = DateTimeOffset.UtcNow
};

View File

@ -14,7 +14,7 @@ public interface ISetpointApi
/// <param name="setpoitKeys">ключи уставок</param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrentAsync(IEnumerable<Guid> setpoitKeys, CancellationToken token);
Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpoitKeys, CancellationToken token);
/// <summary>
/// Получить значения уставок за определенный момент времени
@ -23,7 +23,7 @@ public interface ISetpointApi
/// <param name="historyMoment">дата, на которую получаем данные</param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistoryAsync(IEnumerable<Guid> setpoitKeys, DateTimeOffset historyMoment, CancellationToken token);
Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory(IEnumerable<Guid> setpoitKeys, DateTimeOffset historyMoment, CancellationToken token);
/// <summary>
/// Получить историю изменений значений уставок
@ -31,7 +31,7 @@ public interface ISetpointApi
/// <param name="setpoitKeys">ключи уставок</param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLogAsync(IEnumerable<Guid> setpoitKeys, CancellationToken token);
Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog(IEnumerable<Guid> setpoitKeys, CancellationToken token);
/// <summary>
/// Метод сохранения уставки
@ -40,5 +40,5 @@ public interface ISetpointApi
/// <param name="newValue">значение</param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<int>> SaveAsync(Guid setpointKey, object newValue, CancellationToken token);
Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token);
Review

Решили, что метод Save не должен ничего возвращать

Решили, что метод Save не должен ничего возвращать
}

View File

@ -7,6 +7,13 @@ namespace Persistence.Repositories;
/// </summary>
public interface ISetpointRepository
{
/// <summary>
/// Получить значения уставок по набору ключей
/// </summary>
/// <param name="setpointKeys"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
/// <summary>
/// Получить значения уставок за определенный момент времени
@ -15,7 +22,7 @@ public interface ISetpointRepository
/// <param name="historyMoment">дата, на которую получаем данные</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SetpointValueDto>> GetHistoryAsync(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token);
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token);
/// <summary>
/// Получить историю изменений значений уставок
@ -23,7 +30,7 @@ public interface ISetpointRepository
/// <param name="setpointKeys"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLogAsync(IEnumerable<Guid> setpointKeys, CancellationToken token);
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
/// <summary>
/// Метод сохранения уставки
@ -35,5 +42,5 @@ public interface ISetpointRepository
/// <returns></returns>
/// to do
/// id User учесть в соответствующем методе репозитория
Task<int> SaveAsync(Guid setpointKey, object newValue, CancellationToken token);
Task<int> Save(Guid setpointKey, object newValue, int idUser, CancellationToken token);
}