using Grpc.Core;
using Mishima.Nexus.Wire.V1;
namespace Robotico.Nexus.Client.Tests.TestSupport;
///
/// In-memory fake standing in for a real Nexus graph engine host, exercising the exact wire
/// contract / NexusGraphSession
/// depend on. Ping honors database-name sentinels so tests
/// can drive both the happy path and the failure branches of the client.
///
public sealed class FakeGraphEngineService : NexusGraphEngineService.NexusGraphEngineServiceBase
{
private readonly Dictionary> _vertexLabels = [];
private readonly HashSet _registeredLabels = [];
private readonly HashSet _registeredEdgeTypes = [];
private readonly HashSet<(ulong Source, ulong Target, string EdgeType)> _edges = [];
private ulong _txn;
///
public override Task Ping(GraphPingRequest request, ServerCallContext context)
{
NexusStatus? failure = FakeNexusTriggers.TryStatusFailure(context);
if (failure is not null)
{
return Task.FromResult(new GraphPingResponse { Status = failure, EngineVersion = "fake" });
}
return Task.FromResult(new GraphPingResponse { Status = NexusStatuses.Ok, EngineVersion = "fake" });
}
///
public override Task RegisterLabel(GraphRegisterLabelRequest request, ServerCallContext context)
{
_registeredLabels.Add(request.LabelName);
return Task.FromResult(new GraphRegisterLabelResponse { Status = NexusStatuses.Ok });
}
///
public override Task RegisterEdgeType(GraphRegisterEdgeTypeRequest request, ServerCallContext context)
{
_registeredEdgeTypes.Add(request.EdgeTypeName);
return Task.FromResult(new GraphRegisterEdgeTypeResponse { Status = NexusStatuses.Ok });
}
///
public override Task UpsertVertex(GraphUpsertVertexRequest request, ServerCallContext context)
{
_vertexLabels[request.VertexId] = [.. request.LabelNames];
return Task.FromResult(new GraphUpsertVertexResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
}
///
public override Task DeleteVertex(GraphDeleteVertexRequest request, ServerCallContext context)
{
_vertexLabels.Remove(request.VertexId);
return Task.FromResult(new GraphDeleteVertexResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
}
///
public override Task GetVertex(GraphGetVertexRequest request, ServerCallContext context)
{
if (!_vertexLabels.TryGetValue(request.VertexId, out List? labels))
{
return Task.FromResult(new GraphGetVertexResponse { Status = NexusStatuses.NotFound($"Vertex {request.VertexId} not found.") });
}
GraphGetVertexResponse response = new() { Status = NexusStatuses.Ok, VertexId = request.VertexId };
response.LabelNames.AddRange(labels);
return Task.FromResult(response);
}
///
public override Task UpsertEdge(GraphUpsertEdgeRequest request, ServerCallContext context)
{
_edges.Add((request.SourceVertexId, request.TargetVertexId, request.EdgeTypeName));
return Task.FromResult(new GraphUpsertEdgeResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
}
///
public override Task DeleteEdge(GraphDeleteEdgeRequest request, ServerCallContext context)
{
_edges.Remove((request.SourceVertexId, request.TargetVertexId, request.EdgeTypeName));
return Task.FromResult(new GraphDeleteEdgeResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
}
///
public override Task GetEdge(GraphGetEdgeRequest request, ServerCallContext context)
{
(ulong, ulong, string) key = (request.SourceVertexId, request.TargetVertexId, request.EdgeTypeName);
if (!_edges.Contains(key))
{
return Task.FromResult(new GraphGetEdgeResponse { Status = NexusStatuses.NotFound("Edge not found.") });
}
return Task.FromResult(new GraphGetEdgeResponse
{
Status = NexusStatuses.Ok,
SourceVertexId = request.SourceVertexId,
TargetVertexId = request.TargetVertexId,
EdgeTypeName = request.EdgeTypeName,
});
}
///
public override Task BreadthFirst(GraphBreadthFirstRequest request, ServerCallContext context)
{
GraphBreadthFirstResponse response = new() { Status = NexusStatuses.Ok };
response.VisitOrder.Add(request.StartVertexId);
response.DistanceByVertex.Add(request.StartVertexId, 0);
return Task.FromResult(response);
}
///
public override Task ListVerticesByLabel(GraphListVerticesByLabelRequest request, ServerCallContext context)
{
List matches = [.. _vertexLabels
.Where(pair => pair.Value.Contains(request.LabelName))
.Select(pair =>
{
GraphVertexWire wire = new() { VertexId = pair.Key };
wire.LabelNames.AddRange(pair.Value);
return wire;
})];
GraphListVerticesByLabelResponse response = new()
{
Status = NexusStatuses.Ok,
LabelName = request.LabelName,
TotalMatching = matches.Count,
Skip = request.Skip,
Limit = request.Limit,
};
response.Vertices.AddRange(matches.Skip(request.Skip).Take(request.Limit is 0 ? matches.Count : request.Limit));
return Task.FromResult(response);
}
}