- Renamed all directories: OpenHarbor.MCP.* → Svrnty.MCP.* - Updated all namespaces in 179 C# files - Renamed 20 .csproj files and 3 .sln files - Updated 193 documentation references - Updated 33 references in main CODEX codebase - Updated Codex.sln with new paths - Build verified: 0 errors Preparing for extraction to standalone repositories. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
223 lines
6.7 KiB
C#
223 lines
6.7 KiB
C#
using Xunit;
|
|
using Svrnty.MCP.Gateway.Infrastructure.Health;
|
|
using Svrnty.MCP.Gateway.Core.Models;
|
|
|
|
namespace Svrnty.MCP.Gateway.Infrastructure.Tests.Health;
|
|
|
|
/// <summary>
|
|
/// Unit tests for PassiveHealthTracker following TDD approach.
|
|
/// Tests passive health tracking based on response times and errors.
|
|
/// </summary>
|
|
public class PassiveHealthTrackerTests
|
|
{
|
|
[Fact]
|
|
public void RecordSuccess_UpdatesHealthStatus()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker();
|
|
var serverId = "server-1";
|
|
var responseTime = TimeSpan.FromMilliseconds(50);
|
|
|
|
// Act
|
|
tracker.RecordSuccess(serverId, responseTime);
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.True(health.IsHealthy);
|
|
Assert.Equal(responseTime, health.ResponseTime);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordFailure_UpdatesHealthStatus()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker
|
|
{
|
|
UnhealthyThreshold = 1 // Mark unhealthy after 1 failure for this test
|
|
};
|
|
var serverId = "server-2";
|
|
var errorMessage = "Connection timeout";
|
|
|
|
// Act
|
|
tracker.RecordFailure(serverId, errorMessage);
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.False(health.IsHealthy);
|
|
Assert.Equal(errorMessage, health.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordSuccess_MultipleRequests_CalculatesAverageResponseTime()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker();
|
|
var serverId = "server-3";
|
|
|
|
// Act - record 3 successful requests
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(100));
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(200));
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(300));
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.True(health.IsHealthy);
|
|
// Average should be around 200ms
|
|
Assert.NotNull(health.ResponseTime);
|
|
Assert.InRange(health.ResponseTime.Value.TotalMilliseconds, 150, 250);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordFailure_MultipleFailures_MarksServerUnhealthy()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker
|
|
{
|
|
UnhealthyThreshold = 3 // Mark unhealthy after 3 failures
|
|
};
|
|
var serverId = "server-4";
|
|
|
|
// Act - record 3 failures
|
|
tracker.RecordFailure(serverId, "Error 1");
|
|
tracker.RecordFailure(serverId, "Error 2");
|
|
tracker.RecordFailure(serverId, "Error 3");
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.False(health.IsHealthy);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordSuccess_AfterFailures_RecoverToHealthy()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker
|
|
{
|
|
UnhealthyThreshold = 2,
|
|
HealthyThreshold = 3 // Recover after 3 successes
|
|
};
|
|
var serverId = "server-5";
|
|
|
|
// Record failures to make unhealthy
|
|
tracker.RecordFailure(serverId, "Error 1");
|
|
tracker.RecordFailure(serverId, "Error 2");
|
|
|
|
// Act - record successes to recover
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(50));
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(50));
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(50));
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.True(health.IsHealthy);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetServerHealth_WithUnknownServer_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker();
|
|
|
|
// Act
|
|
var health = tracker.GetServerHealth("unknown-server");
|
|
|
|
// Assert
|
|
Assert.Null(health);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetAllServerHealth_ReturnsAllTrackedServers()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker
|
|
{
|
|
UnhealthyThreshold = 1 // Mark unhealthy after 1 failure for this test
|
|
};
|
|
|
|
tracker.RecordSuccess("server-1", TimeSpan.FromMilliseconds(50));
|
|
tracker.RecordSuccess("server-2", TimeSpan.FromMilliseconds(100));
|
|
tracker.RecordFailure("server-3", "Connection failed");
|
|
|
|
// Act
|
|
var allHealth = tracker.GetAllServerHealth();
|
|
|
|
// Assert
|
|
Assert.Equal(3, allHealth.Count());
|
|
Assert.Contains(allHealth, h => h.ServerId == "server-1" && h.IsHealthy);
|
|
Assert.Contains(allHealth, h => h.ServerId == "server-2" && h.IsHealthy);
|
|
Assert.Contains(allHealth, h => h.ServerId == "server-3" && !h.IsHealthy);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordSuccess_WithSlowResponse_MarksAsUnhealthy()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker
|
|
{
|
|
SlowResponseThreshold = TimeSpan.FromMilliseconds(100)
|
|
};
|
|
var serverId = "server-6";
|
|
|
|
// Act - record slow response
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(500));
|
|
|
|
// Assert - should still be marked as success, but noted as slow
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.True(health.IsHealthy); // Still healthy, just slow
|
|
Assert.Equal(TimeSpan.FromMilliseconds(500), health.ResponseTime);
|
|
}
|
|
|
|
[Fact]
|
|
public void Reset_ClearsAllHealthData()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker();
|
|
tracker.RecordSuccess("server-1", TimeSpan.FromMilliseconds(50));
|
|
tracker.RecordFailure("server-2", "Error");
|
|
|
|
// Act
|
|
tracker.Reset();
|
|
|
|
// Assert
|
|
var allHealth = tracker.GetAllServerHealth();
|
|
Assert.Empty(allHealth);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordSuccess_UpdatesLastCheckTime()
|
|
{
|
|
// Arrange
|
|
var tracker = new PassiveHealthTracker();
|
|
var serverId = "server-7";
|
|
var beforeRecord = DateTime.UtcNow;
|
|
|
|
// Act
|
|
tracker.RecordSuccess(serverId, TimeSpan.FromMilliseconds(50));
|
|
var afterRecord = DateTime.UtcNow;
|
|
|
|
// Assert
|
|
var health = tracker.GetServerHealth(serverId);
|
|
Assert.NotNull(health);
|
|
Assert.True(health.LastCheck >= beforeRecord);
|
|
Assert.True(health.LastCheck <= afterRecord);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_SetsDefaultThresholds()
|
|
{
|
|
// Act
|
|
var tracker = new PassiveHealthTracker();
|
|
|
|
// Assert
|
|
Assert.Equal(5, tracker.UnhealthyThreshold);
|
|
Assert.Equal(3, tracker.HealthyThreshold);
|
|
Assert.Equal(TimeSpan.FromSeconds(5), tracker.SlowResponseThreshold);
|
|
}
|
|
}
|