detector_unittest.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. # Copyright 2024 The Chromium Authors
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """The tests for resource detector classes."""
  5. import getpass
  6. import logging
  7. import os
  8. from pathlib import Path
  9. import platform
  10. import sys
  11. from . import detector
  12. from opentelemetry.sdk import resources
  13. def mock_exists(path: os.PathLike, val: bool):
  14. """Mock Path.exists for specified path."""
  15. exists = Path.exists
  16. def _mock_exists(*args, **kwargs):
  17. if args[0] == path:
  18. return val
  19. return exists(*args, **kwargs)
  20. return _mock_exists
  21. def mock_read_text(path: os.PathLike, val: str):
  22. """Mock Path.read_text for specified path."""
  23. real_read_text = Path.read_text
  24. def _mock_read_text(*args, **kwargs):
  25. if args[0] == path:
  26. return val
  27. return real_read_text(*args, **kwargs)
  28. return _mock_read_text
  29. def test_process_info_capture() -> None:
  30. """Test that ProcessDetector captures correct process info."""
  31. env_var = list(os.environ.keys())[0]
  32. d = detector.ProcessDetector(allowed_env=[env_var])
  33. attrs = d.detect().attributes
  34. assert attrs[resources.PROCESS_PID] == os.getpid()
  35. assert attrs[detector.PROCESS_CWD] == os.getcwd()
  36. assert attrs[resources.PROCESS_COMMAND] == sys.argv[0]
  37. assert attrs[resources.PROCESS_COMMAND_ARGS] == tuple(sys.argv[1:])
  38. assert attrs[resources.PROCESS_EXECUTABLE_NAME] == Path(sys.executable).name
  39. assert attrs[resources.PROCESS_EXECUTABLE_PATH] == sys.executable
  40. assert attrs[f"process.env.{env_var}"] == os.environ[env_var]
  41. def test_system_info_captured(monkeypatch) -> None:
  42. """Test that SystemDetector captures the correct system info."""
  43. monkeypatch.setattr(getpass, "getuser", lambda: "someuser")
  44. monkeypatch.setattr(Path, "exists", mock_exists(detector.DMI_PATH, True))
  45. monkeypatch.setattr(
  46. Path,
  47. "read_text",
  48. mock_read_text(detector.DMI_PATH, detector.GCE_DMI),
  49. )
  50. d = detector.SystemDetector()
  51. attrs = d.detect().attributes
  52. assert attrs[detector.CPU_COUNT] == os.cpu_count()
  53. assert attrs[detector.HOST_TYPE] == "Google Compute Engine"
  54. assert attrs[detector.OS_NAME] == os.name
  55. assert attrs[resources.OS_TYPE] == platform.system()
  56. assert attrs[resources.OS_DESCRIPTION] == platform.platform()
  57. assert attrs[detector.CPU_ARCHITECTURE] == platform.machine()
  58. assert attrs[detector.CPU_NAME] == platform.processor()
  59. def test_memory_info_class(monkeypatch) -> None:
  60. proc_meminfo_contents = """
  61. SwapTotal: 15 kB
  62. VmallocTotal: 25 kB
  63. MemTotal: 35 kB
  64. """
  65. monkeypatch.setattr(Path, "exists",
  66. mock_exists(detector.PROC_MEMINFO_PATH, True))
  67. monkeypatch.setattr(
  68. Path,
  69. "read_text",
  70. mock_read_text(detector.PROC_MEMINFO_PATH, proc_meminfo_contents),
  71. )
  72. m = detector.MemoryInfo()
  73. assert m.total_swap_memory == 15 * 1024
  74. assert m.total_physical_ram == 35 * 1024
  75. assert m.total_virtual_memory == 25 * 1024
  76. def test_memory_info_class_warns_on_unexpected_unit(monkeypatch,
  77. caplog) -> None:
  78. proc_meminfo_contents = """
  79. SwapTotal: 15 mB
  80. VmallocTotal: 25 gB
  81. MemTotal: 35 tB
  82. """
  83. monkeypatch.setattr(Path, "exists",
  84. mock_exists(detector.PROC_MEMINFO_PATH, True))
  85. monkeypatch.setattr(
  86. Path,
  87. "read_text",
  88. mock_read_text(detector.PROC_MEMINFO_PATH, proc_meminfo_contents),
  89. )
  90. caplog.set_level(logging.WARNING)
  91. m = detector.MemoryInfo()
  92. assert "Unit for memory consumption in /proc/meminfo" in caplog.text
  93. # We do not attempt to correct unexpected units
  94. assert m.total_swap_memory == 15 * 1024
  95. assert m.total_physical_ram == 35 * 1024
  96. assert m.total_virtual_memory == 25 * 1024
  97. def test_memory_info_class_no_units(monkeypatch) -> None:
  98. proc_meminfo_contents = """
  99. SwapTotal: 15
  100. """
  101. monkeypatch.setattr(Path, "exists",
  102. mock_exists(detector.PROC_MEMINFO_PATH, True))
  103. monkeypatch.setattr(
  104. Path,
  105. "read_text",
  106. mock_read_text(detector.PROC_MEMINFO_PATH, proc_meminfo_contents),
  107. )
  108. m = detector.MemoryInfo()
  109. assert m.total_swap_memory == 15
  110. def test_memory_info_class_no_provided_value(monkeypatch, caplog) -> None:
  111. proc_meminfo_contents = """
  112. SwapTotal:
  113. """
  114. monkeypatch.setattr(Path, "exists",
  115. mock_exists(detector.PROC_MEMINFO_PATH, True))
  116. monkeypatch.setattr(
  117. Path,
  118. "read_text",
  119. mock_read_text(detector.PROC_MEMINFO_PATH, proc_meminfo_contents),
  120. )
  121. caplog.set_level(logging.WARNING)
  122. detector.MemoryInfo()
  123. assert "Unexpected /proc/meminfo entry with no label:number" in caplog.text
  124. def test_system_info_to_capture_memory_resources(monkeypatch) -> None:
  125. proc_meminfo_contents = """
  126. SwapTotal: 15 kB
  127. VmallocTotal: 25 kB
  128. MemTotal: 35 kB
  129. """
  130. monkeypatch.setattr(Path, "exists",
  131. mock_exists(detector.PROC_MEMINFO_PATH, True))
  132. monkeypatch.setattr(
  133. Path,
  134. "read_text",
  135. mock_read_text(detector.PROC_MEMINFO_PATH, proc_meminfo_contents),
  136. )
  137. d = detector.SystemDetector()
  138. attrs = d.detect().attributes
  139. assert attrs[detector.MEMORY_TOTAL] == 35 * 1024
  140. assert attrs[detector.MEMORY_SWAP_TOTAL] == 15 * 1024
  141. def test_system_info_to_capture_host_type_bot(monkeypatch) -> None:
  142. """Test that SystemDetector captures host type as Google Compute Engine."""
  143. monkeypatch.setattr(Path, "exists", mock_exists(detector.DMI_PATH, True))
  144. monkeypatch.setattr(
  145. Path,
  146. "read_text",
  147. mock_read_text(detector.DMI_PATH, detector.GCE_DMI),
  148. )
  149. d = detector.SystemDetector()
  150. attrs = d.detect().attributes
  151. assert attrs[detector.CPU_COUNT] == os.cpu_count()
  152. assert attrs[detector.HOST_TYPE] == detector.GCE_DMI
  153. assert attrs[detector.OS_NAME] == os.name
  154. assert attrs[resources.OS_TYPE] == platform.system()
  155. assert attrs[resources.OS_DESCRIPTION] == platform.platform()
  156. assert attrs[detector.CPU_ARCHITECTURE] == platform.machine()
  157. assert attrs[detector.CPU_NAME] == platform.processor()
  158. def test_system_info_to_capture_host_type_from_dmi(monkeypatch) -> None:
  159. """Test that SystemDetector captures dmi product name as host type."""
  160. monkeypatch.setattr(getpass, "getuser", lambda: "someuser")
  161. monkeypatch.setattr(Path, "exists", mock_exists(detector.DMI_PATH, True))
  162. monkeypatch.setattr(Path, "read_text",
  163. mock_read_text(detector.DMI_PATH, "SomeId"))
  164. d = detector.SystemDetector()
  165. attrs = d.detect().attributes
  166. assert attrs[detector.CPU_COUNT] == os.cpu_count()
  167. assert attrs[detector.HOST_TYPE] == "SomeId"
  168. assert attrs[detector.OS_NAME] == os.name
  169. assert attrs[resources.OS_TYPE] == platform.system()
  170. assert attrs[resources.OS_DESCRIPTION] == platform.platform()
  171. assert attrs[detector.CPU_ARCHITECTURE] == platform.machine()
  172. assert attrs[detector.CPU_NAME] == platform.processor()
  173. def test_system_info_to_capture_host_type_unknown(monkeypatch) -> None:
  174. """Test that SystemDetector captures host type as UNKNOWN."""
  175. monkeypatch.setattr(Path, "exists", mock_exists(detector.DMI_PATH, False))
  176. d = detector.SystemDetector()
  177. attrs = d.detect().attributes
  178. assert attrs[detector.CPU_COUNT] == os.cpu_count()
  179. assert attrs[detector.HOST_TYPE] == "UNKNOWN"
  180. assert attrs[detector.OS_NAME] == os.name
  181. assert attrs[resources.OS_TYPE] == platform.system()
  182. assert attrs[resources.OS_DESCRIPTION] == platform.platform()
  183. assert attrs[detector.CPU_ARCHITECTURE] == platform.machine()
  184. assert attrs[detector.CPU_NAME] == platform.processor()