< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.SignalR.KestrunHub
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/SignalR/KestrunHub.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
100%
Covered lines: 22
Uncovered lines: 0
Coverable lines: 22
Total lines: 76
Line coverage: 100%
Branch coverage
100%
Covered branches: 2
Total branches: 2
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/15/2025 - 21:27:26 Line coverage: 13.6% (3/22) Branch coverage: 0% (0/2) Total lines: 76 Tag: Kestrun/Kestrun@c33ec02a85e4f8d6061aeaab5a5e8c3a8b66559412/15/2025 - 18:44:50 Line coverage: 100% (22/22) Branch coverage: 100% (2/2) Total lines: 76 Tag: Kestrun/Kestrun@6b9e56ea2de904fc3597033ef0f9bc7839d5d618 10/15/2025 - 21:27:26 Line coverage: 13.6% (3/22) Branch coverage: 0% (0/2) Total lines: 76 Tag: Kestrun/Kestrun@c33ec02a85e4f8d6061aeaab5a5e8c3a8b66559412/15/2025 - 18:44:50 Line coverage: 100% (22/22) Branch coverage: 100% (2/2) Total lines: 76 Tag: Kestrun/Kestrun@6b9e56ea2de904fc3597033ef0f9bc7839d5d618

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
OnConnectedAsync()100%11100%
OnDisconnectedAsync()100%22100%
JoinGroup()100%11100%
LeaveGroup()100%11100%
Echo()100%11100%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/SignalR/KestrunHub.cs

#LineLine coverage
 1using Microsoft.AspNetCore.SignalR;
 2
 3namespace Kestrun.SignalR;
 4
 5/// <summary>
 6/// Default SignalR hub for Kestrun providing real-time communication capabilities.
 7/// Clients can connect to this hub to receive log messages, events, and other real-time updates.
 8/// </summary>
 9/// <remarks>
 10/// Initializes a new instance of the <see cref="KestrunHub"/> class.
 11/// </remarks>
 12/// <param name="logger">The Serilog logger instance.</param>
 13/// <param name="tracker">The connection tracker for counting connected clients.</param>
 1514public class KestrunHub(Serilog.ILogger logger, IConnectionTracker tracker) : Hub
 15{
 1516    private readonly Serilog.ILogger _logger = logger;
 1517    private readonly IConnectionTracker _tracker = tracker;
 18
 19    /// <summary>
 20    /// Called when a client connects to the hub.
 21    /// </summary>
 22    public override async Task OnConnectedAsync()
 23    {
 224        _logger.Information("SignalR client connected: {ConnectionId}", Context.ConnectionId);
 225        _tracker.OnConnected(Context.ConnectionId);
 226        await base.OnConnectedAsync();
 227    }
 28
 29    /// <summary>
 30    /// Called when a client disconnects from the hub.
 31    /// </summary>
 32    /// <param name="exception">The exception that caused the disconnection, if any.</param>
 33    public override async Task OnDisconnectedAsync(Exception? exception)
 34    {
 335        if (exception != null)
 36        {
 137            _logger.Warning(exception, "SignalR client disconnected with error: {ConnectionId}", Context.ConnectionId);
 38        }
 39        else
 40        {
 241            _logger.Information("SignalR client disconnected: {ConnectionId}", Context.ConnectionId);
 42        }
 343        _tracker.OnDisconnected(Context.ConnectionId);
 344        await base.OnDisconnectedAsync(exception);
 345    }
 46
 47    /// <summary>
 48    /// Allows a client to join a specific group.
 49    /// </summary>
 50    /// <param name="groupName">The name of the group to join.</param>
 51    public async Task JoinGroup(string groupName)
 52    {
 553        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
 554        _logger.Information("Client {ConnectionId} joined group {GroupName}", Context.ConnectionId, groupName);
 55        // Notify caller so UI can update membership state
 556        await Clients.Caller.SendAsync("GroupJoined", groupName);
 557    }
 58
 59    /// <summary>
 60    /// Allows a client to leave a specific group.
 61    /// </summary>
 62    /// <param name="groupName">The name of the group to leave.</param>
 63    public async Task LeaveGroup(string groupName)
 64    {
 565        await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
 566        _logger.Information("Client {ConnectionId} left group {GroupName}", Context.ConnectionId, groupName);
 67        // Notify caller so UI can update membership state
 568        await Clients.Caller.SendAsync("GroupLeft", groupName);
 569    }
 70
 71    /// <summary>
 72    /// Echoes a message back to the caller (useful for testing).
 73    /// </summary>
 74    /// <param name="message">The message to echo.</param>
 275    public async Task Echo(string message) => await Clients.Caller.SendAsync("ReceiveEcho", message);
 76}