Add promt fix tests
All checks were successful
SonarQube / Build and analyze (push) Successful in 2m54s
All checks were successful
SonarQube / Build and analyze (push) Successful in 2m54s
This commit is contained in:
12
.windsurf/rules/basesettings.md
Normal file
12
.windsurf/rules/basesettings.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
MCP предоставляет ассистенту доступ к данным SonarQube. Используй инструменты для:
|
||||||
|
Поиска проблем: search_sonar_issues_in_projects, search_dependency_risks
|
||||||
|
Проверки статуса: get_project_quality_gate_status, get_system_status, get_system_health
|
||||||
|
Анализа кода: analyze_code_snippet, get_raw_source
|
||||||
|
Работы с задачами: change_sonar_issue_status
|
||||||
|
Получения метрик: get_component_measures, search_metrics
|
||||||
|
Не гадай — запрашивай данные. Уточняй ключи проектов и issue. Действуй точно, опираясь на информацию из SonarQube.
|
||||||
|
Текущий проект ChatBot
|
||||||
@@ -54,7 +54,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
var expectedResponse = "I'm doing well, thank you!";
|
var expectedResponse = "I'm doing well, thank you!";
|
||||||
|
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
_sessionStorageMock.Setup(x => x.GetOrCreate(chatId, "private", "")).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetOrCreateAsync(chatId, "private", "")).ReturnsAsync(session);
|
||||||
|
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
@@ -89,8 +89,8 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
var expectedResponse = "Hi there!";
|
var expectedResponse = "Hi there!";
|
||||||
|
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.GetOrCreate(chatId, "private", ""))
|
.Setup(x => x.GetOrCreateAsync(chatId, "private", ""))
|
||||||
.Returns(TestDataBuilder.ChatSessions.CreateBasicSession(chatId));
|
.ReturnsAsync(TestDataBuilder.ChatSessions.CreateBasicSession(chatId));
|
||||||
|
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
@@ -106,7 +106,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedResponse);
|
result.Should().Be(expectedResponse);
|
||||||
_sessionStorageMock.Verify(x => x.GetOrCreate(chatId, "private", ""), Times.Once);
|
_sessionStorageMock.Verify(x => x.GetOrCreateAsync(chatId, "private", ""), Times.Once);
|
||||||
_sessionStorageMock.Verify(
|
_sessionStorageMock.Verify(
|
||||||
x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()),
|
x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()),
|
||||||
Times.Exactly(2)
|
Times.Exactly(2)
|
||||||
@@ -123,7 +123,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
var expectedResponse = "I didn't receive a message. Could you please try again?";
|
var expectedResponse = "I didn't receive a message. Could you please try again?";
|
||||||
|
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
_sessionStorageMock.Setup(x => x.GetOrCreate(chatId, "private", "")).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetOrCreateAsync(chatId, "private", "")).ReturnsAsync(session);
|
||||||
|
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
@@ -151,7 +151,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
var message = "Hello";
|
var message = "Hello";
|
||||||
|
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
_sessionStorageMock.Setup(x => x.GetOrCreate(chatId, "private", "")).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetOrCreateAsync(chatId, "private", "")).ReturnsAsync(session);
|
||||||
|
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
@@ -179,7 +179,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
var expectedResponse = "Hi there!";
|
var expectedResponse = "Hi there!";
|
||||||
|
|
||||||
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 10); // 10 messages
|
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 10); // 10 messages
|
||||||
_sessionStorageMock.Setup(x => x.GetOrCreate(chatId, "private", "")).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetOrCreateAsync(chatId, "private", "")).ReturnsAsync(session);
|
||||||
|
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
@@ -211,7 +211,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _chatService.ClearHistoryAsync(chatId);
|
await _chatService.ClearHistoryAsync(chatId);
|
||||||
@@ -226,7 +226,7 @@ public class ChatServiceIntegrationTests : TestBase
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns((ChatBot.Models.ChatSession?)null);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync((ChatBot.Models.ChatSession?)null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _chatService.ClearHistoryAsync(chatId);
|
await _chatService.ClearHistoryAsync(chatId);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreateSession_ShouldCreateNewSession_WhenSessionDoesNotExist()
|
public async Task GetOrCreateSession_ShouldCreateNewSession_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
@@ -45,7 +45,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var chatTitle = "Test Chat";
|
var chatTitle = "Test Chat";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var session = _chatService.GetOrCreateSession(chatId, chatType, chatTitle);
|
var session = await _chatService.GetOrCreateSessionAsync(chatId, chatType, chatTitle);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
session.Should().NotBeNull();
|
session.Should().NotBeNull();
|
||||||
@@ -53,22 +53,22 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
session.ChatType.Should().Be(chatType);
|
session.ChatType.Should().Be(chatType);
|
||||||
session.ChatTitle.Should().Be(chatTitle);
|
session.ChatTitle.Should().Be(chatTitle);
|
||||||
|
|
||||||
_sessionStorageMock.Verify(x => x.GetOrCreate(chatId, chatType, chatTitle), Times.Once);
|
_sessionStorageMock.Verify(x => x.GetOrCreateAsync(chatId, chatType, chatTitle), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreateSession_ShouldSetCompressionService_WhenCompressionIsEnabled()
|
public async Task GetOrCreateSession_ShouldSetCompressionService_WhenCompressionIsEnabled()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
_aiSettings.EnableHistoryCompression = true;
|
_aiSettings.EnableHistoryCompression = true;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var session = _chatService.GetOrCreateSession(chatId);
|
var session = await _chatService.GetOrCreateSessionAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
session.Should().NotBeNull();
|
session.Should().NotBeNull();
|
||||||
_sessionStorageMock.Verify(x => x.GetOrCreate(chatId, "private", ""), Times.Once);
|
_sessionStorageMock.Verify(x => x.GetOrCreateAsync(chatId, "private", ""), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -191,7 +191,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var newModel = "llama3.2";
|
var newModel = "llama3.2";
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _chatService.UpdateSessionParametersAsync(chatId, newModel);
|
await _chatService.UpdateSessionParametersAsync(chatId, newModel);
|
||||||
@@ -208,7 +208,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var newModel = "llama3.2";
|
var newModel = "llama3.2";
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns((ChatBot.Models.ChatSession?)null);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync((ChatBot.Models.ChatSession?)null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _chatService.UpdateSessionParametersAsync(chatId, newModel);
|
await _chatService.UpdateSessionParametersAsync(chatId, newModel);
|
||||||
@@ -227,7 +227,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _chatService.ClearHistoryAsync(chatId);
|
await _chatService.ClearHistoryAsync(chatId);
|
||||||
@@ -238,82 +238,82 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetSession_ShouldReturnSession_WhenSessionExists()
|
public async Task GetSession_ShouldReturnSession_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.GetSession(chatId);
|
var result = await _chatService.GetSessionAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(session);
|
result.Should().Be(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetSession_ShouldReturnNull_WhenSessionDoesNotExist()
|
public async Task GetSession_ShouldReturnNull_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns((ChatBot.Models.ChatSession?)null);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync((ChatBot.Models.ChatSession?)null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.GetSession(chatId);
|
var result = await _chatService.GetSessionAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RemoveSession_ShouldReturnTrue_WhenSessionExists()
|
public async Task RemoveSession_ShouldReturnTrue_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Remove(chatId)).Returns(true);
|
_sessionStorageMock.Setup(x => x.RemoveAsync(chatId)).ReturnsAsync(true);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.RemoveSession(chatId);
|
var result = await _chatService.RemoveSessionAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeTrue();
|
result.Should().BeTrue();
|
||||||
_sessionStorageMock.Verify(x => x.Remove(chatId), Times.Once);
|
_sessionStorageMock.Verify(x => x.RemoveAsync(chatId), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetActiveSessionsCount_ShouldReturnCorrectCount()
|
public async Task GetActiveSessionsCount_ShouldReturnCorrectCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedCount = 5;
|
var expectedCount = 5;
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.GetActiveSessionsCount()).Returns(expectedCount);
|
_sessionStorageMock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(expectedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.GetActiveSessionsCount();
|
var result = await _chatService.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCount);
|
result.Should().Be(expectedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldReturnCleanedCount()
|
public async Task CleanupOldSessions_ShouldReturnCleanedCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var hoursOld = 24;
|
var hoursOld = 24;
|
||||||
var expectedCleaned = 3;
|
var expectedCleaned = 3;
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.CleanupOldSessions(hoursOld)).Returns(expectedCleaned);
|
_sessionStorageMock.Setup(x => x.CleanupOldSessionsAsync(hoursOld)).ReturnsAsync(expectedCleaned);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.CleanupOldSessions(hoursOld);
|
var result = await _chatService.CleanupOldSessionsAsync(hoursOld);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCleaned);
|
result.Should().Be(expectedCleaned);
|
||||||
_sessionStorageMock.Verify(x => x.CleanupOldSessions(hoursOld), Times.Once);
|
_sessionStorageMock.Verify(x => x.CleanupOldSessionsAsync(hoursOld), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -395,8 +395,8 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var message = "Hello, bot!";
|
var message = "Hello, bot!";
|
||||||
|
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.GetOrCreate(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
.Setup(x => x.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Throws(new Exception("Database connection failed"));
|
.ThrowsAsync(new Exception("Database connection failed"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await _chatService.ProcessMessageAsync(chatId, username, message);
|
var result = await _chatService.ProcessMessageAsync(chatId, username, message);
|
||||||
@@ -585,9 +585,9 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
session.MaxHistoryLength = 5; // force small history limit
|
session.MaxHistoryLength = 5; // force small history limit
|
||||||
|
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.GetOrCreate(chatId, It.IsAny<string>(), It.IsAny<string>()))
|
.Setup(x => x.GetOrCreateAsync(chatId, It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns(session);
|
.ReturnsAsync(session);
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
x.GenerateChatCompletionWithCompressionAsync(
|
x.GenerateChatCompletionWithCompressionAsync(
|
||||||
@@ -620,9 +620,9 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
session.MaxHistoryLength = 50; // avoid trimming impacting compression assertion
|
session.MaxHistoryLength = 50; // avoid trimming impacting compression assertion
|
||||||
|
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.GetOrCreate(chatId, It.IsAny<string>(), It.IsAny<string>()))
|
.Setup(x => x.GetOrCreateAsync(chatId, It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns(session);
|
.ReturnsAsync(session);
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
_aiServiceMock
|
_aiServiceMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
x.GenerateChatCompletionWithCompressionAsync(
|
x.GenerateChatCompletionWithCompressionAsync(
|
||||||
@@ -692,7 +692,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var newModel = "llama3.2";
|
var newModel = "llama3.2";
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()))
|
.Setup(x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()))
|
||||||
.ThrowsAsync(new Exception("Database save failed"));
|
.ThrowsAsync(new Exception("Database save failed"));
|
||||||
@@ -709,7 +709,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
var session = TestDataBuilder.ChatSessions.CreateSessionWithMessages(chatId, 5);
|
||||||
|
|
||||||
_sessionStorageMock.Setup(x => x.Get(chatId)).Returns(session);
|
_sessionStorageMock.Setup(x => x.GetAsync(chatId)).ReturnsAsync(session);
|
||||||
_sessionStorageMock
|
_sessionStorageMock
|
||||||
.Setup(x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()))
|
.Setup(x => x.SaveSessionAsync(It.IsAny<ChatBot.Models.ChatSession>()))
|
||||||
.ThrowsAsync(new Exception("Database save failed"));
|
.ThrowsAsync(new Exception("Database save failed"));
|
||||||
@@ -723,18 +723,18 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
[InlineData(0)]
|
[InlineData(0)]
|
||||||
[InlineData(-1)]
|
[InlineData(-1)]
|
||||||
[InlineData(int.MinValue)]
|
[InlineData(int.MinValue)]
|
||||||
public void CleanupOldSessions_ShouldHandleInvalidHoursOld(int hoursOld)
|
public async Task CleanupOldSessions_ShouldHandleInvalidHoursOld(int hoursOld)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedCleaned = 0;
|
var expectedCleaned = 0;
|
||||||
_sessionStorageMock.Setup(x => x.CleanupOldSessions(hoursOld)).Returns(expectedCleaned);
|
_sessionStorageMock.Setup(x => x.CleanupOldSessionsAsync(hoursOld)).ReturnsAsync(expectedCleaned);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _chatService.CleanupOldSessions(hoursOld);
|
var result = await _chatService.CleanupOldSessionsAsync(hoursOld);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCleaned);
|
result.Should().Be(expectedCleaned);
|
||||||
_sessionStorageMock.Verify(x => x.CleanupOldSessions(hoursOld), Times.Once);
|
_sessionStorageMock.Verify(x => x.CleanupOldSessionsAsync(hoursOld), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -763,7 +763,7 @@ public class ChatServiceTests : UnitTestBase
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedResponse);
|
result.Should().Be(expectedResponse);
|
||||||
_sessionStorageMock.Verify(x => x.GetOrCreate(chatId, "private", ""), Times.Once);
|
_sessionStorageMock.Verify(x => x.GetOrCreateAsync(chatId, "private", ""), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ChatBot.Services;
|
|||||||
using ChatBot.Tests.TestUtilities;
|
using ChatBot.Tests.TestUtilities;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Moq;
|
using Moq;
|
||||||
@@ -27,6 +28,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
// Add in-memory database
|
// Add in-memory database
|
||||||
services.AddDbContext<ChatBotDbContext>(options =>
|
services.AddDbContext<ChatBotDbContext>(options =>
|
||||||
options.UseInMemoryDatabase("TestDatabase")
|
options.UseInMemoryDatabase("TestDatabase")
|
||||||
|
.ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add mocked repository
|
// Add mocked repository
|
||||||
@@ -52,7 +54,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldReturnExistingSession_WhenSessionExists()
|
public async Task GetOrCreateAsync_ShouldReturnExistingSession_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var existingSession = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
var existingSession = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
||||||
@@ -61,7 +63,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ReturnsAsync(existingSession);
|
.ReturnsAsync(existingSession);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
var result = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -70,14 +72,14 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_ShouldReturnSession_WhenSessionExists()
|
public async Task GetAsync_ShouldReturnSession_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var sessionEntity = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
var sessionEntity = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
||||||
_repositoryMock.Setup(x => x.GetByChatIdAsync(12345)).ReturnsAsync(sessionEntity);
|
_repositoryMock.Setup(x => x.GetByChatIdAsync(12345)).ReturnsAsync(sessionEntity);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Get(12345);
|
var result = await _sessionStorage.GetAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -86,7 +88,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_ShouldReturnNull_WhenSessionDoesNotExist()
|
public async Task GetAsync_ShouldReturnNull_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
@@ -94,7 +96,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ReturnsAsync((ChatSessionEntity?)null);
|
.ReturnsAsync((ChatSessionEntity?)null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Get(12345);
|
var result = await _sessionStorage.GetAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
@@ -120,13 +122,13 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldReturnTrue_WhenSessionExists()
|
public async Task RemoveAsync_ShouldReturnTrue_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock.Setup(x => x.DeleteAsync(12345)).ReturnsAsync(true);
|
_repositoryMock.Setup(x => x.DeleteAsync(12345)).ReturnsAsync(true);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Remove(12345);
|
var result = await _sessionStorage.RemoveAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeTrue();
|
result.Should().BeTrue();
|
||||||
@@ -134,13 +136,13 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldReturnFalse_WhenSessionDoesNotExist()
|
public async Task RemoveAsync_ShouldReturnFalse_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock.Setup(x => x.DeleteAsync(12345)).ReturnsAsync(false);
|
_repositoryMock.Setup(x => x.DeleteAsync(12345)).ReturnsAsync(false);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Remove(12345);
|
var result = await _sessionStorage.RemoveAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeFalse();
|
result.Should().BeFalse();
|
||||||
@@ -148,14 +150,14 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetActiveSessionsCount_ShouldReturnCorrectCount()
|
public async Task GetActiveSessionsCountAsync_ShouldReturnCorrectCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedCount = 5;
|
var expectedCount = 5;
|
||||||
_repositoryMock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(expectedCount);
|
_repositoryMock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(expectedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetActiveSessionsCount();
|
var result = await _sessionStorage.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCount);
|
result.Should().Be(expectedCount);
|
||||||
@@ -163,14 +165,14 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldReturnCorrectCount()
|
public async Task CleanupOldSessionsAsync_ShouldReturnCorrectCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedCount = 3;
|
var expectedCount = 3;
|
||||||
_repositoryMock.Setup(x => x.CleanupOldSessionsAsync(24)).ReturnsAsync(expectedCount);
|
_repositoryMock.Setup(x => x.CleanupOldSessionsAsync(24)).ReturnsAsync(expectedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.CleanupOldSessions(24);
|
var result = await _sessionStorage.CleanupOldSessionsAsync(24);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCount);
|
result.Should().Be(expectedCount);
|
||||||
@@ -178,34 +180,32 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldThrowInvalidOperationException_WhenRepositoryThrows()
|
public async Task GetOrCreateAsync_ShouldThrowInvalidOperationException_WhenRepositoryThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
.Setup(x => x.GetOrCreateAsync(12345, "private", "Test Chat"))
|
.Setup(x => x.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var act = () => _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
Func<Task> act = async () => await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
act.Should()
|
await act.Should()
|
||||||
.Throw<InvalidOperationException>()
|
.ThrowAsync<InvalidOperationException>()
|
||||||
.WithMessage("Failed to get or create session for chat 12345")
|
.WithMessage("Failed to get or create session for chat 12345");
|
||||||
.WithInnerException<Exception>()
|
|
||||||
.WithMessage("Database error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_ShouldReturnNull_WhenRepositoryThrows()
|
public async Task GetAsync_ShouldReturnNull_WhenRepositoryThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
.Setup(x => x.GetByChatIdAsync(12345))
|
.Setup(x => x.GetByChatIdAsync(It.IsAny<long>()))
|
||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Get(12345);
|
var result = await _sessionStorage.GetAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
@@ -238,7 +238,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var act = async () => await _sessionStorage.SaveSessionAsync(session);
|
Func<Task> act = async () => await _sessionStorage.SaveSessionAsync(session);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var exception = await act.Should()
|
var exception = await act.Should()
|
||||||
@@ -284,22 +284,22 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldReturnFalse_WhenRepositoryThrows()
|
public async Task RemoveAsync_ShouldReturnFalse_WhenRepositoryThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
.Setup(x => x.DeleteAsync(12345))
|
.Setup(x => x.DeleteAsync(It.IsAny<long>()))
|
||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Remove(12345);
|
var result = await _sessionStorage.RemoveAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeFalse();
|
result.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetActiveSessionsCount_ShouldReturnZero_WhenRepositoryThrows()
|
public async Task GetActiveSessionsCountAsync_ShouldReturnZero_WhenRepositoryThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
@@ -307,14 +307,14 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetActiveSessionsCount();
|
var result = await _sessionStorage.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(0);
|
result.Should().Be(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldReturnZero_WhenRepositoryThrows()
|
public async Task CleanupOldSessionsAsync_ShouldReturnZero_WhenRepositoryThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_repositoryMock
|
_repositoryMock
|
||||||
@@ -322,20 +322,21 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ThrowsAsync(new Exception("Database error"));
|
.ThrowsAsync(new Exception("Database error"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.CleanupOldSessions(24);
|
var result = await _sessionStorage.CleanupOldSessionsAsync(24);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(0);
|
result.Should().Be(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_WithCompressionService_ShouldSetCompressionService()
|
public async Task GetOrCreateAsync_WithCompressionService_ShouldSetCompressionService()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var compressionServiceMock = TestDataBuilder.Mocks.CreateCompressionServiceMock();
|
var compressionServiceMock = TestDataBuilder.Mocks.CreateCompressionServiceMock();
|
||||||
var storageWithCompression = new DatabaseSessionStorage(
|
var storageWithCompression = new DatabaseSessionStorage(
|
||||||
_repositoryMock.Object,
|
_repositoryMock.Object,
|
||||||
Mock.Of<ILogger<DatabaseSessionStorage>>(),
|
Mock.Of<ILogger<DatabaseSessionStorage>>(),
|
||||||
|
_dbContext,
|
||||||
compressionServiceMock.Object
|
compressionServiceMock.Object
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -345,7 +346,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ReturnsAsync(sessionEntity);
|
.ReturnsAsync(sessionEntity);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = storageWithCompression.GetOrCreate(12345, "private", "Test Chat");
|
var result = await storageWithCompression.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -353,7 +354,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_WithCompressionService_ShouldSetCompressionService()
|
public async Task GetAsync_WithCompressionService_ShouldSetCompressionService()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var loggerMock = new Mock<ILogger<DatabaseSessionStorage>>();
|
var loggerMock = new Mock<ILogger<DatabaseSessionStorage>>();
|
||||||
@@ -361,6 +362,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
var storageWithCompression = new DatabaseSessionStorage(
|
var storageWithCompression = new DatabaseSessionStorage(
|
||||||
_repositoryMock.Object,
|
_repositoryMock.Object,
|
||||||
loggerMock.Object,
|
loggerMock.Object,
|
||||||
|
_dbContext,
|
||||||
compressionServiceMock.Object
|
compressionServiceMock.Object
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -380,7 +382,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
_repositoryMock.Setup(x => x.GetByChatIdAsync(12345)).ReturnsAsync(sessionEntity);
|
_repositoryMock.Setup(x => x.GetByChatIdAsync(12345)).ReturnsAsync(sessionEntity);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = storageWithCompression.Get(12345);
|
var result = await storageWithCompression.GetAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_repositoryMock.Verify(x => x.GetByChatIdAsync(12345), Times.Once);
|
_repositoryMock.Verify(x => x.GetByChatIdAsync(12345), Times.Once);
|
||||||
@@ -422,7 +424,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_WithDefaultParameters_ShouldUseDefaults()
|
public async Task GetOrCreateAsync_WithDefaultParameters_ShouldUseDefaults()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var sessionEntity = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
var sessionEntity = TestDataBuilder.Mocks.CreateChatSessionEntity();
|
||||||
@@ -431,7 +433,7 @@ public class DatabaseSessionStorageTests : TestBase
|
|||||||
.ReturnsAsync(sessionEntity);
|
.ReturnsAsync(sessionEntity);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetOrCreate(12345);
|
var result = await _sessionStorage.GetOrCreateAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ public class InMemorySessionStorageTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldReturnExistingSession_WhenSessionExists()
|
public async Task GetOrCreateAsync_ShouldReturnExistingSession_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
var result = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -32,10 +32,10 @@ public class InMemorySessionStorageTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldCreateNewSession_WhenSessionDoesNotExist()
|
public async Task GetOrCreateAsync_ShouldCreateNewSession_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetOrCreate(12345, "group", "Test Group");
|
var result = await _sessionStorage.GetOrCreateAsync(12345, "group", "Test Group");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -45,10 +45,10 @@ public class InMemorySessionStorageTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldUseDefaultValues_WhenParametersNotProvided()
|
public async Task GetOrCreateAsync_ShouldUseDefaultValues_WhenParametersNotProvided()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.GetOrCreate(12345);
|
var result = await _sessionStorage.GetOrCreateAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
@@ -58,23 +58,23 @@ public class InMemorySessionStorageTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_ShouldReturnSession_WhenSessionExists()
|
public async Task GetAsync_ShouldReturnSession_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var session = _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Get(12345);
|
var result = await _sessionStorage.GetAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeSameAs(session);
|
result.Should().BeSameAs(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Get_ShouldReturnNull_WhenSessionDoesNotExist()
|
public async Task GetAsync_ShouldReturnNull_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Get(99999);
|
var result = await _sessionStorage.GetAsync(99999);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
@@ -84,7 +84,7 @@ public class InMemorySessionStorageTests
|
|||||||
public async Task SaveSessionAsync_ShouldUpdateExistingSession()
|
public async Task SaveSessionAsync_ShouldUpdateExistingSession()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var session = _sessionStorage.GetOrCreate(12345, "private", "Original Title");
|
var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Original Title");
|
||||||
session.ChatTitle = "Updated Title";
|
session.ChatTitle = "Updated Title";
|
||||||
session.LastUpdatedAt = DateTime.UtcNow;
|
session.LastUpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ public class InMemorySessionStorageTests
|
|||||||
await _sessionStorage.SaveSessionAsync(session);
|
await _sessionStorage.SaveSessionAsync(session);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var savedSession = _sessionStorage.Get(12345);
|
var savedSession = await _sessionStorage.GetAsync(12345);
|
||||||
savedSession.Should().NotBeNull();
|
savedSession.Should().NotBeNull();
|
||||||
savedSession!.ChatTitle.Should().Be("Updated Title");
|
savedSession!.ChatTitle.Should().Be("Updated Title");
|
||||||
}
|
}
|
||||||
@@ -101,121 +101,123 @@ public class InMemorySessionStorageTests
|
|||||||
public async Task SaveSessionAsync_ShouldAddNewSession()
|
public async Task SaveSessionAsync_ShouldAddNewSession()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var session = _sessionStorage.GetOrCreate(12345, "private", "Original Title");
|
var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Original Title");
|
||||||
session.ChatTitle = "New Session";
|
session.ChatTitle = "New Session";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await _sessionStorage.SaveSessionAsync(session);
|
await _sessionStorage.SaveSessionAsync(session);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var savedSession = _sessionStorage.Get(12345);
|
var savedSession = await _sessionStorage.GetAsync(12345);
|
||||||
savedSession.Should().NotBeNull();
|
savedSession.Should().NotBeNull();
|
||||||
savedSession!.ChatTitle.Should().Be("New Session");
|
savedSession!.ChatTitle.Should().Be("New Session");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldReturnTrue_WhenSessionExists()
|
public async Task RemoveAsync_ShouldReturnTrue_WhenSessionExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Remove(12345);
|
var result = await _sessionStorage.RemoveAsync(12345);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeTrue();
|
result.Should().BeTrue();
|
||||||
_sessionStorage.Get(12345).Should().BeNull();
|
(await _sessionStorage.GetAsync(12345)).Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldReturnFalse_WhenSessionDoesNotExist()
|
public async Task RemoveAsync_ShouldReturnFalse_WhenSessionDoesNotExist()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var result = _sessionStorage.Remove(99999);
|
var result = await _sessionStorage.RemoveAsync(99999);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeFalse();
|
result.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetActiveSessionsCount_ShouldReturnCorrectCount()
|
public async Task GetActiveSessionsCountAsync_ShouldReturnCorrectCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_sessionStorage.GetOrCreate(12345, "private", "Chat 1");
|
await _sessionStorage.GetOrCreateAsync(12345, "private", "Chat 1");
|
||||||
_sessionStorage.GetOrCreate(67890, "group", "Chat 2");
|
await _sessionStorage.GetOrCreateAsync(67890, "group", "Chat 2");
|
||||||
_sessionStorage.GetOrCreate(11111, "private", "Chat 3");
|
await _sessionStorage.GetOrCreateAsync(11111, "private", "Chat 3");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var count = _sessionStorage.GetActiveSessionsCount();
|
var count = await _sessionStorage.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
count.Should().Be(3);
|
count.Should().Be(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetActiveSessionsCount_ShouldReturnZero_WhenNoSessions()
|
public async Task GetActiveSessionsCountAsync_ShouldReturnZero_WhenNoSessions()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var count = _sessionStorage.GetActiveSessionsCount();
|
var count = await _sessionStorage.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
count.Should().Be(0);
|
count.Should().Be(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldDeleteOldSessions()
|
public async Task CleanupOldSessionsAsync_ShouldDeleteOldSessions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldSession = _sessionStorage.GetOrCreate(99999, "private", "Old Chat");
|
var oldSession = await _sessionStorage.GetOrCreateAsync(99999, "private", "Old Chat");
|
||||||
// Manually set CreatedAt to 2 days ago using test method
|
// Manually set CreatedAt to 2 days ago using test method
|
||||||
oldSession.SetCreatedAtForTesting(DateTime.UtcNow.AddDays(-2));
|
oldSession.SetCreatedAtForTesting(DateTime.UtcNow.AddDays(-2));
|
||||||
|
|
||||||
var recentSession = _sessionStorage.GetOrCreate(88888, "private", "Recent Chat");
|
var recentSession = await _sessionStorage.GetOrCreateAsync(88888, "private", "Recent Chat");
|
||||||
// Manually set CreatedAt to 30 minutes ago using test method
|
// Manually set CreatedAt to 30 minutes ago using test method
|
||||||
recentSession.SetCreatedAtForTesting(DateTime.UtcNow.AddMinutes(-30));
|
recentSession.SetCreatedAtForTesting(DateTime.UtcNow.AddMinutes(-30));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
_sessionStorage.CleanupOldSessions(1); // Delete sessions older than 1 day
|
await _sessionStorage.CleanupOldSessionsAsync(1); // Delete sessions older than 1 day
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_sessionStorage.Get(99999).Should().BeNull(); // Old session should be deleted
|
(await _sessionStorage.GetAsync(99999))
|
||||||
_sessionStorage.Get(88888).Should().NotBeNull(); // Recent session should remain
|
.Should()
|
||||||
|
.BeNull(); // Old session should be deleted
|
||||||
|
(await _sessionStorage.GetAsync(88888)).Should().NotBeNull(); // Recent session should remain
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldNotDeleteRecentSessions()
|
public async Task CleanupOldSessionsAsync_ShouldNotDeleteRecentSessions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var recentSession1 = _sessionStorage.GetOrCreate(12345, "private", "Recent 1");
|
var recentSession1 = await _sessionStorage.GetOrCreateAsync(12345, "private", "Recent 1");
|
||||||
recentSession1.CreatedAt = DateTime.UtcNow.AddHours(-1);
|
recentSession1.CreatedAt = DateTime.UtcNow.AddHours(-1);
|
||||||
|
|
||||||
var recentSession2 = _sessionStorage.GetOrCreate(67890, "private", "Recent 2");
|
var recentSession2 = await _sessionStorage.GetOrCreateAsync(67890, "private", "Recent 2");
|
||||||
recentSession2.CreatedAt = DateTime.UtcNow.AddMinutes(-30);
|
recentSession2.CreatedAt = DateTime.UtcNow.AddMinutes(-30);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var deletedCount = _sessionStorage.CleanupOldSessions(24); // Delete sessions older than 24 hours
|
var deletedCount = await _sessionStorage.CleanupOldSessionsAsync(24); // Delete sessions older than 24 hours
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
deletedCount.Should().Be(0);
|
deletedCount.Should().Be(0);
|
||||||
_sessionStorage.Get(12345).Should().NotBeNull();
|
(await _sessionStorage.GetAsync(12345)).Should().NotBeNull();
|
||||||
_sessionStorage.Get(67890).Should().NotBeNull();
|
(await _sessionStorage.GetAsync(67890)).Should().NotBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CleanupOldSessions_ShouldReturnZero_WhenNoSessions()
|
public async Task CleanupOldSessionsAsync_ShouldReturnZero_WhenNoSessions()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var deletedCount = _sessionStorage.CleanupOldSessions(1);
|
var deletedCount = await _sessionStorage.CleanupOldSessionsAsync(1);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
deletedCount.Should().Be(0);
|
deletedCount.Should().Be(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetOrCreate_ShouldCreateSessionWithCorrectTimestamp()
|
public async Task GetOrCreateAsync_ShouldCreateSessionWithCorrectTimestamp()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var session = _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
session.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1));
|
session.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1));
|
||||||
@@ -226,7 +228,7 @@ public class InMemorySessionStorageTests
|
|||||||
public async Task SaveSessionAsync_ShouldUpdateLastUpdatedAt()
|
public async Task SaveSessionAsync_ShouldUpdateLastUpdatedAt()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var session = _sessionStorage.GetOrCreate(12345, "private", "Test Chat");
|
var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat");
|
||||||
var originalTime = session.LastUpdatedAt;
|
var originalTime = session.LastUpdatedAt;
|
||||||
|
|
||||||
// Wait a bit to ensure time difference
|
// Wait a bit to ensure time difference
|
||||||
@@ -238,12 +240,12 @@ public class InMemorySessionStorageTests
|
|||||||
await _sessionStorage.SaveSessionAsync(session);
|
await _sessionStorage.SaveSessionAsync(session);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var savedSession = _sessionStorage.Get(12345);
|
var savedSession = await _sessionStorage.GetAsync(12345);
|
||||||
savedSession!.LastUpdatedAt.Should().BeAfter(originalTime);
|
savedSession!.LastUpdatedAt.Should().BeAfter(originalTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetOrCreate_ShouldHandleConcurrentAccess()
|
public async Task GetOrCreateAsync_ShouldHandleConcurrentAccess()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tasks = new List<Task<ChatSession>>();
|
var tasks = new List<Task<ChatSession>>();
|
||||||
@@ -253,40 +255,46 @@ public class InMemorySessionStorageTests
|
|||||||
{
|
{
|
||||||
var chatId = 1000 + i;
|
var chatId = 1000 + i;
|
||||||
tasks.Add(
|
tasks.Add(
|
||||||
Task.Run(() => _sessionStorage.GetOrCreate(chatId, "private", $"Chat {chatId}"))
|
Task.Run(async () =>
|
||||||
|
await _sessionStorage.GetOrCreateAsync(chatId, "private", $"Chat {chatId}")
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(tasks);
|
await Task.WhenAll(tasks);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_sessionStorage.GetActiveSessionsCount().Should().Be(100);
|
(await _sessionStorage.GetActiveSessionsCountAsync())
|
||||||
|
.Should()
|
||||||
|
.Be(100);
|
||||||
|
|
||||||
// Verify all sessions were created
|
// Verify all sessions were created
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
var chatId = 1000 + i;
|
var chatId = 1000 + i;
|
||||||
var session = _sessionStorage.Get(chatId);
|
var session = await _sessionStorage.GetAsync(chatId);
|
||||||
session.Should().NotBeNull();
|
session.Should().NotBeNull();
|
||||||
session!.ChatId.Should().Be(chatId);
|
session!.ChatId.Should().Be(chatId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Remove_ShouldDecreaseActiveSessionsCount()
|
public async Task RemoveAsync_ShouldDecreaseActiveSessionsCount()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_sessionStorage.GetOrCreate(12345, "private", "Chat 1");
|
await _sessionStorage.GetOrCreateAsync(12345, "private", "Chat 1");
|
||||||
_sessionStorage.GetOrCreate(67890, "private", "Chat 2");
|
await _sessionStorage.GetOrCreateAsync(67890, "private", "Chat 2");
|
||||||
_sessionStorage.GetOrCreate(11111, "private", "Chat 3");
|
await _sessionStorage.GetOrCreateAsync(11111, "private", "Chat 3");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
_sessionStorage.Remove(67890);
|
await _sessionStorage.RemoveAsync(67890);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_sessionStorage.GetActiveSessionsCount().Should().Be(2);
|
(await _sessionStorage.GetActiveSessionsCountAsync())
|
||||||
_sessionStorage.Get(12345).Should().NotBeNull();
|
.Should()
|
||||||
_sessionStorage.Get(67890).Should().BeNull();
|
.Be(2);
|
||||||
_sessionStorage.Get(11111).Should().NotBeNull();
|
(await _sessionStorage.GetAsync(12345)).Should().NotBeNull();
|
||||||
|
(await _sessionStorage.GetAsync(67890)).Should().BeNull();
|
||||||
|
(await _sessionStorage.GetAsync(11111)).Should().NotBeNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,41 +19,41 @@ public class ISessionStorageTests : UnitTestBase
|
|||||||
// Assert
|
// Assert
|
||||||
methods.Should().HaveCount(6);
|
methods.Should().HaveCount(6);
|
||||||
|
|
||||||
// GetOrCreate method
|
// GetOrCreateAsync method
|
||||||
var getOrCreateMethod = methods.FirstOrDefault(m => m.Name == "GetOrCreate");
|
var getOrCreateMethod = methods.FirstOrDefault(m => m.Name == "GetOrCreateAsync");
|
||||||
getOrCreateMethod.Should().NotBeNull();
|
getOrCreateMethod.Should().NotBeNull();
|
||||||
getOrCreateMethod!.ReturnType.Should().Be<ChatSession>();
|
getOrCreateMethod!.ReturnType.Should().Be(typeof(Task<ChatSession>));
|
||||||
getOrCreateMethod.GetParameters().Should().HaveCount(3);
|
getOrCreateMethod.GetParameters().Should().HaveCount(3);
|
||||||
getOrCreateMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
getOrCreateMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
||||||
getOrCreateMethod.GetParameters()[1].ParameterType.Should().Be<string>();
|
getOrCreateMethod.GetParameters()[1].ParameterType.Should().Be<string>();
|
||||||
getOrCreateMethod.GetParameters()[2].ParameterType.Should().Be<string>();
|
getOrCreateMethod.GetParameters()[2].ParameterType.Should().Be<string>();
|
||||||
|
|
||||||
// Get method
|
// GetAsync method
|
||||||
var getMethod = methods.FirstOrDefault(m => m.Name == "Get");
|
var getMethod = methods.FirstOrDefault(m => m.Name == "GetAsync");
|
||||||
getMethod.Should().NotBeNull();
|
getMethod.Should().NotBeNull();
|
||||||
getMethod!.ReturnType.Should().Be<ChatSession>();
|
getMethod!.ReturnType.Should().Be(typeof(Task<ChatSession?>));
|
||||||
getMethod.GetParameters().Should().HaveCount(1);
|
getMethod.GetParameters().Should().HaveCount(1);
|
||||||
getMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
getMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
||||||
|
|
||||||
// Remove method
|
// RemoveAsync method
|
||||||
var removeMethod = methods.FirstOrDefault(m => m.Name == "Remove");
|
var removeMethod = methods.FirstOrDefault(m => m.Name == "RemoveAsync");
|
||||||
removeMethod.Should().NotBeNull();
|
removeMethod.Should().NotBeNull();
|
||||||
removeMethod!.ReturnType.Should().Be<bool>();
|
removeMethod!.ReturnType.Should().Be(typeof(Task<bool>));
|
||||||
removeMethod.GetParameters().Should().HaveCount(1);
|
removeMethod.GetParameters().Should().HaveCount(1);
|
||||||
removeMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
removeMethod.GetParameters()[0].ParameterType.Should().Be<long>();
|
||||||
|
|
||||||
// GetActiveSessionsCount method
|
// GetActiveSessionsCountAsync method
|
||||||
var getActiveSessionsCountMethod = methods.FirstOrDefault(m =>
|
var getActiveSessionsCountMethod = methods.FirstOrDefault(m =>
|
||||||
m.Name == "GetActiveSessionsCount"
|
m.Name == "GetActiveSessionsCountAsync"
|
||||||
);
|
);
|
||||||
getActiveSessionsCountMethod.Should().NotBeNull();
|
getActiveSessionsCountMethod.Should().NotBeNull();
|
||||||
getActiveSessionsCountMethod!.ReturnType.Should().Be<int>();
|
getActiveSessionsCountMethod!.ReturnType.Should().Be(typeof(Task<int>));
|
||||||
getActiveSessionsCountMethod.GetParameters().Should().BeEmpty();
|
getActiveSessionsCountMethod.GetParameters().Should().BeEmpty();
|
||||||
|
|
||||||
// CleanupOldSessions method
|
// CleanupOldSessionsAsync method
|
||||||
var cleanupOldSessionsMethod = methods.FirstOrDefault(m => m.Name == "CleanupOldSessions");
|
var cleanupOldSessionsMethod = methods.FirstOrDefault(m => m.Name == "CleanupOldSessionsAsync");
|
||||||
cleanupOldSessionsMethod.Should().NotBeNull();
|
cleanupOldSessionsMethod.Should().NotBeNull();
|
||||||
cleanupOldSessionsMethod!.ReturnType.Should().Be<int>();
|
cleanupOldSessionsMethod!.ReturnType.Should().Be(typeof(Task<int>));
|
||||||
cleanupOldSessionsMethod.GetParameters().Should().HaveCount(1);
|
cleanupOldSessionsMethod.GetParameters().Should().HaveCount(1);
|
||||||
cleanupOldSessionsMethod.GetParameters()[0].ParameterType.Should().Be<int>();
|
cleanupOldSessionsMethod.GetParameters()[0].ParameterType.Should().Be<int>();
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ public class ISessionStorageTests : UnitTestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_GetOrCreate_ShouldReturnChatSession()
|
public async Task ISessionStorage_GetOrCreateAsync_ShouldReturnChatSession()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
@@ -97,120 +97,120 @@ public class ISessionStorageTests : UnitTestBase
|
|||||||
var chatTitle = "Test Chat";
|
var chatTitle = "Test Chat";
|
||||||
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, chatType);
|
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, chatType);
|
||||||
|
|
||||||
mock.Setup(x => x.GetOrCreate(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
mock.Setup(x => x.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns(expectedSession);
|
.ReturnsAsync(expectedSession);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.GetOrCreate(chatId, chatType, chatTitle);
|
var result = await mock.Object.GetOrCreateAsync(chatId, chatType, chatTitle);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedSession);
|
result.Should().Be(expectedSession);
|
||||||
mock.Verify(x => x.GetOrCreate(chatId, chatType, chatTitle), Times.Once);
|
mock.Verify(x => x.GetOrCreateAsync(chatId, chatType, chatTitle), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_Get_ShouldReturnChatSessionOrNull()
|
public async Task ISessionStorage_GetAsync_ShouldReturnChatSessionOrNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, "private");
|
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, "private");
|
||||||
|
|
||||||
mock.Setup(x => x.Get(It.IsAny<long>())).Returns(expectedSession);
|
mock.Setup(x => x.GetAsync(It.IsAny<long>())).ReturnsAsync(expectedSession);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.Get(chatId);
|
var result = await mock.Object.GetAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedSession);
|
result.Should().Be(expectedSession);
|
||||||
mock.Verify(x => x.Get(chatId), Times.Once);
|
mock.Verify(x => x.GetAsync(chatId), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_Get_ShouldReturnNullWhenSessionNotFound()
|
public async Task ISessionStorage_GetAsync_ShouldReturnNullWhenSessionNotFound()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
|
|
||||||
mock.Setup(x => x.Get(It.IsAny<long>())).Returns((ChatSession?)null);
|
mock.Setup(x => x.GetAsync(It.IsAny<long>())).ReturnsAsync((ChatSession?)null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.Get(chatId);
|
var result = await mock.Object.GetAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
mock.Verify(x => x.Get(chatId), Times.Once);
|
mock.Verify(x => x.GetAsync(chatId), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_Remove_ShouldReturnBoolean()
|
public async Task ISessionStorage_RemoveAsync_ShouldReturnBoolean()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var expectedResult = true;
|
var expectedResult = true;
|
||||||
|
|
||||||
mock.Setup(x => x.Remove(It.IsAny<long>())).Returns(expectedResult);
|
mock.Setup(x => x.RemoveAsync(It.IsAny<long>())).ReturnsAsync(expectedResult);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.Remove(chatId);
|
var result = await mock.Object.RemoveAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedResult);
|
result.Should().Be(expectedResult);
|
||||||
mock.Verify(x => x.Remove(chatId), Times.Once);
|
mock.Verify(x => x.RemoveAsync(chatId), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_GetActiveSessionsCount_ShouldReturnInt()
|
public async Task ISessionStorage_GetActiveSessionsCountAsync_ShouldReturnInt()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var expectedCount = 5;
|
var expectedCount = 5;
|
||||||
|
|
||||||
mock.Setup(x => x.GetActiveSessionsCount()).Returns(expectedCount);
|
mock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(expectedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.GetActiveSessionsCount();
|
var result = await mock.Object.GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCount);
|
result.Should().Be(expectedCount);
|
||||||
mock.Verify(x => x.GetActiveSessionsCount(), Times.Once);
|
mock.Verify(x => x.GetActiveSessionsCountAsync(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_CleanupOldSessions_ShouldReturnInt()
|
public async Task ISessionStorage_CleanupOldSessionsAsync_ShouldReturnInt()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var hoursOld = 24;
|
var hoursOld = 24;
|
||||||
var expectedCleanedCount = 3;
|
var expectedCleanedCount = 3;
|
||||||
|
|
||||||
mock.Setup(x => x.CleanupOldSessions(It.IsAny<int>())).Returns(expectedCleanedCount);
|
mock.Setup(x => x.CleanupOldSessionsAsync(It.IsAny<int>())).ReturnsAsync(expectedCleanedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.CleanupOldSessions(hoursOld);
|
var result = await mock.Object.CleanupOldSessionsAsync(hoursOld);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCleanedCount);
|
result.Should().Be(expectedCleanedCount);
|
||||||
mock.Verify(x => x.CleanupOldSessions(hoursOld), Times.Once);
|
mock.Verify(x => x.CleanupOldSessionsAsync(hoursOld), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_CleanupOldSessions_ShouldUseDefaultValue()
|
public async Task ISessionStorage_CleanupOldSessionsAsync_ShouldUseDefaultValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var expectedCleanedCount = 2;
|
var expectedCleanedCount = 2;
|
||||||
|
|
||||||
mock.Setup(x => x.CleanupOldSessions(It.IsAny<int>())).Returns(expectedCleanedCount);
|
mock.Setup(x => x.CleanupOldSessionsAsync(It.IsAny<int>())).ReturnsAsync(expectedCleanedCount);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.CleanupOldSessions();
|
var result = await mock.Object.CleanupOldSessionsAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedCleanedCount);
|
result.Should().Be(expectedCleanedCount);
|
||||||
mock.Verify(x => x.CleanupOldSessions(24), Times.Once); // Default value is 24
|
mock.Verify(x => x.CleanupOldSessionsAsync(24), Times.Once); // Default value is 24
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -230,22 +230,22 @@ public class ISessionStorageTests : UnitTestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ISessionStorage_GetOrCreate_ShouldUseDefaultValues()
|
public async Task ISessionStorage_GetOrCreateAsync_ShouldUseDefaultValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, "private");
|
var expectedSession = TestDataBuilder.ChatSessions.CreateBasicSession(chatId, "private");
|
||||||
|
|
||||||
mock.Setup(x => x.GetOrCreate(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
mock.Setup(x => x.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns(expectedSession);
|
.ReturnsAsync(expectedSession);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = mock.Object.GetOrCreate(chatId);
|
var result = await mock.Object.GetOrCreateAsync(chatId);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Be(expectedSession);
|
result.Should().Be(expectedSession);
|
||||||
mock.Verify(x => x.GetOrCreate(chatId, "private", ""), Times.Once); // Default values
|
mock.Verify(x => x.GetOrCreateAsync(chatId, "private", ""), Times.Once); // Default values
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -280,15 +280,15 @@ public class ISessionStorageTests : UnitTestBase
|
|||||||
// All methods should be public
|
// All methods should be public
|
||||||
methods.All(m => m.IsPublic).Should().BeTrue();
|
methods.All(m => m.IsPublic).Should().BeTrue();
|
||||||
|
|
||||||
// GetOrCreate should have default parameters
|
// GetOrCreateAsync should have default parameters
|
||||||
var getOrCreateMethod = methods.First(m => m.Name == "GetOrCreate");
|
var getOrCreateMethod = methods.First(m => m.Name == "GetOrCreateAsync");
|
||||||
getOrCreateMethod.GetParameters()[1].HasDefaultValue.Should().BeTrue();
|
getOrCreateMethod.GetParameters()[1].HasDefaultValue.Should().BeTrue();
|
||||||
getOrCreateMethod.GetParameters()[1].DefaultValue.Should().Be("private");
|
getOrCreateMethod.GetParameters()[1].DefaultValue.Should().Be("private");
|
||||||
getOrCreateMethod.GetParameters()[2].HasDefaultValue.Should().BeTrue();
|
getOrCreateMethod.GetParameters()[2].HasDefaultValue.Should().BeTrue();
|
||||||
getOrCreateMethod.GetParameters()[2].DefaultValue.Should().Be("");
|
getOrCreateMethod.GetParameters()[2].DefaultValue.Should().Be("");
|
||||||
|
|
||||||
// CleanupOldSessions should have default parameter
|
// CleanupOldSessionsAsync should have default parameter
|
||||||
var cleanupMethod = methods.First(m => m.Name == "CleanupOldSessions");
|
var cleanupMethod = methods.First(m => m.Name == "CleanupOldSessionsAsync");
|
||||||
cleanupMethod.GetParameters()[0].HasDefaultValue.Should().BeTrue();
|
cleanupMethod.GetParameters()[0].HasDefaultValue.Should().BeTrue();
|
||||||
cleanupMethod.GetParameters()[0].DefaultValue.Should().Be(24);
|
cleanupMethod.GetParameters()[0].DefaultValue.Should().Be(24);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class SettingsCommandTests : UnitTestBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(chatId);
|
||||||
_chatServiceMock.Setup(x => x.GetSession(chatId)).Returns(session);
|
_chatServiceMock.Setup(x => x.GetSessionAsync(chatId)).ReturnsAsync(session);
|
||||||
|
|
||||||
var context = new TelegramCommandContext
|
var context = new TelegramCommandContext
|
||||||
{
|
{
|
||||||
@@ -70,8 +70,8 @@ public class SettingsCommandTests : UnitTestBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var chatId = 12345L;
|
var chatId = 12345L;
|
||||||
_chatServiceMock
|
_chatServiceMock
|
||||||
.Setup(x => x.GetSession(chatId))
|
.Setup(x => x.GetSessionAsync(chatId))
|
||||||
.Returns((ChatBot.Models.ChatSession?)null);
|
.ReturnsAsync((ChatBot.Models.ChatSession?)null);
|
||||||
|
|
||||||
var context = new TelegramCommandContext
|
var context = new TelegramCommandContext
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ public class StatusCommandTests : UnitTestBase
|
|||||||
|
|
||||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(12345, "private");
|
var session = TestDataBuilder.ChatSessions.CreateBasicSession(12345, "private");
|
||||||
session.AddUserMessage("Test", "user");
|
session.AddUserMessage("Test", "user");
|
||||||
chatServiceMock.Setup(x => x.GetSession(12345)).Returns(session);
|
chatServiceMock.Setup(x => x.GetSessionAsync(12345)).ReturnsAsync(session);
|
||||||
|
|
||||||
var statusCommand = new StatusCommand(
|
var statusCommand = new StatusCommand(
|
||||||
chatServiceMock.Object,
|
chatServiceMock.Object,
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ public class TelegramCommandProcessorTests : UnitTestBase
|
|||||||
var chatTitle = "Test Chat";
|
var chatTitle = "Test Chat";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await _processor.ProcessMessageAsync(
|
Func<Task> act = async () => await _processor.ProcessMessageAsync(
|
||||||
messageText,
|
messageText,
|
||||||
chatId,
|
chatId,
|
||||||
username,
|
username,
|
||||||
@@ -245,7 +245,8 @@ public class TelegramCommandProcessorTests : UnitTestBase
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().NotBeNull();
|
await act.Should().ThrowAsync<ArgumentException>()
|
||||||
|
.WithMessage("ChatId cannot be 0*");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -746,7 +747,7 @@ public class TelegramCommandProcessorTests : UnitTestBase
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
result.Should().Contain("Произошла ошибка");
|
result.Should().Contain("Произошла непредвиденная ошибка");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -152,9 +152,8 @@ public static class TestDataBuilder
|
|||||||
var mock = new Mock<ISessionStorage>();
|
var mock = new Mock<ISessionStorage>();
|
||||||
var sessions = new Dictionary<long, ChatSession>();
|
var sessions = new Dictionary<long, ChatSession>();
|
||||||
|
|
||||||
mock.Setup(x => x.GetOrCreate(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
mock.Setup(x => x.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns<long, string, string>(
|
.ReturnsAsync((long chatId, string chatType, string chatTitle) =>
|
||||||
(chatId, chatType, chatTitle) =>
|
|
||||||
{
|
{
|
||||||
if (!sessions.TryGetValue(chatId, out var session))
|
if (!sessions.TryGetValue(chatId, out var session))
|
||||||
{
|
{
|
||||||
@@ -166,11 +165,10 @@ public static class TestDataBuilder
|
|||||||
sessions[chatId] = session;
|
sessions[chatId] = session;
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
mock.Setup(x => x.Get(It.IsAny<long>()))
|
mock.Setup(x => x.GetAsync(It.IsAny<long>()))
|
||||||
.Returns<long>(chatId =>
|
.ReturnsAsync((long chatId) =>
|
||||||
sessions.TryGetValue(chatId, out var session) ? session : null
|
sessions.TryGetValue(chatId, out var session) ? session : null
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -181,12 +179,12 @@ public static class TestDataBuilder
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
mock.Setup(x => x.Remove(It.IsAny<long>()))
|
mock.Setup(x => x.RemoveAsync(It.IsAny<long>()))
|
||||||
.Returns<long>(chatId => sessions.Remove(chatId));
|
.ReturnsAsync((long chatId) => sessions.Remove(chatId));
|
||||||
|
|
||||||
mock.Setup(x => x.GetActiveSessionsCount()).Returns(() => sessions.Count);
|
mock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(() => sessions.Count);
|
||||||
|
|
||||||
mock.Setup(x => x.CleanupOldSessions(It.IsAny<int>())).Returns<int>(hoursOld => 0);
|
mock.Setup(x => x.CleanupOldSessionsAsync(It.IsAny<int>())).ReturnsAsync((int hoursOld) => 0);
|
||||||
|
|
||||||
return mock;
|
return mock;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace ChatBot.Models
|
|||||||
public class ChatSession
|
public class ChatSession
|
||||||
{
|
{
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
|
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
||||||
private readonly List<ChatMessage> _messageHistory = new List<ChatMessage>();
|
private readonly List<ChatMessage> _messageHistory = new List<ChatMessage>();
|
||||||
private IHistoryCompressionService? _compressionService;
|
private IHistoryCompressionService? _compressionService;
|
||||||
|
|
||||||
@@ -110,11 +111,11 @@ namespace ChatBot.Models
|
|||||||
int compressionTarget
|
int compressionTarget
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
await _semaphore.WaitAsync();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
_messageHistory.Add(message);
|
_messageHistory.Add(message);
|
||||||
LastUpdatedAt = DateTime.UtcNow;
|
LastUpdatedAt = DateTime.UtcNow;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if compression is needed and perform it asynchronously
|
// Check if compression is needed and perform it asynchronously
|
||||||
if (
|
if (
|
||||||
@@ -130,15 +131,21 @@ namespace ChatBot.Models
|
|||||||
await TrimHistoryAsync();
|
await TrimHistoryAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_semaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compress message history using the compression service
|
/// Compress message history using the compression service
|
||||||
|
/// Note: This method should be called within a semaphore lock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task CompressHistoryAsync(int targetCount)
|
private async Task CompressHistoryAsync(int targetCount)
|
||||||
{
|
{
|
||||||
if (_compressionService == null)
|
if (_compressionService == null)
|
||||||
{
|
{
|
||||||
await TrimHistoryAsync();
|
TrimHistoryInternal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,29 +156,33 @@ namespace ChatBot.Models
|
|||||||
targetCount
|
targetCount
|
||||||
);
|
);
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_messageHistory.Clear();
|
_messageHistory.Clear();
|
||||||
_messageHistory.AddRange(compressedMessages);
|
_messageHistory.AddRange(compressedMessages);
|
||||||
LastUpdatedAt = DateTime.UtcNow;
|
LastUpdatedAt = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// Log error and fallback to simple trimming
|
// Log error and fallback to simple trimming
|
||||||
// Note: We can't inject ILogger here, so we'll just fallback
|
// Note: We can't inject ILogger here, so we'll just fallback
|
||||||
await TrimHistoryAsync();
|
TrimHistoryInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple history trimming without compression
|
/// Simple history trimming without compression (async wrapper)
|
||||||
|
/// Note: This method should be called within a semaphore lock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task TrimHistoryAsync()
|
private Task TrimHistoryAsync()
|
||||||
{
|
{
|
||||||
await Task.Run(() =>
|
TrimHistoryInternal();
|
||||||
{
|
return Task.CompletedTask;
|
||||||
lock (_lock)
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to trim history without async overhead
|
||||||
|
/// Note: This method should be called within a semaphore lock
|
||||||
|
/// </summary>
|
||||||
|
private void TrimHistoryInternal()
|
||||||
{
|
{
|
||||||
if (_messageHistory.Count > MaxHistoryLength)
|
if (_messageHistory.Count > MaxHistoryLength)
|
||||||
{
|
{
|
||||||
@@ -192,8 +203,6 @@ namespace ChatBot.Models
|
|||||||
LastUpdatedAt = DateTime.UtcNow;
|
LastUpdatedAt = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a user message with username information
|
/// Add a user message with username information
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ namespace ChatBot.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get or create a chat session for the given chat ID
|
/// Get or create a chat session for the given chat ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ChatSession GetOrCreateSession(
|
public async Task<ChatSession> GetOrCreateSessionAsync(
|
||||||
long chatId,
|
long chatId,
|
||||||
string chatType = ChatTypes.Private,
|
string chatType = ChatTypes.Private,
|
||||||
string chatTitle = ""
|
string chatTitle = ""
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var session = _sessionStorage.GetOrCreate(chatId, chatType, chatTitle);
|
var session = await _sessionStorage.GetOrCreateAsync(chatId, chatType, chatTitle);
|
||||||
|
|
||||||
// Set compression service if compression is enabled
|
// Set compression service if compression is enabled
|
||||||
if (_aiSettings.EnableHistoryCompression)
|
if (_aiSettings.EnableHistoryCompression)
|
||||||
@@ -66,7 +66,7 @@ namespace ChatBot.Services
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var session = GetOrCreateSession(chatId, chatType, chatTitle);
|
var session = await GetOrCreateSessionAsync(chatId, chatType, chatTitle);
|
||||||
|
|
||||||
// Add user message to history with username
|
// Add user message to history with username
|
||||||
if (_aiSettings.EnableHistoryCompression)
|
if (_aiSettings.EnableHistoryCompression)
|
||||||
@@ -157,7 +157,7 @@ namespace ChatBot.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task UpdateSessionParametersAsync(long chatId, string? model = null)
|
public async Task UpdateSessionParametersAsync(long chatId, string? model = null)
|
||||||
{
|
{
|
||||||
var session = _sessionStorage.Get(chatId);
|
var session = await _sessionStorage.GetAsync(chatId);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(model))
|
if (!string.IsNullOrEmpty(model))
|
||||||
@@ -177,7 +177,7 @@ namespace ChatBot.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task ClearHistoryAsync(long chatId)
|
public virtual async Task ClearHistoryAsync(long chatId)
|
||||||
{
|
{
|
||||||
var session = _sessionStorage.Get(chatId);
|
var session = await _sessionStorage.GetAsync(chatId);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
session.ClearHistory();
|
session.ClearHistory();
|
||||||
@@ -192,33 +192,33 @@ namespace ChatBot.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get session information
|
/// Get session information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ChatSession? GetSession(long chatId)
|
public virtual async Task<ChatSession?> GetSessionAsync(long chatId)
|
||||||
{
|
{
|
||||||
return _sessionStorage.Get(chatId);
|
return await _sessionStorage.GetAsync(chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove a session
|
/// Remove a session
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RemoveSession(long chatId)
|
public async Task<bool> RemoveSessionAsync(long chatId)
|
||||||
{
|
{
|
||||||
return _sessionStorage.Remove(chatId);
|
return await _sessionStorage.RemoveAsync(chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all active sessions count
|
/// Get all active sessions count
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int GetActiveSessionsCount()
|
public async Task<int> GetActiveSessionsCountAsync()
|
||||||
{
|
{
|
||||||
return _sessionStorage.GetActiveSessionsCount();
|
return await _sessionStorage.GetActiveSessionsCountAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up old sessions (older than specified hours)
|
/// Clean up old sessions (older than specified hours)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CleanupOldSessions(int hoursOld = 24)
|
public async Task<int> CleanupOldSessionsAsync(int hoursOld = 24)
|
||||||
{
|
{
|
||||||
return _sessionStorage.CleanupOldSessions(hoursOld);
|
return await _sessionStorage.CleanupOldSessionsAsync(hoursOld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ChatBot.Data;
|
||||||
using ChatBot.Data.Interfaces;
|
using ChatBot.Data.Interfaces;
|
||||||
using ChatBot.Models;
|
using ChatBot.Models;
|
||||||
using ChatBot.Models.Dto;
|
using ChatBot.Models.Dto;
|
||||||
@@ -15,19 +16,22 @@ namespace ChatBot.Services
|
|||||||
private readonly IChatSessionRepository _repository;
|
private readonly IChatSessionRepository _repository;
|
||||||
private readonly ILogger<DatabaseSessionStorage> _logger;
|
private readonly ILogger<DatabaseSessionStorage> _logger;
|
||||||
private readonly IHistoryCompressionService? _compressionService;
|
private readonly IHistoryCompressionService? _compressionService;
|
||||||
|
private readonly ChatBotDbContext _context;
|
||||||
|
|
||||||
public DatabaseSessionStorage(
|
public DatabaseSessionStorage(
|
||||||
IChatSessionRepository repository,
|
IChatSessionRepository repository,
|
||||||
ILogger<DatabaseSessionStorage> logger,
|
ILogger<DatabaseSessionStorage> logger,
|
||||||
|
ChatBotDbContext context,
|
||||||
IHistoryCompressionService? compressionService = null
|
IHistoryCompressionService? compressionService = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_context = context;
|
||||||
_compressionService = compressionService;
|
_compressionService = compressionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatSession GetOrCreate(
|
public async Task<ChatSession> GetOrCreateAsync(
|
||||||
long chatId,
|
long chatId,
|
||||||
string chatType = "private",
|
string chatType = "private",
|
||||||
string chatTitle = ""
|
string chatTitle = ""
|
||||||
@@ -35,10 +39,7 @@ namespace ChatBot.Services
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sessionEntity = _repository
|
var sessionEntity = await _repository.GetOrCreateAsync(chatId, chatType, chatTitle);
|
||||||
.GetOrCreateAsync(chatId, chatType, chatTitle)
|
|
||||||
.GetAwaiter()
|
|
||||||
.GetResult();
|
|
||||||
return ConvertToChatSession(sessionEntity);
|
return ConvertToChatSession(sessionEntity);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -51,11 +52,11 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatSession? Get(long chatId)
|
public async Task<ChatSession?> GetAsync(long chatId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sessionEntity = _repository.GetByChatIdAsync(chatId).GetAwaiter().GetResult();
|
var sessionEntity = await _repository.GetByChatIdAsync(chatId);
|
||||||
return sessionEntity != null ? ConvertToChatSession(sessionEntity) : null;
|
return sessionEntity != null ? ConvertToChatSession(sessionEntity) : null;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -65,11 +66,11 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(long chatId)
|
public async Task<bool> RemoveAsync(long chatId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _repository.DeleteAsync(chatId).GetAwaiter().GetResult();
|
return await _repository.DeleteAsync(chatId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -78,11 +79,11 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetActiveSessionsCount()
|
public async Task<int> GetActiveSessionsCountAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _repository.GetActiveSessionsCountAsync().GetAwaiter().GetResult();
|
return await _repository.GetActiveSessionsCountAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -91,11 +92,11 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CleanupOldSessions(int hoursOld = 24)
|
public async Task<int> CleanupOldSessionsAsync(int hoursOld = 24)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _repository.CleanupOldSessionsAsync(hoursOld).GetAwaiter().GetResult();
|
return await _repository.CleanupOldSessionsAsync(hoursOld);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -105,10 +106,11 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save session changes to database
|
/// Save session changes to database with transaction support
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task SaveSessionAsync(ChatSession session)
|
public async Task SaveSessionAsync(ChatSession session)
|
||||||
{
|
{
|
||||||
|
await using var transaction = await _context.Database.BeginTransactionAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sessionEntity = await _repository.GetByChatIdAsync(session.ChatId);
|
var sessionEntity = await _repository.GetByChatIdAsync(session.ChatId);
|
||||||
@@ -126,7 +128,7 @@ namespace ChatBot.Services
|
|||||||
sessionEntity.MaxHistoryLength = session.MaxHistoryLength;
|
sessionEntity.MaxHistoryLength = session.MaxHistoryLength;
|
||||||
sessionEntity.LastUpdatedAt = DateTime.UtcNow;
|
sessionEntity.LastUpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
// Clear existing messages and add new ones
|
// Clear existing messages and add new ones in a transaction
|
||||||
await _repository.ClearMessagesAsync(sessionEntity.Id);
|
await _repository.ClearMessagesAsync(sessionEntity.Id);
|
||||||
|
|
||||||
var messages = session.GetAllMessages();
|
var messages = session.GetAllMessages();
|
||||||
@@ -141,9 +143,14 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _repository.UpdateAsync(sessionEntity);
|
await _repository.UpdateAsync(sessionEntity);
|
||||||
|
|
||||||
|
// Commit transaction if all operations succeeded
|
||||||
|
await transaction.CommitAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Transaction will be automatically rolled back on exception
|
||||||
|
await transaction.RollbackAsync();
|
||||||
_logger.LogError(ex, "Failed to save session for chat {ChatId}", session.ChatId);
|
_logger.LogError(ex, "Failed to save session for chat {ChatId}", session.ChatId);
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"Failed to save session for chat {session.ChatId}",
|
$"Failed to save session for chat {session.ChatId}",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace ChatBot.Services
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatSession GetOrCreate(
|
public Task<ChatSession> GetOrCreateAsync(
|
||||||
long chatId,
|
long chatId,
|
||||||
string chatType = "private",
|
string chatType = "private",
|
||||||
string chatTitle = ""
|
string chatTitle = ""
|
||||||
@@ -54,31 +54,31 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return session;
|
return Task.FromResult(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatSession? Get(long chatId)
|
public Task<ChatSession?> GetAsync(long chatId)
|
||||||
{
|
{
|
||||||
_sessions.TryGetValue(chatId, out var session);
|
_sessions.TryGetValue(chatId, out var session);
|
||||||
return session;
|
return Task.FromResult(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(long chatId)
|
public Task<bool> RemoveAsync(long chatId)
|
||||||
{
|
{
|
||||||
var removed = _sessions.TryRemove(chatId, out _);
|
var removed = _sessions.TryRemove(chatId, out _);
|
||||||
if (removed)
|
if (removed)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Removed session for chat {ChatId}", chatId);
|
_logger.LogInformation("Removed session for chat {ChatId}", chatId);
|
||||||
}
|
}
|
||||||
return removed;
|
return Task.FromResult(removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetActiveSessionsCount()
|
public Task<int> GetActiveSessionsCountAsync()
|
||||||
{
|
{
|
||||||
return _sessions.Count;
|
return Task.FromResult(_sessions.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CleanupOldSessions(int hoursOld = 24)
|
public Task<int> CleanupOldSessionsAsync(int hoursOld = 24)
|
||||||
{
|
{
|
||||||
var cutoffTime = DateTime.UtcNow.AddHours(-hoursOld);
|
var cutoffTime = DateTime.UtcNow.AddHours(-hoursOld);
|
||||||
var sessionsToRemove = _sessions
|
var sessionsToRemove = _sessions
|
||||||
@@ -97,7 +97,7 @@ namespace ChatBot.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Cleaned up {DeletedCount} old sessions", deletedCount);
|
_logger.LogInformation("Cleaned up {DeletedCount} old sessions", deletedCount);
|
||||||
return deletedCount;
|
return Task.FromResult(deletedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SaveSessionAsync(ChatSession session)
|
public Task SaveSessionAsync(ChatSession session)
|
||||||
|
|||||||
@@ -10,27 +10,27 @@ namespace ChatBot.Services.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get or create a chat session
|
/// Get or create a chat session
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ChatSession GetOrCreate(long chatId, string chatType = "private", string chatTitle = "");
|
Task<ChatSession> GetOrCreateAsync(long chatId, string chatType = "private", string chatTitle = "");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a session by chat ID
|
/// Get a session by chat ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ChatSession? Get(long chatId);
|
Task<ChatSession?> GetAsync(long chatId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove a session
|
/// Remove a session
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Remove(long chatId);
|
Task<bool> RemoveAsync(long chatId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get count of active sessions
|
/// Get count of active sessions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int GetActiveSessionsCount();
|
Task<int> GetActiveSessionsCountAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up old sessions
|
/// Clean up old sessions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int CleanupOldSessions(int hoursOld = 24);
|
Task<int> CleanupOldSessionsAsync(int hoursOld = 24);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save session changes to storage (for database implementations)
|
/// Save session changes to storage (for database implementations)
|
||||||
|
|||||||
@@ -24,17 +24,15 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
public override string CommandName => "/settings";
|
public override string CommandName => "/settings";
|
||||||
public override string Description => "Показать настройки чата";
|
public override string Description => "Показать настройки чата";
|
||||||
|
|
||||||
public override Task<string> ExecuteAsync(
|
public override async Task<string> ExecuteAsync(
|
||||||
TelegramCommandContext context,
|
TelegramCommandContext context,
|
||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var session = _chatService.GetSession(context.ChatId);
|
var session = await _chatService.GetSessionAsync(context.ChatId);
|
||||||
if (session == null)
|
if (session == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(
|
return "Сессия не найдена. Отправьте любое сообщение для создания новой сессии.";
|
||||||
"Сессия не найдена. Отправьте любое сообщение для создания новой сессии."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var compressionStatus = _aiSettings.EnableHistoryCompression ? "Включено" : "Отключено";
|
var compressionStatus = _aiSettings.EnableHistoryCompression ? "Включено" : "Отключено";
|
||||||
@@ -42,15 +40,13 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
? $"\nСжатие истории: {compressionStatus}\nПорог сжатия: {_aiSettings.CompressionThreshold} сообщений\nЦелевое количество: {_aiSettings.CompressionTarget} сообщений"
|
? $"\nСжатие истории: {compressionStatus}\nПорог сжатия: {_aiSettings.CompressionThreshold} сообщений\nЦелевое количество: {_aiSettings.CompressionTarget} сообщений"
|
||||||
: $"\nСжатие истории: {compressionStatus}";
|
: $"\nСжатие истории: {compressionStatus}";
|
||||||
|
|
||||||
return Task.FromResult(
|
return $"Настройки чата:\n"
|
||||||
$"Настройки чата:\n"
|
|
||||||
+ $"Тип чата: {session.ChatType}\n"
|
+ $"Тип чата: {session.ChatType}\n"
|
||||||
+ $"Название: {session.ChatTitle}\n"
|
+ $"Название: {session.ChatTitle}\n"
|
||||||
+ $"Модель: {session.Model}\n"
|
+ $"Модель: {session.Model}\n"
|
||||||
+ $"Сообщений в истории: {session.GetMessageCount()}\n"
|
+ $"Сообщений в истории: {session.GetMessageCount()}\n"
|
||||||
+ $"Создана: {session.CreatedAt:dd.MM.yyyy HH:mm}"
|
+ $"Создана: {session.CreatedAt:dd.MM.yyyy HH:mm}"
|
||||||
+ compressionInfo
|
+ compressionInfo;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
statusBuilder.AppendLine();
|
statusBuilder.AppendLine();
|
||||||
|
|
||||||
// Информация о сессии
|
// Информация о сессии
|
||||||
var session = _chatService.GetSession(context.ChatId);
|
var session = await _chatService.GetSessionAsync(context.ChatId);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
statusBuilder.AppendLine($"📊 **Сессия:**");
|
statusBuilder.AppendLine($"📊 **Сессия:**");
|
||||||
|
|||||||
@@ -39,6 +39,23 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
// Input validation
|
||||||
|
if (string.IsNullOrWhiteSpace(messageText))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Empty message received for chat {ChatId}", chatId);
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chatId == 0)
|
||||||
|
{
|
||||||
|
_logger.LogError("Invalid chatId (0) received");
|
||||||
|
throw new ArgumentException("ChatId cannot be 0", nameof(chatId));
|
||||||
|
}
|
||||||
|
|
||||||
|
username = username ?? "Unknown";
|
||||||
|
chatType = chatType ?? "private";
|
||||||
|
chatTitle = chatTitle ?? string.Empty;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Получаем информацию о боте
|
// Получаем информацию о боте
|
||||||
@@ -121,10 +138,25 @@ namespace ChatBot.Services.Telegram.Commands
|
|||||||
cancellationToken
|
cancellationToken
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Network error processing message for chat {ChatId}", chatId);
|
||||||
|
return "Ошибка сети при обработке сообщения. Проверьте подключение к AI сервису.";
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Request timeout for chat {ChatId}", chatId);
|
||||||
|
return "Превышено время ожидания ответа. Попробуйте еще раз.";
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Invalid operation for chat {ChatId}", chatId);
|
||||||
|
return "Ошибка в работе системы. Попробуйте позже.";
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing message for chat {ChatId}", chatId);
|
_logger.LogError(ex, "Unexpected error processing message for chat {ChatId}", chatId);
|
||||||
return "Произошла ошибка при обработке сообщения. Попробуйте еще раз.";
|
return "Произошла непредвиденная ошибка. Попробуйте еще раз.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user