Refactor LibraryDebugCollector and TelegramApi for improved data handling and clarity
Updated the LibraryDebugCollector to introduce a new CompositionEntry record for better organization of group composition data. Refactored the composition logic to utilize this new structure, enhancing readability and maintainability. In the TelegramApi, replaced inline allowed_updates array with a static readonly field to reduce redundancy and improve clarity in API call configurations. Adjusted related tests to ensure proper handling of message assertions, enhancing overall test reliability.
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
using NSubstitute;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Notifications.Link;
|
||||
using TeleWave.Application.Notifications.Settings;
|
||||
using TeleWave.Application.Notifications.Subscribers;
|
||||
using TeleWave.Application.Tests.Support;
|
||||
using TeleWave.Domain.Broadcast;
|
||||
using TeleWave.Domain.Notifications;
|
||||
using Xunit;
|
||||
|
||||
namespace TeleWave.Application.Tests.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// Что видит и делает админ вокруг бота: выдача ссылки зрителю и список подписчиков. Ссылка —
|
||||
/// единственная дверь в подписку, поэтому проверяем, что старые коды при выдаче новой гаснут.
|
||||
/// </summary>
|
||||
public class TelegramAdminTests
|
||||
{
|
||||
private static readonly DateTimeOffset T0 = new(2026, 8, 1, 12, 0, 0, TimeSpan.Zero);
|
||||
|
||||
[Fact]
|
||||
public async Task Link_BurnsPreviousCodesOfTheSameUser()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var userId = Guid.NewGuid();
|
||||
var stale = TelegramLinkCode.Issue("old", userId, T0);
|
||||
var foreign = TelegramLinkCode.Issue("alien", Guid.NewGuid(), T0);
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.TelegramSettings.Add(Configured());
|
||||
seed.TelegramLinkCodes.AddRange(stale, foreign);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new IssueTelegramLinkCommandHandler(
|
||||
db,
|
||||
new TelegramSettingsService(db),
|
||||
CurrentUser(userId)
|
||||
).Handle(new IssueTelegramLinkCommand(), CancellationToken.None);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.StartsWith("https://t.me/telewave_bot?start=", result.Value.Url);
|
||||
|
||||
await using var check = fixture.New();
|
||||
var codes = check.TelegramLinkCodes.ToList();
|
||||
// Своя старая ссылка гасится — две живые двери в один аккаунт не нужны; чужая не трогается.
|
||||
Assert.NotNull(codes.Single(c => c.Code == "old").UsedAt);
|
||||
Assert.Null(codes.Single(c => c.Code == "alien").UsedAt);
|
||||
var issued = codes.Single(c => c.UserId == userId && c.UsedAt is null);
|
||||
Assert.EndsWith(issued.Code, result.Value.Url);
|
||||
Assert.Equal(TelegramLinkCode.Lifetime, issued.ExpiresAt - issued.CreatedAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Link_WithoutConfiguredBot_IsRefused()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new IssueTelegramLinkCommandHandler(
|
||||
db,
|
||||
new TelegramSettingsService(db),
|
||||
CurrentUser(Guid.NewGuid())
|
||||
).Handle(new IssueTelegramLinkCommand(), CancellationToken.None);
|
||||
|
||||
// Ссылку не из чего собрать: имя бота приходит только после успешной проверки токена.
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.Equal("Telegram.NotConfigured", result.Error.Code);
|
||||
Assert.Empty(db.TelegramLinkCodes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Link_WithoutSignedInViewer_IsRefused()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.TelegramSettings.Add(Configured());
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var anonymous = Substitute.For<ICurrentUser>();
|
||||
anonymous.UserId.Returns((Guid?)null);
|
||||
|
||||
var result = await new IssueTelegramLinkCommandHandler(
|
||||
db,
|
||||
new TelegramSettingsService(db),
|
||||
anonymous
|
||||
).Handle(new IssueTelegramLinkCommand(), CancellationToken.None);
|
||||
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.Empty(db.TelegramLinkCodes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Subscribers_ShowChannelsAndUserNamesNewestFirst()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("Мультреалити", "mult", T0);
|
||||
var userId = Guid.NewGuid();
|
||||
|
||||
var active = TelegramSubscriber.Create(100, userId, "viewer", T0);
|
||||
active.Touch(T0.AddHours(2));
|
||||
active.Toggle(channel.Id, TelegramNotificationKind.ShowStart);
|
||||
active.Toggle(channel.Id, TelegramNotificationKind.UpNext);
|
||||
// Канал удалили, а подписка осталась висеть — это должно быть видно, а не пропасть.
|
||||
active.Toggle(Guid.NewGuid(), TelegramNotificationKind.ShowStart);
|
||||
|
||||
var older = TelegramSubscriber.Create(101, Guid.NewGuid(), "gone", T0.AddHours(-1));
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.TelegramSubscribers.AddRange(active, older);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
var identity = Substitute.For<IIdentityService>();
|
||||
identity
|
||||
.GetProfileAsync(userId, Arg.Any<CancellationToken>())
|
||||
.Returns(new CurrentUserProfile(userId, "leonid", "user", false));
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new ListTelegramSubscribersQueryHandler(db, identity).Handle(
|
||||
new ListTelegramSubscribersQuery(),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
var subscribers = result.Value;
|
||||
Assert.Equal([100L, 101L], subscribers.Select(s => s.ChatId).ToArray());
|
||||
Assert.Equal("leonid", subscribers[0].UserName);
|
||||
// Учётку без профиля показываем как есть: чат жив, а пользователя уже нет.
|
||||
Assert.Null(subscribers[1].UserName);
|
||||
|
||||
var live = subscribers[0].Channels.Single(c => c.ChannelId == channel.Id);
|
||||
Assert.Equal("Мультреалити", live.ChannelName);
|
||||
Assert.Equal(["ShowStart", "UpNext"], live.Kinds);
|
||||
Assert.Equal(
|
||||
"—",
|
||||
subscribers[0].Channels.Single(c => c.ChannelId != channel.Id).ChannelName
|
||||
);
|
||||
}
|
||||
|
||||
private static TelegramSettings Configured()
|
||||
{
|
||||
var settings = TelegramSettings.CreateDefault();
|
||||
settings.Update(
|
||||
new TelegramSettingsUpdate(
|
||||
true,
|
||||
TelegramTransport.Polling,
|
||||
"123:ABC",
|
||||
null,
|
||||
TelegramProxyKind.None,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
settings.SetBotUsername("telewave_bot");
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static ICurrentUser CurrentUser(Guid userId)
|
||||
{
|
||||
var currentUser = Substitute.For<ICurrentUser>();
|
||||
currentUser.UserId.Returns(userId);
|
||||
return currentUser;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user