using ChatBot.Models; using ChatBot.Services; using ChatBot.Tests.TestUtilities; using FluentAssertions; namespace ChatBot.Tests.Services; public class InMemorySessionStorageTests { private readonly InMemorySessionStorage _sessionStorage; public InMemorySessionStorageTests() { _sessionStorage = new InMemorySessionStorage( TestDataBuilder.Mocks.CreateLoggerMock().Object ); } [Fact] public async Task GetOrCreateAsync_ShouldReturnExistingSession_WhenSessionExists() { // Arrange await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); // Act var result = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); // Assert result.Should().NotBeNull(); result.ChatId.Should().Be(12345); result.ChatType.Should().Be("private"); } [Fact] public async Task GetOrCreateAsync_ShouldCreateNewSession_WhenSessionDoesNotExist() { // Act var result = await _sessionStorage.GetOrCreateAsync(12345, "group", "Test Group"); // Assert result.Should().NotBeNull(); result.ChatId.Should().Be(12345); result.ChatType.Should().Be("group"); result.ChatTitle.Should().Be("Test Group"); } [Fact] public async Task GetOrCreateAsync_ShouldUseDefaultValues_WhenParametersNotProvided() { // Act var result = await _sessionStorage.GetOrCreateAsync(12345); // Assert result.Should().NotBeNull(); result.ChatId.Should().Be(12345); result.ChatType.Should().Be("private"); result.ChatTitle.Should().BeEmpty(); } [Fact] public async Task GetAsync_ShouldReturnSession_WhenSessionExists() { // Arrange var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); // Act var result = await _sessionStorage.GetAsync(12345); // Assert result.Should().BeSameAs(session); } [Fact] public async Task GetAsync_ShouldReturnNull_WhenSessionDoesNotExist() { // Act var result = await _sessionStorage.GetAsync(99999); // Assert result.Should().BeNull(); } [Fact] public async Task SaveSessionAsync_ShouldUpdateExistingSession() { // Arrange var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Original Title"); session.ChatTitle = "Updated Title"; session.LastUpdatedAt = DateTime.UtcNow; // Act await _sessionStorage.SaveSessionAsync(session); // Assert var savedSession = await _sessionStorage.GetAsync(12345); savedSession.Should().NotBeNull(); savedSession!.ChatTitle.Should().Be("Updated Title"); } [Fact] public async Task SaveSessionAsync_ShouldAddNewSession() { // Arrange var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Original Title"); session.ChatTitle = "New Session"; // Act await _sessionStorage.SaveSessionAsync(session); // Assert var savedSession = await _sessionStorage.GetAsync(12345); savedSession.Should().NotBeNull(); savedSession!.ChatTitle.Should().Be("New Session"); } [Fact] public async Task RemoveAsync_ShouldReturnTrue_WhenSessionExists() { // Arrange await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); // Act var result = await _sessionStorage.RemoveAsync(12345); // Assert result.Should().BeTrue(); (await _sessionStorage.GetAsync(12345)).Should().BeNull(); } [Fact] public async Task RemoveAsync_ShouldReturnFalse_WhenSessionDoesNotExist() { // Act var result = await _sessionStorage.RemoveAsync(99999); // Assert result.Should().BeFalse(); } [Fact] public async Task GetActiveSessionsCountAsync_ShouldReturnCorrectCount() { // Arrange await _sessionStorage.GetOrCreateAsync(12345, "private", "Chat 1"); await _sessionStorage.GetOrCreateAsync(67890, "group", "Chat 2"); await _sessionStorage.GetOrCreateAsync(11111, "private", "Chat 3"); // Act var count = await _sessionStorage.GetActiveSessionsCountAsync(); // Assert count.Should().Be(3); } [Fact] public async Task GetActiveSessionsCountAsync_ShouldReturnZero_WhenNoSessions() { // Act var count = await _sessionStorage.GetActiveSessionsCountAsync(); // Assert count.Should().Be(0); } [Fact] public async Task CleanupOldSessionsAsync_ShouldDeleteOldSessions() { // Arrange var oldSession = await _sessionStorage.GetOrCreateAsync(99999, "private", "Old Chat"); // Manually set CreatedAt to 2 days ago using test method oldSession.SetCreatedAtForTesting(DateTime.UtcNow.AddDays(-2)); var recentSession = await _sessionStorage.GetOrCreateAsync(88888, "private", "Recent Chat"); // Manually set CreatedAt to 30 minutes ago using test method recentSession.SetCreatedAtForTesting(DateTime.UtcNow.AddMinutes(-30)); // Act await _sessionStorage.CleanupOldSessionsAsync(1); // Delete sessions older than 1 day // Assert (await _sessionStorage.GetAsync(99999)) .Should() .BeNull(); // Old session should be deleted (await _sessionStorage.GetAsync(88888)).Should().NotBeNull(); // Recent session should remain } [Fact] public async Task CleanupOldSessionsAsync_ShouldNotDeleteRecentSessions() { // Arrange var recentSession1 = await _sessionStorage.GetOrCreateAsync(12345, "private", "Recent 1"); recentSession1.CreatedAt = DateTime.UtcNow.AddHours(-1); var recentSession2 = await _sessionStorage.GetOrCreateAsync(67890, "private", "Recent 2"); recentSession2.CreatedAt = DateTime.UtcNow.AddMinutes(-30); // Act var deletedCount = await _sessionStorage.CleanupOldSessionsAsync(24); // Delete sessions older than 24 hours // Assert deletedCount.Should().Be(0); (await _sessionStorage.GetAsync(12345)).Should().NotBeNull(); (await _sessionStorage.GetAsync(67890)).Should().NotBeNull(); } [Fact] public async Task CleanupOldSessionsAsync_ShouldReturnZero_WhenNoSessions() { // Act var deletedCount = await _sessionStorage.CleanupOldSessionsAsync(1); // Assert deletedCount.Should().Be(0); } [Fact] public async Task GetOrCreateAsync_ShouldCreateSessionWithCorrectTimestamp() { // Act var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); // Assert session.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1)); session.LastUpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromMinutes(1)); } [Fact] public async Task SaveSessionAsync_ShouldUpdateLastUpdatedAt() { // Arrange var session = await _sessionStorage.GetOrCreateAsync(12345, "private", "Test Chat"); var originalTime = session.LastUpdatedAt; // Wait a bit to ensure time difference await Task.Delay(10); session.ChatTitle = "Updated Title"; // Act await _sessionStorage.SaveSessionAsync(session); // Assert var savedSession = await _sessionStorage.GetAsync(12345); savedSession!.LastUpdatedAt.Should().BeAfter(originalTime); } [Fact] public async Task GetOrCreateAsync_ShouldHandleConcurrentAccess() { // Arrange var tasks = new List>(); // Act - Create sessions concurrently for (int i = 0; i < 100; i++) { var chatId = 1000 + i; tasks.Add( Task.Run(async () => await _sessionStorage.GetOrCreateAsync(chatId, "private", $"Chat {chatId}") ) ); } await Task.WhenAll(tasks); // Assert (await _sessionStorage.GetActiveSessionsCountAsync()) .Should() .Be(100); // Verify all sessions were created for (int i = 0; i < 100; i++) { var chatId = 1000 + i; var session = await _sessionStorage.GetAsync(chatId); session.Should().NotBeNull(); session!.ChatId.Should().Be(chatId); } } [Fact] public async Task RemoveAsync_ShouldDecreaseActiveSessionsCount() { // Arrange await _sessionStorage.GetOrCreateAsync(12345, "private", "Chat 1"); await _sessionStorage.GetOrCreateAsync(67890, "private", "Chat 2"); await _sessionStorage.GetOrCreateAsync(11111, "private", "Chat 3"); // Act await _sessionStorage.RemoveAsync(67890); // Assert (await _sessionStorage.GetActiveSessionsCountAsync()) .Should() .Be(2); (await _sessionStorage.GetAsync(12345)).Should().NotBeNull(); (await _sessionStorage.GetAsync(67890)).Should().BeNull(); (await _sessionStorage.GetAsync(11111)).Should().NotBeNull(); } }