using System.Text.Json;
using NATS.Server.Events;
namespace NATS.Server.Monitoring.Tests.Events;
///
/// Tests for remote server and leaf node event DTOs and subject constants.
/// Go reference: events.go — remote server lifecycle, leaf node advisory subjects.
/// Gap 10.8: RemoteServerShutdown, RemoteServerUpdate, LeafNodeConnected events.
///
public class RemoteServerEventTests
{
// --- RemoteServerShutdownEvent ---
[Fact]
public void RemoteServerShutdownEvent_HasCorrectEventType()
{
RemoteServerShutdownEvent.EventType.ShouldBe("io.nats.server.advisory.v1.remote_shutdown");
var ev = new RemoteServerShutdownEvent();
ev.Type.ShouldBe(RemoteServerShutdownEvent.EventType);
}
[Fact]
public void RemoteServerShutdownEvent_GeneratesUniqueId()
{
var ev1 = new RemoteServerShutdownEvent();
var ev2 = new RemoteServerShutdownEvent();
ev1.Id.ShouldNotBeNullOrEmpty();
ev2.Id.ShouldNotBeNullOrEmpty();
ev1.Id.ShouldNotBe(ev2.Id);
}
// --- RemoteServerUpdateEvent ---
[Fact]
public void RemoteServerUpdateEvent_HasCorrectEventType()
{
RemoteServerUpdateEvent.EventType.ShouldBe("io.nats.server.advisory.v1.remote_update");
var ev = new RemoteServerUpdateEvent();
ev.Type.ShouldBe(RemoteServerUpdateEvent.EventType);
}
[Fact]
public void RemoteServerUpdateEvent_AllFieldsSettable()
{
var server = new EventServerInfo { Id = "srv1", Name = "my-server" };
var ev = new RemoteServerUpdateEvent
{
Server = server,
RemoteServerId = "remote-id-123",
RemoteServerName = "remote-server",
UpdateType = "routes_changed",
};
ev.Server.ShouldBeSameAs(server);
ev.RemoteServerId.ShouldBe("remote-id-123");
ev.RemoteServerName.ShouldBe("remote-server");
ev.UpdateType.ShouldBe("routes_changed");
}
// --- LeafNodeConnectEvent ---
[Fact]
public void LeafNodeConnectEvent_HasCorrectEventType()
{
LeafNodeConnectEvent.EventType.ShouldBe("io.nats.server.advisory.v1.leafnode_connect");
var ev = new LeafNodeConnectEvent();
ev.Type.ShouldBe(LeafNodeConnectEvent.EventType);
}
[Fact]
public void LeafNodeConnectEvent_AllFieldsSettable()
{
var server = new EventServerInfo { Id = "srv1", Name = "hub" };
var ev = new LeafNodeConnectEvent
{
Server = server,
LeafNodeId = "leaf-id-abc",
LeafNodeName = "leaf-node-1",
RemoteUrl = "nats://10.0.0.1:7422",
Account = "ACC",
};
ev.Server.ShouldBeSameAs(server);
ev.LeafNodeId.ShouldBe("leaf-id-abc");
ev.LeafNodeName.ShouldBe("leaf-node-1");
ev.RemoteUrl.ShouldBe("nats://10.0.0.1:7422");
ev.Account.ShouldBe("ACC");
}
// --- LeafNodeDisconnectEvent ---
[Fact]
public void LeafNodeDisconnectEvent_HasCorrectEventType()
{
LeafNodeDisconnectEvent.EventType.ShouldBe("io.nats.server.advisory.v1.leafnode_disconnect");
var ev = new LeafNodeDisconnectEvent();
ev.Type.ShouldBe(LeafNodeDisconnectEvent.EventType);
}
[Fact]
public void LeafNodeDisconnectEvent_AllFieldsSettable()
{
var server = new EventServerInfo { Id = "srv1", Name = "hub" };
var ev = new LeafNodeDisconnectEvent
{
Server = server,
LeafNodeId = "leaf-id-xyz",
Reason = "connection closed",
};
ev.Server.ShouldBeSameAs(server);
ev.LeafNodeId.ShouldBe("leaf-id-xyz");
ev.Reason.ShouldBe("connection closed");
}
// --- EventSubjects ---
[Fact]
public void EventSubjects_RemoteShutdown_HasPlaceholder()
{
EventSubjects.RemoteServerShutdown.ShouldContain("{0}");
EventSubjects.RemoteServerUpdate.ShouldContain("{0}");
EventSubjects.LeafNodeConnected.ShouldContain("{0}");
EventSubjects.LeafNodeDisconnected.ShouldContain("{0}");
// Verify format strings produce expected subjects when formatted
var serverId = "ABCDEF123456";
string.Format(EventSubjects.RemoteServerShutdown, serverId)
.ShouldBe($"$SYS.SERVER.{serverId}.REMOTE.SHUTDOWN");
string.Format(EventSubjects.LeafNodeConnected, serverId)
.ShouldBe($"$SYS.ACCOUNT.{serverId}.LEAFNODE.CONNECT");
}
// --- JSON serialization ---
[Fact]
public void AllRemoteEvents_SerializeToJson()
{
var server = new EventServerInfo { Id = "srv-id", Name = "test-server" };
var shutdown = new RemoteServerShutdownEvent
{
Server = server,
RemoteServerId = "r1",
RemoteServerName = "remote",
Reason = "graceful",
};
var shutdownJson = JsonSerializer.Serialize(shutdown);
var shutdownDoc = JsonDocument.Parse(shutdownJson).RootElement;
shutdownDoc.GetProperty("type").GetString().ShouldBe(RemoteServerShutdownEvent.EventType);
shutdownDoc.GetProperty("id").GetString().ShouldNotBeNullOrEmpty();
shutdownDoc.GetProperty("remote_server_id").GetString().ShouldBe("r1");
shutdownDoc.GetProperty("reason").GetString().ShouldBe("graceful");
var update = new RemoteServerUpdateEvent
{
Server = server,
RemoteServerId = "r2",
RemoteServerName = "remote2",
UpdateType = "config_updated",
};
var updateJson = JsonSerializer.Serialize(update);
var updateDoc = JsonDocument.Parse(updateJson).RootElement;
updateDoc.GetProperty("type").GetString().ShouldBe(RemoteServerUpdateEvent.EventType);
updateDoc.GetProperty("update_type").GetString().ShouldBe("config_updated");
var connect = new LeafNodeConnectEvent
{
Server = server,
LeafNodeId = "leaf1",
LeafNodeName = "leaf-node",
RemoteUrl = "nats://10.0.0.1:7422",
Account = "ACC",
};
var connectJson = JsonSerializer.Serialize(connect);
var connectDoc = JsonDocument.Parse(connectJson).RootElement;
connectDoc.GetProperty("type").GetString().ShouldBe(LeafNodeConnectEvent.EventType);
connectDoc.GetProperty("leaf_node_id").GetString().ShouldBe("leaf1");
connectDoc.GetProperty("account").GetString().ShouldBe("ACC");
var disconnect = new LeafNodeDisconnectEvent
{
Server = server,
LeafNodeId = "leaf1",
Reason = "timeout",
};
var disconnectJson = JsonSerializer.Serialize(disconnect);
var disconnectDoc = JsonDocument.Parse(disconnectJson).RootElement;
disconnectDoc.GetProperty("type").GetString().ShouldBe(LeafNodeDisconnectEvent.EventType);
disconnectDoc.GetProperty("leaf_node_id").GetString().ShouldBe("leaf1");
disconnectDoc.GetProperty("reason").GetString().ShouldBe("timeout");
// Roundtrip: deserialize back and verify type field survives
var shutdownRt = JsonSerializer.Deserialize(shutdownJson);
shutdownRt.ShouldNotBeNull();
shutdownRt!.Type.ShouldBe(RemoteServerShutdownEvent.EventType);
shutdownRt.RemoteServerId.ShouldBe("r1");
}
}