Files
satellite-provider/SatelliteProvider.Tests/RegionRequestQueueTests.cs
T
Oleksandr Bezdieniezhnykh 8b0ddae075 [AZ-312] [AZ-313] [AZ-314] Split Services into per-component csprojs
Phase B of architecture coupling refactor (epic AZ-309). Replaces
the monolithic SatelliteProvider.Services with three per-component
csprojs to add a compiler-enforced module boundary (resolves F4):

- SatelliteProvider.Services.TileDownloader
- SatelliteProvider.Services.RegionProcessing
- SatelliteProvider.Services.RouteManagement

DI registrations relocated into per-component AddTileDownloader /
AddRegionProcessing / AddRouteManagement extension methods called
from Program.cs. RateLimitException moved to Common/Exceptions/ to
keep the three new csprojs as siblings (no Region->TileDownloader
ProjectReference). Dockerfiles and consumer csprojs (Api, Tests)
rewired to the new project paths. No DI lifetime or hosted-service
order changes.

Build: 0 warn, 0 err. Unit tests: 40/40. Smoke integration: green.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 07:15:44 +03:00

86 lines
2.6 KiB
C#

using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using SatelliteProvider.Common.DTO;
using SatelliteProvider.Services.RegionProcessing;
namespace SatelliteProvider.Tests;
public class RegionRequestQueueTests
{
private static RegionRequest BuildRequest() => new()
{
Id = Guid.NewGuid(),
Latitude = 47.461747,
Longitude = 37.647063,
SizeMeters = 200,
ZoomLevel = 18,
StitchTiles = false
};
[Fact]
public async Task EnqueueAsync_RespectsCapacity_WritesUpToCapacityWithoutBlocking_RS04()
{
const int capacity = 10;
var queue = new RegionRequestQueue(capacity, NullLogger<RegionRequestQueue>.Instance);
for (var i = 0; i < capacity; i++)
{
await queue.EnqueueAsync(BuildRequest());
}
queue.Count.Should().Be(capacity);
}
[Fact]
public async Task EnqueueAsync_BlocksWhenAtCapacity_UntilDequeue_RL02()
{
const int capacity = 2;
var queue = new RegionRequestQueue(capacity, NullLogger<RegionRequestQueue>.Instance);
await queue.EnqueueAsync(BuildRequest());
await queue.EnqueueAsync(BuildRequest());
var overflow = queue.EnqueueAsync(BuildRequest()).AsTask();
var completedFirst = await Task.WhenAny(overflow, Task.Delay(150));
completedFirst.Should().NotBeSameAs(overflow, "overflow enqueue must wait while queue is full");
var dequeued = await queue.DequeueAsync();
dequeued.Should().NotBeNull();
await overflow.WaitAsync(TimeSpan.FromSeconds(1));
queue.Count.Should().Be(capacity);
}
[Fact]
public async Task EnqueueAsync_HonorsCancellation_WhenFull()
{
var queue = new RegionRequestQueue(1, NullLogger<RegionRequestQueue>.Instance);
await queue.EnqueueAsync(BuildRequest());
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(150));
Func<Task> act = async () => await queue.EnqueueAsync(BuildRequest(), cts.Token);
await act.Should().ThrowAsync<OperationCanceledException>();
}
[Fact]
public async Task DequeueAsync_ReturnsItemsInFifoOrder()
{
var queue = new RegionRequestQueue(8, NullLogger<RegionRequestQueue>.Instance);
var first = BuildRequest();
var second = BuildRequest();
await queue.EnqueueAsync(first);
await queue.EnqueueAsync(second);
var dequeued1 = await queue.DequeueAsync();
var dequeued2 = await queue.DequeueAsync();
dequeued1!.Id.Should().Be(first.Id);
dequeued2!.Id.Should().Be(second.Id);
queue.Count.Should().Be(0);
}
}