up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-26 07:47:08 +02:00
parent 56e2f64d07
commit 1c782897f7
184 changed files with 8991 additions and 649 deletions

View File

@@ -0,0 +1,114 @@
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;
namespace StellaOps.Graph.Api.Tests;
public class QueryServiceTests
{
[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\""));
}
[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]);
}
[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 overlays = new InMemoryOverlayService(cache);
var service = new InMemoryGraphQueryService(repo, cache, overlays);
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 overlays = new InMemoryOverlayService(cache);
return new InMemoryGraphQueryService(repository ?? new InMemoryGraphRepository(), cache, overlays);
}
}