a46782920b
GET /api/basis-requests?requestTypeId=&basisKey= читает заявки от имени приложения по всем партициям, а по каждой проверяет, может ли вызывающий её открыть. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.4 KiB
C#
92 lines
4.4 KiB
C#
using System.Text.Json;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Moq;
|
|
using Shouldly;
|
|
using Tnsu.ApprovalRoute.Application.BasisRequests;
|
|
using Tnsu.ApprovalRoute.Application.ListPartitioning;
|
|
using Tnsu.ApprovalRoute.Application.RequestTypes;
|
|
using Tnsu.ApprovalRoute.Infrastructure.Persistence;
|
|
using Tnsu.ApprovalRoute.Infrastructure.SharePoint;
|
|
using Tnsu.ApprovalRoute.IntegrationTests.Infrastructure;
|
|
|
|
namespace Tnsu.ApprovalRoute.IntegrationTests.ApplicationServices;
|
|
|
|
/// <summary>
|
|
/// Заявки по одному основанию: видны все (чтение от имени приложения), а
|
|
/// CanOpen — только там, где у вызывающего есть права на элемент.
|
|
/// </summary>
|
|
public sealed class BasisRequestsServiceTests : IClassFixture<PostgresDatabaseFixture>
|
|
{
|
|
private const string SiteUrl = "https://tnsukz.sharepoint.com/sites/requests";
|
|
private const string CallerEmail = "initiator@tnsu.kz";
|
|
private const string BasisKey = "need:8028c7ac-ac23-8dd8-11f0-946facc42464";
|
|
|
|
private readonly ServiceProvider _services;
|
|
|
|
public BasisRequestsServiceTests(PostgresDatabaseFixture fixture)
|
|
{
|
|
_services = TestServiceProviderFactory.Build(fixture.ConnectionString, CallerEmail);
|
|
}
|
|
|
|
private static JsonElement Json(object value) => JsonSerializer.SerializeToElement(value);
|
|
|
|
private async Task<(BasisRequestsService Service, Mock<ISharePointClient> SharePoint, int TypeId)> BuildAsync(
|
|
string name, string listUrl, IReadOnlyList<object> items, IReadOnlySet<int> openableIds)
|
|
{
|
|
var type = await _services.GetRequiredService<RequestTypeService>().CreateAsync(
|
|
new CreateRequestTypeRequest($"Оплата {name}", $"/оплата-{name}", listUrl, SiteUrl, "General"),
|
|
CancellationToken.None);
|
|
|
|
var sharePoint = new Mock<ISharePointClient>();
|
|
sharePoint
|
|
.Setup(x => x.GetItemsByListUrlAsync(SiteUrl, listUrl, It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(items.Select(Json).ToList());
|
|
sharePoint
|
|
.Setup(x => x.CanUserViewItemAsync(SiteUrl, listUrl, It.IsAny<int>(), CallerEmail, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((string _, string _, int id, string _, CancellationToken _) => openableIds.Contains(id));
|
|
|
|
var service = new BasisRequestsService(
|
|
_services.GetRequiredService<ApprovalRouteDbContext>(),
|
|
sharePoint.Object,
|
|
_services.GetRequiredService<ListPartitionRegistry>(),
|
|
new TestCurrentUser(CallerEmail));
|
|
|
|
return (service, sharePoint, type.Value.Id);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Returns_all_requests_and_marks_only_permitted_as_openable()
|
|
{
|
|
const string list = "/sites/requests/Lists/Оплата-all";
|
|
var (service, sharePoint, typeId) = await BuildAsync("all", list,
|
|
[
|
|
// Number-колонка приходит дробной («50000.0») — тест держит её такой же.
|
|
new { Id = 1, RequestUniqueCode = "24-2610-1", RequestStatus = "Согласовано", PayAmount = 50000.0 },
|
|
new { Id = 2, RequestUniqueCode = "24-2610-2", RequestStatus = "На согласовании", PayAmount = 35000.5 }
|
|
], new HashSet<int> { 2 });
|
|
|
|
var result = await service.GetByBasisAsync(typeId, BasisKey, CancellationToken.None);
|
|
|
|
result.IsSuccess.ShouldBeTrue();
|
|
result.Value.Count.ShouldBe(2);
|
|
result.Value.Single(x => x.Id == 1).ShouldBe(new BasisRequestDto(1, list, "24-2610-1", "Согласовано", 50000, false));
|
|
result.Value.Single(x => x.Id == 2).ShouldBe(new BasisRequestDto(2, list, "24-2610-2", "На согласовании", 35000.5, true));
|
|
|
|
// Фильтр по основанию уходит в SharePoint, а не применяется в памяти.
|
|
sharePoint.Verify(x => x.GetItemsByListUrlAsync(
|
|
SiteUrl, list,
|
|
It.Is<string>(q => q.Contains("BasisKey eq 'need%3A8028c7ac-ac23-8dd8-11f0-946facc42464'")),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Empty_basis_key_is_a_validation_error()
|
|
{
|
|
var (service, _, typeId) = await BuildAsync("empty", "/sites/requests/Lists/Оплата-empty", [], new HashSet<int>());
|
|
|
|
var result = await service.GetByBasisAsync(typeId, " ", CancellationToken.None);
|
|
|
|
result.IsFailed.ShouldBeTrue();
|
|
}
|
|
}
|