using Deal.Api;
using Deal.Api.Dtos;
using Deal.Api.Services;
using Deal.Tests.Unit.Support;
namespace Deal.Tests.Unit.Api;
///
/// Тесты PipelinePumpGate — общий воркер-гейт pump тенанта (план Task 11, Ruling 8; аналог
/// asyncio.Lock pipeline.py L38–42): admin/tick и фоновый цикл не разбирают очередь одного тенанта
/// одновременно, разные тенанты не связаны.
///
///
/// Семантика — как прототип pump_once L901–902: занятый pump тенанта → повторный вход (TryEnter) даёт
/// false, вызывающий пропускает проход (очередь дождётся следующего срабатывания). Exit освобождает
/// гейт; гейт потокобезопасен (ConcurrentDictionary + атомарный TryAdd), параллельные входы одного
/// тенанта выигрывает ровно один.
///
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));
}
}