RealProbeTests.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using RackPeek.Domain.Discovery;
  2. using RackPeek.Domain.Resources.SystemResources;
  3. namespace Tests.Discovery;
  4. /// <summary>
  5. /// Everywhere else in this project the probes are bypassed and the parser is driven
  6. /// from fixtures. These tests do the opposite: they run the real probe against the
  7. /// real machine, which is the only way to catch a wrong path or a changed command.
  8. /// Each one is skipped off its own platform, so the CI matrix covers Linux on the
  9. /// ubuntu runner and macOS on the macos runner.
  10. /// </summary>
  11. public class RealProbeTests {
  12. [Fact]
  13. public async Task The_linux_probe_reads_this_machine() {
  14. // No-op off Linux. xUnit v2 has no skip-at-runtime, and a custom attribute is
  15. // more machinery than this needs — the CI matrix is what makes it run.
  16. if (!OperatingSystem.IsLinux())
  17. return;
  18. RawSystemSnapshot snapshot = await new LinuxSystemProbe().ReadAsync(CancellationToken.None);
  19. Assert.False(string.IsNullOrWhiteSpace(snapshot.Hostname));
  20. Assert.True(snapshot.Cores > 0);
  21. // Each of these guards a hard-coded path. If one is wrong the probe silently
  22. // returns null and the resource quietly loses a field, which no fixture can catch.
  23. AssertReadIfPresent("/etc/os-release", snapshot.OsReleaseFile);
  24. AssertReadIfPresent("/proc/meminfo", snapshot.MemInfoFile);
  25. AssertReadIfPresent("/proc/1/cgroup", snapshot.CgroupFile);
  26. AssertReadIfPresent("/etc/machine-id", snapshot.MachineIdFile);
  27. AssertReadIfPresent("/sys/class/dmi/id/sys_vendor", snapshot.DmiVendor);
  28. AssertReadIfPresent("/sys/class/dmi/id/product_name", snapshot.DmiProduct);
  29. if (Directory.Exists("/sys/block") && Directory.EnumerateDirectories("/sys/block").Any())
  30. Assert.NotEmpty(snapshot.BlockDevices);
  31. AssertUsable(SystemFactsParser.Parse(snapshot));
  32. }
  33. [Fact]
  34. public async Task The_macos_probe_reads_this_machine() {
  35. if (!OperatingSystem.IsMacOS())
  36. return;
  37. RawSystemSnapshot snapshot = await new MacSystemProbe().ReadAsync(CancellationToken.None);
  38. Assert.False(string.IsNullOrWhiteSpace(snapshot.Hostname));
  39. Assert.True(snapshot.Cores > 0);
  40. // These come from sw_vers, sysctl and ioreg — all shell-outs, none of which a
  41. // fixture can prove are still spelled correctly.
  42. Assert.StartsWith("macOS", snapshot.OsName);
  43. Assert.True(snapshot.MemoryBytes > 0);
  44. Assert.False(string.IsNullOrWhiteSpace(snapshot.PlatformUuid));
  45. AssertUsable(SystemFactsParser.Parse(snapshot));
  46. }
  47. [Fact]
  48. public void Exactly_one_probe_claims_this_platform() {
  49. ISystemProbe[] probes = [new LinuxSystemProbe(), new MacSystemProbe()];
  50. var supported = probes.Count(p => p.IsSupported);
  51. Assert.Equal(OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() ? 1 : 0, supported);
  52. }
  53. /// <summary>
  54. /// Reads the file itself and, if this machine actually has content there, insists
  55. /// the probe found it too. Note the test has to read rather than stat: everything
  56. /// under /proc reports a length of zero, so a size check silently passes and
  57. /// covers none of the paths that matter most.
  58. /// </summary>
  59. private static void AssertReadIfPresent(string path, string? value) {
  60. string? actual;
  61. try {
  62. actual = File.Exists(path) ? File.ReadAllText(path) : null;
  63. }
  64. catch {
  65. return; // Present but unreadable for this user; nothing to hold the probe to.
  66. }
  67. if (string.IsNullOrWhiteSpace(actual))
  68. return;
  69. Assert.False(
  70. string.IsNullOrWhiteSpace(value),
  71. $"{path} has content on this machine but the probe read nothing from it.");
  72. }
  73. private static void AssertUsable(SystemFacts facts) {
  74. Assert.Contains(facts.Type, SystemResource.ValidSystemTypes);
  75. Assert.NotEqual("Unknown", facts.Os);
  76. Assert.True(facts.RamGb > 0);
  77. // The schema requires type, os, cores and ram, so a real machine has to produce
  78. // something importable rather than a half-filled resource.
  79. Fixture.AssertConformsToSchema(
  80. DiscoveryDocument.ToYaml([SystemResourceMapper.ToResource(facts)]));
  81. }
  82. }