mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 19:54:55 +00:00
Refactor: Revert to hard deletes for messages. Remove IsDeleted flag and update repository and configurations accordingly.
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using Govor.API.Hubs;
|
||||
using Govor.Application.Interfaces.Messages;
|
||||
using Govor.Application.Interfaces.Messages.Parameters;
|
||||
using Govor.Core.Models;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Govor.API; // Assuming Startup or Program is here for WebApplicationFactory
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
using Govor.Contracts.Requests.SignalR; // For MessageRequest etc.
|
||||
using Govor.Contracts.Responses.SignalR; // For UserMessageResponse etc.
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Govor.API.Tests.IntegrationTests.Hubs;
|
||||
|
||||
// Base class for Hub tests to handle TestServer and client creation
|
||||
public abstract class HubTestBase : IAsyncLifetime
|
||||
{
|
||||
protected TestServer TestServer;
|
||||
protected HubConnection ClientConnection;
|
||||
protected Mock<IMessageService> MockMessageService;
|
||||
protected Guid TestUserId = Guid.NewGuid();
|
||||
protected string TestUserToken;
|
||||
|
||||
public virtual async Task InitializeAsync()
|
||||
{
|
||||
MockMessageService = new Mock<IMessageService>();
|
||||
TestUserToken = GenerateTestToken(TestUserId.ToString(), "testuser");
|
||||
|
||||
var webHostBuilder = new WebHostBuilder()
|
||||
.UseEnvironment("Testing") // Use a specific environment for tests
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
// Replace the real IMessageService with our mock for testing Hub logic
|
||||
services.AddSingleton(MockMessageService.Object);
|
||||
|
||||
// Configure Authentication
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateLifetime = false,
|
||||
ValidateIssuerSigningKey = false,
|
||||
SignatureValidator = (token, parameters) => new JwtSecurityToken(token), // Bypass signature validation for test tokens
|
||||
NameClaimType = ClaimTypes.NameIdentifier
|
||||
};
|
||||
// For SignalR, need to allow token in query string for WebSocket
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
if (!string.IsNullOrEmpty(accessToken) &&
|
||||
(context.HttpContext.Request.Path.StartsWithSegments("/hubs/chats"))) // Adjust path if needed
|
||||
{
|
||||
context.Token = accessToken;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
services.AddAuthorization();
|
||||
services.AddSignalR();
|
||||
|
||||
// Add other necessary services that ChatsHub might depend on, possibly mocked
|
||||
// services.AddSingleton(Mock.Of<IUserService>()); // If ChatsHub uses IUserService for groups
|
||||
})
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.AddDebug(); // Or any other logger
|
||||
})
|
||||
.UseStartup<Startup>(); // Assuming you have a Startup.cs, or use Program.cs for .NET 6+
|
||||
|
||||
TestServer = new TestServer(webHostBuilder);
|
||||
ClientConnection = new HubConnectionBuilder()
|
||||
.WithUrl($"ws://localhost/hubs/chats", options => // Adjust URL as per your hub route
|
||||
{
|
||||
options.HttpMessageHandlerFactory = _ => TestServer.CreateHandler();
|
||||
options.AccessTokenProvider = () => Task.FromResult<string?>(TestUserToken);
|
||||
})
|
||||
.Build();
|
||||
|
||||
await ClientConnection.StartAsync();
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (ClientConnection != null)
|
||||
{
|
||||
await ClientConnection.DisposeAsync();
|
||||
}
|
||||
TestServer?.Dispose();
|
||||
}
|
||||
|
||||
private string GenerateTestToken(string userId, string userName)
|
||||
{
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim("userID", userId), // Ensure this matches the claim name used in ChatsHub.GetUserId()
|
||||
new Claim(ClaimTypes.Name, userName)
|
||||
};
|
||||
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-super-secret-key-that-is-long-enough")); // Use a key from config or a test key
|
||||
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
|
||||
var token = new JwtSecurityToken("TestIssuer", "TestAudience", claims, expires: DateTime.Now.AddHours(1), signingCredentials: credentials);
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ChatsHubTests : HubTestBase
|
||||
{
|
||||
[Fact]
|
||||
public async Task Send_ValidMessageToUser_CallsServiceAndNotifiesRecipientAndSender()
|
||||
{
|
||||
// Arrange
|
||||
var recipientId = Guid.NewGuid();
|
||||
var messageContent = "Hello from integration test";
|
||||
var messageId = Guid.NewGuid();
|
||||
|
||||
MockMessageService.Setup(s => s.SendMessageAsync(It.Is<SendMessage>(p =>
|
||||
p.FromUserId == TestUserId &&
|
||||
p.RecipientId == recipientId &&
|
||||
p.RecipientType == RecipientType.User)))
|
||||
.ReturnsAsync(new SendMessageResult(true, null, messageId));
|
||||
|
||||
var messageReceivedTcs = new TaskCompletionSource<UserMessageResponse>();
|
||||
var messageSentTcs = new TaskCompletionSource<UserMessageResponse>();
|
||||
|
||||
// Simulate recipient client being connected and in their own group
|
||||
// This is tricky without a second client connection. For now, we assume SignalR handles group delivery.
|
||||
// A more thorough test would involve a second client.
|
||||
ClientConnection.On<UserMessageResponse>("ReceiveMessage", (response) =>
|
||||
{
|
||||
// This would ideally be for the recipient. For a single client test, this might be tricky.
|
||||
// If sender also receives their own message via "ReceiveMessage" to their own user group:
|
||||
if(response.SenderId == TestUserId && response.RecipientId == recipientId)
|
||||
{
|
||||
//This is if sender also gets ReceiveMessage, for simplicity in single client test
|
||||
messageReceivedTcs.TrySetResult(response);
|
||||
}
|
||||
});
|
||||
ClientConnection.On<UserMessageResponse>("MessageSent", (response) => // Confirmation to sender
|
||||
{
|
||||
if(response.MessageId == messageId) messageSentTcs.TrySetResult(response);
|
||||
});
|
||||
|
||||
var request = new MessageRequest
|
||||
{
|
||||
RecipientId = recipientId,
|
||||
RecipientType = RecipientType.User,
|
||||
EncryptedContent = messageContent,
|
||||
MediaAttachments = new List<MediaReference>()
|
||||
};
|
||||
|
||||
// Act
|
||||
await ClientConnection.InvokeAsync("Send", request);
|
||||
|
||||
// Assert
|
||||
var sentConfirmation = await Task.WhenAny(messageSentTcs.Task, Task.Delay(TimeSpan.FromSeconds(5))) == messageSentTcs.Task
|
||||
? messageSentTcs.Task.Result : null;
|
||||
|
||||
// var receivedMessage = await Task.WhenAny(messageReceivedTcs.Task, Task.Delay(TimeSpan.FromSeconds(5))) == messageReceivedTcs.Task
|
||||
// ? messageReceivedTcs.Task.Result : null;
|
||||
|
||||
|
||||
Assert.NotNull(sentConfirmation);
|
||||
Assert.Equal(messageId, sentConfirmation.MessageId);
|
||||
Assert.Equal(messageContent, sentConfirmation.EncryptedContent);
|
||||
|
||||
// Assert.NotNull(receivedMessage); // This part is harder to assert reliably with one client for recipient
|
||||
// Assert.Equal(messageId, receivedMessage.MessageId);
|
||||
|
||||
|
||||
MockMessageService.Verify(s => s.SendMessageAsync(It.Is<SendMessage>(p =>
|
||||
p.FromUserId == TestUserId &&
|
||||
p.RecipientId == recipientId &&
|
||||
p.EncryptContent == messageContent)), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Edit_ValidEditRequest_CallsServiceAndNotifies()
|
||||
{
|
||||
// Arrange
|
||||
var originalSenderId = TestUserId; // Editor must be the sender
|
||||
var messageToEditId = Guid.NewGuid();
|
||||
var newContent = "Updated content";
|
||||
var recipientId = Guid.NewGuid(); // Could be user or group
|
||||
|
||||
var originalMessage = new Message {
|
||||
Id = messageToEditId,
|
||||
SenderId = originalSenderId,
|
||||
RecipientId = recipientId,
|
||||
RecipientType = RecipientType.User
|
||||
};
|
||||
|
||||
MockMessageService.Setup(s => s.EditMessageAsync(It.Is<EditMessage>(p =>
|
||||
p.EditorId == TestUserId &&
|
||||
p.MessageId == messageToEditId &&
|
||||
p.NewContent == newContent)))
|
||||
.ReturnsAsync(new EditMessageResult(true, null, originalMessage));
|
||||
|
||||
var messageEditedTcs = new TaskCompletionSource<MessageEditedResponse>();
|
||||
ClientConnection.On<MessageEditedResponse>("MessageEdited", (response) =>
|
||||
{
|
||||
if(response.MessageId == messageToEditId) messageEditedTcs.TrySetResult(response);
|
||||
});
|
||||
|
||||
var request = new EditMessageRequest
|
||||
{
|
||||
MessageId = messageToEditId,
|
||||
NewEncryptedContent = newContent
|
||||
};
|
||||
|
||||
// Act
|
||||
await ClientConnection.InvokeAsync("Edit", request);
|
||||
|
||||
// Assert
|
||||
var editedNotification = await Task.WhenAny(messageEditedTcs.Task, Task.Delay(TimeSpan.FromSeconds(5))) == messageEditedTcs.Task
|
||||
? messageEditedTcs.Task.Result : null;
|
||||
|
||||
Assert.NotNull(editedNotification);
|
||||
Assert.Equal(messageToEditId, editedNotification.MessageId);
|
||||
Assert.Equal(newContent, editedNotification.NewEncryptedContent);
|
||||
Assert.Equal(originalSenderId, editedNotification.SenderId); // Verify original sender is preserved
|
||||
|
||||
MockMessageService.Verify(s => s.EditMessageAsync(It.Is<EditMessage>(p =>
|
||||
p.EditorId == TestUserId &&
|
||||
p.MessageId == messageToEditId &&
|
||||
p.NewContent == newContent)), Times.Once);
|
||||
}
|
||||
|
||||
// TODO: Add tests for Remove method
|
||||
// TODO: Add tests for OnConnectedAsync (e.g., joining groups - might require IUserService mock)
|
||||
// TODO: Add tests for unauthorized scenarios (e.g., editing/deleting someone else's message)
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
using Moq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Govor.Application.Services;
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Interfaces.Messages;
|
||||
using Govor.Application.Interfaces.Messages.Parameters;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Repositories.Messages;
|
||||
using Govor.Core.Repositories.Users;
|
||||
using Govor.Core.Repositories.Groups;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Govor.Application.Exceptions.VerifyFriendship; // Assuming this exception type
|
||||
|
||||
namespace Govor.API.Tests.UnitTests.Services;
|
||||
|
||||
public class MessageServiceTests
|
||||
{
|
||||
private readonly Mock<IMessagesRepository> _mockMessagesRepo;
|
||||
private readonly Mock<IUsersRepository> _mockUsersRepo;
|
||||
private readonly Mock<IGroupsRepository> _mockGroupsRepo;
|
||||
private readonly Mock<IVerifyFriendship> _mockVerifyFriendship;
|
||||
private readonly Mock<ILogger<MessageService>> _mockLogger;
|
||||
private readonly MessageService _messageService;
|
||||
|
||||
public MessageServiceTests()
|
||||
{
|
||||
_mockMessagesRepo = new Mock<IMessagesRepository>();
|
||||
_mockUsersRepo = new Mock<IUsersRepository>();
|
||||
_mockGroupsRepo = new Mock<IGroupsRepository>();
|
||||
_mockVerifyFriendship = new Mock<IVerifyFriendship>();
|
||||
_mockLogger = new Mock<ILogger<MessageService>>();
|
||||
|
||||
_messageService = new MessageService(
|
||||
_mockMessagesRepo.Object,
|
||||
_mockUsersRepo.Object,
|
||||
_mockGroupsRepo.Object,
|
||||
_mockVerifyFriendship.Object,
|
||||
_mockLogger.Object);
|
||||
}
|
||||
|
||||
// --- SendMessageAsync Tests ---
|
||||
|
||||
[Fact]
|
||||
public async Task SendMessageAsync_ToUser_Success()
|
||||
{
|
||||
// Arrange
|
||||
var senderId = Guid.NewGuid();
|
||||
var recipientId = Guid.NewGuid();
|
||||
var sendMessageParams = new SendMessage("Hello", null, recipientId, RecipientType.User, senderId, DateTime.UtcNow, new List<SendMedia>());
|
||||
|
||||
_mockUsersRepo.Setup(r => r.ExistsByIdAsync(recipientId)).ReturnsAsync(true);
|
||||
_mockVerifyFriendship.Setup(v => v.VerifyAsync(senderId, recipientId)).Returns(Task.CompletedTask);
|
||||
_mockMessagesRepo.Setup(r => r.AddAsync(It.IsAny<Message>())).Returns(Task.CompletedTask);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.SendMessageAsync(sendMessageParams);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.Null(result.Exception);
|
||||
Assert.NotEqual(Guid.Empty, result.MessageId);
|
||||
_mockMessagesRepo.Verify(r => r.AddAsync(It.Is<Message>(m =>
|
||||
m.SenderId == senderId &&
|
||||
m.RecipientId == recipientId &&
|
||||
m.RecipientType == RecipientType.User &&
|
||||
m.EncryptedContent == "Hello")), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendMessageAsync_ToGroup_Success()
|
||||
{
|
||||
// Arrange
|
||||
var senderId = Guid.NewGuid();
|
||||
var groupId = Guid.NewGuid();
|
||||
var sendMessageParams = new SendMessage("Hello Group", null, groupId, RecipientType.Group, senderId, DateTime.UtcNow, new List<SendMedia>());
|
||||
|
||||
_mockGroupsRepo.Setup(r => r.ExistsAsync(groupId)).ReturnsAsync(true);
|
||||
// _mockGroupsRepo.Setup(r => r.IsUserMemberOfGroupAsync(senderId, groupId)).ReturnsAsync(true); // Assuming membership check
|
||||
_mockMessagesRepo.Setup(r => r.AddAsync(It.IsAny<Message>())).Returns(Task.CompletedTask);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.SendMessageAsync(sendMessageParams);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotEqual(Guid.Empty, result.MessageId);
|
||||
_mockMessagesRepo.Verify(r => r.AddAsync(It.Is<Message>(m => m.RecipientId == groupId && m.RecipientType == RecipientType.Group)), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendMessageAsync_ToUser_RecipientNotFound_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var senderId = Guid.NewGuid();
|
||||
var recipientId = Guid.NewGuid();
|
||||
var sendMessageParams = new SendMessage("Hello", null, recipientId, RecipientType.User, senderId, DateTime.UtcNow, new List<SendMedia>());
|
||||
|
||||
_mockUsersRepo.Setup(r => r.ExistsByIdAsync(recipientId)).ReturnsAsync(false);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.SendMessageAsync(sendMessageParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.NotNull(result.Exception);
|
||||
Assert.IsType<KeyNotFoundException>(result.Exception);
|
||||
Assert.Equal(Guid.Empty, result.MessageId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendMessageAsync_ToUser_FriendshipVerificationFails_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var senderId = Guid.NewGuid();
|
||||
var recipientId = Guid.NewGuid();
|
||||
var sendMessageParams = new SendMessage("Hello", null, recipientId, RecipientType.User, senderId, DateTime.UtcNow, new List<SendMedia>());
|
||||
|
||||
_mockUsersRepo.Setup(r => r.ExistsByIdAsync(recipientId)).ReturnsAsync(true);
|
||||
_mockVerifyFriendship.Setup(v => v.VerifyAsync(senderId, recipientId)).ThrowsAsync(new FriendshipException("Not friends"));
|
||||
|
||||
// Act
|
||||
var result = await _messageService.SendMessageAsync(sendMessageParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.NotNull(result.Exception);
|
||||
Assert.IsType<FriendshipException>(result.Exception);
|
||||
Assert.Equal(Guid.Empty, result.MessageId);
|
||||
}
|
||||
|
||||
|
||||
// --- EditMessageAsync Tests ---
|
||||
|
||||
[Fact]
|
||||
public async Task EditMessageAsync_Success()
|
||||
{
|
||||
// Arrange
|
||||
var editorId = Guid.NewGuid();
|
||||
var messageId = Guid.NewGuid();
|
||||
var originalMessage = new Message { Id = messageId, SenderId = editorId, EncryptedContent = "Old", RecipientId = Guid.NewGuid(), RecipientType = RecipientType.User };
|
||||
var editParams = new EditMessage(editorId, messageId, "New Content", DateTime.UtcNow);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync(originalMessage);
|
||||
_mockMessagesRepo.Setup(r => r.UpdateAsync(It.IsAny<Message>())).Returns(Task.CompletedTask);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.EditMessageAsync(editParams);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotNull(result.OriginalMessage);
|
||||
Assert.Equal(messageId, result.OriginalMessage!.Id);
|
||||
_mockMessagesRepo.Verify(r => r.UpdateAsync(It.Is<Message>(m =>
|
||||
m.Id == messageId &&
|
||||
m.EncryptedContent == "New Content" &&
|
||||
m.IsEdited == true &&
|
||||
m.EditedAt == editParams.EditedAt)), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EditMessageAsync_MessageNotFound_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var editorId = Guid.NewGuid();
|
||||
var messageId = Guid.NewGuid();
|
||||
var editParams = new EditMessage(editorId, messageId, "New Content", DateTime.UtcNow);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync((Message?)null);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.EditMessageAsync(editParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.IsType<KeyNotFoundException>(result.Exception);
|
||||
Assert.Null(result.OriginalMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EditMessageAsync_NotSender_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var editorId = Guid.NewGuid();
|
||||
var senderId = Guid.NewGuid(); // Different from editorId
|
||||
var messageId = Guid.NewGuid();
|
||||
var originalMessage = new Message { Id = messageId, SenderId = senderId, EncryptedContent = "Old" };
|
||||
var editParams = new EditMessage(editorId, messageId, "New Content", DateTime.UtcNow);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync(originalMessage);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.EditMessageAsync(editParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.IsType<UnauthorizedAccessException>(result.Exception);
|
||||
Assert.Null(result.OriginalMessage);
|
||||
}
|
||||
|
||||
// --- DeleteMessageAsync Tests ---
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteMessageAsync_Success()
|
||||
{
|
||||
// Arrange
|
||||
var deleterId = Guid.NewGuid();
|
||||
var messageId = Guid.NewGuid();
|
||||
var originalMessage = new Message { Id = messageId, SenderId = deleterId, RecipientId = Guid.NewGuid(), RecipientType = RecipientType.User };
|
||||
var deleteParams = new DeleteMessage(deleterId, messageId);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync(originalMessage);
|
||||
// For soft delete, the repo's DeleteAsync would internally mark IsDeleted=true and save.
|
||||
// If it were hard delete, it would be _mockMessagesRepo.Setup(r => r.DeleteAsync(messageId)).Returns(Task.CompletedTask);
|
||||
// Assuming DeleteAsync in repo handles the soft delete logic (sets IsDeleted, DeletedAt, then calls UpdateAsync or similar)
|
||||
// For this test, we verify that the service calls the repo's DeleteAsync method.
|
||||
// The actual soft delete implementation is tested at the repository level.
|
||||
// However, MessageService is responsible for *initiating* the delete.
|
||||
// If MessageService directly manipulated IsDeleted, we'd mock repo.UpdateAsync.
|
||||
// Since it calls repo.DeleteAsync, we mock that.
|
||||
_mockMessagesRepo.Setup(r => r.DeleteAsync(messageId)).Returns(Task.CompletedTask);
|
||||
|
||||
|
||||
// Act
|
||||
var result = await _messageService.DeleteMessageAsync(deleteParams);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.NotNull(result.OriginalMessage);
|
||||
Assert.Equal(messageId, result.OriginalMessage!.Id);
|
||||
_mockMessagesRepo.Verify(r => r.DeleteAsync(messageId), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteMessageAsync_MessageNotFound_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var deleterId = Guid.NewGuid();
|
||||
var messageId = Guid.NewGuid();
|
||||
var deleteParams = new DeleteMessage(deleterId, messageId);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync((Message?)null);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.DeleteMessageAsync(deleteParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.IsType<KeyNotFoundException>(result.Exception);
|
||||
Assert.Null(result.OriginalMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteMessageAsync_NotSender_ReturnsFailure()
|
||||
{
|
||||
// Arrange
|
||||
var deleterId = Guid.NewGuid();
|
||||
var senderId = Guid.NewGuid(); // Different
|
||||
var messageId = Guid.NewGuid();
|
||||
var originalMessage = new Message { Id = messageId, SenderId = senderId };
|
||||
var deleteParams = new DeleteMessage(deleterId, messageId);
|
||||
|
||||
_mockMessagesRepo.Setup(r => r.GetByIdAsync(messageId)).ReturnsAsync(originalMessage);
|
||||
|
||||
// Act
|
||||
var result = await _messageService.DeleteMessageAsync(deleteParams);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.IsType<UnauthorizedAccessException>(result.Exception);
|
||||
Assert.Null(result.OriginalMessage);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user