Add GatewayCommands static class with wire-format byte sequences (GINFO, GS+, GS-, GMODE, GMSG, GPING, GPONG) and FormatSub/FormatUnsub/FormatMode/ParseCommandType helpers matching Go's gateway.go protocol constants. Add GatewayCommandType enum. 10 tests covering all wire formats and command parsing.
100 lines
3.4 KiB
C#
100 lines
3.4 KiB
C#
using System.Text;
|
|
using NATS.Server.Gateways;
|
|
using Shouldly;
|
|
|
|
namespace NATS.Server.Tests.Gateways;
|
|
|
|
// Go reference: gateway.go:90-120 — gateway protocol constants and command formatting.
|
|
|
|
public class GatewayCommandTests
|
|
{
|
|
[Fact]
|
|
public void FormatSub_produces_correct_wire_format()
|
|
{
|
|
// Go reference: gateway.go — RS+ propagation, sendGatewaySubsToGateway
|
|
var bytes = GatewayCommands.FormatSub("$G", "orders.>");
|
|
var line = Encoding.UTF8.GetString(bytes);
|
|
line.ShouldBe("GS+ $G orders.>\r\n");
|
|
}
|
|
|
|
[Fact]
|
|
public void FormatUnsub_produces_correct_wire_format()
|
|
{
|
|
// Go reference: gateway.go — RS- propagation, sendGatewayUnsubToGateway
|
|
var bytes = GatewayCommands.FormatUnsub("$G", "orders.>");
|
|
var line = Encoding.UTF8.GetString(bytes);
|
|
line.ShouldBe("GS- $G orders.>\r\n");
|
|
}
|
|
|
|
[Fact]
|
|
public void FormatMode_optimistic_produces_O()
|
|
{
|
|
// Go reference: gateway.go — GMODE command, "O" = Optimistic mode
|
|
var bytes = GatewayCommands.FormatMode("$G", GatewayInterestMode.Optimistic);
|
|
var line = Encoding.UTF8.GetString(bytes);
|
|
line.ShouldBe("GMODE $G O\r\n");
|
|
}
|
|
|
|
[Fact]
|
|
public void FormatMode_interest_only_produces_I()
|
|
{
|
|
// Go reference: gateway.go — GMODE command, "I" = InterestOnly mode
|
|
var bytes = GatewayCommands.FormatMode("$G", GatewayInterestMode.InterestOnly);
|
|
var line = Encoding.UTF8.GetString(bytes);
|
|
line.ShouldBe("GMODE $G I\r\n");
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseCommandType_identifies_sub()
|
|
{
|
|
// Go reference: gateway.go — processGatewayMsg dispatch on GS+
|
|
var line = Encoding.UTF8.GetBytes("GS+ ACC foo.bar\r\n");
|
|
var result = GatewayCommands.ParseCommandType(line);
|
|
result.ShouldBe(GatewayCommandType.Sub);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseCommandType_identifies_unsub()
|
|
{
|
|
// Go reference: gateway.go — processGatewayMsg dispatch on GS-
|
|
var line = Encoding.UTF8.GetBytes("GS- ACC foo.bar\r\n");
|
|
var result = GatewayCommands.ParseCommandType(line);
|
|
result.ShouldBe(GatewayCommandType.Unsub);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseCommandType_identifies_ping()
|
|
{
|
|
// Go reference: gateway.go — keepalive GPING command
|
|
var result = GatewayCommands.ParseCommandType(GatewayCommands.Ping);
|
|
result.ShouldBe(GatewayCommandType.Ping);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseCommandType_identifies_pong()
|
|
{
|
|
// Go reference: gateway.go — keepalive GPONG response
|
|
var result = GatewayCommands.ParseCommandType(GatewayCommands.Pong);
|
|
result.ShouldBe(GatewayCommandType.Pong);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseCommandType_returns_null_for_unknown()
|
|
{
|
|
// Unrecognized commands should return null for graceful handling
|
|
var line = Encoding.UTF8.GetBytes("UNKNOWN something\r\n");
|
|
var result = GatewayCommands.ParseCommandType(line);
|
|
result.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Wire_format_constants_end_correctly()
|
|
{
|
|
// Go reference: gateway.go — all gateway commands use CRLF line endings
|
|
var crlf = new byte[] { (byte)'\r', (byte)'\n' };
|
|
GatewayCommands.Ping.TakeLast(2).ShouldBe(crlf);
|
|
GatewayCommands.Pong.TakeLast(2).ShouldBe(crlf);
|
|
GatewayCommands.Crlf.ShouldBe(crlf);
|
|
}
|
|
}
|