using RackPeek.Domain.Discovery;
using RackPeek.Domain.Resources;
using RackPeek.Domain.Resources.Servers;
using RackPeek.Domain.Resources.SystemResources;
namespace Tests.Discovery;
///
/// The MAC bridge between collectors: an agent card carries the machine's MACs
/// (a "macs" label), a scan card carries the one it was found by (a "mac" label),
/// and a shared MAC means the same box — so both collectors land on one card,
/// whichever arrived first. These pin the resolver's side of that contract.
///
public class MacUnificationTests {
private const string _mac = "dc:a6:32:0f:11:22";
private static SystemResource ScanCard(string name = "host-595109fb", string mac = _mac) => new() {
Kind = SystemResource.KindLabel,
Name = name,
DiscoveryId = DiscoveryId.Create(DiscoveryId.NetworkScheme, mac),
Ip = "192.168.1.20",
Labels = { ["mac"] = mac }
};
private static SystemResource AgentCard(
string name = "nas01",
string machineId = "machine-a",
string macs = _mac) => new() {
Kind = SystemResource.KindLabel,
Name = name,
DiscoveryId = DiscoveryId.Create(DiscoveryId.SystemScheme, machineId),
Type = "baremetal",
Os = "Debian",
Cores = 12,
Labels = { ["macs"] = macs }
};
[Fact]
public void An_agent_claims_the_scan_card_and_upgrades_its_identity() {
// Scan ran first; now `rpk discover system` reports the same box.
List existing = [ScanCard()];
List incoming = [AgentCard()];
DiscoveryIdResolver.ResolveNames(existing, incoming);
// The stored card's name wins (names are user-owned), and the agent's id
// survives so the merge upgrades the card to the stronger identity.
Assert.Equal("host-595109fb", incoming[0].Name);
Assert.StartsWith("rpk1:sys:", incoming[0].DiscoveryId);
}
[Fact]
public void A_scan_enriches_the_agents_card_without_touching_its_identity() {
// Agent ran first; now a sweep sees the same box from outside.
List existing = [AgentCard()];
List incoming = [ScanCard()];
DiscoveryIdResolver.ResolveNames(existing, incoming);
Assert.Equal("nas01", incoming[0].Name);
// The weak scan id is dropped so the merge cannot downgrade the sys id.
Assert.Null(incoming[0].DiscoveryId);
}
[Fact]
public void The_macs_are_matched_however_each_side_spells_them() {
// The agent records padded lowercase; suppose a stored label was hand-edited
// to Windows-style dashes — normalisation makes them the same machine anyway.
SystemResource stored = ScanCard();
stored.Labels["mac"] = "DC-A6-32-0F-11-22";
List existing = [stored];
List incoming = [AgentCard()];
DiscoveryIdResolver.ResolveNames(existing, incoming);
Assert.Equal("host-595109fb", incoming[0].Name);
}
[Fact]
public void An_id_match_always_beats_a_mac_match() {
// The scan card was renamed by the user; a rescan must follow its own id to
// the rename, not rediscover it via the MAC of some other card.
SystemResource renamed = ScanCard(name: "storage-primary");
List existing = [renamed, AgentCard(macs: _mac)];
List incoming = [ScanCard()];
DiscoveryIdResolver.ResolveNames(existing, incoming);
Assert.Equal("storage-primary", incoming[0].Name);
Assert.NotNull(incoming[0].DiscoveryId);
}
[Fact]
public void A_mac_claimed_by_two_stored_cards_identifies_nothing() {
// Ambiguity never unifies: fall through to the ordinary name rules.
List existing = [
AgentCard(name: "clone-a", machineId: "machine-a"),
AgentCard(name: "clone-b", machineId: "machine-b")
];
List incoming = [ScanCard(name: "host-xyz")];
DiscoveryIdResolver.ResolveNames(existing, incoming);
Assert.Equal("host-xyz", incoming[0].Name);
Assert.NotNull(incoming[0].DiscoveryId);
}
[Fact]
public void Two_agent_grade_identities_sharing_a_mac_never_unify() {
// Cloned VMs can share a NIC MAC while having distinct machine-ids; the
// machine-id is the authority between agent-grade collectors.
List existing = [AgentCard(name: "vm-a", machineId: "machine-a")];
List incoming = [AgentCard(name: "vm-b", machineId: "machine-b")];
DiscoveryIdResolver.ResolveNames(existing, incoming);
Assert.Equal("vm-b", incoming[0].Name);
}
[Fact]
public void A_mac_on_a_different_kind_of_card_is_not_a_bridge() {
// The user put a mac label on the Server card describing the box's hardware;
// the scan's System card is a different kind of thing and stays separate.
var server = new Server {
Kind = "Server",
Name = "rack-server",
Labels = { ["mac"] = _mac }
};
List incoming = [ScanCard(name: "host-xyz")];
DiscoveryIdResolver.ResolveNames([server], incoming);
Assert.Equal("host-xyz", incoming[0].Name);
}
[Fact]
public void A_hand_written_card_with_a_mac_label_is_adopted_like_a_name_match() {
// No id on the stored card: whoever arrives first with an identity stamps it.
var handWritten = new SystemResource {
Kind = SystemResource.KindLabel,
Name = "nas01",
Type = "baremetal",
Labels = { ["mac"] = _mac }
};
List incoming = [ScanCard(name: "host-xyz")];
DiscoveryIdResolver.ResolveNames([handWritten], incoming);
Assert.Equal("nas01", incoming[0].Name);
Assert.NotNull(incoming[0].DiscoveryId); // the scan id gets stamped on
}
}