using Xunit; using OpenHarbor.MCP.Gateway.Infrastructure.Routing; using OpenHarbor.MCP.Gateway.Core.Models; namespace OpenHarbor.MCP.Gateway.Infrastructure.Tests.Routing; /// /// Unit tests for RoundRobinStrategy following TDD approach. /// Tests round-robin server selection. /// public class RoundRobinStrategyTests { [Fact] public async Task SelectServerAsync_WithOneServer_ReturnsServer() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = true } }; var context = new RoutingContext(); // Act var selected = await strategy.SelectServerAsync(servers, context); // Assert Assert.NotNull(selected); Assert.Equal("server-1", selected.Id); } [Fact] public async Task SelectServerAsync_WithMultipleServers_RotatesServers() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = true }, new ServerInfo { Id = "server-2", IsHealthy = true }, new ServerInfo { Id = "server-3", IsHealthy = true } }; var context = new RoutingContext(); // Act var selected1 = await strategy.SelectServerAsync(servers, context); var selected2 = await strategy.SelectServerAsync(servers, context); var selected3 = await strategy.SelectServerAsync(servers, context); var selected4 = await strategy.SelectServerAsync(servers, context); // Assert - should rotate through all servers Assert.Equal("server-1", selected1.Id); Assert.Equal("server-2", selected2.Id); Assert.Equal("server-3", selected3.Id); Assert.Equal("server-1", selected4.Id); // Back to first } [Fact] public async Task SelectServerAsync_WithNoHealthyServers_ReturnsNull() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = false }, new ServerInfo { Id = "server-2", IsHealthy = false } }; var context = new RoutingContext(); // Act var selected = await strategy.SelectServerAsync(servers, context); // Assert Assert.Null(selected); } [Fact] public async Task SelectServerAsync_WithEmptyList_ReturnsNull() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List(); var context = new RoutingContext(); // Act var selected = await strategy.SelectServerAsync(servers, context); // Assert Assert.Null(selected); } [Fact] public async Task SelectServerAsync_OnlySelectsHealthyServers() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = true }, new ServerInfo { Id = "server-2", IsHealthy = false }, new ServerInfo { Id = "server-3", IsHealthy = true } }; var context = new RoutingContext(); // Act var selected1 = await strategy.SelectServerAsync(servers, context); var selected2 = await strategy.SelectServerAsync(servers, context); var selected3 = await strategy.SelectServerAsync(servers, context); // Assert - should only select healthy servers Assert.Equal("server-1", selected1.Id); Assert.Equal("server-3", selected2.Id); Assert.Equal("server-1", selected3.Id); // Back to first healthy } [Fact] public async Task SelectServerAsync_WithMixedHealth_SkipsUnhealthy() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = false }, new ServerInfo { Id = "server-2", IsHealthy = true }, new ServerInfo { Id = "server-3", IsHealthy = false }, new ServerInfo { Id = "server-4", IsHealthy = true } }; var context = new RoutingContext(); // Act var selected1 = await strategy.SelectServerAsync(servers, context); var selected2 = await strategy.SelectServerAsync(servers, context); // Assert Assert.Equal("server-2", selected1.Id); Assert.Equal("server-4", selected2.Id); } [Fact] public async Task SelectServerAsync_IsThreadSafe() { // Arrange var strategy = new RoundRobinStrategy(); var servers = new List { new ServerInfo { Id = "server-1", IsHealthy = true }, new ServerInfo { Id = "server-2", IsHealthy = true } }; var context = new RoutingContext(); // Act - call concurrently from multiple tasks var tasks = Enumerable.Range(0, 100) .Select(_ => strategy.SelectServerAsync(servers, context)) .ToList(); var results = await Task.WhenAll(tasks); // Assert - all calls should complete successfully Assert.Equal(100, results.Length); Assert.All(results, r => Assert.NotNull(r)); } }