A probe now links to the backend like an agent (probe.json carries the server address). The backend sends the agent list as desired state and the probe reports its platform and build in its own hello. The agent no longer relays the list or the probe platform. Existing probes must be re-created.
86 lines
3.1 KiB
C#
86 lines
3.1 KiB
C#
using Fleet.Core;
|
|
using Fleet.Hosting;
|
|
using Monitor.Protocol;
|
|
|
|
namespace Monitor.Probe.Tests;
|
|
|
|
public sealed class ProbeTests
|
|
{
|
|
[Fact]
|
|
public void ClockEstimator_UsesTheSampleWithTheShortestRoundTrip()
|
|
{
|
|
var clock = new ClockEstimator();
|
|
Assert.False(clock.HasEstimate);
|
|
|
|
// Offset 1000 with a 50 ms round trip, offset 5000 with a 2 ms round trip (symmetry assumption is far better here)
|
|
clock.Add(sendUs: 0, agentUs: 25_000 + 1000, receiveUs: 50_000);
|
|
clock.Add(sendUs: 100_000, agentUs: 101_000 + 5000, receiveUs: 102_000);
|
|
Assert.True(clock.HasEstimate);
|
|
Assert.Equal(5000, clock.OffsetUs);
|
|
|
|
// Slow samples do not displace the good one
|
|
clock.Add(sendUs: 200_000, agentUs: 300_000, receiveUs: 400_000);
|
|
Assert.Equal(5000, clock.OffsetUs);
|
|
}
|
|
|
|
private static string NewDirectory()
|
|
{
|
|
string path = Path.Combine(Path.GetTempPath(), "probe-tests-" + Guid.NewGuid().ToString("N"));
|
|
Directory.CreateDirectory(path);
|
|
return path;
|
|
}
|
|
|
|
private static ProbeAgentList List(long version, params string[] ids) => new()
|
|
{
|
|
Version = version,
|
|
Agents = [.. ids.Select(id => new AgentEndpoint { AgentId = new NodeId(id), Host = id + ".example", TcpPort = 7443, Spki = "c3BraQ==" })],
|
|
};
|
|
|
|
[Fact]
|
|
public void AgentDirectory_StartsEmpty_IgnoresStaleLists_PersistsChanges_AndReloadsThem()
|
|
{
|
|
string directory = NewDirectory();
|
|
try
|
|
{
|
|
var directoryA = new AgentDirectory(new ConfigStore(directory), directory, NullNodeLog.Instance);
|
|
int changes = 0;
|
|
directoryA.Changed += () => changes++;
|
|
Assert.Empty(directoryA.Agents);
|
|
|
|
directoryA.Apply(List(5, "agt_1", "agt_2"));
|
|
Assert.Equal(1, changes);
|
|
Assert.Equal(["agt_1", "agt_2"], directoryA.Agents.Select(a => a.AgentId));
|
|
|
|
directoryA.Apply(List(4, "agt_old")); // out-of-order older push
|
|
directoryA.Apply(List(5, "agt_1", "agt_2")); // same version and content
|
|
Assert.Equal(1, changes);
|
|
Assert.Equal(5, directoryA.Version);
|
|
|
|
// The next start uses the saved list while the panel is not reachable yet
|
|
var directoryB = new AgentDirectory(new ConfigStore(directory), directory, NullNodeLog.Instance);
|
|
Assert.Equal(["agt_1", "agt_2"], directoryB.Agents.Select(a => a.AgentId));
|
|
Assert.Equal(5, directoryB.Version);
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(directory, recursive: true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void AgentDirectory_StartsEmpty_WhenTheSavedFileIsCorrupt()
|
|
{
|
|
string directory = NewDirectory();
|
|
try
|
|
{
|
|
new ConfigStore(directory).Write(AgentDirectory.FileName, "{ not json"u8.ToArray());
|
|
var loaded = new AgentDirectory(new ConfigStore(directory), directory, NullNodeLog.Instance);
|
|
Assert.Empty(loaded.Agents);
|
|
}
|
|
finally
|
|
{
|
|
Directory.Delete(directory, recursive: true);
|
|
}
|
|
}
|
|
}
|