Compare commits

...

14 Commits

Author SHA1 Message Date
Developer 02
5aab46a221 refactor(tests): Verbesserung der Nachrichtenbehandlung und Assert-Bedingungen in AuthClientTests
- Vereinfachte Assertions in StartAsync_ShouldConnectSuccessfully durch Entfernen expliziter Strings
- Aktualisierte ReceiveMessage_ShouldCallOnMessageReceived, um Nachrichteninhalte zu überprüfen
- Refaktorisierte Variablennamen in ReceiveMessage_ShouldCallOnMessageReceived für bessere Verständlichkeit
2025-02-03 17:09:57 +01:00
Developer 02
9fee7ea381 feat(tests): Refaktorierung und Erweiterung von AuthClientTests für Verbindungs- und Nachrichtenbehandlung
- Ersetzte das statische Setup für die Client-Erstellung durch eine wiederverwendbare Build-Methode.
- Ein neuer Test `StartAsync_ShouldConnectSuccessfully` wurde hinzugefügt, um den Verbindungsaufbau zu überprüfen.
- Refactored `ReceiveMessage_ShouldCallOnMessageReceived` für die Einrichtung mehrerer Clients (Sender und Empfänger).
- Konsolidierte hartkodierte URL in eine wiederverwendbare Konstante `HubUrl`.
2025-02-03 16:53:46 +01:00
Developer 02
cfe5df4b1d feat(IAuthClient): IsConnected, ConnectionError und ConnectionError Eigenschaften hinzugefügt.
- Umwandlung der Eigenschaft IsConnectionFailed in eine Erweiterungsmethode.
2025-02-03 16:38:22 +01:00
Developer 02
31ccd93b0d refactor(AuthClient): Enhance AuthClient with lazy initialization and connection error handling
- Replaced immediate connection start with lazy initialization via Lazy<Task<bool>>.
- Added IsConnected and ConnectionError properties to track connection status and errors.
- Introduced TryStartAsync method to safely attempt connection startup without throwing exceptions.
2025-02-03 16:22:41 +01:00
Developer 02
48970a1e13 refactor(AuthClientTests): Methode durch einen statischen Readonly-Delegaten für den Service Provider ersetzen 2025-02-03 15:42:46 +01:00
Developer 02
0614b205bd feat(IAuthClientHandler): Umbenennung der Methode ReceiveMessage in ReceiveMessageAsync 2025-02-03 15:39:30 +01:00
Developer 02
b533634e14 feat(AuthClientTests): ReceiveMessage_ShouldCallOnMessageReceived Testmethode hinzugefügt.
- Angeordnete Abhängigkeiten
2025-02-03 15:37:19 +01:00
Developer 02
766e4e6d27 feat(IAuthClientHandler): getrennte Klasse erstellt, um die Hub-Aktion von IAuthClient zu unterteilen
- ReceiveMessage-Methode zu IAuthClientHandler verschoben
 - StartAsync-Methode zu IAuthClient hinzugefügt
2025-02-03 14:51:13 +01:00
Developer 02
878e927be9 refactor: ReceiveMessage yöntemini ayrı bir görevde asenkron olarak çalışacak şekilde değiştirin
- ReceiveMessage çağrısı, asenkron olarak yürütülmesini sağlamak için Task.Run'a sarılacak şekilde güncellendi.
2025-02-03 14:44:28 +01:00
Developer 02
24a0efb979 Revert "fix(AuthClient): Konvertiere den Rückgabetyp von ReceiveMessage von Nachricht zu"
This reverts commit 8e450f7934.
2025-02-03 14:40:35 +01:00
Developer 02
8e450f7934 fix(AuthClient): Konvertiere den Rückgabetyp von ReceiveMessage von Nachricht zu 2025-02-03 14:35:46 +01:00
Developer 02
77bbcfe4f1 refactor(ClientEvents): OnMessageReceived in Action umwandeln 2025-02-03 13:53:10 +01:00
Developer 02
c8eacc1d54 feat(AuthClientTests): Initalisiert. 2025-02-03 13:49:35 +01:00
Developer 02
bea08ce06c feat(Client.DIExtensions): Methode zur Behandlung von Dependency Injection erstellt 2025-02-03 13:36:59 +01:00
10 changed files with 166 additions and 21 deletions

View File

@@ -0,0 +1,6 @@
namespace DigitalData.Auth.Abstractions;
public static class ClientExtensions
{
public static bool IsConnectionFailed(this IAuthClient client) => client.ConnectionError is not null;
}

View File

@@ -1,6 +1,14 @@
namespace DigitalData.Auth.Abstractions;
public interface IAuthClient
public interface IAuthClient : IAuthClientHandler
{
Task ReceiveMessage(string user, string message);
bool IsConnected { get; }
Exception? ConnectionError { get; }
bool IsConnectionFailed => ConnectionError is not null;
Task StartAsync();
Task<bool> TryStartAsync();
}

View File

@@ -0,0 +1,6 @@
namespace DigitalData.Auth.Abstractions;
public interface IAuthClientHandler
{
Task ReceiveMessageAsync(string user, string message);
}

View File

