Files
Deal/src/core/tests/Deal.Tests.Unit/Api/PipelinePumpGateTests.cs
T
Rustam Khalimov 5bfa92a4ac Сгруппировать тестовые проекты по областям
Deal.Tests.Unit, Deal.Telegram.Tests, Deal.Ai.Tests, Deal.Ml.Tests
разложены по областям (Modules/<X>, Api, Infrastructure, Contracts,
Grpc, ...), общие хелперы -> Support; namespace = папка, using
между областями добавлены итеративно по ошибкам сборки.
2026-09-11 13:28:26 +03:00

70 lines
2.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 L3842): admin/tick и фоновый цикл не разбирают очередь одного тенанта
/// одновременно, разные тенанты не связаны.
/// </summary>
/// <remarks>
/// Семантика — как прототип pump_once L901902: занятый 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));
}
}