Files
MoShiro/backend/probe/tests/Monitor.Probe.Tests/ProbeTests.cs
T
justme 993dd5c41c
ci/woodpecker/push/main-amd64-build Pipeline was successful
feat!: probes link to the panel; signed release updates for container nodes [CI]
Probes connect to the panel directly and get the agent list as desired state.
CI signs the image digest of agent and probe releases, the panel forwards the
manifest, and a host updater verifies it with a local public key, pulls by
digest and rolls back when the new version is unhealthy.
2026-10-06 22:42:12 +08:00

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);
}
}
}