Move 39 monitoring, events, and system endpoint test files from NATS.Server.Tests into a dedicated NATS.Server.Monitoring.Tests project. Update namespaces, replace private GetFreePort/ReadUntilAsync with TestUtilities shared helpers, add InternalsVisibleTo, and register in the solution file. All 439 tests pass.
470 lines
18 KiB
C#
470 lines
18 KiB
C#
using System.Text.Json;
|
|
using NATS.Server.Events;
|
|
|
|
namespace NATS.Server.Monitoring.Tests.Events;
|
|
|
|
/// <summary>
|
|
/// Tests that all event DTOs have complete JSON fields matching Go's output.
|
|
/// Go reference: events.go:100-300 — TypedEvent, ServerInfo, ClientInfo,
|
|
/// DataStats, ServerStats, ConnectEventMsg, DisconnectEventMsg, AccountNumConns.
|
|
/// </summary>
|
|
public class EventPayloadTests
|
|
{
|
|
// --- EventServerInfo ---
|
|
|
|
[Fact]
|
|
public void EventServerInfo_serializes_all_fields_matching_Go()
|
|
{
|
|
var info = new EventServerInfo
|
|
{
|
|
Name = "test-server",
|
|
Host = "127.0.0.1",
|
|
Id = "ABCDEF123456",
|
|
Cluster = "test-cluster",
|
|
Domain = "test-domain",
|
|
Version = "2.10.0",
|
|
Tags = ["tag1", "tag2"],
|
|
Metadata = new Dictionary<string, string> { ["env"] = "test" },
|
|
JetStream = true,
|
|
Flags = 1,
|
|
Seq = 42,
|
|
Time = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(info);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("name").GetString().ShouldBe("test-server");
|
|
root.GetProperty("host").GetString().ShouldBe("127.0.0.1");
|
|
root.GetProperty("id").GetString().ShouldBe("ABCDEF123456");
|
|
root.GetProperty("cluster").GetString().ShouldBe("test-cluster");
|
|
root.GetProperty("domain").GetString().ShouldBe("test-domain");
|
|
root.GetProperty("ver").GetString().ShouldBe("2.10.0");
|
|
root.GetProperty("tags").GetArrayLength().ShouldBe(2);
|
|
root.GetProperty("metadata").GetProperty("env").GetString().ShouldBe("test");
|
|
root.GetProperty("jetstream").GetBoolean().ShouldBeTrue();
|
|
root.GetProperty("flags").GetUInt64().ShouldBe(1UL);
|
|
root.GetProperty("seq").GetUInt64().ShouldBe(42UL);
|
|
root.GetProperty("time").GetDateTime().Year.ShouldBe(2025);
|
|
}
|
|
|
|
[Fact]
|
|
public void EventServerInfo_omits_null_optional_fields()
|
|
{
|
|
var info = new EventServerInfo
|
|
{
|
|
Name = "s",
|
|
Id = "ID",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(info);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.TryGetProperty("cluster", out _).ShouldBeFalse();
|
|
root.TryGetProperty("domain", out _).ShouldBeFalse();
|
|
root.TryGetProperty("tags", out _).ShouldBeFalse();
|
|
root.TryGetProperty("metadata", out _).ShouldBeFalse();
|
|
}
|
|
|
|
// --- EventClientInfo ---
|
|
|
|
[Fact]
|
|
public void EventClientInfo_serializes_all_fields_matching_Go()
|
|
{
|
|
var ci = new EventClientInfo
|
|
{
|
|
Start = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
|
Stop = new DateTime(2025, 1, 1, 1, 0, 0, DateTimeKind.Utc),
|
|
Host = "10.0.0.1",
|
|
Id = 99,
|
|
Account = "$G",
|
|
Service = "orders",
|
|
User = "admin",
|
|
Name = "my-client",
|
|
Lang = "go",
|
|
Version = "1.30.0",
|
|
RttNanos = 5_000_000, // 5ms
|
|
Server = "srv-1",
|
|
Cluster = "cluster-east",
|
|
Alternates = ["alt1", "alt2"],
|
|
Jwt = "eyJ...",
|
|
IssuerKey = "OABC...",
|
|
NameTag = "test-tag",
|
|
Tags = ["dev"],
|
|
Kind = "Client",
|
|
ClientType = "nats",
|
|
MqttClient = "mqtt-abc",
|
|
Nonce = "nonce123",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(ci);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("host").GetString().ShouldBe("10.0.0.1");
|
|
root.GetProperty("id").GetUInt64().ShouldBe(99UL);
|
|
root.GetProperty("acc").GetString().ShouldBe("$G");
|
|
root.GetProperty("svc").GetString().ShouldBe("orders");
|
|
root.GetProperty("user").GetString().ShouldBe("admin");
|
|
root.GetProperty("name").GetString().ShouldBe("my-client");
|
|
root.GetProperty("lang").GetString().ShouldBe("go");
|
|
root.GetProperty("ver").GetString().ShouldBe("1.30.0");
|
|
root.GetProperty("rtt").GetInt64().ShouldBe(5_000_000);
|
|
root.GetProperty("server").GetString().ShouldBe("srv-1");
|
|
root.GetProperty("cluster").GetString().ShouldBe("cluster-east");
|
|
root.GetProperty("alts").GetArrayLength().ShouldBe(2);
|
|
root.GetProperty("jwt").GetString().ShouldBe("eyJ...");
|
|
root.GetProperty("issuer_key").GetString().ShouldBe("OABC...");
|
|
root.GetProperty("name_tag").GetString().ShouldBe("test-tag");
|
|
root.GetProperty("tags").GetArrayLength().ShouldBe(1);
|
|
root.GetProperty("kind").GetString().ShouldBe("Client");
|
|
root.GetProperty("client_type").GetString().ShouldBe("nats");
|
|
root.GetProperty("client_id").GetString().ShouldBe("mqtt-abc");
|
|
root.GetProperty("nonce").GetString().ShouldBe("nonce123");
|
|
}
|
|
|
|
[Fact]
|
|
public void EventClientInfo_omits_null_optional_fields()
|
|
{
|
|
var ci = new EventClientInfo { Id = 1 };
|
|
var json = JsonSerializer.Serialize(ci);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.TryGetProperty("svc", out _).ShouldBeFalse();
|
|
root.TryGetProperty("user", out _).ShouldBeFalse();
|
|
root.TryGetProperty("server", out _).ShouldBeFalse();
|
|
root.TryGetProperty("cluster", out _).ShouldBeFalse();
|
|
root.TryGetProperty("alts", out _).ShouldBeFalse();
|
|
root.TryGetProperty("jwt", out _).ShouldBeFalse();
|
|
root.TryGetProperty("issuer_key", out _).ShouldBeFalse();
|
|
root.TryGetProperty("nonce", out _).ShouldBeFalse();
|
|
}
|
|
|
|
// --- DataStats ---
|
|
|
|
[Fact]
|
|
public void DataStats_serializes_with_optional_sub_stats()
|
|
{
|
|
var ds = new DataStats
|
|
{
|
|
Msgs = 100,
|
|
Bytes = 2048,
|
|
Gateways = new MsgBytesStats { Msgs = 10, Bytes = 256 },
|
|
Routes = new MsgBytesStats { Msgs = 50, Bytes = 1024 },
|
|
Leafs = new MsgBytesStats { Msgs = 40, Bytes = 768 },
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(ds);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("msgs").GetInt64().ShouldBe(100);
|
|
root.GetProperty("bytes").GetInt64().ShouldBe(2048);
|
|
root.GetProperty("gateways").GetProperty("msgs").GetInt64().ShouldBe(10);
|
|
root.GetProperty("routes").GetProperty("bytes").GetInt64().ShouldBe(1024);
|
|
root.GetProperty("leafs").GetProperty("msgs").GetInt64().ShouldBe(40);
|
|
}
|
|
|
|
[Fact]
|
|
public void DataStats_omits_null_sub_stats()
|
|
{
|
|
var ds = new DataStats { Msgs = 5, Bytes = 50 };
|
|
var json = JsonSerializer.Serialize(ds);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.TryGetProperty("gateways", out _).ShouldBeFalse();
|
|
root.TryGetProperty("routes", out _).ShouldBeFalse();
|
|
root.TryGetProperty("leafs", out _).ShouldBeFalse();
|
|
}
|
|
|
|
// --- ConnectEventMsg ---
|
|
|
|
[Fact]
|
|
public void ConnectEventMsg_has_correct_type_and_required_fields()
|
|
{
|
|
var evt = new ConnectEventMsg
|
|
{
|
|
Id = "evt-1",
|
|
Time = DateTime.UtcNow,
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Client = new EventClientInfo { Id = 42, Name = "test-client" },
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("type").GetString().ShouldBe("io.nats.server.advisory.v1.client_connect");
|
|
root.GetProperty("id").GetString().ShouldBe("evt-1");
|
|
root.GetProperty("server").GetProperty("name").GetString().ShouldBe("s1");
|
|
root.GetProperty("client").GetProperty("id").GetUInt64().ShouldBe(42UL);
|
|
}
|
|
|
|
// --- DisconnectEventMsg ---
|
|
|
|
[Fact]
|
|
public void DisconnectEventMsg_has_correct_type_and_data_stats()
|
|
{
|
|
var evt = new DisconnectEventMsg
|
|
{
|
|
Id = "evt-2",
|
|
Time = DateTime.UtcNow,
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Client = new EventClientInfo { Id = 42 },
|
|
Sent = new DataStats { Msgs = 100, Bytes = 2000 },
|
|
Received = new DataStats { Msgs = 50, Bytes = 1000 },
|
|
Reason = "Client Closed",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("type").GetString().ShouldBe("io.nats.server.advisory.v1.client_disconnect");
|
|
root.GetProperty("sent").GetProperty("msgs").GetInt64().ShouldBe(100);
|
|
root.GetProperty("received").GetProperty("bytes").GetInt64().ShouldBe(1000);
|
|
root.GetProperty("reason").GetString().ShouldBe("Client Closed");
|
|
}
|
|
|
|
// --- AccountNumConns ---
|
|
|
|
[Fact]
|
|
public void AccountNumConns_serializes_all_Go_AccountStat_fields()
|
|
{
|
|
var evt = new AccountNumConns
|
|
{
|
|
Id = "evt-3",
|
|
Time = DateTime.UtcNow,
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
AccountName = "$G",
|
|
Name = "Global",
|
|
Connections = 5,
|
|
LeafNodes = 2,
|
|
TotalConnections = 100,
|
|
NumSubscriptions = 42,
|
|
Sent = new DataStats { Msgs = 500, Bytes = 10_000 },
|
|
Received = new DataStats { Msgs = 400, Bytes = 8_000 },
|
|
SlowConsumers = 1,
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("type").GetString().ShouldBe("io.nats.server.advisory.v1.account_connections");
|
|
root.GetProperty("acc").GetString().ShouldBe("$G");
|
|
root.GetProperty("name").GetString().ShouldBe("Global");
|
|
root.GetProperty("conns").GetInt32().ShouldBe(5);
|
|
root.GetProperty("leafnodes").GetInt32().ShouldBe(2);
|
|
root.GetProperty("total_conns").GetInt32().ShouldBe(100);
|
|
root.GetProperty("num_subscriptions").GetUInt32().ShouldBe(42u);
|
|
root.GetProperty("sent").GetProperty("msgs").GetInt64().ShouldBe(500);
|
|
root.GetProperty("received").GetProperty("bytes").GetInt64().ShouldBe(8_000);
|
|
root.GetProperty("slow_consumers").GetInt64().ShouldBe(1);
|
|
}
|
|
|
|
// --- ServerStatsMsg ---
|
|
|
|
[Fact]
|
|
public void ServerStatsMsg_has_sent_received_and_breakdown_fields()
|
|
{
|
|
var msg = new ServerStatsMsg
|
|
{
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1", Seq = 1 },
|
|
Stats = new ServerStatsData
|
|
{
|
|
Start = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
|
Mem = 100_000_000,
|
|
Cores = 8,
|
|
Cpu = 12.5,
|
|
Connections = 10,
|
|
TotalConnections = 500,
|
|
ActiveAccounts = 3,
|
|
Subscriptions = 50,
|
|
Sent = new DataStats { Msgs = 1000, Bytes = 50_000 },
|
|
Received = new DataStats { Msgs = 800, Bytes = 40_000 },
|
|
InMsgs = 800,
|
|
OutMsgs = 1000,
|
|
InBytes = 40_000,
|
|
OutBytes = 50_000,
|
|
SlowConsumers = 2,
|
|
SlowConsumerStats = new NATS.Server.Events.SlowConsumersStats { Clients = 1, Routes = 1 },
|
|
StaleConnections = 3,
|
|
StaleConnectionStats = new NATS.Server.Events.StaleConnectionStats { Clients = 2, Leafs = 1 },
|
|
ActiveServers = 3,
|
|
Routes = [new RouteStat { Id = 1, Name = "r1", Sent = new DataStats { Msgs = 10 }, Received = new DataStats { Msgs = 5 }, Pending = 0 }],
|
|
Gateways = [new GatewayStat { Id = 1, Name = "gw1", Sent = new DataStats { Msgs = 20 }, Received = new DataStats { Msgs = 15 }, InboundConnections = 2 }],
|
|
},
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(msg);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
var stats = root.GetProperty("statsz");
|
|
|
|
stats.GetProperty("mem").GetInt64().ShouldBe(100_000_000);
|
|
stats.GetProperty("cores").GetInt32().ShouldBe(8);
|
|
stats.GetProperty("cpu").GetDouble().ShouldBe(12.5);
|
|
stats.GetProperty("connections").GetInt32().ShouldBe(10);
|
|
stats.GetProperty("total_connections").GetInt64().ShouldBe(500);
|
|
stats.GetProperty("active_accounts").GetInt32().ShouldBe(3);
|
|
stats.GetProperty("subscriptions").GetInt64().ShouldBe(50);
|
|
stats.GetProperty("sent").GetProperty("msgs").GetInt64().ShouldBe(1000);
|
|
stats.GetProperty("received").GetProperty("bytes").GetInt64().ShouldBe(40_000);
|
|
stats.GetProperty("in_msgs").GetInt64().ShouldBe(800);
|
|
stats.GetProperty("out_msgs").GetInt64().ShouldBe(1000);
|
|
stats.GetProperty("slow_consumers").GetInt64().ShouldBe(2);
|
|
stats.GetProperty("slow_consumer_stats").GetProperty("clients").GetInt64().ShouldBe(1);
|
|
stats.GetProperty("stale_connections").GetInt64().ShouldBe(3);
|
|
stats.GetProperty("stale_connection_stats").GetProperty("leafs").GetInt64().ShouldBe(1);
|
|
stats.GetProperty("active_servers").GetInt32().ShouldBe(3);
|
|
stats.GetProperty("routes").GetArrayLength().ShouldBe(1);
|
|
stats.GetProperty("routes")[0].GetProperty("rid").GetUInt64().ShouldBe(1UL);
|
|
stats.GetProperty("gateways").GetArrayLength().ShouldBe(1);
|
|
stats.GetProperty("gateways")[0].GetProperty("name").GetString().ShouldBe("gw1");
|
|
}
|
|
|
|
// --- AuthErrorEventMsg ---
|
|
|
|
[Fact]
|
|
public void AuthErrorEventMsg_has_correct_type()
|
|
{
|
|
var evt = new AuthErrorEventMsg
|
|
{
|
|
Id = "evt-4",
|
|
Time = DateTime.UtcNow,
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Client = new EventClientInfo { Id = 99, Host = "10.0.0.1" },
|
|
Reason = "Authorization Violation",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("type").GetString().ShouldBe("io.nats.server.advisory.v1.client_auth");
|
|
root.GetProperty("reason").GetString().ShouldBe("Authorization Violation");
|
|
root.GetProperty("client").GetProperty("host").GetString().ShouldBe("10.0.0.1");
|
|
}
|
|
|
|
// --- OcspPeerRejectEventMsg ---
|
|
|
|
[Fact]
|
|
public void OcspPeerRejectEventMsg_has_correct_type()
|
|
{
|
|
var evt = new OcspPeerRejectEventMsg
|
|
{
|
|
Id = "evt-5",
|
|
Time = DateTime.UtcNow,
|
|
Kind = "client",
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Reason = "OCSP revoked",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
root.GetProperty("type").GetString().ShouldBe("io.nats.server.advisory.v1.ocsp_peer_reject");
|
|
root.GetProperty("kind").GetString().ShouldBe("client");
|
|
root.GetProperty("reason").GetString().ShouldBe("OCSP revoked");
|
|
}
|
|
|
|
// --- ShutdownEventMsg ---
|
|
|
|
[Fact]
|
|
public void ShutdownEventMsg_serializes_reason()
|
|
{
|
|
var evt = new ShutdownEventMsg
|
|
{
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Reason = "Server Shutdown",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(evt);
|
|
var doc = JsonDocument.Parse(json);
|
|
doc.RootElement.GetProperty("reason").GetString().ShouldBe("Server Shutdown");
|
|
}
|
|
|
|
// --- AccNumConnsReq ---
|
|
|
|
[Fact]
|
|
public void AccNumConnsReq_serializes_account()
|
|
{
|
|
var req = new AccNumConnsReq
|
|
{
|
|
Server = new EventServerInfo { Name = "s1", Id = "SRV1" },
|
|
Account = "myAccount",
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(req);
|
|
var doc = JsonDocument.Parse(json);
|
|
doc.RootElement.GetProperty("acc").GetString().ShouldBe("myAccount");
|
|
}
|
|
|
|
// --- Round-trip deserialization ---
|
|
|
|
[Fact]
|
|
public void ConnectEventMsg_roundtrips_through_json()
|
|
{
|
|
var original = new ConnectEventMsg
|
|
{
|
|
Id = "rt-1",
|
|
Time = new DateTime(2025, 6, 15, 12, 0, 0, DateTimeKind.Utc),
|
|
Server = new EventServerInfo { Name = "srv", Id = "SRV1", Version = "2.10.0", Seq = 5 },
|
|
Client = new EventClientInfo
|
|
{
|
|
Id = 42,
|
|
Host = "10.0.0.1",
|
|
Account = "$G",
|
|
Name = "test",
|
|
Lang = "dotnet",
|
|
Version = "1.0.0",
|
|
RttNanos = 1_000_000,
|
|
Kind = "Client",
|
|
},
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(original);
|
|
var deserialized = JsonSerializer.Deserialize<ConnectEventMsg>(json);
|
|
|
|
deserialized.ShouldNotBeNull();
|
|
deserialized.Type.ShouldBe(ConnectEventMsg.EventType);
|
|
deserialized.Id.ShouldBe("rt-1");
|
|
deserialized.Server.Name.ShouldBe("srv");
|
|
deserialized.Server.Seq.ShouldBe(5UL);
|
|
deserialized.Client.Id.ShouldBe(42UL);
|
|
deserialized.Client.Kind.ShouldBe("Client");
|
|
deserialized.Client.RttNanos.ShouldBe(1_000_000);
|
|
}
|
|
|
|
[Fact]
|
|
public void ServerStatsMsg_roundtrips_through_json()
|
|
{
|
|
var original = new ServerStatsMsg
|
|
{
|
|
Server = new EventServerInfo { Name = "srv", Id = "SRV1" },
|
|
Stats = new ServerStatsData
|
|
{
|
|
Connections = 10,
|
|
Sent = new DataStats { Msgs = 100, Bytes = 5000 },
|
|
Received = new DataStats { Msgs = 80, Bytes = 4000 },
|
|
InMsgs = 80,
|
|
OutMsgs = 100,
|
|
},
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(original);
|
|
var deserialized = JsonSerializer.Deserialize<ServerStatsMsg>(json);
|
|
|
|
deserialized.ShouldNotBeNull();
|
|
deserialized.Stats.Connections.ShouldBe(10);
|
|
deserialized.Stats.Sent.Msgs.ShouldBe(100);
|
|
deserialized.Stats.Received.Bytes.ShouldBe(4000);
|
|
}
|
|
}
|