321 lines
9.8 KiB
C#
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
|
|
);
|
|
}
|
|
}
|