MacVendorLookupTests.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using RackPeek.Domain.Discovery;
  2. namespace Tests.Discovery;
  3. /// <summary>
  4. /// The vendor a MAC implies. Every expectation here is a real IEEE assignment, and
  5. /// several are addresses observed on a live homelab — a lookup that silently drifted
  6. /// would be worse than no lookup, because a confident wrong vendor is unfalsifiable
  7. /// to whoever reads the card.
  8. /// </summary>
  9. public class MacVendorLookupTests {
  10. [Theory]
  11. [InlineData("bc:24:11:00:1a:01", "Proxmox")]
  12. [InlineData("a0:36:9f:00:1a:02", "Intel")]
  13. [InlineData("1c:6a:1b:00:1a:03", "Ubiquiti")]
  14. [InlineData("48:b0:2d:00:1a:04", "NVIDIA")]
  15. [InlineData("80:f3:da:00:1a:06", "Espressif")]
  16. [InlineData("b8:27:eb:11:22:33", "Raspberry Pi")]
  17. [InlineData("00:0c:29:aa:bb:cc", "VMware")]
  18. public void Assigned_prefixes_resolve_to_their_owner(string mac, string expected) =>
  19. Assert.Equal(expected, MacVendorLookup.Lookup(mac));
  20. [Theory]
  21. [InlineData("BC:24:11:14:59:DF")]
  22. [InlineData("bc-24-11-14-59-df")]
  23. [InlineData("bc2411145 9df")]
  24. [InlineData("bc24.1114.59df")]
  25. public void Separators_and_case_do_not_matter(string mac) =>
  26. Assert.Equal("Proxmox", MacVendorLookup.Lookup(mac));
  27. [Fact]
  28. // KVM mints guest addresses from the locally-administered range rather than buying
  29. // an OUI. Reporting "randomised" here would hide the most useful fact about the
  30. // host — that it is a virtual machine.
  31. public void A_hypervisors_own_prefix_beats_the_locally_administered_bit() =>
  32. Assert.Equal("QEMU/KVM", MacVendorLookup.Lookup("52:54:00:12:34:56"));
  33. [Theory]
  34. [InlineData("92:16:01:00:1a:07")]
  35. [InlineData("6a:34:ce:00:1a:08")]
  36. public void Self_assigned_addresses_are_reported_as_randomised(string mac) {
  37. // A phone or laptop randomising per network. The OUI half names no one, so
  38. // saying so beats reporting whichever company owns the matching block.
  39. Assert.Equal("Randomised (locally administered)", MacVendorLookup.Lookup(mac));
  40. Assert.True(MacVendorLookup.IsLocallyAdministered(mac));
  41. }
  42. [Fact]
  43. public void A_universally_administered_address_is_not_flagged_as_randomised() =>
  44. Assert.False(MacVendorLookup.IsLocallyAdministered("bc:24:11:00:1a:01"));
  45. [Theory]
  46. [InlineData(null)]
  47. [InlineData("")]
  48. [InlineData(" ")]
  49. [InlineData("not-a-mac")]
  50. [InlineData("bc:24")]
  51. public void Unreadable_input_yields_no_vendor(string? mac) {
  52. Assert.Null(MacVendorLookup.Lookup(mac));
  53. Assert.False(MacVendorLookup.IsLocallyAdministered(mac));
  54. }
  55. [Fact]
  56. // 00:00:00 is assigned to Xerox and deliberately not in the curated table. Null
  57. // means "not known", which is honest; a nearest-match would not be.
  58. public void An_unlisted_but_assigned_prefix_is_null_rather_than_a_guess() =>
  59. Assert.Null(MacVendorLookup.Lookup("00:00:00:11:22:33"));
  60. [Fact]
  61. public void Every_packed_record_resolves_to_a_real_vendor_name() {
  62. // Guards the generated table's index encoding: an off-by-one in the index char
  63. // would map prefixes to the wrong vendor, or off the end of the array. Also
  64. // proves the records are sorted, which the binary search depends on.
  65. var records = MacVendorTable.Records;
  66. var count = records.Length / MacVendorTable.RecordLength;
  67. Assert.True(count > 1000, $"The table holds only {count} records — did generation fail?");
  68. string? previous = null;
  69. for (var i = 0; i < count; i++) {
  70. var prefix = records.Substring(i * MacVendorTable.RecordLength, 6);
  71. if (previous != null)
  72. Assert.True(
  73. string.CompareOrdinal(previous, prefix) < 0,
  74. $"Records are not sorted ascending: {previous} precedes {prefix}.");
  75. previous = prefix;
  76. Assert.False(
  77. string.IsNullOrWhiteSpace(MacVendorLookup.Lookup(prefix + "000000")),
  78. $"{prefix} resolved to nothing.");
  79. }
  80. }
  81. }