test_contracts.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Contracts tests. These tests mainly check API sanity in terms of
  6. returned types and APIs availability.
  7. Some of these are duplicates of tests test_system.py and test_process.py.
  8. """
  9. import signal
  10. import psutil
  11. from psutil import AIX
  12. from psutil import FREEBSD
  13. from psutil import LINUX
  14. from psutil import MACOS
  15. from psutil import NETBSD
  16. from psutil import OPENBSD
  17. from psutil import POSIX
  18. from psutil import SUNOS
  19. from psutil import WINDOWS
  20. from psutil.tests import AARCH64
  21. from psutil.tests import GITHUB_ACTIONS
  22. from psutil.tests import HAS_CPU_FREQ
  23. from psutil.tests import HAS_NET_IO_COUNTERS
  24. from psutil.tests import HAS_SENSORS_FANS
  25. from psutil.tests import HAS_SENSORS_TEMPERATURES
  26. from psutil.tests import SKIP_SYSCONS
  27. from psutil.tests import PsutilTestCase
  28. from psutil.tests import create_sockets
  29. from psutil.tests import enum
  30. from psutil.tests import is_namedtuple
  31. from psutil.tests import kernel_version
  32. from psutil.tests import pytest
  33. # ===================================================================
  34. # --- APIs availability
  35. # ===================================================================
  36. # Make sure code reflects what doc promises in terms of APIs
  37. # availability.
  38. class TestAvailConstantsAPIs(PsutilTestCase):
  39. def test_PROCFS_PATH(self):
  40. assert hasattr(psutil, "PROCFS_PATH") == (LINUX or SUNOS or AIX)
  41. def test_win_priority(self):
  42. assert hasattr(psutil, "ABOVE_NORMAL_PRIORITY_CLASS") == WINDOWS
  43. assert hasattr(psutil, "BELOW_NORMAL_PRIORITY_CLASS") == WINDOWS
  44. assert hasattr(psutil, "HIGH_PRIORITY_CLASS") == WINDOWS
  45. assert hasattr(psutil, "IDLE_PRIORITY_CLASS") == WINDOWS
  46. assert hasattr(psutil, "NORMAL_PRIORITY_CLASS") == WINDOWS
  47. assert hasattr(psutil, "REALTIME_PRIORITY_CLASS") == WINDOWS
  48. def test_linux_ioprio_linux(self):
  49. assert hasattr(psutil, "IOPRIO_CLASS_NONE") == LINUX
  50. assert hasattr(psutil, "IOPRIO_CLASS_RT") == LINUX
  51. assert hasattr(psutil, "IOPRIO_CLASS_BE") == LINUX
  52. assert hasattr(psutil, "IOPRIO_CLASS_IDLE") == LINUX
  53. def test_linux_ioprio_windows(self):
  54. assert hasattr(psutil, "IOPRIO_HIGH") == WINDOWS
  55. assert hasattr(psutil, "IOPRIO_NORMAL") == WINDOWS
  56. assert hasattr(psutil, "IOPRIO_LOW") == WINDOWS
  57. assert hasattr(psutil, "IOPRIO_VERYLOW") == WINDOWS
  58. @pytest.mark.skipif(
  59. GITHUB_ACTIONS and LINUX,
  60. reason="unsupported on GITHUB_ACTIONS + LINUX",
  61. )
  62. def test_rlimit(self):
  63. assert hasattr(psutil, "RLIM_INFINITY") == LINUX or FREEBSD
  64. assert hasattr(psutil, "RLIMIT_AS") == LINUX or FREEBSD
  65. assert hasattr(psutil, "RLIMIT_CORE") == LINUX or FREEBSD
  66. assert hasattr(psutil, "RLIMIT_CPU") == LINUX or FREEBSD
  67. assert hasattr(psutil, "RLIMIT_DATA") == LINUX or FREEBSD
  68. assert hasattr(psutil, "RLIMIT_FSIZE") == LINUX or FREEBSD
  69. assert hasattr(psutil, "RLIMIT_MEMLOCK") == LINUX or FREEBSD
  70. assert hasattr(psutil, "RLIMIT_NOFILE") == LINUX or FREEBSD
  71. assert hasattr(psutil, "RLIMIT_NPROC") == LINUX or FREEBSD
  72. assert hasattr(psutil, "RLIMIT_RSS") == LINUX or FREEBSD
  73. assert hasattr(psutil, "RLIMIT_STACK") == LINUX or FREEBSD
  74. assert hasattr(psutil, "RLIMIT_LOCKS") == LINUX
  75. if POSIX:
  76. if kernel_version() >= (2, 6, 8):
  77. assert hasattr(psutil, "RLIMIT_MSGQUEUE") == LINUX
  78. if kernel_version() >= (2, 6, 12):
  79. assert hasattr(psutil, "RLIMIT_NICE") == LINUX
  80. if kernel_version() >= (2, 6, 12):
  81. assert hasattr(psutil, "RLIMIT_RTPRIO") == LINUX
  82. if kernel_version() >= (2, 6, 25):
  83. assert hasattr(psutil, "RLIMIT_RTTIME") == LINUX
  84. if kernel_version() >= (2, 6, 8):
  85. assert hasattr(psutil, "RLIMIT_SIGPENDING") == LINUX
  86. assert hasattr(psutil, "RLIMIT_SWAP") == FREEBSD
  87. assert hasattr(psutil, "RLIMIT_SBSIZE") == FREEBSD
  88. assert hasattr(psutil, "RLIMIT_NPTS") == FREEBSD
  89. class TestAvailSystemAPIs(PsutilTestCase):
  90. def test_win_service_iter(self):
  91. assert hasattr(psutil, "win_service_iter") == WINDOWS
  92. def test_win_service_get(self):
  93. assert hasattr(psutil, "win_service_get") == WINDOWS
  94. @pytest.mark.skipif(MACOS and AARCH64, reason="skipped due to #1892")
  95. def test_cpu_freq(self):
  96. assert hasattr(psutil, "cpu_freq") == (
  97. LINUX or MACOS or WINDOWS or FREEBSD or OPENBSD
  98. )
  99. def test_sensors_temperatures(self):
  100. assert hasattr(psutil, "sensors_temperatures") == (LINUX or FREEBSD)
  101. def test_sensors_fans(self):
  102. assert hasattr(psutil, "sensors_fans") == LINUX
  103. def test_battery(self):
  104. assert hasattr(psutil, "sensors_battery") == (
  105. LINUX or WINDOWS or FREEBSD or MACOS
  106. )
  107. class TestAvailProcessAPIs(PsutilTestCase):
  108. def test_environ(self):
  109. assert hasattr(psutil.Process, "environ") == (
  110. LINUX
  111. or MACOS
  112. or WINDOWS
  113. or AIX
  114. or SUNOS
  115. or FREEBSD
  116. or OPENBSD
  117. or NETBSD
  118. )
  119. def test_uids(self):
  120. assert hasattr(psutil.Process, "uids") == POSIX
  121. def test_gids(self):
  122. assert hasattr(psutil.Process, "uids") == POSIX
  123. def test_terminal(self):
  124. assert hasattr(psutil.Process, "terminal") == POSIX
  125. def test_ionice(self):
  126. assert hasattr(psutil.Process, "ionice") == (LINUX or WINDOWS)
  127. @pytest.mark.skipif(
  128. GITHUB_ACTIONS and LINUX,
  129. reason="unsupported on GITHUB_ACTIONS + LINUX",
  130. )
  131. def test_rlimit(self):
  132. assert hasattr(psutil.Process, "rlimit") == (LINUX or FREEBSD)
  133. def test_io_counters(self):
  134. hasit = hasattr(psutil.Process, "io_counters")
  135. assert hasit == (not (MACOS or SUNOS))
  136. def test_num_fds(self):
  137. assert hasattr(psutil.Process, "num_fds") == POSIX
  138. def test_num_handles(self):
  139. assert hasattr(psutil.Process, "num_handles") == WINDOWS
  140. def test_cpu_affinity(self):
  141. assert hasattr(psutil.Process, "cpu_affinity") == (
  142. LINUX or WINDOWS or FREEBSD
  143. )
  144. def test_cpu_num(self):
  145. assert hasattr(psutil.Process, "cpu_num") == (
  146. LINUX or FREEBSD or SUNOS
  147. )
  148. def test_memory_maps(self):
  149. hasit = hasattr(psutil.Process, "memory_maps")
  150. assert hasit == (not (OPENBSD or NETBSD or AIX or MACOS))
  151. # ===================================================================
  152. # --- API types
  153. # ===================================================================
  154. class TestSystemAPITypes(PsutilTestCase):
  155. """Check the return types of system related APIs.
  156. https://github.com/giampaolo/psutil/issues/1039.
  157. """
  158. @classmethod
  159. def setUpClass(cls):
  160. cls.proc = psutil.Process()
  161. def assert_ntuple_of_nums(self, nt, type_=float, gezero=True):
  162. assert is_namedtuple(nt)
  163. for n in nt:
  164. assert isinstance(n, type_)
  165. if gezero:
  166. assert n >= 0
  167. def test_cpu_times(self):
  168. self.assert_ntuple_of_nums(psutil.cpu_times())
  169. for nt in psutil.cpu_times(percpu=True):
  170. self.assert_ntuple_of_nums(nt)
  171. def test_cpu_percent(self):
  172. assert isinstance(psutil.cpu_percent(interval=None), float)
  173. assert isinstance(psutil.cpu_percent(interval=0.00001), float)
  174. def test_cpu_times_percent(self):
  175. self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=None))
  176. self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=0.0001))
  177. def test_cpu_count(self):
  178. assert isinstance(psutil.cpu_count(), int)
  179. # TODO: remove this once 1892 is fixed
  180. @pytest.mark.skipif(MACOS and AARCH64, reason="skipped due to #1892")
  181. @pytest.mark.skipif(not HAS_CPU_FREQ, reason="not supported")
  182. def test_cpu_freq(self):
  183. if psutil.cpu_freq() is None:
  184. return pytest.skip("cpu_freq() returns None")
  185. self.assert_ntuple_of_nums(psutil.cpu_freq(), type_=(float, int))
  186. def test_disk_io_counters(self):
  187. # Duplicate of test_system.py. Keep it anyway.
  188. for k, v in psutil.disk_io_counters(perdisk=True).items():
  189. assert isinstance(k, str)
  190. self.assert_ntuple_of_nums(v, type_=int)
  191. def test_disk_partitions(self):
  192. # Duplicate of test_system.py. Keep it anyway.
  193. for disk in psutil.disk_partitions():
  194. assert isinstance(disk.device, str)
  195. assert isinstance(disk.mountpoint, str)
  196. assert isinstance(disk.fstype, str)
  197. assert isinstance(disk.opts, str)
  198. @pytest.mark.skipif(SKIP_SYSCONS, reason="requires root")
  199. def test_net_connections(self):
  200. with create_sockets():
  201. ret = psutil.net_connections('all')
  202. assert len(ret) == len(set(ret))
  203. for conn in ret:
  204. assert is_namedtuple(conn)
  205. def test_net_if_addrs(self):
  206. # Duplicate of test_system.py. Keep it anyway.
  207. for ifname, addrs in psutil.net_if_addrs().items():
  208. assert isinstance(ifname, str)
  209. for addr in addrs:
  210. assert isinstance(addr.family, enum.IntEnum)
  211. assert isinstance(addr.address, str)
  212. assert isinstance(addr.netmask, (str, type(None)))
  213. assert isinstance(addr.broadcast, (str, type(None)))
  214. def test_net_if_stats(self):
  215. # Duplicate of test_system.py. Keep it anyway.
  216. for ifname, info in psutil.net_if_stats().items():
  217. assert isinstance(ifname, str)
  218. assert isinstance(info.isup, bool)
  219. assert isinstance(info.duplex, enum.IntEnum)
  220. assert isinstance(info.speed, int)
  221. assert isinstance(info.mtu, int)
  222. @pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
  223. def test_net_io_counters(self):
  224. # Duplicate of test_system.py. Keep it anyway.
  225. for ifname in psutil.net_io_counters(pernic=True):
  226. assert isinstance(ifname, str)
  227. @pytest.mark.skipif(not HAS_SENSORS_FANS, reason="not supported")
  228. def test_sensors_fans(self):
  229. # Duplicate of test_system.py. Keep it anyway.
  230. for name, units in psutil.sensors_fans().items():
  231. assert isinstance(name, str)
  232. for unit in units:
  233. assert isinstance(unit.label, str)
  234. assert isinstance(unit.current, (float, int, type(None)))
  235. @pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
  236. def test_sensors_temperatures(self):
  237. # Duplicate of test_system.py. Keep it anyway.
  238. for name, units in psutil.sensors_temperatures().items():
  239. assert isinstance(name, str)
  240. for unit in units:
  241. assert isinstance(unit.label, str)
  242. assert isinstance(unit.current, (float, int, type(None)))
  243. assert isinstance(unit.high, (float, int, type(None)))
  244. assert isinstance(unit.critical, (float, int, type(None)))
  245. def test_boot_time(self):
  246. # Duplicate of test_system.py. Keep it anyway.
  247. assert isinstance(psutil.boot_time(), float)
  248. def test_users(self):
  249. # Duplicate of test_system.py. Keep it anyway.
  250. for user in psutil.users():
  251. assert isinstance(user.name, str)
  252. assert isinstance(user.terminal, (str, type(None)))
  253. assert isinstance(user.host, (str, type(None)))
  254. assert isinstance(user.pid, (int, type(None)))
  255. if isinstance(user.pid, int):
  256. assert user.pid > 0
  257. class TestProcessWaitType(PsutilTestCase):
  258. @pytest.mark.skipif(not POSIX, reason="not POSIX")
  259. def test_negative_signal(self):
  260. p = psutil.Process(self.spawn_subproc().pid)
  261. p.terminate()
  262. code = p.wait()
  263. assert code == -signal.SIGTERM
  264. assert isinstance(code, enum.IntEnum)