138 lines
5.9 KiB
C#
138 lines
5.9 KiB
C#
|
|
using Grpc.Core;
|
||
|
|
using Mishima.Nexus.Wire.V1;
|
||
|
|
|
||
|
|
namespace Robotico.Nexus.Client.Tests.TestSupport;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// In-memory fake standing in for a real Nexus graph engine host, exercising the exact wire
|
||
|
|
/// contract <see cref="Robotico.Nexus.Client.Graph.NexusGraphStore"/> / <c>NexusGraphSession</c>
|
||
|
|
/// depend on. <c>Ping</c> honors <see cref="FakeNexusTriggers"/> database-name sentinels so tests
|
||
|
|
/// can drive both the happy path and the failure branches of the client.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class FakeGraphEngineService : NexusGraphEngineService.NexusGraphEngineServiceBase
|
||
|
|
{
|
||
|
|
private readonly Dictionary<ulong, List<string>> _vertexLabels = [];
|
||
|
|
private readonly HashSet<string> _registeredLabels = [];
|
||
|
|
private readonly HashSet<string> _registeredEdgeTypes = [];
|
||
|
|
private readonly HashSet<(ulong Source, ulong Target, string EdgeType)> _edges = [];
|
||
|
|
private ulong _txn;
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphPingResponse> 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" });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphRegisterLabelResponse> RegisterLabel(GraphRegisterLabelRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_registeredLabels.Add(request.LabelName);
|
||
|
|
return Task.FromResult(new GraphRegisterLabelResponse { Status = NexusStatuses.Ok });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphRegisterEdgeTypeResponse> RegisterEdgeType(GraphRegisterEdgeTypeRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_registeredEdgeTypes.Add(request.EdgeTypeName);
|
||
|
|
return Task.FromResult(new GraphRegisterEdgeTypeResponse { Status = NexusStatuses.Ok });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphUpsertVertexResponse> UpsertVertex(GraphUpsertVertexRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_vertexLabels[request.VertexId] = [.. request.LabelNames];
|
||
|
|
return Task.FromResult(new GraphUpsertVertexResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphDeleteVertexResponse> DeleteVertex(GraphDeleteVertexRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_vertexLabels.Remove(request.VertexId);
|
||
|
|
return Task.FromResult(new GraphDeleteVertexResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphGetVertexResponse> GetVertex(GraphGetVertexRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
if (!_vertexLabels.TryGetValue(request.VertexId, out List<string>? 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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphUpsertEdgeResponse> UpsertEdge(GraphUpsertEdgeRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_edges.Add((request.SourceVertexId, request.TargetVertexId, request.EdgeTypeName));
|
||
|
|
return Task.FromResult(new GraphUpsertEdgeResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphDeleteEdgeResponse> DeleteEdge(GraphDeleteEdgeRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
_edges.Remove((request.SourceVertexId, request.TargetVertexId, request.EdgeTypeName));
|
||
|
|
return Task.FromResult(new GraphDeleteEdgeResponse { Status = NexusStatuses.Ok, CommittedTxnId = ++_txn });
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphGetEdgeResponse> 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,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphBreadthFirstResponse> 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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc />
|
||
|
|
public override Task<GraphListVerticesByLabelResponse> ListVerticesByLabel(GraphListVerticesByLabelRequest request, ServerCallContext context)
|
||
|
|
{
|
||
|
|
List<GraphVertexWire> 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);
|
||
|
|
}
|
||
|
|
}
|