add tests
All checks were successful
SonarQube / Build and analyze (push) Successful in 3m39s

This commit is contained in:
Leonid Pershin
2025-10-21 02:30:04 +03:00
parent 928ae0555e
commit 2a26e84100
15 changed files with 1837 additions and 61 deletions

View File

@@ -10,16 +10,15 @@ namespace ChatBot.Tests.Telegram.Commands;
public class SettingsCommandTests : UnitTestBase
{
private readonly Mock<ISessionStorage> _sessionStorageMock;
private readonly Mock<ChatService> _chatServiceMock;
private readonly SettingsCommand _settingsCommand;
public SettingsCommandTests()
{
_sessionStorageMock = TestDataBuilder.Mocks.CreateSessionStorageMock();
var chatServiceMock = new Mock<ChatService>(
_chatServiceMock = new Mock<ChatService>(
TestDataBuilder.Mocks.CreateLoggerMock<ChatService>().Object,
TestDataBuilder.Mocks.CreateAIServiceMock().Object,
_sessionStorageMock.Object,
TestDataBuilder.Mocks.CreateSessionStorageMock().Object,
TestDataBuilder
.Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings())
.Object,
@@ -33,7 +32,7 @@ public class SettingsCommandTests : UnitTestBase
);
var aiSettingsMock = TestDataBuilder.Mocks.CreateOptionsMock(new AISettings());
_settingsCommand = new SettingsCommand(
chatServiceMock.Object,
_chatServiceMock.Object,
modelServiceMock.Object,
aiSettingsMock.Object
);
@@ -45,7 +44,7 @@ public class SettingsCommandTests : UnitTestBase
// Arrange
var chatId = 12345L;
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
_chatServiceMock.Setup(x => x.GetSession(chatId)).Returns(session);
var context = new TelegramCommandContext
{
@@ -70,7 +69,9 @@ public class SettingsCommandTests : UnitTestBase
{
// Arrange
var chatId = 12345L;
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns((ChatBot.Models.ChatSession?)null);
_chatServiceMock
.Setup(x => x.GetSession(chatId))
.Returns((ChatBot.Models.ChatSession?)null);
var context = new TelegramCommandContext
{

View File

@@ -155,4 +155,284 @@ public class StatusCommandTests : UnitTestBase
result.Should().Contain("системы");
result.Should().Contain("Доступен");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnTimeoutStatus_WhenRequestTimesOut()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws<TaskCanceledException>();
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("Таймаут");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnHttpError502_WhenBadGateway()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
var httpException = new HttpRequestException(
"Response status code does not indicate success: 502"
);
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws(httpException);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("502");
result.Should().Contain("Bad Gateway");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnHttpError503_WhenServiceUnavailable()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
var httpException = new HttpRequestException(
"Response status code does not indicate success: 503"
);
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws(httpException);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("503");
result.Should().Contain("Service Unavailable");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnHttpError504_WhenGatewayTimeout()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
var httpException = new HttpRequestException(
"Response status code does not indicate success: 504"
);
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws(httpException);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("504");
result.Should().Contain("Gateway Timeout");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnHttpError429_WhenTooManyRequests()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
var httpException = new HttpRequestException(
"Response status code does not indicate success: 429"
);
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws(httpException);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("429");
result.Should().Contain("Too Many Requests");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnHttpError500_WhenInternalServerError()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
var httpException = new HttpRequestException(
"Response status code does not indicate success: 500"
);
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Throws(httpException);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("500");
result.Should().Contain("Internal Server Error");
}
[Fact]
public async Task ExecuteAsync_ShouldReturnNoResponseStatus_WhenResponseIsEmpty()
{
// Arrange
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
// Return empty response
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Returns(
TestDataBuilder.Mocks.CreateAsyncEnumerable(
new List<OllamaSharp.Models.Chat.ChatResponseStream>
{
new OllamaSharp.Models.Chat.ChatResponseStream { Message = null! },
}
)
);
// Act
var result = await _statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("Нет ответа");
}
[Fact]
public async Task ExecuteAsync_WithSession_ShouldShowSessionInfo()
{
// Arrange
var chatServiceMock = new Mock<ChatService>(
TestDataBuilder.Mocks.CreateLoggerMock<ChatService>().Object,
TestDataBuilder.Mocks.CreateAIServiceMock().Object,
TestDataBuilder.Mocks.CreateSessionStorageMock().Object,
TestDataBuilder
.Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings())
.Object,
TestDataBuilder.Mocks.CreateCompressionServiceMock().Object
);
var session = TestDataBuilder.ChatSessions.CreateBasicSession(12345, "private");
session.AddUserMessage("Test", "user");
chatServiceMock.Setup(x => x.GetSession(12345)).Returns(session);
var statusCommand = new StatusCommand(
chatServiceMock.Object,
new Mock<ModelService>(
TestDataBuilder.Mocks.CreateLoggerMock<ModelService>().Object,
_ollamaOptionsMock.Object
).Object,
TestDataBuilder.Mocks.CreateOptionsMock(new AISettings()).Object,
_ollamaClientMock.Object
);
var context = new TelegramCommandContext
{
ChatId = 12345,
Username = "testuser",
MessageText = "/status",
ChatType = "private",
ChatTitle = "Test Chat",
};
_ollamaClientMock
.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
.Returns(
TestDataBuilder.Mocks.CreateAsyncEnumerable(
new List<OllamaSharp.Models.Chat.ChatResponseStream>
{
new OllamaSharp.Models.Chat.ChatResponseStream
{
Message = new OllamaSharp.Models.Chat.Message(
ChatRole.Assistant,
"Test"
),
},
}
)
);
// Act
var result = await statusCommand.ExecuteAsync(context);
// Assert
result.Should().NotBeNull();
result.Should().Contain("Сессия");
result.Should().Contain("Сообщений в истории");
}
[Fact]
public void CommandName_ShouldReturnCorrectName()
{
// Act & Assert
_statusCommand.CommandName.Should().Be("/status");
}
[Fact]
public void Description_ShouldReturnCorrectDescription()
{
// Act & Assert
_statusCommand.Description.Should().Be("Показать статус системы и API");
}
}

View File

@@ -6,6 +6,7 @@ using ChatBot.Tests.TestUtilities;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using Telegram.Bot;
using Telegram.Bot.Types;
namespace ChatBot.Tests.Telegram.Commands;
@@ -417,8 +418,8 @@ public class TelegramCommandProcessorTests : UnitTestBase
var username = "testuser";
var chatType = "private";
var chatTitle = "Test Chat";
var cts = new CancellationTokenSource();
cts.Cancel();
using var cts = new CancellationTokenSource();
await cts.CancelAsync();
// Act
var result = await _processor.ProcessMessageAsync(
@@ -488,4 +489,347 @@ public class TelegramCommandProcessorTests : UnitTestBase
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_WithReplyToBot_ShouldProcessMessage()
{
// Arrange
var botUser = new User
{
Id = 999,
Username = "testbot",
IsBot = true,
};
var botInfoServiceMock = new Mock<BotInfoService>(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
botInfoServiceMock.Setup(x => x.GetBotInfoAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(botUser);
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
botInfoServiceMock.Object
);
var replyInfo = new ReplyInfo
{
MessageId = 1,
UserId = 999,
Username = "testbot",
};
// Act
var result = await processor.ProcessMessageAsync(
"Test reply",
12345L,
"user",
"private",
"Test Chat",
replyInfo
);
// Assert
result.Should().NotBeNullOrEmpty();
}
[Fact]
public async Task ProcessMessageAsync_WithReplyToOtherUser_ShouldReturnEmpty()
{
// Arrange
var botUser = new User
{
Id = 999,
Username = "testbot",
IsBot = true,
};
var botInfoServiceMock = new Mock<BotInfoService>(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
botInfoServiceMock.Setup(x => x.GetBotInfoAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(botUser);
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
botInfoServiceMock.Object
);
var replyInfo = new ReplyInfo
{
MessageId = 1,
UserId = 123,
Username = "otheruser",
};
// Act
var result = await processor.ProcessMessageAsync(
"Test reply",
12345L,
"user",
"private",
"Test Chat",
replyInfo
);
// Assert
result.Should().BeEmpty();
}
[Fact]
public async Task ProcessMessageAsync_WithBotMention_ShouldProcessMessage()
{
// Arrange
var botUser = new User
{
Id = 999,
Username = "testbot",
IsBot = true,
};
var botInfoServiceMock = new Mock<BotInfoService>(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
botInfoServiceMock.Setup(x => x.GetBotInfoAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(botUser);
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
botInfoServiceMock.Object
);
// Act
var result = await processor.ProcessMessageAsync(
"Hello @testbot",
12345L,
"user",
"private",
"Test Chat"
);
// Assert
result.Should().NotBeNullOrEmpty();
}
[Fact]
public async Task ProcessMessageAsync_WithOtherUserMention_ShouldReturnEmpty()
{
// Arrange
var botUser = new User
{
Id = 999,
Username = "testbot",
IsBot = true,
};
var botInfoServiceMock = new Mock<BotInfoService>(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
botInfoServiceMock.Setup(x => x.GetBotInfoAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(botUser);
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
botInfoServiceMock.Object
);
// Act
var result = await processor.ProcessMessageAsync(
"Hello @otheruser",
12345L,
"user",
"private",
"Test Chat"
);
// Assert
result.Should().BeEmpty();
}
[Fact]
public async Task ProcessMessageAsync_WithCommand_ShouldExecuteCommand()
{
// Arrange
var commandMock = new Mock<ITelegramCommand>();
commandMock.Setup(x => x.CommandName).Returns("/test");
commandMock
.Setup(x => x.CanHandle(It.IsAny<string>()))
.Returns((string msg) => msg.StartsWith("/test"));
commandMock
.Setup(x =>
x.ExecuteAsync(It.IsAny<TelegramCommandContext>(), It.IsAny<CancellationToken>())
)
.ReturnsAsync("Command executed");
var commandRegistry = new CommandRegistry(
TestDataBuilder.Mocks.CreateLoggerMock<CommandRegistry>().Object,
new[] { commandMock.Object }
);
var processor = new TelegramCommandProcessor(
commandRegistry,
_chatService,
_loggerMock.Object,
_botInfoService
);
// Act
var result = await processor.ProcessMessageAsync(
"/test argument",
12345L,
"user",
"private",
"Test Chat"
);
// Assert
result.Should().Be("Command executed");
commandMock.Verify(
x => x.ExecuteAsync(It.IsAny<TelegramCommandContext>(), It.IsAny<CancellationToken>()),
Times.Once
);
}
[Fact]
public async Task ProcessMessageAsync_WithException_ShouldReturnErrorMessage()
{
// Arrange
var chatServiceMock = new Mock<ChatService>(
TestDataBuilder.Mocks.CreateLoggerMock<ChatService>().Object,
TestDataBuilder.Mocks.CreateAIServiceMock().Object,
TestDataBuilder.Mocks.CreateSessionStorageMock().Object,
TestDataBuilder
.Mocks.CreateOptionsMock(TestDataBuilder.Configurations.CreateAISettings())
.Object,
TestDataBuilder.Mocks.CreateCompressionServiceMock().Object
);
chatServiceMock
.Setup(x =>
x.ProcessMessageAsync(
It.IsAny<long>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<CancellationToken>()
)
)
.ThrowsAsync(new Exception("Test error"));
var processor = new TelegramCommandProcessor(
_commandRegistry,
chatServiceMock.Object,
_loggerMock.Object,
_botInfoService
);
// Act
var result = await processor.ProcessMessageAsync(
"Test message",
12345L,
"user",
"private",
"Test Chat"
);
// Assert
result.Should().Contain("Произошла ошибка");
}
[Fact]
public async Task ProcessMessageAsync_WithGroupChat_ShouldProcessCorrectly()
{
// Arrange
var messageText = "Hello";
var chatId = -100123456789L; // Group chat ID
var username = "testuser";
var chatType = "group";
var chatTitle = "Test Group";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_WithSupergroupChat_ShouldProcessCorrectly()
{
// Arrange
var messageText = "Hello";
var chatId = -100123456789L;
var username = "testuser";
var chatType = "supergroup";
var chatTitle = "Test Supergroup";
// Act
var result = await _processor.ProcessMessageAsync(
messageText,
chatId,
username,
chatType,
chatTitle
);
// Assert
result.Should().NotBeNull();
}
[Fact]
public async Task ProcessMessageAsync_WithMultipleMentions_IncludingBot_ShouldProcessMessage()
{
// Arrange
var botUser = new User
{
Id = 999,
Username = "testbot",
IsBot = true,
};
var botInfoServiceMock = new Mock<BotInfoService>(
TestDataBuilder.Mocks.CreateTelegramBotClient().Object,
TestDataBuilder.Mocks.CreateLoggerMock<BotInfoService>().Object
);
botInfoServiceMock.Setup(x => x.GetBotInfoAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(botUser);
var processor = new TelegramCommandProcessor(
_commandRegistry,
_chatService,
_loggerMock.Object,
botInfoServiceMock.Object
);
// Act
var result = await processor.ProcessMessageAsync(
"Hello @testbot and @otheruser",
12345L,
"user",
"group",
"Test Group"
);
// Assert
result.Should().NotBeNullOrEmpty();
}
}