tuitio/test/UnitTests/Tuitio.Application.Tests/UserServiceTests.cs

198 lines
7.0 KiB
C#

// Copyright (c) 2020 Tudor Stanciu
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Tuitio.Application.Services.Abstractions;
using Tuitio.Application.Tests.Fixtures;
using Tuitio.Domain.Data.DbContexts;
using Tuitio.Domain.Models.Account;
using Xunit;
namespace Tuitio.Application.Tests
{
public class UserServiceTests : IClassFixture<DependencyInjectionFixture>, IDisposable
{
private readonly IServiceScope _tuitioScope;
private readonly IUserService _userService;
public UserServiceTests(DependencyInjectionFixture fixture)
{
_tuitioScope = fixture.ServiceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
_userService = _tuitioScope.ServiceProvider.GetRequiredService<IUserService>();
}
public void Dispose()
{
_tuitioScope.Dispose();
}
[Fact]
public async Task Login_ShouldThrowArgumentExceptionIfUserNameIsNullOrEmptyString()
{
// Arrange
var userName = "";
var password = "";
// Act
// Assert
await Assert.ThrowsAsync<ArgumentException>(nameof(userName), () => _userService.Login(userName, password));
await Assert.ThrowsAsync<ArgumentException>(nameof(userName), () => _userService.Login(null, password));
}
[Fact]
public async Task Login_ShouldThrowArgumentExceptionIfPasswordIsNullOrEmptyString()
{
// Arrange
var userName = "tuitio.test.user";
var password = "";
// Act
// Assert
await Assert.ThrowsAsync<ArgumentException>(nameof(password), () => _userService.Login(userName, password));
await Assert.ThrowsAsync<ArgumentException>(nameof(password), () => _userService.Login(userName, null));
}
[Fact]
public async Task Login_ShouldReturnAValidToken()
{
// Arrange
var userName = "tuitio.user";
var password = "pass123";
// Act
var result = await _userService.Login(userName, password);
// Assert
Assert.NotNull(result);
Assert.NotNull(result.Token);
Assert.NotEmpty(result.Raw);
Assert.Equal(userName, result.Token.UserName);
Assert.True(result.Token.TokenId != Guid.Empty, "Token id cannot be an empty guid.");
Assert.NotEmpty(result.Token.LockStamp);
Assert.True(result.Token.ExpiresIn > 0, "Token expiration must be a positive number.");
Assert.True((DateTime.UtcNow - result.Token.CreatedAt).TotalMinutes <= 1, "Token creation date must be within the last minute.");
}
[Fact]
public async Task Login_ShouldSetCorrectLastLoginDate()
{
// Arrange
var userName = "tuitio.user";
var password = "pass123";
var dbContext = _tuitioScope.ServiceProvider.GetRequiredService<TuitioDbContext>();
await _userService.Login(userName, password);
// Act
var userFromDb = await dbContext.Users.FirstOrDefaultAsync(z => z.UserName == userName);
// Assert
Assert.NotNull(userFromDb);
Assert.True(userFromDb.LastLoginDate.HasValue, "Last login date cannot be null after user login");
Assert.True((DateTime.UtcNow - userFromDb.LastLoginDate.Value).TotalMinutes <= 1, "Last login date must be within the last minute.");
}
[Fact]
public async Task Login_ShouldSaveTokenInDatabase()
{
// Arrange
var userName = "tuitio.user";
var password = "pass123";
var dbContext = _tuitioScope.ServiceProvider.GetRequiredService<TuitioDbContext>();
var loginResult = await _userService.Login(userName, password);
// Act
var userTokenFromDb = await dbContext.UserTokens.FirstOrDefaultAsync(z => z.TokenId == loginResult.Token.TokenId);
// Assert
Assert.NotNull(userTokenFromDb);
Assert.True(loginResult.Token.TokenId != Guid.Empty, "Token id cannot be an empty guid.");
Assert.True((DateTime.UtcNow - userTokenFromDb.ValidFrom).TotalMinutes <= 1, "Token valid from date must be within the last minute.");
Assert.True(userTokenFromDb.ValidUntil > DateTime.UtcNow, "Token valid until date must be greater than the current date.");
}
[Fact]
public async Task Login_ShouldReturnNullResultForWrongCredentials()
{
// Arrange
var userName = "tuitio.user";
var password = "wrong_password";
// Act
var result = await _userService.Login(userName, password);
// Assert
Assert.Null(result);
}
[Fact]
public async Task Authorize_ShouldReturnAValidToken()
{
// Arrange
var userName = "tuitio.user";
var password = "pass123";
var loginResult = await _userService.Login(userName, password);
// Act
var result = _userService.Authorize(loginResult.Raw);
// Assert
Assert.NotNull(result);
Assert.Equal(userName, result.UserName);
Assert.NotNull(result.SecurityStamp);
Assert.NotNull(result.LockStamp);
Assert.True(result.TokenId != Guid.Empty, "Token id cannot be an empty guid.");
Assert.True(result.ExpiresIn > 0, "Token expiration must be a positive number.");
}
[Fact]
public void Authorize_ShouldReturnNull()
{
// Arrange
var unauthorizedToken = "unauthorized-token";
// Act
var result = _userService.Authorize(unauthorizedToken);
// Assert
Assert.Null(result);
}
[Fact]
public async Task Logout_ShouldSuccessfullyLogoutTheUser()
{
// Arrange
var userName = "tuitio.user";
var password = "pass123";
var loginResult = await _userService.Login(userName, password);
// Act
LogoutResult result;
using (var scope = _tuitioScope.ServiceProvider.CreateScope())
{
var newUserService = scope.ServiceProvider.GetRequiredService<IUserService>();
result = await newUserService.Logout(loginResult.Raw);
}
// Assert
Assert.NotNull(result);
Assert.Equal(userName, result.UserName);
Assert.True((DateTime.UtcNow - result.LogoutDate).TotalMinutes <= 1, "Logout date must be within the last minute.");
}
[Fact]
public async Task Logout_ShouldReturnNullResultForUnauthenticatedToken()
{
// Arrange
var unauthenticatedToken = "unauthenticated-token";
// Act
var result = await _userService.Logout(unauthenticatedToken);
// Assert
Assert.Null(result);
}
}
}