using NSubstitute; using PnvPanel.Application.Common.Interfaces; using PnvPanel.Application.Common.Models; using PnvPanel.Application.Support; using PnvPanel.Application.Support.AddComment; using PnvPanel.Application.Tests.TestSupport; using PnvPanel.Domain.Support; using Xunit; namespace PnvPanel.Application.Tests.Support; public class AddTicketCommentCommandHandlerTests { private readonly IIdentityService _identityService = Substitute.For(); private readonly IFileStorage _fileStorage = Substitute.For(); private readonly IRealtimeNotifier _notifier = Substitute.For(); private static CurrentUserProfile Profile(Guid userId, string role) => new(userId, "user", Guid.NewGuid(), role, IsActivated: true, IsBlocked: false, MaxConfigs: 3, MaxIpLimit: RoleQuota.Unlimited, SubscriptionToken: "token"); [Fact] public async Task Handle_WhenOwnerComments_AddsCommentAndDoesNotNotifySelf() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); var ticket = SupportTicket.CreateBugReport(userId); dbContext.SupportTickets.Add(ticket); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService.GetProfileAsync(userId, Arg.Any()).Returns(Profile(userId, "user")); var currentUser = FakeCurrentUser.Authenticated(userId, "alice"); var handler = new AddTicketCommentCommandHandler(dbContext, _identityService, _fileStorage, _notifier, currentUser); var result = await handler.Handle(new AddTicketCommentCommand(ticket.Id, "апдейт", []), CancellationToken.None); Assert.True(result.IsSuccess); Assert.Equal("апдейт", result.Value.Body); await _notifier.DidNotReceive().NotifyTicketUpdatedAsync(Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] public async Task Handle_WhenAdminComments_NotifiesOwner() { using var dbContext = InMemoryDbContextFactory.Create(); var ownerId = Guid.NewGuid(); var adminId = Guid.NewGuid(); var ticket = SupportTicket.CreateBugReport(ownerId); dbContext.SupportTickets.Add(ticket); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService.GetProfileAsync(adminId, Arg.Any()).Returns(Profile(adminId, "admin")); var currentUser = FakeCurrentUser.Authenticated(adminId, "admin"); var handler = new AddTicketCommentCommandHandler(dbContext, _identityService, _fileStorage, _notifier, currentUser); var result = await handler.Handle(new AddTicketCommentCommand(ticket.Id, "ответ админа", []), CancellationToken.None); Assert.True(result.IsSuccess); await _notifier.Received(1).NotifyTicketUpdatedAsync(ticket.Id, ownerId, Arg.Any()); } [Fact] public async Task Handle_WhenNotOwnerAndNotAdmin_ReturnsNotFound() { using var dbContext = InMemoryDbContextFactory.Create(); var ownerId = Guid.NewGuid(); var strangerId = Guid.NewGuid(); var ticket = SupportTicket.CreateBugReport(ownerId); dbContext.SupportTickets.Add(ticket); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService.GetProfileAsync(strangerId, Arg.Any()).Returns(Profile(strangerId, "user")); var currentUser = FakeCurrentUser.Authenticated(strangerId); var handler = new AddTicketCommentCommandHandler(dbContext, _identityService, _fileStorage, _notifier, currentUser); var result = await handler.Handle(new AddTicketCommentCommand(ticket.Id, "текст", []), CancellationToken.None); Assert.False(result.IsSuccess); Assert.Equal(SupportErrors.NotFound, result.Error); } [Fact] public async Task Handle_WhenTicketClosed_ReturnsTicketClosedError() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); var ticket = SupportTicket.CreateBugReport(userId); ticket.Close(); dbContext.SupportTickets.Add(ticket); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService.GetProfileAsync(userId, Arg.Any()).Returns(Profile(userId, "user")); var currentUser = FakeCurrentUser.Authenticated(userId); var handler = new AddTicketCommentCommandHandler(dbContext, _identityService, _fileStorage, _notifier, currentUser); var result = await handler.Handle(new AddTicketCommentCommand(ticket.Id, "текст", []), CancellationToken.None); Assert.False(result.IsSuccess); Assert.Equal(SupportErrors.TicketClosed, result.Error); } }