@@ -9,6 +9,8 @@ public class AuthClient : IAuthClient
{
private readonly HubConnection _connection;
private readonly Lazy<Task<bool>> _lazyInitiator;
private readonly ILogger? _logger;
private readonly ClientParams _params;
@@ -19,14 +21,45 @@ public class AuthClient : IAuthClient
.WithUrl(paramsOptions.Value.Url)
.Build();
_connection.On<string, string>(nameof(ReceiveMessage), ReceiveMessage);
_connection.On<string, string>(nameof(ReceiveMessageAsync), ReceiveMessageAsync);
_logger = logger;
_params = paramsOptions.Value;
_lazyInitiator = new(async () =>
{
try
{
await _connection.StartAsync();
IsConnected = true;
return true;
}
catch(Exception ex)
{
ConnectionError = ex;
throw;
}
});
}
public async Task StartAsync() => await _connection.StartAsync();
public bool IsConnected { get; private set; } = false;
public Task ReceiveMessage(string user, string message) => _params.Events.OnMessageReceived(user, message, _logger);
public Exception? ConnectionError { get; private set; }
public async Task StartAsync() => await _lazyInitiator.Value;
public async Task<bool> TryStartAsync()
{
try
{
return await _lazyInitiator.Value;
}
catch
{
return false;
}
}
public Task ReceiveMessageAsync(string user, string message) => Task.Run(() => _params.Events.OnMessageReceived(user, message, _logger));
}

View File

@@ -4,9 +4,7 @@ namespace DigitalData.Auth.Client
{
public class ClientEvents
{
public Func<string, string, ILogger?, Task> OnMessageReceived { get; set; } = (user, message, logger)
=> Task.Run(
() => logger?.LogInformation("{user}: {message}", user, message)
);
public Action<string, string, ILogger?> OnMessageReceived { get; set; } = (user, message, logger)
=> logger?.LogInformation("{user}: {message}", user, message);
}
}

View File

@@ -2,7 +2,9 @@
public class ClientParams
{
public required string Url { get; init; }
#pragma warning disable CS8618 // throw exception in DI extension if it not set
public string Url { get; set; }
#pragma warning restore CS8618
public readonly ClientEvents Events = new();
}

View File

@@ -0,0 +1,19 @@
using DigitalData.Auth.Abstractions;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace DigitalData.Auth.Client;
public static class DIExtensions
{
public static IServiceCollection AddAuthHubClient(this IServiceCollection services, Action<ClientParams> options)
{
services
.Configure(options)
.AddSingleton<IAuthClient, AuthClient>()
.TryAddSingleton<HubConnectionBuilder>();
return services;
}
}

View File

@@ -0,0 +1,78 @@
using DigitalData.Auth.Abstractions;
using DigitalData.Auth.Client;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Auth.Tests.Client;
[TestFixture]
public class AuthClientTests
{
private static readonly string HubUrl = "https://localhost:7192/auth-hub";
private Func<Action<ClientParams>, ServiceProvider> Build;
[SetUp]
public void Setup()
{
Build = options => new ServiceCollection()
.AddAuthHubClient(options)
.BuildServiceProvider();
}
[Test]
public async Task StartAsync_ShouldConnectSuccessfully()
{
// Arrange
using var provider = Build(opt => opt.Url = HubUrl);
var client = provider.GetRequiredService<IAuthClient>();
// Act
await client.TryStartAsync();
// Assert
Assert.Multiple(() =>
{
Assert.That(client.IsConnected);
Assert.That(!client.IsConnectionFailed);
Assert.That(client.ConnectionError, Is.Null);
});
}
[Test]
public async Task ReceiveMessage_ShouldCallOnMessageReceived()
{
// Arrange
string rcv_user = string.Empty;
string rcv_msg = string.Empty;
// Sender client
using var provider_sender = Build(opt => opt.Url = HubUrl);
var sender_client = provider_sender.GetRequiredService<IAuthClient>();
await sender_client.TryStartAsync();
// Receiver client
using var provider_receiver = Build(opt =>
{
opt.Url = HubUrl;
opt.Events.OnMessageReceived = (user, message, logger) =>
{
rcv_user = user;
rcv_msg = message;
};
});
var client_receiver = provider_receiver.GetRequiredService<IAuthClient>();
string user = "user";
string message = "message";
// Act
await client_receiver.ReceiveMessageAsync(user, message);
// Assert
Assert.Multiple(() =>
{
Assert.That(rcv_user, Is.EqualTo(user));
Assert.That(rcv_msg, Is.EqualTo(message));
});
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
@@ -9,12 +9,6 @@
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<Compile Remove="NewFolder\**" />
<EmbeddedResource Remove="NewFolder\**" />
<None Remove="NewFolder\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
@@ -25,6 +19,7 @@
<ItemGroup>
<ProjectReference Include="..\DigitalData.Auth.Client\DigitalData.Auth.Client.csproj" />
<ProjectReference Include="..\src\DigitalData.Auth.API\DigitalData.Auth.API.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,14 +3,14 @@ using Microsoft.AspNetCore.SignalR;
namespace DigitalData.Auth.API.Hubs;
public class AuthHub : Hub<IAuthClient>
public class AuthHub : Hub<IAuthClientHandler>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
=> await Clients.All.ReceiveMessageAsync(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
=> await Clients.Caller.ReceiveMessageAsync(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("Auth.API Consumers").ReceiveMessage(user, message);
=> await Clients.Group("Auth.API Consumers").ReceiveMessageAsync(user, message);
}