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:
@@ -0,0 +1,188 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// PythonCallGraphExtractorTests.cs
|
||||
// Sprint: SPRINT_3610_0004_0001_python_callgraph
|
||||
// Description: Unit tests for Python call graph extraction.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Scanner.CallGraph.Python;
|
||||
using StellaOps.Scanner.Reachability;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.CallGraph.Tests;
|
||||
|
||||
public class PythonCallGraphExtractorTests
|
||||
{
|
||||
[Fact]
|
||||
public void PythonEntrypointClassifier_ClassifiesFlaskRoute()
|
||||
{
|
||||
// Arrange
|
||||
var classifier = new PythonEntrypointClassifier();
|
||||
var node = new CallGraphNode(
|
||||
NodeId: "py:myapp/views.get_users",
|
||||
Symbol: "get_users",
|
||||
File: "views.py",
|
||||
Line: 10,
|
||||
Package: "myapp",
|
||||
Visibility: Visibility.Public,
|
||||
IsEntrypoint: false,
|
||||
EntrypointType: null,
|
||||
IsSink: false,
|
||||
SinkCategory: null);
|
||||
|
||||
var decorators = new[] { "@app.route('/users')", "@login_required" };
|
||||
|
||||
// Act
|
||||
var result = classifier.Classify(node, decorators);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasValue);
|
||||
Assert.Equal(EntrypointType.HttpHandler, result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonEntrypointClassifier_ClassifiesFastApiRoute()
|
||||
{
|
||||
// Arrange
|
||||
var classifier = new PythonEntrypointClassifier();
|
||||
var node = new CallGraphNode(
|
||||
NodeId: "py:api/endpoints.create_user",
|
||||
Symbol: "create_user",
|
||||
File: "endpoints.py",
|
||||
Line: 25,
|
||||
Package: "api",
|
||||
Visibility: Visibility.Public,
|
||||
IsEntrypoint: false,
|
||||
EntrypointType: null,
|
||||
IsSink: false,
|
||||
SinkCategory: null);
|
||||
|
||||
var decorators = new[] { "@router.post('/users')" };
|
||||
|
||||
// Act
|
||||
var result = classifier.Classify(node, decorators);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasValue);
|
||||
Assert.Equal(EntrypointType.HttpHandler, result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonEntrypointClassifier_ClassifiesCeleryTask()
|
||||
{
|
||||
// Arrange
|
||||
var classifier = new PythonEntrypointClassifier();
|
||||
var node = new CallGraphNode(
|
||||
NodeId: "py:tasks/email.send_notification",
|
||||
Symbol: "send_notification",
|
||||
File: "email.py",
|
||||
Line: 15,
|
||||
Package: "tasks",
|
||||
Visibility: Visibility.Public,
|
||||
IsEntrypoint: false,
|
||||
EntrypointType: null,
|
||||
IsSink: false,
|
||||
SinkCategory: null);
|
||||
|
||||
var decorators = new[] { "@app.task(bind=True)" };
|
||||
|
||||
// Act
|
||||
var result = classifier.Classify(node, decorators);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasValue);
|
||||
Assert.Equal(EntrypointType.BackgroundJob, result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonEntrypointClassifier_ClassifiesClickCommand()
|
||||
{
|
||||
// Arrange
|
||||
var classifier = new PythonEntrypointClassifier();
|
||||
var node = new CallGraphNode(
|
||||
NodeId: "py:cli/commands.deploy",
|
||||
Symbol: "deploy",
|
||||
File: "commands.py",
|
||||
Line: 50,
|
||||
Package: "cli",
|
||||
Visibility: Visibility.Public,
|
||||
IsEntrypoint: false,
|
||||
EntrypointType: null,
|
||||
IsSink: false,
|
||||
SinkCategory: null);
|
||||
|
||||
var decorators = new[] { "@cli.command()" };
|
||||
|
||||
// Act
|
||||
var result = classifier.Classify(node, decorators);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasValue);
|
||||
Assert.Equal(EntrypointType.CliCommand, result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonSinkMatcher_MatchesSubprocessCall()
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new PythonSinkMatcher();
|
||||
|
||||
// Act
|
||||
var result = matcher.Match("subprocess", "call");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SinkCategory.CmdExec, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonSinkMatcher_MatchesEval()
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new PythonSinkMatcher();
|
||||
|
||||
// Act
|
||||
var result = matcher.Match("builtins", "eval");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SinkCategory.CodeInjection, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonSinkMatcher_MatchesPickleLoads()
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new PythonSinkMatcher();
|
||||
|
||||
// Act
|
||||
var result = matcher.Match("pickle", "loads");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SinkCategory.UnsafeDeser, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonSinkMatcher_MatchesSqlAlchemyExecute()
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new PythonSinkMatcher();
|
||||
|
||||
// Act
|
||||
var result = matcher.Match("sqlalchemy.engine.Connection", "execute");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SinkCategory.SqlRaw, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PythonSinkMatcher_ReturnsNullForSafeFunction()
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new PythonSinkMatcher();
|
||||
|
||||
// Act
|
||||
var result = matcher.Match("myapp.utils", "format_string");
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user