Files
ChatBot/ChatBot.Tests/Services/Telegram/TelegramErrorHandlerTests.cs
Leonid Pershin f4892efbb5
All checks were successful
SonarQube / Build and analyze (push) Successful in 3m31s
Unit Tests / Run Tests (push) Successful in 2m28s
fix
2025-10-20 10:25:40 +03:00

321 lines
9.8 KiB
C#

using ChatBot.Services.Telegram.Services;
using ChatBot.Tests.TestUtilities;
using Microsoft.Extensions.Logging;
using Moq;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
namespace ChatBot.Tests.Services.Telegram;
public class TelegramErrorHandlerTests : UnitTestBase
{
private readonly Mock<ILogger<TelegramErrorHandler>> _loggerMock;
private readonly Mock<ITelegramBotClient> _botClientMock;
private readonly TelegramErrorHandler _errorHandler;
public TelegramErrorHandlerTests()
{
_loggerMock = new Mock<ILogger<TelegramErrorHandler>>();
_botClientMock = new Mock<ITelegramBotClient>();
_errorHandler = new TelegramErrorHandler(_loggerMock.Object);
}
[Fact]
public void Constructor_ShouldCreateInstance()
{
// Act & Assert
Assert.NotNull(_errorHandler);
}
[Fact]
public async Task HandlePollingErrorAsync_WithApiRequestException_ShouldLogErrorWithFormattedMessage()
{
// Arrange
var errorCode = 400;
var errorMessage = "Bad Request: chat not found";
var apiException = new ApiRequestException(errorMessage, errorCode);
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
apiException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains($"Telegram API Error:\n[{errorCode}]\n{errorMessage}")
),
apiException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Theory]
[InlineData(400, "Bad Request")]
[InlineData(401, "Unauthorized")]
[InlineData(403, "Forbidden")]
[InlineData(404, "Not Found")]
[InlineData(429, "Too Many Requests")]
[InlineData(500, "Internal Server Error")]
public async Task HandlePollingErrorAsync_WithDifferentApiErrorCodes_ShouldLogCorrectFormat(
int errorCode,
string errorMessage
)
{
// Arrange
var apiException = new ApiRequestException(errorMessage, errorCode);
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
apiException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains($"Telegram API Error:\n[{errorCode}]\n{errorMessage}")
),
apiException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_WithGenericException_ShouldLogExceptionToString()
{
// Arrange
var genericException = new InvalidOperationException("Something went wrong");
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
genericException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("System.InvalidOperationException: Something went wrong")
),
genericException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_WithTimeoutException_ShouldLogTimeoutException()
{
// Arrange
var timeoutException = new TimeoutException("Request timed out");
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
timeoutException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!.Contains("System.TimeoutException: Request timed out")
),
timeoutException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_WithHttpRequestException_ShouldLogHttpRequestException()
{
// Arrange
var httpException = new HttpRequestException("Network error occurred");
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
httpException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains(
"System.Net.Http.HttpRequestException: Network error occurred"
)
),
httpException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_WithCancelledToken_ShouldCompleteSuccessfully()
{
// Arrange
var exception = new InvalidOperationException("Test exception");
using var cancellationTokenSource = new CancellationTokenSource();
await cancellationTokenSource.CancelAsync();
var cancelledToken = cancellationTokenSource.Token;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
exception,
cancelledToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
exception,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_ShouldReturnCompletedTask()
{
// Arrange
var exception = new Exception("Test exception");
var cancellationToken = CancellationToken.None;
// Act
var task = _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
exception,
cancellationToken
);
// Assert
Assert.True(task.IsCompleted);
await task; // Ensure no exceptions are thrown
}
[Fact]
public async Task HandlePollingErrorAsync_WithNestedException_ShouldLogOuterException()
{
// Arrange
var innerException = new ArgumentException("Inner exception");
var outerException = new InvalidOperationException("Outer exception", innerException);
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
outerException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("System.InvalidOperationException: Outer exception")
),
outerException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task HandlePollingErrorAsync_WithAggregateException_ShouldLogAggregateException()
{
// Arrange
var exceptions = new Exception[]
{
new InvalidOperationException("First exception"),
new ArgumentException("Second exception"),
};
var aggregateException = new AggregateException("Multiple exceptions occurred", exceptions);
var cancellationToken = CancellationToken.None;
// Act
await _errorHandler.HandlePollingErrorAsync(
_botClientMock.Object,
aggregateException,
cancellationToken
);
// Assert
_loggerMock.Verify(
x =>
x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("System.AggregateException: Multiple exceptions occurred")
),
aggregateException,
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
}