Add unit tests for Router configuration and transport layers
- Implemented tests for RouterConfig, RoutingOptions, StaticInstanceConfig, and RouterConfigOptions to ensure default values are set correctly. - Added tests for RouterConfigProvider to validate configurations and ensure defaults are returned when no file is specified. - Created tests for ConfigValidationResult to check success and error scenarios. - Developed tests for ServiceCollectionExtensions to verify service registration for RouterConfig. - Introduced UdpTransportTests to validate serialization, connection, request-response, and error handling in UDP transport. - Added scripts for signing authority gaps and hashing DevPortal SDK snippets.
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using StellaOps.Microservice;
|
||||
using StellaOps.Router.Common.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Microservice.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for EndpointOverrideMerger - verifies merge logic and precedence.
|
||||
/// </summary>
|
||||
public class EndpointOverrideMergerTests
|
||||
{
|
||||
private readonly EndpointOverrideMerger _merger;
|
||||
private readonly Mock<ILogger<EndpointOverrideMerger>> _loggerMock;
|
||||
|
||||
public EndpointOverrideMergerTests()
|
||||
{
|
||||
_loggerMock = new Mock<ILogger<EndpointOverrideMerger>>();
|
||||
_merger = new EndpointOverrideMerger(_loggerMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_WithNullYamlConfig_ReturnsCodeEndpointsUnchanged()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/test", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, null);
|
||||
|
||||
result.Should().BeEquivalentTo(codeEndpoints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_WithEmptyYamlConfig_ReturnsCodeEndpointsUnchanged()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/test", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig { Endpoints = [] };
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().BeEquivalentTo(codeEndpoints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_OverridesTimeout_WhenYamlSpecifiesTimeout()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("POST", "/api/generate", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "POST",
|
||||
Path = "/api/generate",
|
||||
DefaultTimeout = "5m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_OverridesStreaming_WhenYamlSpecifiesStreaming()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/data", TimeSpan.FromSeconds(30), supportsStreaming: false)
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "GET",
|
||||
Path = "/api/data",
|
||||
SupportsStreaming = true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].SupportsStreaming.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_OverridesClaims_WhenYamlSpecifiesClaims()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("DELETE", "/api/users/{id}", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "DELETE",
|
||||
Path = "/api/users/{id}",
|
||||
RequiringClaims =
|
||||
[
|
||||
new ClaimRequirementConfig { Type = "role", Value = "admin" }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].RequiringClaims.Should().HaveCount(1);
|
||||
result[0].RequiringClaims![0].Type.Should().Be("role");
|
||||
result[0].RequiringClaims[0].Value.Should().Be("admin");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_PreservesCodeDefaults_WhenYamlDoesNotOverride()
|
||||
{
|
||||
var originalTimeout = TimeSpan.FromSeconds(45);
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/test", originalTimeout, supportsStreaming: true)
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "GET",
|
||||
Path = "/api/test"
|
||||
// No overrides specified
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].DefaultTimeout.Should().Be(originalTimeout);
|
||||
result[0].SupportsStreaming.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_MatchesCaseInsensitively()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/Test", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "get", // lowercase
|
||||
Path = "/API/TEST", // uppercase
|
||||
DefaultTimeout = "1m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_LeavesUnmatchedEndpointsUnchanged()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/one", TimeSpan.FromSeconds(10)),
|
||||
CreateEndpoint("POST", "/api/two", TimeSpan.FromSeconds(20)),
|
||||
CreateEndpoint("PUT", "/api/three", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "POST",
|
||||
Path = "/api/two",
|
||||
DefaultTimeout = "5m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(3);
|
||||
result[0].DefaultTimeout.Should().Be(TimeSpan.FromSeconds(10)); // unchanged
|
||||
result[1].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(5)); // overridden
|
||||
result[2].DefaultTimeout.Should().Be(TimeSpan.FromSeconds(30)); // unchanged
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_LogsWarning_WhenYamlOverrideDoesNotMatchAnyEndpoint()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/existing", TimeSpan.FromSeconds(30))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "POST",
|
||||
Path = "/api/nonexistent",
|
||||
DefaultTimeout = "5m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
_merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
_loggerMock.Verify(
|
||||
x => x.Log(
|
||||
LogLevel.Warning,
|
||||
It.IsAny<EventId>(),
|
||||
It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains("does not match any code endpoint")),
|
||||
It.IsAny<Exception>(),
|
||||
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_AppliesMultipleOverrides()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
CreateEndpoint("GET", "/api/one", TimeSpan.FromSeconds(10)),
|
||||
CreateEndpoint("POST", "/api/two", TimeSpan.FromSeconds(20))
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "GET",
|
||||
Path = "/api/one",
|
||||
DefaultTimeout = "1m"
|
||||
},
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "POST",
|
||||
Path = "/api/two",
|
||||
DefaultTimeout = "2m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(2);
|
||||
result[0].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(1));
|
||||
result[1].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_PreservesOriginalEndpointProperties()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
new()
|
||||
{
|
||||
ServiceName = "test-service",
|
||||
Version = "2.0.0",
|
||||
Method = "GET",
|
||||
Path = "/api/test",
|
||||
DefaultTimeout = TimeSpan.FromSeconds(30),
|
||||
SupportsStreaming = false,
|
||||
HandlerType = typeof(object)
|
||||
}
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "GET",
|
||||
Path = "/api/test",
|
||||
DefaultTimeout = "1m"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result[0].ServiceName.Should().Be("test-service");
|
||||
result[0].Version.Should().Be("2.0.0");
|
||||
result[0].Method.Should().Be("GET");
|
||||
result[0].Path.Should().Be("/api/test");
|
||||
result[0].DefaultTimeout.Should().Be(TimeSpan.FromMinutes(1));
|
||||
result[0].HandlerType.Should().Be(typeof(object));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_YamlOverridesCodeClaims_Completely()
|
||||
{
|
||||
var codeEndpoints = new List<EndpointDescriptor>
|
||||
{
|
||||
new()
|
||||
{
|
||||
ServiceName = "test-service",
|
||||
Version = "1.0.0",
|
||||
Method = "GET",
|
||||
Path = "/api/test",
|
||||
DefaultTimeout = TimeSpan.FromSeconds(30),
|
||||
RequiringClaims =
|
||||
[
|
||||
new ClaimRequirement { Type = "original", Value = "claim" }
|
||||
]
|
||||
}
|
||||
};
|
||||
var yamlConfig = new MicroserviceYamlConfig
|
||||
{
|
||||
Endpoints =
|
||||
[
|
||||
new EndpointOverrideConfig
|
||||
{
|
||||
Method = "GET",
|
||||
Path = "/api/test",
|
||||
RequiringClaims =
|
||||
[
|
||||
new ClaimRequirementConfig { Type = "new", Value = "claim1" },
|
||||
new ClaimRequirementConfig { Type = "new", Value = "claim2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var result = _merger.Merge(codeEndpoints, yamlConfig);
|
||||
|
||||
result[0].RequiringClaims.Should().HaveCount(2);
|
||||
result[0].RequiringClaims!.All(c => c.Type == "new").Should().BeTrue();
|
||||
}
|
||||
|
||||
private static EndpointDescriptor CreateEndpoint(
|
||||
string method,
|
||||
string path,
|
||||
TimeSpan timeout,
|
||||
bool supportsStreaming = false)
|
||||
{
|
||||
return new EndpointDescriptor
|
||||
{
|
||||
ServiceName = "test-service",
|
||||
Version = "1.0.0",
|
||||
Method = method,
|
||||
Path = path,
|
||||
DefaultTimeout = timeout,
|
||||
SupportsStreaming = supportsStreaming
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user