using System; using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Moq; using TeleBot.Models; using TeleBot.Services; using Xunit; namespace TeleBot.Tests.Services { public class SessionManagerTests { private readonly SessionManager _sessionManager; private readonly Mock _mockConfiguration; private readonly Mock> _mockLogger; private readonly Mock _mockPrivacyService; private readonly Mock _mockCache; public SessionManagerTests() { _mockConfiguration = new Mock(); _mockLogger = new Mock>(); _mockPrivacyService = new Mock(); _mockCache = new Mock(); // Set up default configuration _mockConfiguration.Setup(x => x["Privacy:SessionTimeoutMinutes"]) .Returns("30"); _mockConfiguration.Setup(x => x["Privacy:EphemeralByDefault"]) .Returns("true"); _mockConfiguration.Setup(x => x["Redis:Enabled"]) .Returns("false"); // Set up privacy service _mockPrivacyService.Setup(x => x.HashIdentifier(It.IsAny())) .Returns(id => $"HASH_{id}"); _sessionManager = new SessionManager( _mockConfiguration.Object, _mockLogger.Object, _mockPrivacyService.Object, null // No cache for unit tests ); } [Fact] public async Task GetOrCreateSessionAsync_NewUser_ShouldCreateSession() { // Arrange long telegramUserId = 123456; // Act var session = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert session.Should().NotBeNull(); session.HashedUserId.Should().Be($"HASH_{telegramUserId}"); session.IsEphemeral.Should().BeTrue(); session.State.Should().Be(SessionState.MainMenu); session.Cart.Should().NotBeNull(); session.Cart.IsEmpty().Should().BeTrue(); } [Fact] public async Task GetOrCreateSessionAsync_ExistingUser_ShouldReturnSameSession() { // Arrange long telegramUserId = 123456; // Act var session1 = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); var session2 = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert session1.Id.Should().Be(session2.Id); session1.HashedUserId.Should().Be(session2.HashedUserId); } [Fact] public async Task UpdateSessionAsync_ShouldUpdateSession() { // Arrange long telegramUserId = 123456; var session = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Act session.State = SessionState.BrowsingCategories; session.Cart.AddItem(Guid.NewGuid(), "Test Product", 10.00m, 2); await _sessionManager.UpdateSessionAsync(session); var retrievedSession = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert retrievedSession.State.Should().Be(SessionState.BrowsingCategories); retrievedSession.Cart.GetTotalItems().Should().Be(2); } [Fact] public async Task DeleteSessionAsync_ShouldRemoveSession() { // Arrange long telegramUserId = 123456; var session = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); var sessionId = session.Id; // Act await _sessionManager.DeleteSessionAsync(sessionId); var newSession = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert newSession.Id.Should().NotBe(sessionId, "Should create a new session after deletion"); } [Fact] public async Task DeleteUserDataAsync_ShouldRemoveAllUserSessions() { // Arrange long telegramUserId = 123456; var session = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); var originalSessionId = session.Id; // Act await _sessionManager.DeleteUserDataAsync(telegramUserId); var newSession = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert newSession.Id.Should().NotBe(originalSessionId); newSession.Cart.IsEmpty().Should().BeTrue(); newSession.State.Should().Be(SessionState.MainMenu); } [Fact] public async Task CleanupExpiredSessionsAsync_ShouldRemoveExpiredSessions() { // Arrange long userId1 = 111111; long userId2 = 222222; var session1 = await _sessionManager.GetOrCreateSessionAsync(userId1); session1.ExpiresAt = DateTime.UtcNow.AddMinutes(-1); // Expired await _sessionManager.UpdateSessionAsync(session1); var session2 = await _sessionManager.GetOrCreateSessionAsync(userId2); // session2 not expired // Act await _sessionManager.CleanupExpiredSessionsAsync(); var retrievedSession1 = await _sessionManager.GetOrCreateSessionAsync(userId1); var retrievedSession2 = await _sessionManager.GetOrCreateSessionAsync(userId2); // Assert retrievedSession1.Id.Should().NotBe(session1.Id, "Expired session should be recreated"); retrievedSession2.Id.Should().Be(session2.Id, "Non-expired session should remain"); } [Fact] public void Session_IsExpired_ShouldReturnCorrectStatus() { // Arrange var expiredSession = new UserSession { ExpiresAt = DateTime.UtcNow.AddMinutes(-1) }; var activeSession = new UserSession { ExpiresAt = DateTime.UtcNow.AddMinutes(30) }; // Assert expiredSession.IsExpired().Should().BeTrue(); activeSession.IsExpired().Should().BeFalse(); } [Fact] public void Session_UpdateActivity_ShouldUpdateLastActivityTime() { // Arrange var session = new UserSession(); var originalTime = session.LastActivityAt; // Act System.Threading.Thread.Sleep(10); // Small delay session.UpdateActivity(); // Assert session.LastActivityAt.Should().BeAfter(originalTime); } [Fact] public async Task GetOrCreateSessionAsync_WithPrivacySettings_ShouldApplyDefaults() { // Arrange _mockConfiguration.Setup(x => x["Privacy:EphemeralByDefault"]) .Returns("true"); _mockConfiguration.Setup(x => x["Features:EnableDisappearingMessages"]) .Returns("true"); long telegramUserId = 999999; // Act var session = await _sessionManager.GetOrCreateSessionAsync(telegramUserId); // Assert session.Privacy.Should().NotBeNull(); session.Privacy.UseEphemeralMode.Should().BeTrue(); session.Privacy.DisableAnalytics.Should().BeTrue(); session.Privacy.EnableDisappearingMessages.Should().BeTrue(); } } }