171 lines
6.8 KiB
C#
171 lines
6.8 KiB
C#
using Omika.Core.Domain.Entities.Security;
|
|
using Omika.Data.Configuration;
|
|
using Omika.Data.Connection;
|
|
using Omika.Data.Repositories;
|
|
|
|
namespace Omika.Tests.Repositories;
|
|
|
|
/// <summary>
|
|
/// Tests du repository d'authentification Back-Office.
|
|
/// Vérifie que la requête est paramétrée (aucune concaténation du login ni du
|
|
/// hash), que la comparaison du login est insensible à la casse, que le hash est
|
|
/// comparé tel quel, et que la ligne jointe est correctement mappée.
|
|
/// </summary>
|
|
public class BackOfficeAuthRepositoryTests
|
|
{
|
|
private const string Login = "DFO";
|
|
private const string Hash = "FAKE-HASH-0123456789ABCDEF0123456789ABCDEF";
|
|
|
|
[Fact]
|
|
public async Task GetByLoginAndPasswordHashAsync_RequeteParametree_RetourneUtilisateur()
|
|
{
|
|
var connection = new FakeHfsqlConnection(HfsqlConnectionState.Open)
|
|
{
|
|
QueryResult =
|
|
[
|
|
new Dictionary<string, object?>
|
|
{
|
|
["UT_PKID"] = 42L,
|
|
["UT_Login"] = Login,
|
|
["UT_IDCollaborateur"] = 7L,
|
|
["UT_AccesBO"] = true,
|
|
["CO_PKID"] = 7L,
|
|
["CO_AccesBO"] = true,
|
|
["CO_Actif"] = true
|
|
}
|
|
]
|
|
};
|
|
var repository = new BackOfficeAuthRepository(connection);
|
|
|
|
BackOfficeAuthUser? user = await repository.GetByLoginAndPasswordHashAsync(Login, Hash);
|
|
|
|
Assert.NotNull(user);
|
|
Assert.Equal(42, user.UserId);
|
|
Assert.Equal(Login, user.Login);
|
|
Assert.Equal(7, user.CollaborateurId);
|
|
Assert.Equal(7, user.CollaborateurPkId);
|
|
Assert.True(user.UtilisateurAccesBO);
|
|
Assert.True(user.CollaborateurAccesBO);
|
|
Assert.True(user.CollaborateurActif);
|
|
|
|
// Requête paramétrée : login et hash ne sont jamais concaténés au SQL.
|
|
Assert.Contains("UPPER(Utilisateur.UT_Login) = ?", connection.LastSql);
|
|
Assert.Contains("Utilisateur.UT_MotDePasse = ?", connection.LastSql);
|
|
Assert.Contains("LEFT JOIN Collaborateur", connection.LastSql);
|
|
Assert.DoesNotContain(Login, connection.LastSql);
|
|
Assert.DoesNotContain(Hash, connection.LastSql);
|
|
|
|
Assert.NotNull(connection.LastParameters);
|
|
Assert.Equal(2, connection.LastParameters!.Count);
|
|
Assert.Equal(Login.ToUpperInvariant(), connection.LastParameters[0]);
|
|
Assert.Equal(Hash, connection.LastParameters[1]); // hash comparé tel quel
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetByLoginAndPasswordHashAsync_LoginMinuscules_EstUppercasedDansLeParametre()
|
|
{
|
|
var connection = new FakeHfsqlConnection(HfsqlConnectionState.Open) { QueryResult = [] };
|
|
var repository = new BackOfficeAuthRepository(connection);
|
|
|
|
await repository.GetByLoginAndPasswordHashAsync("dfo", Hash);
|
|
|
|
Assert.NotNull(connection.LastParameters);
|
|
Assert.Equal("DFO", connection.LastParameters![0]);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetByLoginAndPasswordHashAsync_AucuneLigne_RetourneNull()
|
|
{
|
|
var connection = new FakeHfsqlConnection(HfsqlConnectionState.Open) { QueryResult = [] };
|
|
var repository = new BackOfficeAuthRepository(connection);
|
|
|
|
Assert.Null(await repository.GetByLoginAndPasswordHashAsync(Login, Hash));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetByLoginAndPasswordHashAsync_ChampsVides_RetourneNullSansRequete()
|
|
{
|
|
var connection = new FakeHfsqlConnection(HfsqlConnectionState.Open);
|
|
var repository = new BackOfficeAuthRepository(connection);
|
|
|
|
Assert.Null(await repository.GetByLoginAndPasswordHashAsync(" ", Hash));
|
|
Assert.Null(await repository.GetByLoginAndPasswordHashAsync(Login, " "));
|
|
Assert.Equal(0, connection.QueryCount);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetByLoginAndPasswordHashAsync_ColonnesQualifiees_RetourneUtilisateur()
|
|
{
|
|
// Le provider peut renvoyer les colonnes sous forme qualifiée
|
|
// (ex. « Utilisateur.UT_PKID ») : le mapping doit rester insensible.
|
|
var connection = new FakeHfsqlConnection(HfsqlConnectionState.Open)
|
|
{
|
|
QueryResult =
|
|
[
|
|
new Dictionary<string, object?>
|
|
{
|
|
["Utilisateur.UT_PKID"] = 42L,
|
|
["Utilisateur.UT_Login"] = Login,
|
|
["Utilisateur.UT_IDCollaborateur"] = 7L,
|
|
["Utilisateur.UT_AccesBO"] = false,
|
|
["Collaborateur.CO_PKID"] = 7L,
|
|
["Collaborateur.CO_AccesBO"] = true,
|
|
["Collaborateur.CO_Actif"] = true
|
|
}
|
|
]
|
|
};
|
|
var repository = new BackOfficeAuthRepository(connection);
|
|
|
|
BackOfficeAuthUser? user = await repository.GetByLoginAndPasswordHashAsync(Login, Hash);
|
|
|
|
Assert.NotNull(user);
|
|
Assert.Equal(42, user.UserId);
|
|
Assert.Equal(7, user.CollaborateurId);
|
|
Assert.True(user.CollaborateurAccesBO);
|
|
}
|
|
|
|
private sealed class FakeHfsqlConnection : IHfsqlConnection
|
|
{
|
|
public FakeHfsqlConnection(HfsqlConnectionState state) => State = state;
|
|
|
|
public HfsqlOptions Options => new();
|
|
public HfsqlConnectionState State { get; private set; }
|
|
|
|
public string? LastSql { get; private set; }
|
|
public IReadOnlyList<object?>? LastParameters { get; private set; }
|
|
public int QueryCount { get; private set; }
|
|
public IReadOnlyList<IReadOnlyDictionary<string, object?>> QueryResult { get; set; } = [];
|
|
|
|
public Task OpenAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
State = HfsqlConnectionState.Open;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task CloseAsync()
|
|
{
|
|
State = HfsqlConnectionState.Closed;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
|
|
|
|
public Task<object?> ExecuteScalarAsync(string sql, IReadOnlyList<object?>? parameters = null, CancellationToken cancellationToken = default)
|
|
=> Task.FromResult<object?>(null);
|
|
|
|
public Task<int> ExecuteNonQueryAsync(string sql, IReadOnlyList<object?>? parameters = null, CancellationToken cancellationToken = default)
|
|
=> Task.FromResult(0);
|
|
|
|
public Task<IReadOnlyList<IReadOnlyDictionary<string, object?>>> QueryAsync(string sql, IReadOnlyList<object?>? parameters = null, CancellationToken cancellationToken = default)
|
|
{
|
|
QueryCount++;
|
|
LastSql = sql;
|
|
LastParameters = parameters;
|
|
return Task.FromResult(QueryResult);
|
|
}
|
|
|
|
public Task<IReadOnlyList<HfsqlColumnMetadata>> GetColumnsAsync(string tableName, CancellationToken cancellationToken = default)
|
|
=> Task.FromResult<IReadOnlyList<HfsqlColumnMetadata>>([]);
|
|
}
|
|
}
|