Сгруппировать тестовые проекты по областям
Deal.Tests.Unit, Deal.Telegram.Tests, Deal.Ai.Tests, Deal.Ml.Tests разложены по областям (Modules/<X>, Api, Infrastructure, Contracts, Grpc, ...), общие хелперы -> Support; namespace = папка, using между областями добавлены итеративно по ошибкам сборки.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
using Deal.Api;
|
||||
using Deal.Api.Dtos;
|
||||
using Deal.Api.Services;
|
||||
using Deal.Tests.Unit.Support;
|
||||
|
||||
namespace Deal.Tests.Unit.Api;
|
||||
|
||||
/// <summary>
|
||||
/// Тесты PipelinePumpGate — общий воркер-гейт pump тенанта (план Task 11, Ruling 8; аналог
|
||||
/// asyncio.Lock pipeline.py L38–42): admin/tick и фоновый цикл не разбирают очередь одного тенанта
|
||||
/// одновременно, разные тенанты не связаны.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Семантика — как прототип pump_once L901–902: занятый pump тенанта → повторный вход (TryEnter) даёт
|
||||
/// false, вызывающий пропускает проход (очередь дождётся следующего срабатывания). Exit освобождает
|
||||
/// гейт; гейт потокобезопасен (ConcurrentDictionary + атомарный TryAdd), параллельные входы одного
|
||||
/// тенанта выигрывает ровно один.
|
||||
/// </remarks>
|
||||
public sealed class PipelinePumpGateTests
|
||||
{
|
||||
// Тенант A теста.
|
||||
private static readonly Guid TenantA = Guid.NewGuid();
|
||||
|
||||
// Тенант B теста.
|
||||
private static readonly Guid TenantB = Guid.NewGuid();
|
||||
|
||||
[Fact]
|
||||
public void TryEnter_FirstEnterWinsSecondForSameTenantIsRejected()
|
||||
{
|
||||
var gate = new PipelinePumpGate();
|
||||
|
||||
Assert.True(gate.TryEnter(TenantA)); // первый воркер (admin/tick или фоновый цикл) вошёл
|
||||
Assert.False(gate.TryEnter(TenantA)); // второй для того же тенанта пропускает проход (L901–902)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exit_ReleasesGateForSameTenant()
|
||||
{
|
||||
var gate = new PipelinePumpGate();
|
||||
Assert.True(gate.TryEnter(TenantA));
|
||||
|
||||
gate.Exit(TenantA);
|
||||
|
||||
Assert.True(gate.TryEnter(TenantA)); // после finally-освобождения гейт снова свободен
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryEnter_DifferentTenantsEnterIndependently()
|
||||
{
|
||||
var gate = new PipelinePumpGate();
|
||||
|
||||
Assert.True(gate.TryEnter(TenantA));
|
||||
Assert.True(gate.TryEnter(TenantB)); // pump разных тенантов не конкурирует (свои схемы/очереди)
|
||||
|
||||
gate.Exit(TenantA);
|
||||
Assert.True(gate.TryEnter(TenantA)); // освобождение A не влияет на занятый B
|
||||
Assert.False(gate.TryEnter(TenantB));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exit_WithoutEnterDoesNotBreakLaterEntry()
|
||||
{
|
||||
var gate = new PipelinePumpGate();
|
||||
|
||||
// Exit без парного TryEnter не роняет состояние (нет «висящего» флага после сбоя до входа).
|
||||
gate.Exit(TenantA);
|
||||
Assert.True(gate.TryEnter(TenantA));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user