122 lines
4.2 KiB
C#
122 lines
4.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using StellaOps.Graph.Api.Contracts;
|
|
using StellaOps.Graph.Api.Services;
|
|
using Xunit;
|
|
|
|
|
|
using StellaOps.TestKit;
|
|
namespace StellaOps.Graph.Api.Tests;
|
|
|
|
public class QueryServiceTests
|
|
{
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task QueryAsync_EmitsNodesEdgesStatsAndCursor()
|
|
{
|
|
var repo = new InMemoryGraphRepository();
|
|
var service = CreateService(repo);
|
|
|
|
var request = new GraphQueryRequest
|
|
{
|
|
Kinds = new[] { "component", "artifact" },
|
|
Query = "component",
|
|
Limit = 1,
|
|
IncludeEdges = true,
|
|
IncludeStats = true
|
|
};
|
|
|
|
var lines = new List<string>();
|
|
await foreach (var line in service.QueryAsync("acme", request))
|
|
{
|
|
lines.Add(line);
|
|
}
|
|
|
|
Assert.Contains(lines, l => l.Contains("\"type\":\"node\""));
|
|
Assert.Contains(lines, l => l.Contains("\"type\":\"edge\""));
|
|
Assert.Contains(lines, l => l.Contains("\"type\":\"stats\""));
|
|
Assert.Contains(lines, l => l.Contains("\"type\":\"cursor\""));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task QueryAsync_ReturnsBudgetExceededError()
|
|
{
|
|
var repo = new InMemoryGraphRepository();
|
|
var service = CreateService(repo);
|
|
|
|
var request = new GraphQueryRequest
|
|
{
|
|
Kinds = new[] { "component", "artifact" },
|
|
Query = "component",
|
|
Budget = new GraphQueryBudget { Nodes = 1, Edges = 0, Tiles = 2 },
|
|
Limit = 10
|
|
};
|
|
|
|
var lines = new List<string>();
|
|
await foreach (var line in service.QueryAsync("acme", request))
|
|
{
|
|
lines.Add(line);
|
|
}
|
|
|
|
Assert.Single(lines);
|
|
Assert.Contains("GRAPH_BUDGET_EXCEEDED", lines[0]);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task QueryAsync_IncludesOverlaysAndSamplesExplainOnce()
|
|
{
|
|
var repo = new InMemoryGraphRepository(new[]
|
|
{
|
|
new NodeTile { Id = "gn:acme:component:one", Kind = "component", Tenant = "acme" },
|
|
new NodeTile { Id = "gn:acme:component:two", Kind = "component", Tenant = "acme" }
|
|
}, Array.Empty<EdgeTile>());
|
|
|
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
|
var metrics = new GraphMetrics();
|
|
var overlays = new InMemoryOverlayService(cache, metrics);
|
|
var service = new InMemoryGraphQueryService(repo, cache, overlays, metrics);
|
|
var request = new GraphQueryRequest
|
|
{
|
|
Kinds = new[] { "component" },
|
|
IncludeOverlays = true,
|
|
Limit = 5
|
|
};
|
|
|
|
var overlayNodes = 0;
|
|
var explainCount = 0;
|
|
|
|
await foreach (var line in service.QueryAsync("acme", request))
|
|
{
|
|
if (!line.Contains("\"type\":\"node\"")) continue;
|
|
using var doc = JsonDocument.Parse(line);
|
|
var data = doc.RootElement.GetProperty("data");
|
|
if (data.TryGetProperty("overlays", out var overlaysElement) && overlaysElement.ValueKind == JsonValueKind.Object)
|
|
{
|
|
overlayNodes++;
|
|
foreach (var overlay in overlaysElement.EnumerateObject())
|
|
{
|
|
if (overlay.Value.ValueKind != JsonValueKind.Object) continue;
|
|
if (overlay.Value.TryGetProperty("data", out var payload) && payload.TryGetProperty("explainTrace", out var trace) && trace.ValueKind == JsonValueKind.Array)
|
|
{
|
|
explainCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert.True(overlayNodes >= 1);
|
|
Assert.Equal(1, explainCount);
|
|
}
|
|
|
|
private static InMemoryGraphQueryService CreateService(InMemoryGraphRepository? repository = null)
|
|
{
|
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
|
var metrics = new GraphMetrics();
|
|
var overlays = new InMemoryOverlayService(cache, metrics);
|
|
return new InMemoryGraphQueryService(repository ?? new InMemoryGraphRepository(), cache, overlays, metrics);
|
|
}
|
|
}
|