feat: add stella-callgraph-node for JavaScript/TypeScript call graph extraction
- Implemented a new tool `stella-callgraph-node` that extracts call graphs from JavaScript/TypeScript projects using Babel AST. - Added command-line interface with options for JSON output and help. - Included functionality to analyze project structure, detect functions, and build call graphs. - Created a package.json file for dependency management. feat: introduce stella-callgraph-python for Python call graph extraction - Developed `stella-callgraph-python` to extract call graphs from Python projects using AST analysis. - Implemented command-line interface with options for JSON output and verbose logging. - Added framework detection to identify popular web frameworks and their entry points. - Created an AST analyzer to traverse Python code and extract function definitions and calls. - Included requirements.txt for project dependencies. chore: add framework detection for Python projects - Implemented framework detection logic to identify frameworks like Flask, FastAPI, Django, and others based on project files and import patterns. - Enhanced the AST analyzer to recognize entry points based on decorators and function definitions.
This commit is contained in:
164
tests/StellaOps.Microservice.Tests/RequestDispatcherTests.cs
Normal file
164
tests/StellaOps.Microservice.Tests/RequestDispatcherTests.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Router.Common.Frames;
|
||||
using StellaOps.Router.Common.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Microservice.Tests;
|
||||
|
||||
public sealed class RequestDispatcherTests
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_WhenEndpointNotFound_Returns404()
|
||||
{
|
||||
var registry = new EndpointRegistry();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var dispatcher = new RequestDispatcher(
|
||||
registry,
|
||||
provider,
|
||||
CreateLogger<RequestDispatcher>());
|
||||
|
||||
var response = await dispatcher.DispatchAsync(
|
||||
new RequestFrame
|
||||
{
|
||||
RequestId = "req-404",
|
||||
Method = "GET",
|
||||
Path = "/missing",
|
||||
Payload = ReadOnlyMemory<byte>.Empty
|
||||
},
|
||||
CancellationToken.None);
|
||||
|
||||
response.StatusCode.Should().Be(404);
|
||||
Encoding.UTF8.GetString(response.Payload.Span).Should().Be("Not Found");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_WhenBodyEmpty_BindsFromPathAndQueryParameters()
|
||||
{
|
||||
var registry = new EndpointRegistry();
|
||||
registry.Register(new EndpointDescriptor
|
||||
{
|
||||
ServiceName = "inventory",
|
||||
Version = "1.0.0",
|
||||
Method = "GET",
|
||||
Path = "/items/{id}",
|
||||
HandlerType = typeof(GetItemHandler)
|
||||
});
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddTransient<GetItemHandler>();
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var dispatcher = new RequestDispatcher(
|
||||
registry,
|
||||
provider,
|
||||
CreateLogger<RequestDispatcher>(),
|
||||
jsonOptions: JsonOptions);
|
||||
|
||||
var response = await dispatcher.DispatchAsync(
|
||||
new RequestFrame
|
||||
{
|
||||
RequestId = "req-params",
|
||||
Method = "GET",
|
||||
Path = "/items/123?filter=active",
|
||||
Payload = ReadOnlyMemory<byte>.Empty
|
||||
},
|
||||
CancellationToken.None);
|
||||
|
||||
response.StatusCode.Should().Be(200);
|
||||
response.Headers.Should().ContainKey("Content-Type");
|
||||
|
||||
var dto = JsonSerializer.Deserialize<GetItemResponse>(response.Payload.Span, JsonOptions);
|
||||
dto.Should().NotBeNull();
|
||||
dto!.Id.Should().Be(123);
|
||||
dto.Filter.Should().Be("active");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_WhenBodyPresent_PathAndQueryOverrideJsonProperties()
|
||||
{
|
||||
var registry = new EndpointRegistry();
|
||||
registry.Register(new EndpointDescriptor
|
||||
{
|
||||
ServiceName = "inventory",
|
||||
Version = "1.0.0",
|
||||
Method = "POST",
|
||||
Path = "/items/{id}",
|
||||
HandlerType = typeof(GetItemHandler)
|
||||
});
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddTransient<GetItemHandler>();
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var dispatcher = new RequestDispatcher(
|
||||
registry,
|
||||
provider,
|
||||
CreateLogger<RequestDispatcher>(),
|
||||
jsonOptions: JsonOptions);
|
||||
|
||||
var body = JsonSerializer.SerializeToUtf8Bytes(
|
||||
new GetItemRequest { Id = 999, Filter = "fromBody" },
|
||||
JsonOptions);
|
||||
|
||||
var response = await dispatcher.DispatchAsync(
|
||||
new RequestFrame
|
||||
{
|
||||
RequestId = "req-body",
|
||||
Method = "POST",
|
||||
Path = "/items/123?filter=active",
|
||||
Payload = body
|
||||
},
|
||||
CancellationToken.None);
|
||||
|
||||
response.StatusCode.Should().Be(200);
|
||||
|
||||
var dto = JsonSerializer.Deserialize<GetItemResponse>(response.Payload.Span, JsonOptions);
|
||||
dto.Should().NotBeNull();
|
||||
dto!.Id.Should().Be(123);
|
||||
dto.Filter.Should().Be("active");
|
||||
}
|
||||
|
||||
private static ILogger<T> CreateLogger<T>()
|
||||
{
|
||||
var factory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.None));
|
||||
return factory.CreateLogger<T>();
|
||||
}
|
||||
|
||||
private sealed class GetItemRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Filter { get; set; }
|
||||
}
|
||||
|
||||
private sealed class GetItemResponse
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Filter { get; set; }
|
||||
}
|
||||
|
||||
private sealed class GetItemHandler : IStellaEndpoint<GetItemRequest, GetItemResponse>
|
||||
{
|
||||
public Task<GetItemResponse> HandleAsync(GetItemRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new GetItemResponse
|
||||
{
|
||||
Id = request.Id,
|
||||
Filter = request.Filter
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user