Refactor and enhance tests for call graph extractors and connection management
- Updated JavaScriptCallGraphExtractorTests to improve naming conventions and test cases for Azure Functions, CLI commands, and socket handling. - Modified NodeCallGraphExtractorTests to correctly assert exceptions for null inputs. - Enhanced WitnessModalComponent tests in Angular to use Jasmine spies and improved assertions for path visualization and signature verification. - Added ConnectionState property for tracking connection establishment time in Router.Common. - Implemented validation for HelloPayload in ConnectionManager to ensure required fields are present. - Introduced RabbitMqContainerFixture method for restarting RabbitMQ container during tests. - Added integration tests for RabbitMq to verify connection recovery after broker restarts. - Created new BinaryCallGraphExtractorTests, GoCallGraphExtractorTests, and PythonCallGraphExtractorTests for comprehensive coverage of binary, Go, and Python call graph extraction functionalities. - Developed ConnectionManagerTests to validate connection handling, including rejection of invalid hello messages and proper cleanup on client disconnects.
This commit is contained in:
@@ -58,6 +58,17 @@ internal sealed class ConnectionManager : IHostedService
|
||||
|
||||
private Task HandleHelloReceivedAsync(ConnectionState connectionState, HelloPayload payload)
|
||||
{
|
||||
if (!TryValidateHelloPayload(payload, out var validationError))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Rejecting HELLO for connection {ConnectionId}: {Error}",
|
||||
connectionState.ConnectionId,
|
||||
validationError);
|
||||
|
||||
_connectionRegistry.RemoveChannel(connectionState.ConnectionId);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
_logger.LogInformation(
|
||||
"Connection registered: {ConnectionId} from {ServiceName}/{Version} with {EndpointCount} endpoints, {SchemaCount} schemas",
|
||||
connectionState.ConnectionId,
|
||||
@@ -78,6 +89,99 @@ internal sealed class ConnectionManager : IHostedService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static bool TryValidateHelloPayload(HelloPayload payload, out string error)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(payload.Instance.ServiceName))
|
||||
{
|
||||
error = "Instance.ServiceName is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(payload.Instance.Version))
|
||||
{
|
||||
error = "Instance.Version is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(payload.Instance.Region))
|
||||
{
|
||||
error = "Instance.Region is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(payload.Instance.InstanceId))
|
||||
{
|
||||
error = "Instance.InstanceId is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
var seen = new HashSet<(string Method, string Path)>(new EndpointKeyComparer());
|
||||
|
||||
foreach (var endpoint in payload.Endpoints)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(endpoint.Method))
|
||||
{
|
||||
error = "Endpoint.Method is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(endpoint.Path) || !endpoint.Path.StartsWith('/'))
|
||||
{
|
||||
error = "Endpoint.Path must start with '/'";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(endpoint.ServiceName, payload.Instance.ServiceName, StringComparison.OrdinalIgnoreCase) ||
|
||||
!string.Equals(endpoint.Version, payload.Instance.Version, StringComparison.Ordinal))
|
||||
{
|
||||
error = "Endpoint.ServiceName/Version must match HelloPayload.Instance";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!seen.Add((endpoint.Method, endpoint.Path)))
|
||||
{
|
||||
error = $"Duplicate endpoint registration for {endpoint.Method} {endpoint.Path}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endpoint.SchemaInfo is not null)
|
||||
{
|
||||
if (endpoint.SchemaInfo.RequestSchemaId is not null &&
|
||||
!payload.Schemas.ContainsKey(endpoint.SchemaInfo.RequestSchemaId))
|
||||
{
|
||||
error = $"Endpoint schema reference missing: requestSchemaId='{endpoint.SchemaInfo.RequestSchemaId}'";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endpoint.SchemaInfo.ResponseSchemaId is not null &&
|
||||
!payload.Schemas.ContainsKey(endpoint.SchemaInfo.ResponseSchemaId))
|
||||
{
|
||||
error = $"Endpoint schema reference missing: responseSchemaId='{endpoint.SchemaInfo.ResponseSchemaId}'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private sealed class EndpointKeyComparer : IEqualityComparer<(string Method, string Path)>
|
||||
{
|
||||
public bool Equals((string Method, string Path) x, (string Method, string Path) y)
|
||||
{
|
||||
return string.Equals(x.Method, y.Method, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(x.Path, y.Path, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public int GetHashCode((string Method, string Path) obj)
|
||||
{
|
||||
return HashCode.Combine(
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Method),
|
||||
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Path));
|
||||
}
|
||||
}
|
||||
|
||||
private Task HandleHeartbeatReceivedAsync(ConnectionState connectionState, HeartbeatPayload payload)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
|
||||
Reference in New Issue
Block a user