week06
This commit is contained in:
2113
env/lib/python3.12/site-packages/psutil/tests/__init__.py
vendored
Normal file
2113
env/lib/python3.12/site-packages/psutil/tests/__init__.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
env/lib/python3.12/site-packages/psutil/tests/__main__.py
vendored
Normal file
12
env/lib/python3.12/site-packages/psutil/tests/__main__.py
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Run unit tests. This is invoked by:
|
||||
$ python -m psutil.tests.
|
||||
"""
|
||||
|
||||
from psutil.tests import pytest
|
||||
|
||||
|
||||
pytest.main(["-v", "-s", "--tb=short"])
|
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/__init__.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/__init__.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/__main__.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/__main__.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_aix.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_aix.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_bsd.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_bsd.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_connections.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_connections.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_contracts.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_contracts.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_linux.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_linux.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_memleaks.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_memleaks.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_misc.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_misc.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_osx.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_osx.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_posix.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_posix.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_process.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_process.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_process_all.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_process_all.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_sunos.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_sunos.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_system.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_system.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_testutils.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_testutils.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_unicode.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_unicode.cpython-312.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_windows.cpython-312.pyc
vendored
Normal file
BIN
env/lib/python3.12/site-packages/psutil/tests/__pycache__/test_windows.cpython-312.pyc
vendored
Normal file
Binary file not shown.
115
env/lib/python3.12/site-packages/psutil/tests/test_aix.py
vendored
Normal file
115
env/lib/python3.12/site-packages/psutil/tests/test_aix.py
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'
|
||||
# Copyright (c) 2017, Arnon Yaari
|
||||
# All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""AIX specific tests."""
|
||||
|
||||
import re
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import sh
|
||||
|
||||
|
||||
@pytest.mark.skipif(not AIX, reason="AIX only")
|
||||
class AIXSpecificTestCase(PsutilTestCase):
|
||||
def test_virtual_memory(self):
|
||||
out = sh('/usr/bin/svmon -O unit=KB')
|
||||
re_pattern = r"memory\s*"
|
||||
for field in ("size inuse free pin virtual available mmode").split():
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
assert matchobj is not None
|
||||
|
||||
KB = 1024
|
||||
total = int(matchobj.group("size")) * KB
|
||||
available = int(matchobj.group("available")) * KB
|
||||
used = int(matchobj.group("inuse")) * KB
|
||||
free = int(matchobj.group("free")) * KB
|
||||
|
||||
psutil_result = psutil.virtual_memory()
|
||||
|
||||
# TOLERANCE_SYS_MEM from psutil.tests is not enough. For some reason
|
||||
# we're seeing differences of ~1.2 MB. 2 MB is still a good tolerance
|
||||
# when compared to GBs.
|
||||
TOLERANCE_SYS_MEM = 2 * KB * KB # 2 MB
|
||||
assert psutil_result.total == total
|
||||
assert abs(psutil_result.used - used) < TOLERANCE_SYS_MEM
|
||||
assert abs(psutil_result.available - available) < TOLERANCE_SYS_MEM
|
||||
assert abs(psutil_result.free - free) < TOLERANCE_SYS_MEM
|
||||
|
||||
def test_swap_memory(self):
|
||||
out = sh('/usr/sbin/lsps -a')
|
||||
# From the man page, "The size is given in megabytes" so we assume
|
||||
# we'll always have 'MB' in the result
|
||||
# TODO maybe try to use "swap -l" to check "used" too, but its units
|
||||
# are not guaranteed to be "MB" so parsing may not be consistent
|
||||
matchobj = re.search(
|
||||
r"(?P<space>\S+)\s+"
|
||||
r"(?P<vol>\S+)\s+"
|
||||
r"(?P<vg>\S+)\s+"
|
||||
r"(?P<size>\d+)MB",
|
||||
out,
|
||||
)
|
||||
|
||||
assert matchobj is not None
|
||||
|
||||
total_mb = int(matchobj.group("size"))
|
||||
MB = 1024**2
|
||||
psutil_result = psutil.swap_memory()
|
||||
# we divide our result by MB instead of multiplying the lsps value by
|
||||
# MB because lsps may round down, so we round down too
|
||||
assert int(psutil_result.total / MB) == total_mb
|
||||
|
||||
def test_cpu_stats(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
|
||||
re_pattern = r"ALL\s*"
|
||||
for field in (
|
||||
"min maj mpcs mpcr dev soft dec ph cs ics bound rq "
|
||||
"push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd "
|
||||
"sysc"
|
||||
).split():
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
assert matchobj is not None
|
||||
|
||||
# numbers are usually in the millions so 1000 is ok for tolerance
|
||||
CPU_STATS_TOLERANCE = 1000
|
||||
psutil_result = psutil.cpu_stats()
|
||||
assert (
|
||||
abs(psutil_result.ctx_switches - int(matchobj.group("cs")))
|
||||
< CPU_STATS_TOLERANCE
|
||||
)
|
||||
assert (
|
||||
abs(psutil_result.syscalls - int(matchobj.group("sysc")))
|
||||
< CPU_STATS_TOLERANCE
|
||||
)
|
||||
assert (
|
||||
abs(psutil_result.interrupts - int(matchobj.group("dev")))
|
||||
< CPU_STATS_TOLERANCE
|
||||
)
|
||||
assert (
|
||||
abs(psutil_result.soft_interrupts - int(matchobj.group("soft")))
|
||||
< CPU_STATS_TOLERANCE
|
||||
)
|
||||
|
||||
def test_cpu_count_logical(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
mpstat_lcpu = int(re.search(r"lcpu=(\d+)", out).group(1))
|
||||
psutil_lcpu = psutil.cpu_count(logical=True)
|
||||
assert mpstat_lcpu == psutil_lcpu
|
||||
|
||||
def test_net_if_addrs_names(self):
|
||||
out = sh('/etc/ifconfig -l')
|
||||
ifconfig_names = set(out.split())
|
||||
psutil_names = set(psutil.net_if_addrs().keys())
|
||||
assert ifconfig_names == psutil_names
|
592
env/lib/python3.12/site-packages/psutil/tests/test_bsd.py
vendored
Normal file
592
env/lib/python3.12/site-packages/psutil/tests/test_bsd.py
vendored
Normal file
@ -0,0 +1,592 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# TODO: (FreeBSD) add test for comparing connections with 'sockstat' cmd.
|
||||
|
||||
|
||||
"""Tests specific to all BSD platforms."""
|
||||
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import TOLERANCE_SYS_MEM
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import terminate
|
||||
from psutil.tests import which
|
||||
|
||||
|
||||
if BSD:
|
||||
from psutil._psutil_posix import getpagesize
|
||||
|
||||
PAGESIZE = getpagesize()
|
||||
# muse requires root privileges
|
||||
MUSE_AVAILABLE = os.getuid() == 0 and which('muse')
|
||||
else:
|
||||
PAGESIZE = None
|
||||
MUSE_AVAILABLE = False
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
result = sh("sysctl " + cmdline)
|
||||
if FREEBSD:
|
||||
result = result[result.find(": ") + 2 :]
|
||||
elif OPENBSD or NETBSD:
|
||||
result = result[result.find("=") + 1 :]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def muse(field):
|
||||
"""Thin wrapper around 'muse' cmdline utility."""
|
||||
out = sh('muse')
|
||||
for line in out.split('\n'):
|
||||
if line.startswith(field):
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(line.split()[1])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- All BSD*
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(not BSD, reason="BSD only")
|
||||
class BSDTestCase(PsutilTestCase):
|
||||
"""Generic tests common to all BSD variants."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
@pytest.mark.skipif(NETBSD, reason="-o lstart doesn't work on NETBSD")
|
||||
def test_process_create_time(self):
|
||||
output = sh("ps -o lstart -p %s" % self.pid)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
start_psutil = time.strftime(
|
||||
"%a %b %e %H:%M:%S %Y", time.localtime(start_psutil)
|
||||
)
|
||||
assert start_ps == start_psutil
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
assert part.device == dev
|
||||
assert usage.total == total
|
||||
# 10 MB tolerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
raise self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
raise self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
@pytest.mark.skipif(not which('sysctl'), reason="sysctl cmd not available")
|
||||
def test_cpu_count_logical(self):
|
||||
syst = sysctl("hw.ncpu")
|
||||
assert psutil.cpu_count(logical=True) == syst
|
||||
|
||||
@pytest.mark.skipif(not which('sysctl'), reason="sysctl cmd not available")
|
||||
@pytest.mark.skipif(
|
||||
NETBSD, reason="skipped on NETBSD" # we check /proc/meminfo
|
||||
)
|
||||
def test_virtual_memory_total(self):
|
||||
num = sysctl('hw.physmem')
|
||||
assert num == psutil.virtual_memory().total
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not which('ifconfig'), reason="ifconfig cmd not available"
|
||||
)
|
||||
def test_net_if_stats(self):
|
||||
for name, stats in psutil.net_if_stats().items():
|
||||
try:
|
||||
out = sh("ifconfig %s" % name)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
assert stats.isup == ('RUNNING' in out)
|
||||
if "mtu" in out:
|
||||
assert stats.mtu == int(re.findall(r'mtu (\d+)', out)[0])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- FreeBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(not FREEBSD, reason="FREEBSD only")
|
||||
class FreeBSDPsutilTestCase(PsutilTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_memory_maps(self):
|
||||
out = sh('procstat -v %s' % self.pid)
|
||||
maps = psutil.Process(self.pid).memory_maps(grouped=False)
|
||||
lines = out.split('\n')[1:]
|
||||
while lines:
|
||||
line = lines.pop()
|
||||
fields = line.split()
|
||||
_, start, stop, _perms, res = fields[:5]
|
||||
map = maps.pop()
|
||||
assert "%s-%s" % (start, stop) == map.addr
|
||||
assert int(res) == map.rss
|
||||
if not map.path.startswith('['):
|
||||
assert fields[10] == map.path
|
||||
|
||||
def test_exe(self):
|
||||
out = sh('procstat -b %s' % self.pid)
|
||||
assert psutil.Process(self.pid).exe() == out.split('\n')[1].split()[-1]
|
||||
|
||||
def test_cmdline(self):
|
||||
out = sh('procstat -c %s' % self.pid)
|
||||
assert ' '.join(psutil.Process(self.pid).cmdline()) == ' '.join(
|
||||
out.split('\n')[1].split()[2:]
|
||||
)
|
||||
|
||||
def test_uids_gids(self):
|
||||
out = sh('procstat -s %s' % self.pid)
|
||||
euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8]
|
||||
p = psutil.Process(self.pid)
|
||||
uids = p.uids()
|
||||
gids = p.gids()
|
||||
assert uids.real == int(ruid)
|
||||
assert uids.effective == int(euid)
|
||||
assert uids.saved == int(suid)
|
||||
assert gids.real == int(rgid)
|
||||
assert gids.effective == int(egid)
|
||||
assert gids.saved == int(sgid)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_ctx_switches(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
for line in out.split('\n'):
|
||||
line = line.lower().strip()
|
||||
if ' voluntary context' in line:
|
||||
pstat_value = int(line.split()[-1])
|
||||
psutil_value = p.num_ctx_switches().voluntary
|
||||
assert pstat_value == psutil_value
|
||||
tested.append(None)
|
||||
elif ' involuntary context' in line:
|
||||
pstat_value = int(line.split()[-1])
|
||||
psutil_value = p.num_ctx_switches().involuntary
|
||||
assert pstat_value == psutil_value
|
||||
tested.append(None)
|
||||
if len(tested) != 2:
|
||||
raise RuntimeError("couldn't find lines match in procstat out")
|
||||
|
||||
@retry_on_failure()
|
||||
def test_cpu_times(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
for line in out.split('\n'):
|
||||
line = line.lower().strip()
|
||||
if 'user time' in line:
|
||||
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||
psutil_value = p.cpu_times().user
|
||||
assert pstat_value == psutil_value
|
||||
tested.append(None)
|
||||
elif 'system time' in line:
|
||||
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||
psutil_value = p.cpu_times().system
|
||||
assert pstat_value == psutil_value
|
||||
tested.append(None)
|
||||
if len(tested) != 2:
|
||||
raise RuntimeError("couldn't find lines match in procstat out")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not FREEBSD, reason="FREEBSD only")
|
||||
class FreeBSDSystemTestCase(PsutilTestCase):
|
||||
@staticmethod
|
||||
def parse_swapinfo():
|
||||
# the last line is always the total
|
||||
output = sh("swapinfo -k").splitlines()[-1]
|
||||
parts = re.split(r'\s+', output)
|
||||
|
||||
if not parts:
|
||||
raise ValueError("Can't parse swapinfo: %s" % output)
|
||||
|
||||
# the size is in 1k units, so multiply by 1024
|
||||
total, used, free = (int(p) * 1024 for p in parts[1:4])
|
||||
return total, used, free
|
||||
|
||||
def test_cpu_frequency_against_sysctl(self):
|
||||
# Currently only cpu 0 is frequency is supported in FreeBSD
|
||||
# All other cores use the same frequency.
|
||||
sensor = "dev.cpu.0.freq"
|
||||
try:
|
||||
sysctl_result = int(sysctl(sensor))
|
||||
except RuntimeError:
|
||||
raise pytest.skip("frequencies not supported by kernel")
|
||||
assert psutil.cpu_freq().current == sysctl_result
|
||||
|
||||
sensor = "dev.cpu.0.freq_levels"
|
||||
sysctl_result = sysctl(sensor)
|
||||
# sysctl returns a string of the format:
|
||||
# <freq_level_1>/<voltage_level_1> <freq_level_2>/<voltage_level_2>...
|
||||
# Ordered highest available to lowest available.
|
||||
max_freq = int(sysctl_result.split()[0].split("/")[0])
|
||||
min_freq = int(sysctl_result.split()[-1].split("/")[0])
|
||||
assert psutil.cpu_freq().max == max_freq
|
||||
assert psutil.cpu_freq().min == min_freq
|
||||
|
||||
# --- virtual_memory(); tests against sysctl
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_active(self):
|
||||
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
|
||||
assert abs(psutil.virtual_memory().active - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_inactive(self):
|
||||
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
|
||||
assert abs(psutil.virtual_memory().inactive - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_wired(self):
|
||||
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
|
||||
assert abs(psutil.virtual_memory().wired - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_cached(self):
|
||||
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
|
||||
assert abs(psutil.virtual_memory().cached - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_free(self):
|
||||
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
|
||||
assert abs(psutil.virtual_memory().free - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_buffers(self):
|
||||
syst = sysctl("vfs.bufspace")
|
||||
assert abs(psutil.virtual_memory().buffers - syst) < TOLERANCE_SYS_MEM
|
||||
|
||||
# --- virtual_memory(); tests against muse
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
def test_muse_vmem_total(self):
|
||||
num = muse('Total')
|
||||
assert psutil.virtual_memory().total == num
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_active(self):
|
||||
num = muse('Active')
|
||||
assert abs(psutil.virtual_memory().active - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_inactive(self):
|
||||
num = muse('Inactive')
|
||||
assert abs(psutil.virtual_memory().inactive - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_wired(self):
|
||||
num = muse('Wired')
|
||||
assert abs(psutil.virtual_memory().wired - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_cached(self):
|
||||
num = muse('Cache')
|
||||
assert abs(psutil.virtual_memory().cached - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_free(self):
|
||||
num = muse('Free')
|
||||
assert abs(psutil.virtual_memory().free - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
@pytest.mark.skipif(not MUSE_AVAILABLE, reason="muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_buffers(self):
|
||||
num = muse('Buffer')
|
||||
assert abs(psutil.virtual_memory().buffers - num) < TOLERANCE_SYS_MEM
|
||||
|
||||
def test_cpu_stats_ctx_switches(self):
|
||||
assert (
|
||||
abs(
|
||||
psutil.cpu_stats().ctx_switches
|
||||
- sysctl('vm.stats.sys.v_swtch')
|
||||
)
|
||||
< 1000
|
||||
)
|
||||
|
||||
def test_cpu_stats_interrupts(self):
|
||||
assert (
|
||||
abs(psutil.cpu_stats().interrupts - sysctl('vm.stats.sys.v_intr'))
|
||||
< 1000
|
||||
)
|
||||
|
||||
def test_cpu_stats_soft_interrupts(self):
|
||||
assert (
|
||||
abs(
|
||||
psutil.cpu_stats().soft_interrupts
|
||||
- sysctl('vm.stats.sys.v_soft')
|
||||
)
|
||||
< 1000
|
||||
)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_cpu_stats_syscalls(self):
|
||||
# pretty high tolerance but it looks like it's OK.
|
||||
assert (
|
||||
abs(psutil.cpu_stats().syscalls - sysctl('vm.stats.sys.v_syscall'))
|
||||
< 200000
|
||||
)
|
||||
|
||||
# def test_cpu_stats_traps(self):
|
||||
# self.assertAlmostEqual(psutil.cpu_stats().traps,
|
||||
# sysctl('vm.stats.sys.v_trap'), delta=1000)
|
||||
|
||||
# --- swap memory
|
||||
|
||||
def test_swapmem_free(self):
|
||||
_total, _used, free = self.parse_swapinfo()
|
||||
assert abs(psutil.swap_memory().free - free) < TOLERANCE_SYS_MEM
|
||||
|
||||
def test_swapmem_used(self):
|
||||
_total, used, _free = self.parse_swapinfo()
|
||||
assert abs(psutil.swap_memory().used - used) < TOLERANCE_SYS_MEM
|
||||
|
||||
def test_swapmem_total(self):
|
||||
total, _used, _free = self.parse_swapinfo()
|
||||
assert abs(psutil.swap_memory().total - total) < TOLERANCE_SYS_MEM
|
||||
|
||||
# --- others
|
||||
|
||||
def test_boot_time(self):
|
||||
s = sysctl('sysctl kern.boottime')
|
||||
s = s[s.find(" sec = ") + 7 :]
|
||||
s = s[: s.find(',')]
|
||||
btime = int(s)
|
||||
assert btime == psutil.boot_time()
|
||||
|
||||
# --- sensors_battery
|
||||
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_sensors_battery(self):
|
||||
def secs2hours(secs):
|
||||
m, _s = divmod(secs, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%d:%02d" % (h, m)
|
||||
|
||||
out = sh("acpiconf -i 0")
|
||||
fields = dict(
|
||||
[(x.split('\t')[0], x.split('\t')[-1]) for x in out.split("\n")]
|
||||
)
|
||||
metrics = psutil.sensors_battery()
|
||||
percent = int(fields['Remaining capacity:'].replace('%', ''))
|
||||
remaining_time = fields['Remaining time:']
|
||||
assert metrics.percent == percent
|
||||
if remaining_time == 'unknown':
|
||||
assert metrics.secsleft == psutil.POWER_TIME_UNLIMITED
|
||||
else:
|
||||
assert secs2hours(metrics.secsleft) == remaining_time
|
||||
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_sensors_battery_against_sysctl(self):
|
||||
assert psutil.sensors_battery().percent == sysctl(
|
||||
"hw.acpi.battery.life"
|
||||
)
|
||||
assert psutil.sensors_battery().power_plugged == (
|
||||
sysctl("hw.acpi.acline") == 1
|
||||
)
|
||||
secsleft = psutil.sensors_battery().secsleft
|
||||
if secsleft < 0:
|
||||
assert sysctl("hw.acpi.battery.time") == -1
|
||||
else:
|
||||
assert secsleft == sysctl("hw.acpi.battery.time") * 60
|
||||
|
||||
@pytest.mark.skipif(HAS_BATTERY, reason="has battery")
|
||||
def test_sensors_battery_no_battery(self):
|
||||
# If no battery is present one of these calls is supposed
|
||||
# to fail, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1074
|
||||
with pytest.raises(RuntimeError):
|
||||
sysctl("hw.acpi.battery.life")
|
||||
sysctl("hw.acpi.battery.time")
|
||||
sysctl("hw.acpi.acline")
|
||||
assert psutil.sensors_battery() is None
|
||||
|
||||
# --- sensors_temperatures
|
||||
|
||||
def test_sensors_temperatures_against_sysctl(self):
|
||||
num_cpus = psutil.cpu_count(True)
|
||||
for cpu in range(num_cpus):
|
||||
sensor = "dev.cpu.%s.temperature" % cpu
|
||||
# sysctl returns a string in the format 46.0C
|
||||
try:
|
||||
sysctl_result = int(float(sysctl(sensor)[:-1]))
|
||||
except RuntimeError:
|
||||
raise pytest.skip("temperatures not supported by kernel")
|
||||
assert (
|
||||
abs(
|
||||
psutil.sensors_temperatures()["coretemp"][cpu].current
|
||||
- sysctl_result
|
||||
)
|
||||
< 10
|
||||
)
|
||||
|
||||
sensor = "dev.cpu.%s.coretemp.tjmax" % cpu
|
||||
sysctl_result = int(float(sysctl(sensor)[:-1]))
|
||||
assert (
|
||||
psutil.sensors_temperatures()["coretemp"][cpu].high
|
||||
== sysctl_result
|
||||
)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- OpenBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(not OPENBSD, reason="OPENBSD only")
|
||||
class OpenBSDTestCase(PsutilTestCase):
|
||||
def test_boot_time(self):
|
||||
s = sysctl('kern.boottime')
|
||||
sys_bt = datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y")
|
||||
psutil_bt = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||
assert sys_bt == psutil_bt
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- NetBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(not NETBSD, reason="NETBSD only")
|
||||
class NetBSDTestCase(PsutilTestCase):
|
||||
@staticmethod
|
||||
def parse_meminfo(look_for):
|
||||
with open('/proc/meminfo') as f:
|
||||
for line in f:
|
||||
if line.startswith(look_for):
|
||||
return int(line.split()[1]) * 1024
|
||||
raise ValueError("can't find %s" % look_for)
|
||||
|
||||
# --- virtual mem
|
||||
|
||||
def test_vmem_total(self):
|
||||
assert psutil.virtual_memory().total == self.parse_meminfo("MemTotal:")
|
||||
|
||||
def test_vmem_free(self):
|
||||
assert (
|
||||
abs(psutil.virtual_memory().free - self.parse_meminfo("MemFree:"))
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_vmem_buffers(self):
|
||||
assert (
|
||||
abs(
|
||||
psutil.virtual_memory().buffers
|
||||
- self.parse_meminfo("Buffers:")
|
||||
)
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_vmem_shared(self):
|
||||
assert (
|
||||
abs(
|
||||
psutil.virtual_memory().shared
|
||||
- self.parse_meminfo("MemShared:")
|
||||
)
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_vmem_cached(self):
|
||||
assert (
|
||||
abs(psutil.virtual_memory().cached - self.parse_meminfo("Cached:"))
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
# --- swap mem
|
||||
|
||||
def test_swapmem_total(self):
|
||||
assert (
|
||||
abs(psutil.swap_memory().total - self.parse_meminfo("SwapTotal:"))
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_swapmem_free(self):
|
||||
assert (
|
||||
abs(psutil.swap_memory().free - self.parse_meminfo("SwapFree:"))
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_swapmem_used(self):
|
||||
smem = psutil.swap_memory()
|
||||
assert smem.used == smem.total - smem.free
|
||||
|
||||
# --- others
|
||||
|
||||
def test_cpu_stats_interrupts(self):
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'intr'):
|
||||
interrupts = int(line.split()[1])
|
||||
break
|
||||
else:
|
||||
raise ValueError("couldn't find line")
|
||||
assert abs(psutil.cpu_stats().interrupts - interrupts) < 1000
|
||||
|
||||
def test_cpu_stats_ctx_switches(self):
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'ctxt'):
|
||||
ctx_switches = int(line.split()[1])
|
||||
break
|
||||
else:
|
||||
raise ValueError("couldn't find line")
|
||||
assert abs(psutil.cpu_stats().ctx_switches - ctx_switches) < 1000
|
567
env/lib/python3.12/site-packages/psutil/tests/test_connections.py
vendored
Normal file
567
env/lib/python3.12/site-packages/psutil/tests/test_connections.py
vendored
Normal file
@ -0,0 +1,567 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Tests for psutil.net_connections() and Process.net_connections() APIs."""
|
||||
|
||||
import os
|
||||
import socket
|
||||
import textwrap
|
||||
from contextlib import closing
|
||||
from socket import AF_INET
|
||||
from socket import AF_INET6
|
||||
from socket import SOCK_DGRAM
|
||||
from socket import SOCK_STREAM
|
||||
|
||||
import psutil
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._common import supports_ipv6
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import AF_UNIX
|
||||
from psutil.tests import HAS_NET_CONNECTIONS_UNIX
|
||||
from psutil.tests import SKIP_SYSCONS
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import bind_socket
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import check_connection_ntuple
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import filter_proc_net_connections
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import tcp_socketpair
|
||||
from psutil.tests import unix_socketpair
|
||||
from psutil.tests import wait_for_file
|
||||
|
||||
|
||||
SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
|
||||
|
||||
|
||||
def this_proc_net_connections(kind):
|
||||
cons = psutil.Process().net_connections(kind=kind)
|
||||
if kind in ("all", "unix"):
|
||||
return filter_proc_net_connections(cons)
|
||||
return cons
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="serial")
|
||||
class ConnectionTestCase(PsutilTestCase):
|
||||
def setUp(self):
|
||||
assert this_proc_net_connections(kind='all') == []
|
||||
|
||||
def tearDown(self):
|
||||
# Make sure we closed all resources.
|
||||
assert this_proc_net_connections(kind='all') == []
|
||||
|
||||
def compare_procsys_connections(self, pid, proc_cons, kind='all'):
|
||||
"""Given a process PID and its list of connections compare
|
||||
those against system-wide connections retrieved via
|
||||
psutil.net_connections.
|
||||
"""
|
||||
try:
|
||||
sys_cons = psutil.net_connections(kind=kind)
|
||||
except psutil.AccessDenied:
|
||||
# On MACOS, system-wide connections are retrieved by iterating
|
||||
# over all processes
|
||||
if MACOS:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
# Filter for this proc PID and exlucde PIDs from the tuple.
|
||||
sys_cons = [c[:-1] for c in sys_cons if c.pid == pid]
|
||||
sys_cons.sort()
|
||||
proc_cons.sort()
|
||||
assert proc_cons == sys_cons
|
||||
|
||||
|
||||
class TestBasicOperations(ConnectionTestCase):
|
||||
@pytest.mark.skipif(SKIP_SYSCONS, reason="requires root")
|
||||
def test_system(self):
|
||||
with create_sockets():
|
||||
for conn in psutil.net_connections(kind='all'):
|
||||
check_connection_ntuple(conn)
|
||||
|
||||
def test_process(self):
|
||||
with create_sockets():
|
||||
for conn in this_proc_net_connections(kind='all'):
|
||||
check_connection_ntuple(conn)
|
||||
|
||||
def test_invalid_kind(self):
|
||||
with pytest.raises(ValueError):
|
||||
this_proc_net_connections(kind='???')
|
||||
with pytest.raises(ValueError):
|
||||
psutil.net_connections(kind='???')
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="serial")
|
||||
class TestUnconnectedSockets(ConnectionTestCase):
|
||||
"""Tests sockets which are open but not connected to anything."""
|
||||
|
||||
def get_conn_from_sock(self, sock):
|
||||
cons = this_proc_net_connections(kind='all')
|
||||
smap = dict([(c.fd, c) for c in cons])
|
||||
if NETBSD or FREEBSD:
|
||||
# NetBSD opens a UNIX socket to /var/log/run
|
||||
# so there may be more connections.
|
||||
return smap[sock.fileno()]
|
||||
else:
|
||||
assert len(cons) == 1
|
||||
if cons[0].fd != -1:
|
||||
assert smap[sock.fileno()].fd == sock.fileno()
|
||||
return cons[0]
|
||||
|
||||
def check_socket(self, sock):
|
||||
"""Given a socket, makes sure it matches the one obtained
|
||||
via psutil. It assumes this process created one connection
|
||||
only (the one supposed to be checked).
|
||||
"""
|
||||
conn = self.get_conn_from_sock(sock)
|
||||
check_connection_ntuple(conn)
|
||||
|
||||
# fd, family, type
|
||||
if conn.fd != -1:
|
||||
assert conn.fd == sock.fileno()
|
||||
assert conn.family == sock.family
|
||||
# see: http://bugs.python.org/issue30204
|
||||
assert conn.type == sock.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE)
|
||||
|
||||
# local address
|
||||
laddr = sock.getsockname()
|
||||
if not laddr and PY3 and isinstance(laddr, bytes):
|
||||
# See: http://bugs.python.org/issue30205
|
||||
laddr = laddr.decode()
|
||||
if sock.family == AF_INET6:
|
||||
laddr = laddr[:2]
|
||||
assert conn.laddr == laddr
|
||||
|
||||
# XXX Solaris can't retrieve system-wide UNIX sockets
|
||||
if sock.family == AF_UNIX and HAS_NET_CONNECTIONS_UNIX:
|
||||
cons = this_proc_net_connections(kind='all')
|
||||
self.compare_procsys_connections(os.getpid(), cons, kind='all')
|
||||
return conn
|
||||
|
||||
def test_tcp_v4(self):
|
||||
addr = ("127.0.0.1", 0)
|
||||
with closing(bind_socket(AF_INET, SOCK_STREAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == ()
|
||||
assert conn.status == psutil.CONN_LISTEN
|
||||
|
||||
@pytest.mark.skipif(not supports_ipv6(), reason="IPv6 not supported")
|
||||
def test_tcp_v6(self):
|
||||
addr = ("::1", 0)
|
||||
with closing(bind_socket(AF_INET6, SOCK_STREAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == ()
|
||||
assert conn.status == psutil.CONN_LISTEN
|
||||
|
||||
def test_udp_v4(self):
|
||||
addr = ("127.0.0.1", 0)
|
||||
with closing(bind_socket(AF_INET, SOCK_DGRAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == ()
|
||||
assert conn.status == psutil.CONN_NONE
|
||||
|
||||
@pytest.mark.skipif(not supports_ipv6(), reason="IPv6 not supported")
|
||||
def test_udp_v6(self):
|
||||
addr = ("::1", 0)
|
||||
with closing(bind_socket(AF_INET6, SOCK_DGRAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == ()
|
||||
assert conn.status == psutil.CONN_NONE
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_unix_tcp(self):
|
||||
testfn = self.get_testfn()
|
||||
with closing(bind_unix_socket(testfn, type=SOCK_STREAM)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == "" # noqa
|
||||
assert conn.status == psutil.CONN_NONE
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_unix_udp(self):
|
||||
testfn = self.get_testfn()
|
||||
with closing(bind_unix_socket(testfn, type=SOCK_STREAM)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert conn.raddr == "" # noqa
|
||||
assert conn.status == psutil.CONN_NONE
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="serial")
|
||||
class TestConnectedSocket(ConnectionTestCase):
|
||||
"""Test socket pairs which are actually connected to
|
||||
each other.
|
||||
"""
|
||||
|
||||
# On SunOS, even after we close() it, the server socket stays around
|
||||
# in TIME_WAIT state.
|
||||
@pytest.mark.skipif(SUNOS, reason="unreliable on SUONS")
|
||||
def test_tcp(self):
|
||||
addr = ("127.0.0.1", 0)
|
||||
assert this_proc_net_connections(kind='tcp4') == []
|
||||
server, client = tcp_socketpair(AF_INET, addr=addr)
|
||||
try:
|
||||
cons = this_proc_net_connections(kind='tcp4')
|
||||
assert len(cons) == 2
|
||||
assert cons[0].status == psutil.CONN_ESTABLISHED
|
||||
assert cons[1].status == psutil.CONN_ESTABLISHED
|
||||
# May not be fast enough to change state so it stays
|
||||
# commenteed.
|
||||
# client.close()
|
||||
# cons = this_proc_net_connections(kind='all')
|
||||
# self.assertEqual(len(cons), 1)
|
||||
# self.assertEqual(cons[0].status, psutil.CONN_CLOSE_WAIT)
|
||||
finally:
|
||||
server.close()
|
||||
client.close()
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_unix(self):
|
||||
testfn = self.get_testfn()
|
||||
server, client = unix_socketpair(testfn)
|
||||
try:
|
||||
cons = this_proc_net_connections(kind='unix')
|
||||
assert not (cons[0].laddr and cons[0].raddr), cons
|
||||
assert not (cons[1].laddr and cons[1].raddr), cons
|
||||
if NETBSD or FREEBSD:
|
||||
# On NetBSD creating a UNIX socket will cause
|
||||
# a UNIX connection to /var/run/log.
|
||||
cons = [c for c in cons if c.raddr != '/var/run/log']
|
||||
assert len(cons) == 2
|
||||
if LINUX or FREEBSD or SUNOS or OPENBSD:
|
||||
# remote path is never set
|
||||
assert cons[0].raddr == "" # noqa
|
||||
assert cons[1].raddr == "" # noqa
|
||||
# one local address should though
|
||||
assert testfn == (cons[0].laddr or cons[1].laddr)
|
||||
else:
|
||||
# On other systems either the laddr or raddr
|
||||
# of both peers are set.
|
||||
assert (cons[0].laddr or cons[1].laddr) == testfn
|
||||
finally:
|
||||
server.close()
|
||||
client.close()
|
||||
|
||||
|
||||
class TestFilters(ConnectionTestCase):
|
||||
def test_filters(self):
|
||||
def check(kind, families, types):
|
||||
for conn in this_proc_net_connections(kind=kind):
|
||||
assert conn.family in families
|
||||
assert conn.type in types
|
||||
if not SKIP_SYSCONS:
|
||||
for conn in psutil.net_connections(kind=kind):
|
||||
assert conn.family in families
|
||||
assert conn.type in types
|
||||
|
||||
with create_sockets():
|
||||
check(
|
||||
'all',
|
||||
[AF_INET, AF_INET6, AF_UNIX],
|
||||
[SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET],
|
||||
)
|
||||
check('inet', [AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM])
|
||||
check('inet4', [AF_INET], [SOCK_STREAM, SOCK_DGRAM])
|
||||
check('tcp', [AF_INET, AF_INET6], [SOCK_STREAM])
|
||||
check('tcp4', [AF_INET], [SOCK_STREAM])
|
||||
check('tcp6', [AF_INET6], [SOCK_STREAM])
|
||||
check('udp', [AF_INET, AF_INET6], [SOCK_DGRAM])
|
||||
check('udp4', [AF_INET], [SOCK_DGRAM])
|
||||
check('udp6', [AF_INET6], [SOCK_DGRAM])
|
||||
if HAS_NET_CONNECTIONS_UNIX:
|
||||
check(
|
||||
'unix',
|
||||
[AF_UNIX],
|
||||
[SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET],
|
||||
)
|
||||
|
||||
@skip_on_access_denied(only_if=MACOS)
|
||||
def test_combos(self):
|
||||
reap_children()
|
||||
|
||||
def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
|
||||
all_kinds = (
|
||||
"all",
|
||||
"inet",
|
||||
"inet4",
|
||||
"inet6",
|
||||
"tcp",
|
||||
"tcp4",
|
||||
"tcp6",
|
||||
"udp",
|
||||
"udp4",
|
||||
"udp6",
|
||||
)
|
||||
check_connection_ntuple(conn)
|
||||
assert conn.family == family
|
||||
assert conn.type == type
|
||||
assert conn.laddr == laddr
|
||||
assert conn.raddr == raddr
|
||||
assert conn.status == status
|
||||
for kind in all_kinds:
|
||||
cons = proc.net_connections(kind=kind)
|
||||
if kind in kinds:
|
||||
assert cons != []
|
||||
else:
|
||||
assert cons == []
|
||||
# compare against system-wide connections
|
||||
# XXX Solaris can't retrieve system-wide UNIX
|
||||
# sockets.
|
||||
if HAS_NET_CONNECTIONS_UNIX:
|
||||
self.compare_procsys_connections(proc.pid, [conn])
|
||||
|
||||
tcp_template = textwrap.dedent("""
|
||||
import socket, time
|
||||
s = socket.socket({family}, socket.SOCK_STREAM)
|
||||
s.bind(('{addr}', 0))
|
||||
s.listen(5)
|
||||
with open('{testfn}', 'w') as f:
|
||||
f.write(str(s.getsockname()[:2]))
|
||||
[time.sleep(0.1) for x in range(100)]
|
||||
""")
|
||||
|
||||
udp_template = textwrap.dedent("""
|
||||
import socket, time
|
||||
s = socket.socket({family}, socket.SOCK_DGRAM)
|
||||
s.bind(('{addr}', 0))
|
||||
with open('{testfn}', 'w') as f:
|
||||
f.write(str(s.getsockname()[:2]))
|
||||
[time.sleep(0.1) for x in range(100)]
|
||||
""")
|
||||
|
||||
# must be relative on Windows
|
||||
testfile = os.path.basename(self.get_testfn(dir=os.getcwd()))
|
||||
tcp4_template = tcp_template.format(
|
||||
family=int(AF_INET), addr="127.0.0.1", testfn=testfile
|
||||
)
|
||||
udp4_template = udp_template.format(
|
||||
family=int(AF_INET), addr="127.0.0.1", testfn=testfile
|
||||
)
|
||||
tcp6_template = tcp_template.format(
|
||||
family=int(AF_INET6), addr="::1", testfn=testfile
|
||||
)
|
||||
udp6_template = udp_template.format(
|
||||
family=int(AF_INET6), addr="::1", testfn=testfile
|
||||
)
|
||||
|
||||
# launch various subprocess instantiating a socket of various
|
||||
# families and types to enrich psutil results
|
||||
tcp4_proc = self.pyrun(tcp4_template)
|
||||
tcp4_addr = eval(wait_for_file(testfile, delete=True)) # noqa
|
||||
udp4_proc = self.pyrun(udp4_template)
|
||||
udp4_addr = eval(wait_for_file(testfile, delete=True)) # noqa
|
||||
if supports_ipv6():
|
||||
tcp6_proc = self.pyrun(tcp6_template)
|
||||
tcp6_addr = eval(wait_for_file(testfile, delete=True)) # noqa
|
||||
udp6_proc = self.pyrun(udp6_template)
|
||||
udp6_addr = eval(wait_for_file(testfile, delete=True)) # noqa
|
||||
else:
|
||||
tcp6_proc = None
|
||||
udp6_proc = None
|
||||
tcp6_addr = None
|
||||
udp6_addr = None
|
||||
|
||||
for p in psutil.Process().children():
|
||||
cons = p.net_connections()
|
||||
assert len(cons) == 1
|
||||
for conn in cons:
|
||||
# TCP v4
|
||||
if p.pid == tcp4_proc.pid:
|
||||
check_conn(
|
||||
p,
|
||||
conn,
|
||||
AF_INET,
|
||||
SOCK_STREAM,
|
||||
tcp4_addr,
|
||||
(),
|
||||
psutil.CONN_LISTEN,
|
||||
("all", "inet", "inet4", "tcp", "tcp4"),
|
||||
)
|
||||
# UDP v4
|
||||
elif p.pid == udp4_proc.pid:
|
||||
check_conn(
|
||||
p,
|
||||
conn,
|
||||
AF_INET,
|
||||
SOCK_DGRAM,
|
||||
udp4_addr,
|
||||
(),
|
||||
psutil.CONN_NONE,
|
||||
("all", "inet", "inet4", "udp", "udp4"),
|
||||
)
|
||||
# TCP v6
|
||||
elif p.pid == getattr(tcp6_proc, "pid", None):
|
||||
check_conn(
|
||||
p,
|
||||
conn,
|
||||
AF_INET6,
|
||||
SOCK_STREAM,
|
||||
tcp6_addr,
|
||||
(),
|
||||
psutil.CONN_LISTEN,
|
||||
("all", "inet", "inet6", "tcp", "tcp6"),
|
||||
)
|
||||
# UDP v6
|
||||
elif p.pid == getattr(udp6_proc, "pid", None):
|
||||
check_conn(
|
||||
p,
|
||||
conn,
|
||||
AF_INET6,
|
||||
SOCK_DGRAM,
|
||||
udp6_addr,
|
||||
(),
|
||||
psutil.CONN_NONE,
|
||||
("all", "inet", "inet6", "udp", "udp6"),
|
||||
)
|
||||
|
||||
def test_count(self):
|
||||
with create_sockets():
|
||||
# tcp
|
||||
cons = this_proc_net_connections(kind='tcp')
|
||||
assert len(cons) == (2 if supports_ipv6() else 1)
|
||||
for conn in cons:
|
||||
assert conn.family in (AF_INET, AF_INET6)
|
||||
assert conn.type == SOCK_STREAM
|
||||
# tcp4
|
||||
cons = this_proc_net_connections(kind='tcp4')
|
||||
assert len(cons) == 1
|
||||
assert cons[0].family == AF_INET
|
||||
assert cons[0].type == SOCK_STREAM
|
||||
# tcp6
|
||||
if supports_ipv6():
|
||||
cons = this_proc_net_connections(kind='tcp6')
|
||||
assert len(cons) == 1
|
||||
assert cons[0].family == AF_INET6
|
||||
assert cons[0].type == SOCK_STREAM
|
||||
# udp
|
||||
cons = this_proc_net_connections(kind='udp')
|
||||
assert len(cons) == (2 if supports_ipv6() else 1)
|
||||
for conn in cons:
|
||||
assert conn.family in (AF_INET, AF_INET6)
|
||||
assert conn.type == SOCK_DGRAM
|
||||
# udp4
|
||||
cons = this_proc_net_connections(kind='udp4')
|
||||
assert len(cons) == 1
|
||||
assert cons[0].family == AF_INET
|
||||
assert cons[0].type == SOCK_DGRAM
|
||||
# udp6
|
||||
if supports_ipv6():
|
||||
cons = this_proc_net_connections(kind='udp6')
|
||||
assert len(cons) == 1
|
||||
assert cons[0].family == AF_INET6
|
||||
assert cons[0].type == SOCK_DGRAM
|
||||
# inet
|
||||
cons = this_proc_net_connections(kind='inet')
|
||||
assert len(cons) == (4 if supports_ipv6() else 2)
|
||||
for conn in cons:
|
||||
assert conn.family in (AF_INET, AF_INET6)
|
||||
assert conn.type in (SOCK_STREAM, SOCK_DGRAM)
|
||||
# inet6
|
||||
if supports_ipv6():
|
||||
cons = this_proc_net_connections(kind='inet6')
|
||||
assert len(cons) == 2
|
||||
for conn in cons:
|
||||
assert conn.family == AF_INET6
|
||||
assert conn.type in (SOCK_STREAM, SOCK_DGRAM)
|
||||
# Skipped on BSD becayse by default the Python process
|
||||
# creates a UNIX socket to '/var/run/log'.
|
||||
if HAS_NET_CONNECTIONS_UNIX and not (FREEBSD or NETBSD):
|
||||
cons = this_proc_net_connections(kind='unix')
|
||||
assert len(cons) == 3
|
||||
for conn in cons:
|
||||
assert conn.family == AF_UNIX
|
||||
assert conn.type in (SOCK_STREAM, SOCK_DGRAM)
|
||||
|
||||
|
||||
@pytest.mark.skipif(SKIP_SYSCONS, reason="requires root")
|
||||
class TestSystemWideConnections(ConnectionTestCase):
|
||||
"""Tests for net_connections()."""
|
||||
|
||||
def test_it(self):
|
||||
def check(cons, families, types_):
|
||||
for conn in cons:
|
||||
assert conn.family in families
|
||||
if conn.family != AF_UNIX:
|
||||
assert conn.type in types_
|
||||
check_connection_ntuple(conn)
|
||||
|
||||
with create_sockets():
|
||||
from psutil._common import conn_tmap
|
||||
|
||||
for kind, groups in conn_tmap.items():
|
||||
# XXX: SunOS does not retrieve UNIX sockets.
|
||||
if kind == 'unix' and not HAS_NET_CONNECTIONS_UNIX:
|
||||
continue
|
||||
families, types_ = groups
|
||||
cons = psutil.net_connections(kind)
|
||||
assert len(cons) == len(set(cons))
|
||||
check(cons, families, types_)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_multi_sockets_procs(self):
|
||||
# Creates multiple sub processes, each creating different
|
||||
# sockets. For each process check that proc.net_connections()
|
||||
# and psutil.net_connections() return the same results.
|
||||
# This is done mainly to check whether net_connections()'s
|
||||
# pid is properly set, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1013
|
||||
with create_sockets() as socks:
|
||||
expected = len(socks)
|
||||
pids = []
|
||||
times = 10
|
||||
fnames = []
|
||||
for _ in range(times):
|
||||
fname = self.get_testfn()
|
||||
fnames.append(fname)
|
||||
src = textwrap.dedent("""\
|
||||
import time, os
|
||||
from psutil.tests import create_sockets
|
||||
with create_sockets():
|
||||
with open(r'%s', 'w') as f:
|
||||
f.write("hello")
|
||||
[time.sleep(0.1) for x in range(100)]
|
||||
""" % fname)
|
||||
sproc = self.pyrun(src)
|
||||
pids.append(sproc.pid)
|
||||
|
||||
# sync
|
||||
for fname in fnames:
|
||||
wait_for_file(fname)
|
||||
|
||||
syscons = [
|
||||
x for x in psutil.net_connections(kind='all') if x.pid in pids
|
||||
]
|
||||
for pid in pids:
|
||||
assert len([x for x in syscons if x.pid == pid]) == expected
|
||||
p = psutil.Process(pid)
|
||||
assert len(p.net_connections('all')) == expected
|
||||
|
||||
|
||||
class TestMisc(PsutilTestCase):
|
||||
def test_net_connection_constants(self):
|
||||
ints = []
|
||||
strs = []
|
||||
for name in dir(psutil):
|
||||
if name.startswith('CONN_'):
|
||||
num = getattr(psutil, name)
|
||||
str_ = str(num)
|
||||
assert str_.isupper(), str_
|
||||
assert str not in strs
|
||||
assert num not in ints
|
||||
ints.append(num)
|
||||
strs.append(str_)
|
||||
if SUNOS:
|
||||
psutil.CONN_IDLE # noqa
|
||||
psutil.CONN_BOUND # noqa
|
||||
if WINDOWS:
|
||||
psutil.CONN_DELETE_TCB # noqa
|
339
env/lib/python3.12/site-packages/psutil/tests/test_contracts.py
vendored
Normal file
339
env/lib/python3.12/site-packages/psutil/tests/test_contracts.py
vendored
Normal file
@ -0,0 +1,339 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Contracts tests. These tests mainly check API sanity in terms of
|
||||
returned types and APIs availability.
|
||||
Some of these are duplicates of tests test_system.py and test_process.py.
|
||||
"""
|
||||
|
||||
import platform
|
||||
import signal
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import long
|
||||
from psutil.tests import GITHUB_ACTIONS
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import QEMU_USER
|
||||
from psutil.tests import SKIP_SYSCONS
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import is_namedtuple
|
||||
from psutil.tests import kernel_version
|
||||
from psutil.tests import pytest
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- APIs availability
|
||||
# ===================================================================
|
||||
|
||||
# Make sure code reflects what doc promises in terms of APIs
|
||||
# availability.
|
||||
|
||||
|
||||
class TestAvailConstantsAPIs(PsutilTestCase):
|
||||
def test_PROCFS_PATH(self):
|
||||
assert hasattr(psutil, "PROCFS_PATH") == (LINUX or SUNOS or AIX)
|
||||
|
||||
def test_win_priority(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "ABOVE_NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "BELOW_NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "HIGH_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "IDLE_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "REALTIME_PRIORITY_CLASS"), WINDOWS)
|
||||
|
||||
def test_linux_ioprio_linux(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_NONE"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_RT"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_BE"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_IDLE"), LINUX)
|
||||
|
||||
def test_linux_ioprio_windows(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "IOPRIO_HIGH"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_NORMAL"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_LOW"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_VERYLOW"), WINDOWS)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
GITHUB_ACTIONS and LINUX,
|
||||
reason="unsupported on GITHUB_ACTIONS + LINUX",
|
||||
)
|
||||
def test_rlimit(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "RLIM_INFINITY"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_AS"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_CORE"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_CPU"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_DATA"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_FSIZE"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_MEMLOCK"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_NOFILE"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_NPROC"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_RSS"), LINUX or FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_STACK"), LINUX or FREEBSD)
|
||||
|
||||
ae(hasattr(psutil, "RLIMIT_LOCKS"), LINUX)
|
||||
if POSIX:
|
||||
if kernel_version() >= (2, 6, 8):
|
||||
ae(hasattr(psutil, "RLIMIT_MSGQUEUE"), LINUX)
|
||||
if kernel_version() >= (2, 6, 12):
|
||||
ae(hasattr(psutil, "RLIMIT_NICE"), LINUX)
|
||||
if kernel_version() >= (2, 6, 12):
|
||||
ae(hasattr(psutil, "RLIMIT_RTPRIO"), LINUX)
|
||||
if kernel_version() >= (2, 6, 25):
|
||||
ae(hasattr(psutil, "RLIMIT_RTTIME"), LINUX)
|
||||
if kernel_version() >= (2, 6, 8):
|
||||
ae(hasattr(psutil, "RLIMIT_SIGPENDING"), LINUX)
|
||||
|
||||
ae(hasattr(psutil, "RLIMIT_SWAP"), FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_SBSIZE"), FREEBSD)
|
||||
ae(hasattr(psutil, "RLIMIT_NPTS"), FREEBSD)
|
||||
|
||||
|
||||
class TestAvailSystemAPIs(PsutilTestCase):
|
||||
def test_win_service_iter(self):
|
||||
assert hasattr(psutil, "win_service_iter") == WINDOWS
|
||||
|
||||
def test_win_service_get(self):
|
||||
assert hasattr(psutil, "win_service_get") == WINDOWS
|
||||
|
||||
def test_cpu_freq(self):
|
||||
assert hasattr(psutil, "cpu_freq") == (
|
||||
LINUX or MACOS or WINDOWS or FREEBSD or OPENBSD
|
||||
)
|
||||
|
||||
def test_sensors_temperatures(self):
|
||||
assert hasattr(psutil, "sensors_temperatures") == (LINUX or FREEBSD)
|
||||
|
||||
def test_sensors_fans(self):
|
||||
assert hasattr(psutil, "sensors_fans") == LINUX
|
||||
|
||||
def test_battery(self):
|
||||
assert hasattr(psutil, "sensors_battery") == (
|
||||
LINUX or WINDOWS or FREEBSD or MACOS
|
||||
)
|
||||
|
||||
|
||||
class TestAvailProcessAPIs(PsutilTestCase):
|
||||
def test_environ(self):
|
||||
assert hasattr(psutil.Process, "environ") == (
|
||||
LINUX
|
||||
or MACOS
|
||||
or WINDOWS
|
||||
or AIX
|
||||
or SUNOS
|
||||
or FREEBSD
|
||||
or OPENBSD
|
||||
or NETBSD
|
||||
)
|
||||
|
||||
def test_uids(self):
|
||||
assert hasattr(psutil.Process, "uids") == POSIX
|
||||
|
||||
def test_gids(self):
|
||||
assert hasattr(psutil.Process, "uids") == POSIX
|
||||
|
||||
def test_terminal(self):
|
||||
assert hasattr(psutil.Process, "terminal") == POSIX
|
||||
|
||||
def test_ionice(self):
|
||||
assert hasattr(psutil.Process, "ionice") == (LINUX or WINDOWS)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
GITHUB_ACTIONS and LINUX,
|
||||
reason="unsupported on GITHUB_ACTIONS + LINUX",
|
||||
)
|
||||
def test_rlimit(self):
|
||||
assert hasattr(psutil.Process, "rlimit") == (LINUX or FREEBSD)
|
||||
|
||||
def test_io_counters(self):
|
||||
hasit = hasattr(psutil.Process, "io_counters")
|
||||
assert hasit == (not (MACOS or SUNOS))
|
||||
|
||||
def test_num_fds(self):
|
||||
assert hasattr(psutil.Process, "num_fds") == POSIX
|
||||
|
||||
def test_num_handles(self):
|
||||
assert hasattr(psutil.Process, "num_handles") == WINDOWS
|
||||
|
||||
def test_cpu_affinity(self):
|
||||
assert hasattr(psutil.Process, "cpu_affinity") == (
|
||||
LINUX or WINDOWS or FREEBSD
|
||||
)
|
||||
|
||||
def test_cpu_num(self):
|
||||
assert hasattr(psutil.Process, "cpu_num") == (
|
||||
LINUX or FREEBSD or SUNOS
|
||||
)
|
||||
|
||||
def test_memory_maps(self):
|
||||
hasit = hasattr(psutil.Process, "memory_maps")
|
||||
assert hasit == (not (OPENBSD or NETBSD or AIX or MACOS))
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- API types
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestSystemAPITypes(PsutilTestCase):
|
||||
"""Check the return types of system related APIs.
|
||||
Mainly we want to test we never return unicode on Python 2, see:
|
||||
https://github.com/giampaolo/psutil/issues/1039.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.proc = psutil.Process()
|
||||
|
||||
def assert_ntuple_of_nums(self, nt, type_=float, gezero=True):
|
||||
assert is_namedtuple(nt)
|
||||
for n in nt:
|
||||
assert isinstance(n, type_)
|
||||
if gezero:
|
||||
assert n >= 0
|
||||
|
||||
def test_cpu_times(self):
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times())
|
||||
for nt in psutil.cpu_times(percpu=True):
|
||||
self.assert_ntuple_of_nums(nt)
|
||||
|
||||
def test_cpu_percent(self):
|
||||
assert isinstance(psutil.cpu_percent(interval=None), float)
|
||||
assert isinstance(psutil.cpu_percent(interval=0.00001), float)
|
||||
|
||||
def test_cpu_times_percent(self):
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=None))
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=0.0001))
|
||||
|
||||
def test_cpu_count(self):
|
||||
assert isinstance(psutil.cpu_count(), int)
|
||||
|
||||
# TODO: remove this once 1892 is fixed
|
||||
@pytest.mark.skipif(
|
||||
MACOS and platform.machine() == 'arm64', reason="skipped due to #1892"
|
||||
)
|
||||
@pytest.mark.skipif(not HAS_CPU_FREQ, reason="not supported")
|
||||
def test_cpu_freq(self):
|
||||
if psutil.cpu_freq() is None:
|
||||
raise pytest.skip("cpu_freq() returns None")
|
||||
self.assert_ntuple_of_nums(psutil.cpu_freq(), type_=(float, int, long))
|
||||
|
||||
def test_disk_io_counters(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for k, v in psutil.disk_io_counters(perdisk=True).items():
|
||||
assert isinstance(k, str)
|
||||
self.assert_ntuple_of_nums(v, type_=(int, long))
|
||||
|
||||
def test_disk_partitions(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for disk in psutil.disk_partitions():
|
||||
assert isinstance(disk.device, str)
|
||||
assert isinstance(disk.mountpoint, str)
|
||||
assert isinstance(disk.fstype, str)
|
||||
assert isinstance(disk.opts, str)
|
||||
|
||||
@pytest.mark.skipif(SKIP_SYSCONS, reason="requires root")
|
||||
def test_net_connections(self):
|
||||
with create_sockets():
|
||||
ret = psutil.net_connections('all')
|
||||
assert len(ret) == len(set(ret))
|
||||
for conn in ret:
|
||||
assert is_namedtuple(conn)
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname, addrs in psutil.net_if_addrs().items():
|
||||
assert isinstance(ifname, str)
|
||||
for addr in addrs:
|
||||
if enum is not None and not PYPY:
|
||||
assert isinstance(addr.family, enum.IntEnum)
|
||||
else:
|
||||
assert isinstance(addr.family, int)
|
||||
assert isinstance(addr.address, str)
|
||||
assert isinstance(addr.netmask, (str, type(None)))
|
||||
assert isinstance(addr.broadcast, (str, type(None)))
|
||||
|
||||
@pytest.mark.skipif(QEMU_USER, reason="QEMU user not supported")
|
||||
def test_net_if_stats(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname, info in psutil.net_if_stats().items():
|
||||
assert isinstance(ifname, str)
|
||||
assert isinstance(info.isup, bool)
|
||||
if enum is not None:
|
||||
assert isinstance(info.duplex, enum.IntEnum)
|
||||
else:
|
||||
assert isinstance(info.duplex, int)
|
||||
assert isinstance(info.speed, int)
|
||||
assert isinstance(info.mtu, int)
|
||||
|
||||
@pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
|
||||
def test_net_io_counters(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname in psutil.net_io_counters(pernic=True):
|
||||
assert isinstance(ifname, str)
|
||||
|
||||
@pytest.mark.skipif(not HAS_SENSORS_FANS, reason="not supported")
|
||||
def test_sensors_fans(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for name, units in psutil.sensors_fans().items():
|
||||
assert isinstance(name, str)
|
||||
for unit in units:
|
||||
assert isinstance(unit.label, str)
|
||||
assert isinstance(unit.current, (float, int, type(None)))
|
||||
|
||||
@pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for name, units in psutil.sensors_temperatures().items():
|
||||
assert isinstance(name, str)
|
||||
for unit in units:
|
||||
assert isinstance(unit.label, str)
|
||||
assert isinstance(unit.current, (float, int, type(None)))
|
||||
assert isinstance(unit.high, (float, int, type(None)))
|
||||
assert isinstance(unit.critical, (float, int, type(None)))
|
||||
|
||||
def test_boot_time(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
assert isinstance(psutil.boot_time(), float)
|
||||
|
||||
def test_users(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for user in psutil.users():
|
||||
assert isinstance(user.name, str)
|
||||
assert isinstance(user.terminal, (str, type(None)))
|
||||
assert isinstance(user.host, (str, type(None)))
|
||||
assert isinstance(user.pid, (int, type(None)))
|
||||
|
||||
|
||||
class TestProcessWaitType(PsutilTestCase):
|
||||
@pytest.mark.skipif(not POSIX, reason="not POSIX")
|
||||
def test_negative_signal(self):
|
||||
p = psutil.Process(self.spawn_testproc().pid)
|
||||
p.terminate()
|
||||
code = p.wait()
|
||||
assert code == -signal.SIGTERM
|
||||
if enum is not None:
|
||||
assert isinstance(code, enum.IntEnum)
|
||||
else:
|
||||
assert isinstance(code, int)
|
2348
env/lib/python3.12/site-packages/psutil/tests/test_linux.py
vendored
Normal file
2348
env/lib/python3.12/site-packages/psutil/tests/test_linux.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
493
env/lib/python3.12/site-packages/psutil/tests/test_memleaks.py
vendored
Normal file
493
env/lib/python3.12/site-packages/psutil/tests/test_memleaks.py
vendored
Normal file
@ -0,0 +1,493 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Tests for detecting function memory leaks (typically the ones
|
||||
implemented in C). It does so by calling a function many times and
|
||||
checking whether process memory usage keeps increasing between
|
||||
calls or over time.
|
||||
Note that this may produce false positives (especially on Windows
|
||||
for some reason).
|
||||
PyPy appears to be completely unstable for this framework, probably
|
||||
because of how its JIT handles memory, so tests are skipped.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import functools
|
||||
import os
|
||||
import platform
|
||||
|
||||
import psutil
|
||||
import psutil._common
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import ProcessLookupError
|
||||
from psutil._compat import super
|
||||
from psutil.tests import HAS_CPU_AFFINITY
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_ENVIRON
|
||||
from psutil.tests import HAS_IONICE
|
||||
from psutil.tests import HAS_MEMORY_MAPS
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_PROC_CPU_NUM
|
||||
from psutil.tests import HAS_PROC_IO_COUNTERS
|
||||
from psutil.tests import HAS_RLIMIT
|
||||
from psutil.tests import HAS_SENSORS_BATTERY
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import QEMU_USER
|
||||
from psutil.tests import TestMemoryLeak
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import get_testfn
|
||||
from psutil.tests import process_namespace
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import system_namespace
|
||||
from psutil.tests import terminate
|
||||
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
thisproc = psutil.Process()
|
||||
FEW_TIMES = 5
|
||||
|
||||
|
||||
def fewtimes_if_linux():
|
||||
"""Decorator for those Linux functions which are implemented in pure
|
||||
Python, and which we want to run faster.
|
||||
"""
|
||||
|
||||
def decorator(fun):
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if LINUX:
|
||||
before = self.__class__.times
|
||||
try:
|
||||
self.__class__.times = FEW_TIMES
|
||||
return fun(self, *args, **kwargs)
|
||||
finally:
|
||||
self.__class__.times = before
|
||||
else:
|
||||
return fun(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Process class
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestProcessObjectLeaks(TestMemoryLeak):
|
||||
"""Test leaks of Process class methods."""
|
||||
|
||||
proc = thisproc
|
||||
|
||||
def test_coverage(self):
|
||||
ns = process_namespace(None)
|
||||
ns.test_class_coverage(self, ns.getters + ns.setters)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_name(self):
|
||||
self.execute(self.proc.name)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cmdline(self):
|
||||
self.execute(self.proc.cmdline)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_exe(self):
|
||||
self.execute(self.proc.exe)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_ppid(self):
|
||||
self.execute(self.proc.ppid)
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@fewtimes_if_linux()
|
||||
def test_uids(self):
|
||||
self.execute(self.proc.uids)
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@fewtimes_if_linux()
|
||||
def test_gids(self):
|
||||
self.execute(self.proc.gids)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_status(self):
|
||||
self.execute(self.proc.status)
|
||||
|
||||
def test_nice(self):
|
||||
self.execute(self.proc.nice)
|
||||
|
||||
def test_nice_set(self):
|
||||
niceness = thisproc.nice()
|
||||
self.execute(lambda: self.proc.nice(niceness))
|
||||
|
||||
@pytest.mark.skipif(not HAS_IONICE, reason="not supported")
|
||||
def test_ionice(self):
|
||||
self.execute(self.proc.ionice)
|
||||
|
||||
@pytest.mark.skipif(not HAS_IONICE, reason="not supported")
|
||||
def test_ionice_set(self):
|
||||
if WINDOWS:
|
||||
value = thisproc.ionice()
|
||||
self.execute(lambda: self.proc.ionice(value))
|
||||
else:
|
||||
self.execute(lambda: self.proc.ionice(psutil.IOPRIO_CLASS_NONE))
|
||||
fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0)
|
||||
self.execute_w_exc(OSError, fun)
|
||||
|
||||
@pytest.mark.skipif(not HAS_PROC_IO_COUNTERS, reason="not supported")
|
||||
@fewtimes_if_linux()
|
||||
def test_io_counters(self):
|
||||
self.execute(self.proc.io_counters)
|
||||
|
||||
@pytest.mark.skipif(POSIX, reason="worthless on POSIX")
|
||||
def test_username(self):
|
||||
# always open 1 handle on Windows (only once)
|
||||
psutil.Process().username()
|
||||
self.execute(self.proc.username)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_create_time(self):
|
||||
self.execute(self.proc.create_time)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@skip_on_access_denied(only_if=OPENBSD)
|
||||
def test_num_threads(self):
|
||||
self.execute(self.proc.num_threads)
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
def test_num_handles(self):
|
||||
self.execute(self.proc.num_handles)
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@fewtimes_if_linux()
|
||||
def test_num_fds(self):
|
||||
self.execute(self.proc.num_fds)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_num_ctx_switches(self):
|
||||
self.execute(self.proc.num_ctx_switches)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@skip_on_access_denied(only_if=OPENBSD)
|
||||
def test_threads(self):
|
||||
self.execute(self.proc.threads)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute(self.proc.cpu_times)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(not HAS_PROC_CPU_NUM, reason="not supported")
|
||||
def test_cpu_num(self):
|
||||
self.execute(self.proc.cpu_num)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_memory_info(self):
|
||||
self.execute(self.proc.memory_info)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_memory_full_info(self):
|
||||
self.execute(self.proc.memory_full_info)
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@fewtimes_if_linux()
|
||||
def test_terminal(self):
|
||||
self.execute(self.proc.terminal)
|
||||
|
||||
def test_resume(self):
|
||||
times = FEW_TIMES if POSIX else self.times
|
||||
self.execute(self.proc.resume, times=times)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cwd(self):
|
||||
self.execute(self.proc.cwd)
|
||||
|
||||
@pytest.mark.skipif(not HAS_CPU_AFFINITY, reason="not supported")
|
||||
def test_cpu_affinity(self):
|
||||
self.execute(self.proc.cpu_affinity)
|
||||
|
||||
@pytest.mark.skipif(not HAS_CPU_AFFINITY, reason="not supported")
|
||||
def test_cpu_affinity_set(self):
|
||||
affinity = thisproc.cpu_affinity()
|
||||
self.execute(lambda: self.proc.cpu_affinity(affinity))
|
||||
self.execute_w_exc(ValueError, lambda: self.proc.cpu_affinity([-1]))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_open_files(self):
|
||||
with open(get_testfn(), 'w'):
|
||||
self.execute(self.proc.open_files)
|
||||
|
||||
@pytest.mark.skipif(not HAS_MEMORY_MAPS, reason="not supported")
|
||||
@fewtimes_if_linux()
|
||||
def test_memory_maps(self):
|
||||
self.execute(self.proc.memory_maps)
|
||||
|
||||
@pytest.mark.skipif(not LINUX, reason="LINUX only")
|
||||
@pytest.mark.skipif(not HAS_RLIMIT, reason="not supported")
|
||||
def test_rlimit(self):
|
||||
self.execute(lambda: self.proc.rlimit(psutil.RLIMIT_NOFILE))
|
||||
|
||||
@pytest.mark.skipif(not LINUX, reason="LINUX only")
|
||||
@pytest.mark.skipif(not HAS_RLIMIT, reason="not supported")
|
||||
def test_rlimit_set(self):
|
||||
limit = thisproc.rlimit(psutil.RLIMIT_NOFILE)
|
||||
self.execute(lambda: self.proc.rlimit(psutil.RLIMIT_NOFILE, limit))
|
||||
self.execute_w_exc((OSError, ValueError), lambda: self.proc.rlimit(-1))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
# Windows implementation is based on a single system-wide
|
||||
# function (tested later).
|
||||
@pytest.mark.skipif(WINDOWS, reason="worthless on WINDOWS")
|
||||
def test_net_connections(self):
|
||||
# TODO: UNIX sockets are temporarily implemented by parsing
|
||||
# 'pfiles' cmd output; we don't want that part of the code to
|
||||
# be executed.
|
||||
with create_sockets():
|
||||
kind = 'inet' if SUNOS else 'all'
|
||||
self.execute(lambda: self.proc.net_connections(kind))
|
||||
|
||||
@pytest.mark.skipif(not HAS_ENVIRON, reason="not supported")
|
||||
def test_environ(self):
|
||||
self.execute(self.proc.environ)
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
def test_proc_info(self):
|
||||
self.execute(lambda: cext.proc_info(os.getpid()))
|
||||
|
||||
|
||||
class TestTerminatedProcessLeaks(TestProcessObjectLeaks):
|
||||
"""Repeat the tests above looking for leaks occurring when dealing
|
||||
with terminated processes raising NoSuchProcess exception.
|
||||
The C functions are still invoked but will follow different code
|
||||
paths. We'll check those code paths.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.subp = spawn_testproc()
|
||||
cls.proc = psutil.Process(cls.subp.pid)
|
||||
cls.proc.kill()
|
||||
cls.proc.wait()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super().tearDownClass()
|
||||
terminate(cls.subp)
|
||||
|
||||
def call(self, fun):
|
||||
try:
|
||||
fun()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
if WINDOWS:
|
||||
|
||||
def test_kill(self):
|
||||
self.execute(self.proc.kill)
|
||||
|
||||
def test_terminate(self):
|
||||
self.execute(self.proc.terminate)
|
||||
|
||||
def test_suspend(self):
|
||||
self.execute(self.proc.suspend)
|
||||
|
||||
def test_resume(self):
|
||||
self.execute(self.proc.resume)
|
||||
|
||||
def test_wait(self):
|
||||
self.execute(self.proc.wait)
|
||||
|
||||
def test_proc_info(self):
|
||||
# test dual implementation
|
||||
def call():
|
||||
try:
|
||||
return cext.proc_info(self.proc.pid)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
|
||||
self.execute(call)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
class TestProcessDualImplementation(TestMemoryLeak):
|
||||
def test_cmdline_peb_true(self):
|
||||
self.execute(lambda: cext.proc_cmdline(os.getpid(), use_peb=True))
|
||||
|
||||
def test_cmdline_peb_false(self):
|
||||
self.execute(lambda: cext.proc_cmdline(os.getpid(), use_peb=False))
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# system APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestModuleFunctionsLeaks(TestMemoryLeak):
|
||||
"""Test leaks of psutil module functions."""
|
||||
|
||||
def test_coverage(self):
|
||||
ns = system_namespace()
|
||||
ns.test_class_coverage(self, ns.all)
|
||||
|
||||
# --- cpu
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cpu_count(self): # logical
|
||||
self.execute(lambda: psutil.cpu_count(logical=True))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cpu_count_cores(self):
|
||||
self.execute(lambda: psutil.cpu_count(logical=False))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute(psutil.cpu_times)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_per_cpu_times(self):
|
||||
self.execute(lambda: psutil.cpu_times(percpu=True))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_cpu_stats(self):
|
||||
self.execute(psutil.cpu_stats)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
# TODO: remove this once 1892 is fixed
|
||||
@pytest.mark.skipif(
|
||||
MACOS and platform.machine() == 'arm64', reason="skipped due to #1892"
|
||||
)
|
||||
@pytest.mark.skipif(not HAS_CPU_FREQ, reason="not supported")
|
||||
def test_cpu_freq(self):
|
||||
self.execute(psutil.cpu_freq)
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
def test_getloadavg(self):
|
||||
psutil.getloadavg()
|
||||
self.execute(psutil.getloadavg)
|
||||
|
||||
# --- mem
|
||||
|
||||
def test_virtual_memory(self):
|
||||
self.execute(psutil.virtual_memory)
|
||||
|
||||
# TODO: remove this skip when this gets fixed
|
||||
@pytest.mark.skipif(SUNOS, reason="worthless on SUNOS (uses a subprocess)")
|
||||
def test_swap_memory(self):
|
||||
self.execute(psutil.swap_memory)
|
||||
|
||||
def test_pid_exists(self):
|
||||
times = FEW_TIMES if POSIX else self.times
|
||||
self.execute(lambda: psutil.pid_exists(os.getpid()), times=times)
|
||||
|
||||
# --- disk
|
||||
|
||||
def test_disk_usage(self):
|
||||
times = FEW_TIMES if POSIX else self.times
|
||||
self.execute(lambda: psutil.disk_usage('.'), times=times)
|
||||
|
||||
@pytest.mark.skipif(QEMU_USER, reason="QEMU user not supported")
|
||||
def test_disk_partitions(self):
|
||||
self.execute(psutil.disk_partitions)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
LINUX and not os.path.exists('/proc/diskstats'),
|
||||
reason="/proc/diskstats not available on this Linux version",
|
||||
)
|
||||
@fewtimes_if_linux()
|
||||
def test_disk_io_counters(self):
|
||||
self.execute(lambda: psutil.disk_io_counters(nowrap=False))
|
||||
|
||||
# --- proc
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_pids(self):
|
||||
self.execute(psutil.pids)
|
||||
|
||||
# --- net
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
|
||||
def test_net_io_counters(self):
|
||||
self.execute(lambda: psutil.net_io_counters(nowrap=False))
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(MACOS and os.getuid() != 0, reason="need root access")
|
||||
def test_net_connections(self):
|
||||
# always opens and handle on Windows() (once)
|
||||
psutil.net_connections(kind='all')
|
||||
with create_sockets():
|
||||
self.execute(lambda: psutil.net_connections(kind='all'))
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
# Note: verified that on Windows this was a false positive.
|
||||
tolerance = 80 * 1024 if WINDOWS else self.tolerance
|
||||
self.execute(psutil.net_if_addrs, tolerance=tolerance)
|
||||
|
||||
@pytest.mark.skipif(QEMU_USER, reason="QEMU user not supported")
|
||||
def test_net_if_stats(self):
|
||||
self.execute(psutil.net_if_stats)
|
||||
|
||||
# --- sensors
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(not HAS_SENSORS_BATTERY, reason="not supported")
|
||||
def test_sensors_battery(self):
|
||||
self.execute(psutil.sensors_battery)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
self.execute(psutil.sensors_temperatures)
|
||||
|
||||
@fewtimes_if_linux()
|
||||
@pytest.mark.skipif(not HAS_SENSORS_FANS, reason="not supported")
|
||||
def test_sensors_fans(self):
|
||||
self.execute(psutil.sensors_fans)
|
||||
|
||||
# --- others
|
||||
|
||||
@fewtimes_if_linux()
|
||||
def test_boot_time(self):
|
||||
self.execute(psutil.boot_time)
|
||||
|
||||
def test_users(self):
|
||||
self.execute(psutil.users)
|
||||
|
||||
def test_set_debug(self):
|
||||
self.execute(lambda: psutil._set_debug(False))
|
||||
|
||||
if WINDOWS:
|
||||
|
||||
# --- win services
|
||||
|
||||
def test_win_service_iter(self):
|
||||
self.execute(cext.winservice_enumerate)
|
||||
|
||||
def test_win_service_get(self):
|
||||
pass
|
||||
|
||||
def test_win_service_get_config(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(lambda: cext.winservice_query_config(name))
|
||||
|
||||
def test_win_service_get_status(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(lambda: cext.winservice_query_status(name))
|
||||
|
||||
def test_win_service_get_description(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(lambda: cext.winservice_query_descr(name))
|
1058
env/lib/python3.12/site-packages/psutil/tests/test_misc.py
vendored
Normal file
1058
env/lib/python3.12/site-packages/psutil/tests/test_misc.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
192
env/lib/python3.12/site-packages/psutil/tests/test_osx.py
vendored
Normal file
192
env/lib/python3.12/site-packages/psutil/tests/test_osx.py
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""macOS specific tests."""
|
||||
|
||||
import platform
|
||||
import re
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import MACOS
|
||||
from psutil import POSIX
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import TOLERANCE_DISK_USAGE
|
||||
from psutil.tests import TOLERANCE_SYS_MEM
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import terminate
|
||||
|
||||
|
||||
if POSIX:
|
||||
from psutil._psutil_posix import getpagesize
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
out = sh(cmdline)
|
||||
result = out.split()[1]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def vm_stat(field):
|
||||
"""Wrapper around 'vm_stat' cmdline utility."""
|
||||
out = sh('vm_stat')
|
||||
for line in out.split('\n'):
|
||||
if field in line:
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(re.search(r'\d+', line).group(0)) * getpagesize()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not MACOS, reason="MACOS only")
|
||||
class TestProcess(PsutilTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
def test_process_create_time(self):
|
||||
output = sh("ps -o lstart -p %s" % self.pid)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
hhmmss = start_ps.split(' ')[-2]
|
||||
year = start_ps.split(' ')[-1]
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
assert hhmmss == time.strftime(
|
||||
"%H:%M:%S", time.localtime(start_psutil)
|
||||
)
|
||||
assert year == time.strftime("%Y", time.localtime(start_psutil))
|
||||
|
||||
|
||||
@pytest.mark.skipif(not MACOS, reason="MACOS only")
|
||||
class TestSystemAPIs(PsutilTestCase):
|
||||
|
||||
# --- disk
|
||||
|
||||
@retry_on_failure()
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
assert part.device == dev
|
||||
assert usage.total == total
|
||||
assert abs(usage.free - free) < TOLERANCE_DISK_USAGE
|
||||
assert abs(usage.used - used) < TOLERANCE_DISK_USAGE
|
||||
|
||||
# --- cpu
|
||||
|
||||
def test_cpu_count_logical(self):
|
||||
num = sysctl("sysctl hw.logicalcpu")
|
||||
assert num == psutil.cpu_count(logical=True)
|
||||
|
||||
def test_cpu_count_cores(self):
|
||||
num = sysctl("sysctl hw.physicalcpu")
|
||||
assert num == psutil.cpu_count(logical=False)
|
||||
|
||||
# TODO: remove this once 1892 is fixed
|
||||
@pytest.mark.skipif(
|
||||
MACOS and platform.machine() == 'arm64', reason="skipped due to #1892"
|
||||
)
|
||||
def test_cpu_freq(self):
|
||||
freq = psutil.cpu_freq()
|
||||
assert freq.current * 1000 * 1000 == sysctl("sysctl hw.cpufrequency")
|
||||
assert freq.min * 1000 * 1000 == sysctl("sysctl hw.cpufrequency_min")
|
||||
assert freq.max * 1000 * 1000 == sysctl("sysctl hw.cpufrequency_max")
|
||||
|
||||
# --- virtual mem
|
||||
|
||||
def test_vmem_total(self):
|
||||
sysctl_hwphymem = sysctl('sysctl hw.memsize')
|
||||
assert sysctl_hwphymem == psutil.virtual_memory().total
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_free(self):
|
||||
vmstat_val = vm_stat("free")
|
||||
psutil_val = psutil.virtual_memory().free
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_active(self):
|
||||
vmstat_val = vm_stat("active")
|
||||
psutil_val = psutil.virtual_memory().active
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_inactive(self):
|
||||
vmstat_val = vm_stat("inactive")
|
||||
psutil_val = psutil.virtual_memory().inactive
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_wired(self):
|
||||
vmstat_val = vm_stat("wired")
|
||||
psutil_val = psutil.virtual_memory().wired
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
# --- swap mem
|
||||
|
||||
@retry_on_failure()
|
||||
def test_swapmem_sin(self):
|
||||
vmstat_val = vm_stat("Pageins")
|
||||
psutil_val = psutil.swap_memory().sin
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
@retry_on_failure()
|
||||
def test_swapmem_sout(self):
|
||||
vmstat_val = vm_stat("Pageout")
|
||||
psutil_val = psutil.swap_memory().sout
|
||||
assert abs(psutil_val - vmstat_val) < TOLERANCE_SYS_MEM
|
||||
|
||||
# --- network
|
||||
|
||||
def test_net_if_stats(self):
|
||||
for name, stats in psutil.net_if_stats().items():
|
||||
try:
|
||||
out = sh("ifconfig %s" % name)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
assert stats.isup == ('RUNNING' in out), out
|
||||
assert stats.mtu == int(re.findall(r'mtu (\d+)', out)[0])
|
||||
|
||||
# --- sensors_battery
|
||||
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_sensors_battery(self):
|
||||
out = sh("pmset -g batt")
|
||||
percent = re.search(r"(\d+)%", out).group(1)
|
||||
drawing_from = re.search("Now drawing from '([^']+)'", out).group(1)
|
||||
power_plugged = drawing_from == "AC Power"
|
||||
psutil_result = psutil.sensors_battery()
|
||||
assert psutil_result.power_plugged == power_plugged
|
||||
assert psutil_result.percent == int(percent)
|
496
env/lib/python3.12/site-packages/psutil/tests/test_posix.py
vendored
Normal file
496
env/lib/python3.12/site-packages/psutil/tests/test_posix.py
vendored
Normal file
@ -0,0 +1,496 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""POSIX specific tests."""
|
||||
|
||||
import datetime
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil.tests import AARCH64
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import PYTHON_EXE
|
||||
from psutil.tests import QEMU_USER
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import terminate
|
||||
from psutil.tests import which
|
||||
|
||||
|
||||
if POSIX:
|
||||
import mmap
|
||||
import resource
|
||||
|
||||
from psutil._psutil_posix import getpagesize
|
||||
|
||||
|
||||
def ps(fmt, pid=None):
|
||||
"""Wrapper for calling the ps command with a little bit of cross-platform
|
||||
support for a narrow range of features.
|
||||
"""
|
||||
|
||||
cmd = ['ps']
|
||||
|
||||
if LINUX:
|
||||
cmd.append('--no-headers')
|
||||
|
||||
if pid is not None:
|
||||
cmd.extend(['-p', str(pid)])
|
||||
else:
|
||||
if SUNOS or AIX:
|
||||
cmd.append('-A')
|
||||
else:
|
||||
cmd.append('ax')
|
||||
|
||||
if SUNOS:
|
||||
fmt = fmt.replace("start", "stime")
|
||||
|
||||
cmd.extend(['-o', fmt])
|
||||
|
||||
output = sh(cmd)
|
||||
|
||||
output = output.splitlines() if LINUX else output.splitlines()[1:]
|
||||
|
||||
all_output = []
|
||||
for line in output:
|
||||
line = line.strip()
|
||||
|
||||
try:
|
||||
line = int(line)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
all_output.append(line)
|
||||
|
||||
if pid is None:
|
||||
return all_output
|
||||
else:
|
||||
return all_output[0]
|
||||
|
||||
|
||||
# ps "-o" field names differ wildly between platforms.
|
||||
# "comm" means "only executable name" but is not available on BSD platforms.
|
||||
# "args" means "command with all its arguments", and is also not available
|
||||
# on BSD platforms.
|
||||
# "command" is like "args" on most platforms, but like "comm" on AIX,
|
||||
# and not available on SUNOS.
|
||||
# so for the executable name we can use "comm" on Solaris and split "command"
|
||||
# on other platforms.
|
||||
# to get the cmdline (with args) we have to use "args" on AIX and
|
||||
# Solaris, and can use "command" on all others.
|
||||
|
||||
|
||||
def ps_name(pid):
|
||||
field = "command"
|
||||
if SUNOS:
|
||||
field = "comm"
|
||||
command = ps(field, pid).split()
|
||||
if QEMU_USER:
|
||||
assert "/bin/qemu-" in command[0]
|
||||
return command[1]
|
||||
return command[0]
|
||||
|
||||
|
||||
def ps_args(pid):
|
||||
field = "command"
|
||||
if AIX or SUNOS:
|
||||
field = "args"
|
||||
out = ps(field, pid)
|
||||
# observed on BSD + Github CI: '/usr/local/bin/python3 -E -O (python3.9)'
|
||||
out = re.sub(r"\(python.*?\)$", "", out)
|
||||
return out.strip()
|
||||
|
||||
|
||||
def ps_rss(pid):
|
||||
field = "rss"
|
||||
if AIX:
|
||||
field = "rssize"
|
||||
return ps(field, pid)
|
||||
|
||||
|
||||
def ps_vsz(pid):
|
||||
field = "vsz"
|
||||
if AIX:
|
||||
field = "vsize"
|
||||
return ps(field, pid)
|
||||
|
||||
|
||||
def df(device):
|
||||
try:
|
||||
out = sh("df -k %s" % device).strip()
|
||||
except RuntimeError as err:
|
||||
if "device busy" in str(err).lower():
|
||||
raise pytest.skip("df returned EBUSY")
|
||||
raise
|
||||
line = out.split('\n')[1]
|
||||
fields = line.split()
|
||||
sys_total = int(fields[1]) * 1024
|
||||
sys_used = int(fields[2]) * 1024
|
||||
sys_free = int(fields[3]) * 1024
|
||||
sys_percent = float(fields[4].replace('%', ''))
|
||||
return (sys_total, sys_used, sys_free, sys_percent)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
class TestProcess(PsutilTestCase):
|
||||
"""Compare psutil results against 'ps' command line utility (mainly)."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc(
|
||||
[PYTHON_EXE, "-E", "-O"], stdin=subprocess.PIPE
|
||||
).pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
def test_ppid(self):
|
||||
ppid_ps = ps('ppid', self.pid)
|
||||
ppid_psutil = psutil.Process(self.pid).ppid()
|
||||
assert ppid_ps == ppid_psutil
|
||||
|
||||
def test_uid(self):
|
||||
uid_ps = ps('uid', self.pid)
|
||||
uid_psutil = psutil.Process(self.pid).uids().real
|
||||
assert uid_ps == uid_psutil
|
||||
|
||||
def test_gid(self):
|
||||
gid_ps = ps('rgid', self.pid)
|
||||
gid_psutil = psutil.Process(self.pid).gids().real
|
||||
assert gid_ps == gid_psutil
|
||||
|
||||
def test_username(self):
|
||||
username_ps = ps('user', self.pid)
|
||||
username_psutil = psutil.Process(self.pid).username()
|
||||
assert username_ps == username_psutil
|
||||
|
||||
def test_username_no_resolution(self):
|
||||
# Emulate a case where the system can't resolve the uid to
|
||||
# a username in which case psutil is supposed to return
|
||||
# the stringified uid.
|
||||
p = psutil.Process()
|
||||
with mock.patch("psutil.pwd.getpwuid", side_effect=KeyError) as fun:
|
||||
assert p.username() == str(p.uids().real)
|
||||
assert fun.called
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_on_failure()
|
||||
def test_rss_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
rss_ps = ps_rss(self.pid)
|
||||
rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024
|
||||
assert rss_ps == rss_psutil
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_on_failure()
|
||||
def test_vsz_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
vsz_ps = ps_vsz(self.pid)
|
||||
vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024
|
||||
assert vsz_ps == vsz_psutil
|
||||
|
||||
def test_name(self):
|
||||
name_ps = ps_name(self.pid)
|
||||
# remove path if there is any, from the command
|
||||
name_ps = os.path.basename(name_ps).lower()
|
||||
name_psutil = psutil.Process(self.pid).name().lower()
|
||||
# ...because of how we calculate PYTHON_EXE; on MACOS this may
|
||||
# be "pythonX.Y".
|
||||
name_ps = re.sub(r"\d.\d", "", name_ps)
|
||||
name_psutil = re.sub(r"\d.\d", "", name_psutil)
|
||||
# ...may also be "python.X"
|
||||
name_ps = re.sub(r"\d", "", name_ps)
|
||||
name_psutil = re.sub(r"\d", "", name_psutil)
|
||||
assert name_ps == name_psutil
|
||||
|
||||
def test_name_long(self):
|
||||
# On UNIX the kernel truncates the name to the first 15
|
||||
# characters. In such a case psutil tries to determine the
|
||||
# full name from the cmdline.
|
||||
name = "long-program-name"
|
||||
cmdline = ["long-program-name-extended", "foo", "bar"]
|
||||
with mock.patch("psutil._psplatform.Process.name", return_value=name):
|
||||
with mock.patch(
|
||||
"psutil._psplatform.Process.cmdline", return_value=cmdline
|
||||
):
|
||||
p = psutil.Process()
|
||||
assert p.name() == "long-program-name-extended"
|
||||
|
||||
def test_name_long_cmdline_ad_exc(self):
|
||||
# Same as above but emulates a case where cmdline() raises
|
||||
# AccessDenied in which case psutil is supposed to return
|
||||
# the truncated name instead of crashing.
|
||||
name = "long-program-name"
|
||||
with mock.patch("psutil._psplatform.Process.name", return_value=name):
|
||||
with mock.patch(
|
||||
"psutil._psplatform.Process.cmdline",
|
||||
side_effect=psutil.AccessDenied(0, ""),
|
||||
):
|
||||
p = psutil.Process()
|
||||
assert p.name() == "long-program-name"
|
||||
|
||||
def test_name_long_cmdline_nsp_exc(self):
|
||||
# Same as above but emulates a case where cmdline() raises NSP
|
||||
# which is supposed to propagate.
|
||||
name = "long-program-name"
|
||||
with mock.patch("psutil._psplatform.Process.name", return_value=name):
|
||||
with mock.patch(
|
||||
"psutil._psplatform.Process.cmdline",
|
||||
side_effect=psutil.NoSuchProcess(0, ""),
|
||||
):
|
||||
p = psutil.Process()
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
p.name()
|
||||
|
||||
@pytest.mark.skipif(MACOS or BSD, reason="ps -o start not available")
|
||||
def test_create_time(self):
|
||||
time_ps = ps('start', self.pid)
|
||||
time_psutil = psutil.Process(self.pid).create_time()
|
||||
time_psutil_tstamp = datetime.datetime.fromtimestamp(
|
||||
time_psutil
|
||||
).strftime("%H:%M:%S")
|
||||
# sometimes ps shows the time rounded up instead of down, so we check
|
||||
# for both possible values
|
||||
round_time_psutil = round(time_psutil)
|
||||
round_time_psutil_tstamp = datetime.datetime.fromtimestamp(
|
||||
round_time_psutil
|
||||
).strftime("%H:%M:%S")
|
||||
assert time_ps in [time_psutil_tstamp, round_time_psutil_tstamp]
|
||||
|
||||
def test_exe(self):
|
||||
ps_pathname = ps_name(self.pid)
|
||||
psutil_pathname = psutil.Process(self.pid).exe()
|
||||
try:
|
||||
assert ps_pathname == psutil_pathname
|
||||
except AssertionError:
|
||||
# certain platforms such as BSD are more accurate returning:
|
||||
# "/usr/local/bin/python2.7"
|
||||
# ...instead of:
|
||||
# "/usr/local/bin/python"
|
||||
# We do not want to consider this difference in accuracy
|
||||
# an error.
|
||||
adjusted_ps_pathname = ps_pathname[: len(ps_pathname)]
|
||||
assert ps_pathname == adjusted_ps_pathname
|
||||
|
||||
# On macOS the official python installer exposes a python wrapper that
|
||||
# executes a python executable hidden inside an application bundle inside
|
||||
# the Python framework.
|
||||
# There's a race condition between the ps call & the psutil call below
|
||||
# depending on the completion of the execve call so let's retry on failure
|
||||
@retry_on_failure()
|
||||
def test_cmdline(self):
|
||||
ps_cmdline = ps_args(self.pid)
|
||||
psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline())
|
||||
if AARCH64 and len(ps_cmdline) < len(psutil_cmdline):
|
||||
assert psutil_cmdline.startswith(ps_cmdline)
|
||||
else:
|
||||
assert ps_cmdline == psutil_cmdline
|
||||
|
||||
# On SUNOS "ps" reads niceness /proc/pid/psinfo which returns an
|
||||
# incorrect value (20); the real deal is getpriority(2) which
|
||||
# returns 0; psutil relies on it, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1082
|
||||
# AIX has the same issue
|
||||
@pytest.mark.skipif(SUNOS, reason="not reliable on SUNOS")
|
||||
@pytest.mark.skipif(AIX, reason="not reliable on AIX")
|
||||
def test_nice(self):
|
||||
ps_nice = ps('nice', self.pid)
|
||||
psutil_nice = psutil.Process().nice()
|
||||
assert ps_nice == psutil_nice
|
||||
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
class TestSystemAPIs(PsutilTestCase):
|
||||
"""Test some system APIs."""
|
||||
|
||||
@retry_on_failure()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
pids_ps = sorted(ps("pid"))
|
||||
pids_psutil = psutil.pids()
|
||||
|
||||
# on MACOS and OPENBSD ps doesn't show pid 0
|
||||
if MACOS or (OPENBSD and 0 not in pids_ps):
|
||||
pids_ps.insert(0, 0)
|
||||
|
||||
# There will often be one more process in pids_ps for ps itself
|
||||
if len(pids_ps) - len(pids_psutil) > 1:
|
||||
difference = [x for x in pids_psutil if x not in pids_ps] + [
|
||||
x for x in pids_ps if x not in pids_psutil
|
||||
]
|
||||
raise self.fail("difference: " + str(difference))
|
||||
|
||||
# for some reason ifconfig -a does not report all interfaces
|
||||
# returned by psutil
|
||||
@pytest.mark.skipif(SUNOS, reason="unreliable on SUNOS")
|
||||
@pytest.mark.skipif(not which('ifconfig'), reason="no ifconfig cmd")
|
||||
@pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
|
||||
def test_nic_names(self):
|
||||
output = sh("ifconfig -a")
|
||||
for nic in psutil.net_io_counters(pernic=True):
|
||||
for line in output.split():
|
||||
if line.startswith(nic):
|
||||
break
|
||||
else:
|
||||
raise self.fail(
|
||||
"couldn't find %s nic in 'ifconfig -a' output\n%s"
|
||||
% (nic, output)
|
||||
)
|
||||
|
||||
# @pytest.mark.skipif(CI_TESTING and not psutil.users(),
|
||||
# reason="unreliable on CI")
|
||||
@retry_on_failure()
|
||||
def test_users(self):
|
||||
out = sh("who -u")
|
||||
if not out.strip():
|
||||
raise pytest.skip("no users on this system")
|
||||
lines = out.split('\n')
|
||||
users = [x.split()[0] for x in lines]
|
||||
terminals = [x.split()[1] for x in lines]
|
||||
assert len(users) == len(psutil.users())
|
||||
with self.subTest(psutil=psutil.users(), who=out):
|
||||
for idx, u in enumerate(psutil.users()):
|
||||
assert u.name == users[idx]
|
||||
assert u.terminal == terminals[idx]
|
||||
if u.pid is not None: # None on OpenBSD
|
||||
psutil.Process(u.pid)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_users_started(self):
|
||||
out = sh("who -u")
|
||||
if not out.strip():
|
||||
raise pytest.skip("no users on this system")
|
||||
tstamp = None
|
||||
# '2023-04-11 09:31' (Linux)
|
||||
started = re.findall(r"\d\d\d\d-\d\d-\d\d \d\d:\d\d", out)
|
||||
if started:
|
||||
tstamp = "%Y-%m-%d %H:%M"
|
||||
else:
|
||||
# 'Apr 10 22:27' (macOS)
|
||||
started = re.findall(r"[A-Z][a-z][a-z] \d\d \d\d:\d\d", out)
|
||||
if started:
|
||||
tstamp = "%b %d %H:%M"
|
||||
else:
|
||||
# 'Apr 10'
|
||||
started = re.findall(r"[A-Z][a-z][a-z] \d\d", out)
|
||||
if started:
|
||||
tstamp = "%b %d"
|
||||
else:
|
||||
# 'apr 10' (sunOS)
|
||||
started = re.findall(r"[a-z][a-z][a-z] \d\d", out)
|
||||
if started:
|
||||
tstamp = "%b %d"
|
||||
started = [x.capitalize() for x in started]
|
||||
|
||||
if not tstamp:
|
||||
raise pytest.skip(
|
||||
"cannot interpret tstamp in who output\n%s" % (out)
|
||||
)
|
||||
|
||||
with self.subTest(psutil=psutil.users(), who=out):
|
||||
for idx, u in enumerate(psutil.users()):
|
||||
psutil_value = datetime.datetime.fromtimestamp(
|
||||
u.started
|
||||
).strftime(tstamp)
|
||||
assert psutil_value == started[idx]
|
||||
|
||||
def test_pid_exists_let_raise(self):
|
||||
# According to "man 2 kill" possible error values for kill
|
||||
# are (EINVAL, EPERM, ESRCH). Test that any other errno
|
||||
# results in an exception.
|
||||
with mock.patch(
|
||||
"psutil._psposix.os.kill", side_effect=OSError(errno.EBADF, "")
|
||||
) as m:
|
||||
with pytest.raises(OSError):
|
||||
psutil._psposix.pid_exists(os.getpid())
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_let_raise(self):
|
||||
# os.waitpid() is supposed to catch EINTR and ECHILD only.
|
||||
# Test that any other errno results in an exception.
|
||||
with mock.patch(
|
||||
"psutil._psposix.os.waitpid", side_effect=OSError(errno.EBADF, "")
|
||||
) as m:
|
||||
with pytest.raises(OSError):
|
||||
psutil._psposix.wait_pid(os.getpid())
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_eintr(self):
|
||||
# os.waitpid() is supposed to "retry" on EINTR.
|
||||
with mock.patch(
|
||||
"psutil._psposix.os.waitpid", side_effect=OSError(errno.EINTR, "")
|
||||
) as m:
|
||||
with pytest.raises(psutil._psposix.TimeoutExpired):
|
||||
psutil._psposix.wait_pid(os.getpid(), timeout=0.01)
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_bad_ret_status(self):
|
||||
# Simulate os.waitpid() returning a bad status.
|
||||
with mock.patch(
|
||||
"psutil._psposix.os.waitpid", return_value=(1, -1)
|
||||
) as m:
|
||||
with pytest.raises(ValueError):
|
||||
psutil._psposix.wait_pid(os.getpid())
|
||||
assert m.called
|
||||
|
||||
# AIX can return '-' in df output instead of numbers, e.g. for /proc
|
||||
@pytest.mark.skipif(AIX, reason="unreliable on AIX")
|
||||
@retry_on_failure()
|
||||
def test_disk_usage(self):
|
||||
tolerance = 4 * 1024 * 1024 # 4MB
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
try:
|
||||
sys_total, sys_used, sys_free, sys_percent = df(part.device)
|
||||
except RuntimeError as err:
|
||||
# see:
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/138338464
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/138343361
|
||||
err = str(err).lower()
|
||||
if (
|
||||
"no such file or directory" in err
|
||||
or "raw devices not supported" in err
|
||||
or "permission denied" in err
|
||||
):
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
assert abs(usage.total - sys_total) < tolerance
|
||||
assert abs(usage.used - sys_used) < tolerance
|
||||
assert abs(usage.free - sys_free) < tolerance
|
||||
assert abs(usage.percent - sys_percent) <= 1
|
||||
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
class TestMisc(PsutilTestCase):
|
||||
def test_getpagesize(self):
|
||||
pagesize = getpagesize()
|
||||
assert pagesize > 0
|
||||
assert pagesize == resource.getpagesize()
|
||||
assert pagesize == mmap.PAGESIZE
|
1746
env/lib/python3.12/site-packages/psutil/tests/test_process.py
vendored
Normal file
1746
env/lib/python3.12/site-packages/psutil/tests/test_process.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
543
env/lib/python3.12/site-packages/psutil/tests/test_process_all.py
vendored
Normal file
543
env/lib/python3.12/site-packages/psutil/tests/test_process_all.py
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Iterate over all process PIDs and for each one of them invoke and
|
||||
test all psutil.Process() methods.
|
||||
"""
|
||||
|
||||
import enum
|
||||
import errno
|
||||
import multiprocessing
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import OSX
|
||||
from psutil import POSIX
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import PY3
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil._compat import long
|
||||
from psutil._compat import unicode
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import PYTEST_PARALLEL
|
||||
from psutil.tests import QEMU_USER
|
||||
from psutil.tests import VALID_PROC_STATUSES
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import check_connection_ntuple
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import is_namedtuple
|
||||
from psutil.tests import is_win_secure_system_proc
|
||||
from psutil.tests import process_namespace
|
||||
from psutil.tests import pytest
|
||||
|
||||
|
||||
# Cuts the time in half, but (e.g.) on macOS the process pool stays
|
||||
# alive after join() (multiprocessing bug?), messing up other tests.
|
||||
USE_PROC_POOL = LINUX and not CI_TESTING and not PYTEST_PARALLEL
|
||||
|
||||
|
||||
def proc_info(pid):
|
||||
tcase = PsutilTestCase()
|
||||
|
||||
def check_exception(exc, proc, name, ppid):
|
||||
tcase.assertEqual(exc.pid, pid)
|
||||
if exc.name is not None:
|
||||
tcase.assertEqual(exc.name, name)
|
||||
if isinstance(exc, psutil.ZombieProcess):
|
||||
tcase.assertProcessZombie(proc)
|
||||
if exc.ppid is not None:
|
||||
tcase.assertGreaterEqual(exc.ppid, 0)
|
||||
tcase.assertEqual(exc.ppid, ppid)
|
||||
elif isinstance(exc, psutil.NoSuchProcess):
|
||||
tcase.assertProcessGone(proc)
|
||||
str(exc)
|
||||
repr(exc)
|
||||
|
||||
def do_wait():
|
||||
if pid != 0:
|
||||
try:
|
||||
proc.wait(0)
|
||||
except psutil.Error as exc:
|
||||
check_exception(exc, proc, name, ppid)
|
||||
|
||||
try:
|
||||
proc = psutil.Process(pid)
|
||||
except psutil.NoSuchProcess:
|
||||
tcase.assertPidGone(pid)
|
||||
return {}
|
||||
try:
|
||||
d = proc.as_dict(['ppid', 'name'])
|
||||
except psutil.NoSuchProcess:
|
||||
tcase.assertProcessGone(proc)
|
||||
else:
|
||||
name, ppid = d['name'], d['ppid']
|
||||
info = {'pid': proc.pid}
|
||||
ns = process_namespace(proc)
|
||||
# We don't use oneshot() because in order not to fool
|
||||
# check_exception() in case of NSP.
|
||||
for fun, fun_name in ns.iter(ns.getters, clear_cache=False):
|
||||
try:
|
||||
info[fun_name] = fun()
|
||||
except psutil.Error as exc:
|
||||
check_exception(exc, proc, name, ppid)
|
||||
continue
|
||||
do_wait()
|
||||
return info
|
||||
|
||||
|
||||
class TestFetchAllProcesses(PsutilTestCase):
|
||||
"""Test which iterates over all running processes and performs
|
||||
some sanity checks against Process API's returned values.
|
||||
Uses a process pool to get info about all processes.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
psutil._set_debug(False)
|
||||
# Using a pool in a CI env may result in deadlock, see:
|
||||
# https://github.com/giampaolo/psutil/issues/2104
|
||||
if USE_PROC_POOL:
|
||||
self.pool = multiprocessing.Pool()
|
||||
|
||||
def tearDown(self):
|
||||
psutil._set_debug(True)
|
||||
if USE_PROC_POOL:
|
||||
self.pool.terminate()
|
||||
self.pool.join()
|
||||
|
||||
def iter_proc_info(self):
|
||||
# Fixes "can't pickle <function proc_info>: it's not the
|
||||
# same object as test_process_all.proc_info".
|
||||
from psutil.tests.test_process_all import proc_info
|
||||
|
||||
if USE_PROC_POOL:
|
||||
return self.pool.imap_unordered(proc_info, psutil.pids())
|
||||
else:
|
||||
ls = []
|
||||
for pid in psutil.pids():
|
||||
ls.append(proc_info(pid))
|
||||
return ls
|
||||
|
||||
def test_all(self):
|
||||
failures = []
|
||||
for info in self.iter_proc_info():
|
||||
for name, value in info.items():
|
||||
meth = getattr(self, name)
|
||||
try:
|
||||
meth(value, info)
|
||||
except Exception: # noqa: BLE001
|
||||
s = '\n' + '=' * 70 + '\n'
|
||||
s += "FAIL: name=test_%s, pid=%s, ret=%s\ninfo=%s\n" % (
|
||||
name,
|
||||
info['pid'],
|
||||
repr(value),
|
||||
info,
|
||||
)
|
||||
s += '-' * 70
|
||||
s += "\n%s" % traceback.format_exc()
|
||||
s = "\n".join((" " * 4) + i for i in s.splitlines()) + "\n"
|
||||
failures.append(s)
|
||||
else:
|
||||
if value not in (0, 0.0, [], None, '', {}):
|
||||
assert value, value
|
||||
if failures:
|
||||
raise self.fail(''.join(failures))
|
||||
|
||||
def cmdline(self, ret, info):
|
||||
assert isinstance(ret, list)
|
||||
for part in ret:
|
||||
assert isinstance(part, str)
|
||||
|
||||
def exe(self, ret, info):
|
||||
assert isinstance(ret, (str, unicode))
|
||||
assert ret.strip() == ret
|
||||
if ret:
|
||||
if WINDOWS and not ret.endswith('.exe'):
|
||||
return # May be "Registry", "MemCompression", ...
|
||||
assert os.path.isabs(ret), ret
|
||||
# Note: os.stat() may return False even if the file is there
|
||||
# hence we skip the test, see:
|
||||
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
|
||||
if POSIX and os.path.isfile(ret):
|
||||
if hasattr(os, 'access') and hasattr(os, "X_OK"):
|
||||
# XXX: may fail on MACOS
|
||||
try:
|
||||
assert os.access(ret, os.X_OK)
|
||||
except AssertionError:
|
||||
if os.path.exists(ret) and not CI_TESTING:
|
||||
raise
|
||||
|
||||
def pid(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
assert ret >= 0
|
||||
|
||||
def ppid(self, ret, info):
|
||||
assert isinstance(ret, (int, long))
|
||||
assert ret >= 0
|
||||
proc_info(ret)
|
||||
|
||||
def name(self, ret, info):
|
||||
assert isinstance(ret, (str, unicode))
|
||||
if WINDOWS and not ret and is_win_secure_system_proc(info['pid']):
|
||||
# https://github.com/giampaolo/psutil/issues/2338
|
||||
return
|
||||
# on AIX, "<exiting>" processes don't have names
|
||||
if not AIX:
|
||||
assert ret, repr(ret)
|
||||
|
||||
def create_time(self, ret, info):
|
||||
assert isinstance(ret, float)
|
||||
try:
|
||||
assert ret >= 0
|
||||
except AssertionError:
|
||||
# XXX
|
||||
if OPENBSD and info['status'] == psutil.STATUS_ZOMBIE:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
# this can't be taken for granted on all platforms
|
||||
# self.assertGreaterEqual(ret, psutil.boot_time())
|
||||
# make sure returned value can be pretty printed
|
||||
# with strftime
|
||||
time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret))
|
||||
|
||||
def uids(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
for uid in ret:
|
||||
assert isinstance(uid, int)
|
||||
assert uid >= 0
|
||||
|
||||
def gids(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
# note: testing all gids as above seems not to be reliable for
|
||||
# gid == 30 (nodoby); not sure why.
|
||||
for gid in ret:
|
||||
assert isinstance(gid, int)
|
||||
if not MACOS and not NETBSD:
|
||||
assert gid >= 0
|
||||
|
||||
def username(self, ret, info):
|
||||
assert isinstance(ret, str)
|
||||
assert ret.strip() == ret
|
||||
assert ret.strip()
|
||||
|
||||
def status(self, ret, info):
|
||||
assert isinstance(ret, str)
|
||||
assert ret, ret
|
||||
if QEMU_USER:
|
||||
# status does not work under qemu user
|
||||
return
|
||||
assert ret != '?' # XXX
|
||||
assert ret in VALID_PROC_STATUSES
|
||||
|
||||
def io_counters(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
for field in ret:
|
||||
assert isinstance(field, (int, long))
|
||||
if field != -1:
|
||||
assert field >= 0
|
||||
|
||||
def ionice(self, ret, info):
|
||||
if LINUX:
|
||||
assert isinstance(ret.ioclass, int)
|
||||
assert isinstance(ret.value, int)
|
||||
assert ret.ioclass >= 0
|
||||
assert ret.value >= 0
|
||||
else: # Windows, Cygwin
|
||||
choices = [
|
||||
psutil.IOPRIO_VERYLOW,
|
||||
psutil.IOPRIO_LOW,
|
||||
psutil.IOPRIO_NORMAL,
|
||||
psutil.IOPRIO_HIGH,
|
||||
]
|
||||
assert isinstance(ret, int)
|
||||
assert ret >= 0
|
||||
assert ret in choices
|
||||
|
||||
def num_threads(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
if WINDOWS and ret == 0 and is_win_secure_system_proc(info['pid']):
|
||||
# https://github.com/giampaolo/psutil/issues/2338
|
||||
return
|
||||
assert ret >= 1
|
||||
|
||||
def threads(self, ret, info):
|
||||
assert isinstance(ret, list)
|
||||
for t in ret:
|
||||
assert is_namedtuple(t)
|
||||
assert t.id >= 0
|
||||
assert t.user_time >= 0
|
||||
assert t.system_time >= 0
|
||||
for field in t:
|
||||
assert isinstance(field, (int, float))
|
||||
|
||||
def cpu_times(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
for n in ret:
|
||||
assert isinstance(n, float)
|
||||
assert n >= 0
|
||||
# TODO: check ntuple fields
|
||||
|
||||
def cpu_percent(self, ret, info):
|
||||
assert isinstance(ret, float)
|
||||
assert 0.0 <= ret <= 100.0, ret
|
||||
|
||||
def cpu_num(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
if FREEBSD and ret == -1:
|
||||
return
|
||||
assert ret >= 0
|
||||
if psutil.cpu_count() == 1:
|
||||
assert ret == 0
|
||||
assert ret in list(range(psutil.cpu_count()))
|
||||
|
||||
def memory_info(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
for value in ret:
|
||||
assert isinstance(value, (int, long))
|
||||
assert value >= 0
|
||||
if WINDOWS:
|
||||
assert ret.peak_wset >= ret.wset
|
||||
assert ret.peak_paged_pool >= ret.paged_pool
|
||||
assert ret.peak_nonpaged_pool >= ret.nonpaged_pool
|
||||
assert ret.peak_pagefile >= ret.pagefile
|
||||
|
||||
def memory_full_info(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
total = psutil.virtual_memory().total
|
||||
for name in ret._fields:
|
||||
value = getattr(ret, name)
|
||||
assert isinstance(value, (int, long))
|
||||
assert value >= 0
|
||||
if LINUX or (OSX and name in ('vms', 'data')):
|
||||
# On Linux there are processes (e.g. 'goa-daemon') whose
|
||||
# VMS is incredibly high for some reason.
|
||||
continue
|
||||
assert value <= total, name
|
||||
|
||||
if LINUX:
|
||||
assert ret.pss >= ret.uss
|
||||
|
||||
def open_files(self, ret, info):
|
||||
assert isinstance(ret, list)
|
||||
for f in ret:
|
||||
assert isinstance(f.fd, int)
|
||||
assert isinstance(f.path, str)
|
||||
assert f.path.strip() == f.path
|
||||
if WINDOWS:
|
||||
assert f.fd == -1
|
||||
elif LINUX:
|
||||
assert isinstance(f.position, int)
|
||||
assert isinstance(f.mode, str)
|
||||
assert isinstance(f.flags, int)
|
||||
assert f.position >= 0
|
||||
assert f.mode in ('r', 'w', 'a', 'r+', 'a+')
|
||||
assert f.flags > 0
|
||||
elif BSD and not f.path:
|
||||
# XXX see: https://github.com/giampaolo/psutil/issues/595
|
||||
continue
|
||||
assert os.path.isabs(f.path), f
|
||||
try:
|
||||
st = os.stat(f.path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
else:
|
||||
assert stat.S_ISREG(st.st_mode), f
|
||||
|
||||
def num_fds(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
assert ret >= 0
|
||||
|
||||
def net_connections(self, ret, info):
|
||||
with create_sockets():
|
||||
assert len(ret) == len(set(ret))
|
||||
for conn in ret:
|
||||
assert is_namedtuple(conn)
|
||||
check_connection_ntuple(conn)
|
||||
|
||||
def cwd(self, ret, info):
|
||||
assert isinstance(ret, (str, unicode))
|
||||
assert ret.strip() == ret
|
||||
if ret:
|
||||
assert os.path.isabs(ret), ret
|
||||
try:
|
||||
st = os.stat(ret)
|
||||
except OSError as err:
|
||||
if WINDOWS and psutil._psplatform.is_permission_err(err):
|
||||
pass
|
||||
# directory has been removed in mean time
|
||||
elif err.errno != errno.ENOENT:
|
||||
raise
|
||||
else:
|
||||
assert stat.S_ISDIR(st.st_mode)
|
||||
|
||||
def memory_percent(self, ret, info):
|
||||
assert isinstance(ret, float)
|
||||
assert 0 <= ret <= 100, ret
|
||||
|
||||
def is_running(self, ret, info):
|
||||
assert isinstance(ret, bool)
|
||||
|
||||
def cpu_affinity(self, ret, info):
|
||||
assert isinstance(ret, list)
|
||||
assert ret != []
|
||||
cpus = list(range(psutil.cpu_count()))
|
||||
for n in ret:
|
||||
assert isinstance(n, int)
|
||||
assert n in cpus
|
||||
|
||||
def terminal(self, ret, info):
|
||||
assert isinstance(ret, (str, type(None)))
|
||||
if ret is not None:
|
||||
assert os.path.isabs(ret), ret
|
||||
assert os.path.exists(ret), ret
|
||||
|
||||
def memory_maps(self, ret, info):
|
||||
for nt in ret:
|
||||
assert isinstance(nt.addr, str)
|
||||
assert isinstance(nt.perms, str)
|
||||
assert isinstance(nt.path, str)
|
||||
for fname in nt._fields:
|
||||
value = getattr(nt, fname)
|
||||
if fname == 'path':
|
||||
if not value.startswith(("[", "anon_inode:")):
|
||||
assert os.path.isabs(nt.path), nt.path
|
||||
# commented as on Linux we might get
|
||||
# '/foo/bar (deleted)'
|
||||
# assert os.path.exists(nt.path), nt.path
|
||||
elif fname == 'addr':
|
||||
assert value, repr(value)
|
||||
elif fname == 'perms':
|
||||
if not WINDOWS:
|
||||
assert value, repr(value)
|
||||
else:
|
||||
assert isinstance(value, (int, long))
|
||||
assert value >= 0
|
||||
|
||||
def num_handles(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
assert ret >= 0
|
||||
|
||||
def nice(self, ret, info):
|
||||
assert isinstance(ret, int)
|
||||
if POSIX:
|
||||
assert -20 <= ret <= 20, ret
|
||||
else:
|
||||
priorities = [
|
||||
getattr(psutil, x)
|
||||
for x in dir(psutil)
|
||||
if x.endswith('_PRIORITY_CLASS')
|
||||
]
|
||||
assert ret in priorities
|
||||
if PY3:
|
||||
assert isinstance(ret, enum.IntEnum)
|
||||
else:
|
||||
assert isinstance(ret, int)
|
||||
|
||||
def num_ctx_switches(self, ret, info):
|
||||
assert is_namedtuple(ret)
|
||||
for value in ret:
|
||||
assert isinstance(value, (int, long))
|
||||
assert value >= 0
|
||||
|
||||
def rlimit(self, ret, info):
|
||||
assert isinstance(ret, tuple)
|
||||
assert len(ret) == 2
|
||||
assert ret[0] >= -1
|
||||
assert ret[1] >= -1
|
||||
|
||||
def environ(self, ret, info):
|
||||
assert isinstance(ret, dict)
|
||||
for k, v in ret.items():
|
||||
assert isinstance(k, str)
|
||||
assert isinstance(v, str)
|
||||
|
||||
|
||||
class TestPidsRange(PsutilTestCase):
|
||||
"""Given pid_exists() return value for a range of PIDs which may or
|
||||
may not exist, make sure that psutil.Process() and psutil.pids()
|
||||
agree with pid_exists(). This guarantees that the 3 APIs are all
|
||||
consistent with each other. See:
|
||||
https://github.com/giampaolo/psutil/issues/2359
|
||||
|
||||
XXX - Note about Windows: it turns out there are some "hidden" PIDs
|
||||
which are not returned by psutil.pids() and are also not revealed
|
||||
by taskmgr.exe and ProcessHacker, still they can be instantiated by
|
||||
psutil.Process() and queried. One of such PIDs is "conhost.exe".
|
||||
Running as_dict() for it reveals that some Process() APIs
|
||||
erroneously raise NoSuchProcess, so we know we have problem there.
|
||||
Let's ignore this for now, since it's quite a corner case (who even
|
||||
imagined hidden PIDs existed on Windows?).
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
psutil._set_debug(False)
|
||||
|
||||
def tearDown(self):
|
||||
psutil._set_debug(True)
|
||||
|
||||
def test_it(self):
|
||||
def is_linux_tid(pid):
|
||||
try:
|
||||
f = open("/proc/%s/status" % pid, "rb")
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
else:
|
||||
with f:
|
||||
for line in f:
|
||||
if line.startswith(b"Tgid:"):
|
||||
tgid = int(line.split()[1])
|
||||
# If tgid and pid are different then we're
|
||||
# dealing with a process TID.
|
||||
return tgid != pid
|
||||
raise ValueError("'Tgid' line not found")
|
||||
|
||||
def check(pid):
|
||||
# In case of failure retry up to 3 times in order to avoid
|
||||
# race conditions, especially when running in a CI
|
||||
# environment where PIDs may appear and disappear at any
|
||||
# time.
|
||||
x = 3
|
||||
while True:
|
||||
exists = psutil.pid_exists(pid)
|
||||
try:
|
||||
if exists:
|
||||
psutil.Process(pid)
|
||||
if not WINDOWS: # see docstring
|
||||
assert pid in psutil.pids()
|
||||
else:
|
||||
# On OpenBSD thread IDs can be instantiated,
|
||||
# and oneshot() succeeds, but other APIs fail
|
||||
# with EINVAL.
|
||||
if not OPENBSD:
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
psutil.Process(pid)
|
||||
if not WINDOWS: # see docstring
|
||||
assert pid not in psutil.pids()
|
||||
except (psutil.Error, AssertionError):
|
||||
x -= 1
|
||||
if x == 0:
|
||||
raise
|
||||
else:
|
||||
return
|
||||
|
||||
for pid in range(1, 3000):
|
||||
if LINUX and is_linux_tid(pid):
|
||||
# On Linux a TID (thread ID) can be passed to the
|
||||
# Process class and is querable like a PID (process
|
||||
# ID). Skip it.
|
||||
continue
|
||||
with self.subTest(pid=pid):
|
||||
check(pid)
|
39
env/lib/python3.12/site-packages/psutil/tests/test_sunos.py
vendored
Normal file
39
env/lib/python3.12/site-packages/psutil/tests/test_sunos.py
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Sun OS specific tests."""
|
||||
|
||||
import os
|
||||
|
||||
import psutil
|
||||
from psutil import SUNOS
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import sh
|
||||
|
||||
|
||||
@pytest.mark.skipif(not SUNOS, reason="SUNOS only")
|
||||
class SunOSSpecificTestCase(PsutilTestCase):
|
||||
def test_swap_memory(self):
|
||||
out = sh('env PATH=/usr/sbin:/sbin:%s swap -l' % os.environ['PATH'])
|
||||
lines = out.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise ValueError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
fields = line.split()
|
||||
total = int(fields[3]) * 512
|
||||
free = int(fields[4]) * 512
|
||||
used = total - free
|
||||
|
||||
psutil_swap = psutil.swap_memory()
|
||||
assert psutil_swap.total == total
|
||||
assert psutil_swap.used == used
|
||||
assert psutil_swap.free == free
|
||||
|
||||
def test_cpu_count(self):
|
||||
out = sh("/usr/sbin/psrinfo")
|
||||
assert psutil.cpu_count() == len(out.split('\n'))
|
987
env/lib/python3.12/site-packages/psutil/tests/test_system.py
vendored
Normal file
987
env/lib/python3.12/site-packages/psutil/tests/test_system.py
vendored
Normal file
@ -0,0 +1,987 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Tests for system APIS."""
|
||||
|
||||
import contextlib
|
||||
import datetime
|
||||
import errno
|
||||
import os
|
||||
import platform
|
||||
import pprint
|
||||
import shutil
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import PY3
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil._compat import long
|
||||
from psutil.tests import ASCII_FS
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import DEVNULL
|
||||
from psutil.tests import GITHUB_ACTIONS
|
||||
from psutil.tests import GLOBAL_TIMEOUT
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_GETLOADAVG
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_SENSORS_BATTERY
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import IS_64BIT
|
||||
from psutil.tests import MACOS_12PLUS
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import QEMU_USER
|
||||
from psutil.tests import UNICODE_SUFFIX
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import check_net_address
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import retry_on_failure
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- System-related API tests
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestProcessIter(PsutilTestCase):
|
||||
def test_pid_presence(self):
|
||||
assert os.getpid() in [x.pid for x in psutil.process_iter()]
|
||||
sproc = self.spawn_testproc()
|
||||
assert sproc.pid in [x.pid for x in psutil.process_iter()]
|
||||
p = psutil.Process(sproc.pid)
|
||||
p.kill()
|
||||
p.wait()
|
||||
assert sproc.pid not in [x.pid for x in psutil.process_iter()]
|
||||
|
||||
def test_no_duplicates(self):
|
||||
ls = [x for x in psutil.process_iter()]
|
||||
assert sorted(ls, key=lambda x: x.pid) == sorted(
|
||||
set(ls), key=lambda x: x.pid
|
||||
)
|
||||
|
||||
def test_emulate_nsp(self):
|
||||
list(psutil.process_iter()) # populate cache
|
||||
for x in range(2):
|
||||
with mock.patch(
|
||||
'psutil.Process.as_dict',
|
||||
side_effect=psutil.NoSuchProcess(os.getpid()),
|
||||
):
|
||||
assert list(psutil.process_iter(attrs=["cpu_times"])) == []
|
||||
psutil.process_iter.cache_clear() # repeat test without cache
|
||||
|
||||
def test_emulate_access_denied(self):
|
||||
list(psutil.process_iter()) # populate cache
|
||||
for x in range(2):
|
||||
with mock.patch(
|
||||
'psutil.Process.as_dict',
|
||||
side_effect=psutil.AccessDenied(os.getpid()),
|
||||
):
|
||||
with pytest.raises(psutil.AccessDenied):
|
||||
list(psutil.process_iter(attrs=["cpu_times"]))
|
||||
psutil.process_iter.cache_clear() # repeat test without cache
|
||||
|
||||
def test_attrs(self):
|
||||
for p in psutil.process_iter(attrs=['pid']):
|
||||
assert list(p.info.keys()) == ['pid']
|
||||
# yield again
|
||||
for p in psutil.process_iter(attrs=['pid']):
|
||||
assert list(p.info.keys()) == ['pid']
|
||||
with pytest.raises(ValueError):
|
||||
list(psutil.process_iter(attrs=['foo']))
|
||||
with mock.patch(
|
||||
"psutil._psplatform.Process.cpu_times",
|
||||
side_effect=psutil.AccessDenied(0, ""),
|
||||
) as m:
|
||||
for p in psutil.process_iter(attrs=["pid", "cpu_times"]):
|
||||
assert p.info['cpu_times'] is None
|
||||
assert p.info['pid'] >= 0
|
||||
assert m.called
|
||||
with mock.patch(
|
||||
"psutil._psplatform.Process.cpu_times",
|
||||
side_effect=psutil.AccessDenied(0, ""),
|
||||
) as m:
|
||||
flag = object()
|
||||
for p in psutil.process_iter(
|
||||
attrs=["pid", "cpu_times"], ad_value=flag
|
||||
):
|
||||
assert p.info['cpu_times'] is flag
|
||||
assert p.info['pid'] >= 0
|
||||
assert m.called
|
||||
|
||||
def test_cache_clear(self):
|
||||
list(psutil.process_iter()) # populate cache
|
||||
assert psutil._pmap
|
||||
psutil.process_iter.cache_clear()
|
||||
assert not psutil._pmap
|
||||
|
||||
|
||||
class TestProcessAPIs(PsutilTestCase):
|
||||
@pytest.mark.skipif(
|
||||
PYPY and WINDOWS,
|
||||
reason="spawn_testproc() unreliable on PYPY + WINDOWS",
|
||||
)
|
||||
def test_wait_procs(self):
|
||||
def callback(p):
|
||||
pids.append(p.pid)
|
||||
|
||||
pids = []
|
||||
sproc1 = self.spawn_testproc()
|
||||
sproc2 = self.spawn_testproc()
|
||||
sproc3 = self.spawn_testproc()
|
||||
procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)]
|
||||
with pytest.raises(ValueError):
|
||||
psutil.wait_procs(procs, timeout=-1)
|
||||
with pytest.raises(TypeError):
|
||||
psutil.wait_procs(procs, callback=1)
|
||||
t = time.time()
|
||||
gone, alive = psutil.wait_procs(procs, timeout=0.01, callback=callback)
|
||||
|
||||
assert time.time() - t < 0.5
|
||||
assert gone == []
|
||||
assert len(alive) == 3
|
||||
assert pids == []
|
||||
for p in alive:
|
||||
assert not hasattr(p, 'returncode')
|
||||
|
||||
@retry_on_failure(30)
|
||||
def test_1(procs, callback):
|
||||
gone, alive = psutil.wait_procs(
|
||||
procs, timeout=0.03, callback=callback
|
||||
)
|
||||
assert len(gone) == 1
|
||||
assert len(alive) == 2
|
||||
return gone, alive
|
||||
|
||||
sproc3.terminate()
|
||||
gone, alive = test_1(procs, callback)
|
||||
assert sproc3.pid in [x.pid for x in gone]
|
||||
if POSIX:
|
||||
assert gone.pop().returncode == -signal.SIGTERM
|
||||
else:
|
||||
assert gone.pop().returncode == 1
|
||||
assert pids == [sproc3.pid]
|
||||
for p in alive:
|
||||
assert not hasattr(p, 'returncode')
|
||||
|
||||
@retry_on_failure(30)
|
||||
def test_2(procs, callback):
|
||||
gone, alive = psutil.wait_procs(
|
||||
procs, timeout=0.03, callback=callback
|
||||
)
|
||||
assert len(gone) == 3
|
||||
assert len(alive) == 0
|
||||
return gone, alive
|
||||
|
||||
sproc1.terminate()
|
||||
sproc2.terminate()
|
||||
gone, alive = test_2(procs, callback)
|
||||
assert set(pids) == set([sproc1.pid, sproc2.pid, sproc3.pid])
|
||||
for p in gone:
|
||||
assert hasattr(p, 'returncode')
|
||||
|
||||
@pytest.mark.skipif(
|
||||
PYPY and WINDOWS,
|
||||
reason="spawn_testproc() unreliable on PYPY + WINDOWS",
|
||||
)
|
||||
def test_wait_procs_no_timeout(self):
|
||||
sproc1 = self.spawn_testproc()
|
||||
sproc2 = self.spawn_testproc()
|
||||
sproc3 = self.spawn_testproc()
|
||||
procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)]
|
||||
for p in procs:
|
||||
p.terminate()
|
||||
psutil.wait_procs(procs)
|
||||
|
||||
def test_pid_exists(self):
|
||||
sproc = self.spawn_testproc()
|
||||
assert psutil.pid_exists(sproc.pid)
|
||||
p = psutil.Process(sproc.pid)
|
||||
p.kill()
|
||||
p.wait()
|
||||
assert not psutil.pid_exists(sproc.pid)
|
||||
assert not psutil.pid_exists(-1)
|
||||
assert psutil.pid_exists(0) == (0 in psutil.pids())
|
||||
|
||||
def test_pid_exists_2(self):
|
||||
pids = psutil.pids()
|
||||
for pid in pids:
|
||||
try:
|
||||
assert psutil.pid_exists(pid)
|
||||
except AssertionError:
|
||||
# in case the process disappeared in meantime fail only
|
||||
# if it is no longer in psutil.pids()
|
||||
time.sleep(0.1)
|
||||
assert pid not in psutil.pids()
|
||||
pids = range(max(pids) + 15000, max(pids) + 16000)
|
||||
for pid in pids:
|
||||
assert not psutil.pid_exists(pid)
|
||||
|
||||
|
||||
class TestMiscAPIs(PsutilTestCase):
|
||||
def test_boot_time(self):
|
||||
bt = psutil.boot_time()
|
||||
assert isinstance(bt, float)
|
||||
assert bt > 0
|
||||
assert bt < time.time()
|
||||
|
||||
@pytest.mark.skipif(
|
||||
CI_TESTING and not psutil.users(), reason="unreliable on CI"
|
||||
)
|
||||
def test_users(self):
|
||||
users = psutil.users()
|
||||
assert users != []
|
||||
for user in users:
|
||||
with self.subTest(user=user):
|
||||
assert user.name
|
||||
assert isinstance(user.name, str)
|
||||
assert isinstance(user.terminal, (str, type(None)))
|
||||
if user.host is not None:
|
||||
assert isinstance(user.host, (str, type(None)))
|
||||
user.terminal # noqa
|
||||
user.host # noqa
|
||||
assert user.started > 0.0
|
||||
datetime.datetime.fromtimestamp(user.started)
|
||||
if WINDOWS or OPENBSD:
|
||||
assert user.pid is None
|
||||
else:
|
||||
psutil.Process(user.pid)
|
||||
|
||||
def test_test(self):
|
||||
# test for psutil.test() function
|
||||
stdout = sys.stdout
|
||||
sys.stdout = DEVNULL
|
||||
try:
|
||||
psutil.test()
|
||||
finally:
|
||||
sys.stdout = stdout
|
||||
|
||||
def test_os_constants(self):
|
||||
names = [
|
||||
"POSIX",
|
||||
"WINDOWS",
|
||||
"LINUX",
|
||||
"MACOS",
|
||||
"FREEBSD",
|
||||
"OPENBSD",
|
||||
"NETBSD",
|
||||
"BSD",
|
||||
"SUNOS",
|
||||
]
|
||||
for name in names:
|
||||
assert isinstance(getattr(psutil, name), bool), name
|
||||
|
||||
if os.name == 'posix':
|
||||
assert psutil.POSIX
|
||||
assert not psutil.WINDOWS
|
||||
names.remove("POSIX")
|
||||
if "linux" in sys.platform.lower():
|
||||
assert psutil.LINUX
|
||||
names.remove("LINUX")
|
||||
elif "bsd" in sys.platform.lower():
|
||||
assert psutil.BSD
|
||||
assert [psutil.FREEBSD, psutil.OPENBSD, psutil.NETBSD].count(
|
||||
True
|
||||
) == 1
|
||||
names.remove("BSD")
|
||||
names.remove("FREEBSD")
|
||||
names.remove("OPENBSD")
|
||||
names.remove("NETBSD")
|
||||
elif (
|
||||
"sunos" in sys.platform.lower()
|
||||
or "solaris" in sys.platform.lower()
|
||||
):
|
||||
assert psutil.SUNOS
|
||||
names.remove("SUNOS")
|
||||
elif "darwin" in sys.platform.lower():
|
||||
assert psutil.MACOS
|
||||
names.remove("MACOS")
|
||||
else:
|
||||
assert psutil.WINDOWS
|
||||
assert not psutil.POSIX
|
||||
names.remove("WINDOWS")
|
||||
|
||||
# assert all other constants are set to False
|
||||
for name in names:
|
||||
assert not getattr(psutil, name), name
|
||||
|
||||
|
||||
class TestMemoryAPIs(PsutilTestCase):
|
||||
def test_virtual_memory(self):
|
||||
mem = psutil.virtual_memory()
|
||||
assert mem.total > 0, mem
|
||||
assert mem.available > 0, mem
|
||||
assert 0 <= mem.percent <= 100, mem
|
||||
assert mem.used > 0, mem
|
||||
assert mem.free >= 0, mem
|
||||
for name in mem._fields:
|
||||
value = getattr(mem, name)
|
||||
if name != 'percent':
|
||||
assert isinstance(value, (int, long))
|
||||
if name != 'total':
|
||||
if not value >= 0:
|
||||
raise self.fail("%r < 0 (%s)" % (name, value))
|
||||
if value > mem.total:
|
||||
raise self.fail(
|
||||
"%r > total (total=%s, %s=%s)"
|
||||
% (name, mem.total, name, value)
|
||||
)
|
||||
|
||||
def test_swap_memory(self):
|
||||
mem = psutil.swap_memory()
|
||||
assert mem._fields == (
|
||||
'total',
|
||||
'used',
|
||||
'free',
|
||||
'percent',
|
||||
'sin',
|
||||
'sout',
|
||||
)
|
||||
|
||||
assert mem.total >= 0, mem
|
||||
assert mem.used >= 0, mem
|
||||
if mem.total > 0:
|
||||
# likely a system with no swap partition
|
||||
assert mem.free > 0, mem
|
||||
else:
|
||||
assert mem.free == 0, mem
|
||||
assert 0 <= mem.percent <= 100, mem
|
||||
assert mem.sin >= 0, mem
|
||||
assert mem.sout >= 0, mem
|
||||
|
||||
|
||||
class TestCpuAPIs(PsutilTestCase):
|
||||
def test_cpu_count_logical(self):
|
||||
logical = psutil.cpu_count()
|
||||
assert logical is not None
|
||||
assert logical == len(psutil.cpu_times(percpu=True))
|
||||
assert logical >= 1
|
||||
|
||||
if os.path.exists("/proc/cpuinfo"):
|
||||
with open("/proc/cpuinfo") as fd:
|
||||
cpuinfo_data = fd.read()
|
||||
if "physical id" not in cpuinfo_data:
|
||||
raise pytest.skip("cpuinfo doesn't include physical id")
|
||||
|
||||
def test_cpu_count_cores(self):
|
||||
logical = psutil.cpu_count()
|
||||
cores = psutil.cpu_count(logical=False)
|
||||
if cores is None:
|
||||
raise pytest.skip("cpu_count_cores() is None")
|
||||
if WINDOWS and sys.getwindowsversion()[:2] <= (6, 1): # <= Vista
|
||||
assert cores is None
|
||||
else:
|
||||
assert cores >= 1
|
||||
assert logical >= cores
|
||||
|
||||
def test_cpu_count_none(self):
|
||||
# https://github.com/giampaolo/psutil/issues/1085
|
||||
for val in (-1, 0, None):
|
||||
with mock.patch(
|
||||
'psutil._psplatform.cpu_count_logical', return_value=val
|
||||
) as m:
|
||||
assert psutil.cpu_count() is None
|
||||
assert m.called
|
||||
with mock.patch(
|
||||
'psutil._psplatform.cpu_count_cores', return_value=val
|
||||
) as m:
|
||||
assert psutil.cpu_count(logical=False) is None
|
||||
assert m.called
|
||||
|
||||
def test_cpu_times(self):
|
||||
# Check type, value >= 0, str().
|
||||
total = 0
|
||||
times = psutil.cpu_times()
|
||||
sum(times)
|
||||
for cp_time in times:
|
||||
assert isinstance(cp_time, float)
|
||||
assert cp_time >= 0.0
|
||||
total += cp_time
|
||||
assert round(abs(total - sum(times)), 6) == 0
|
||||
str(times)
|
||||
# CPU times are always supposed to increase over time
|
||||
# or at least remain the same and that's because time
|
||||
# cannot go backwards.
|
||||
# Surprisingly sometimes this might not be the case (at
|
||||
# least on Windows and Linux), see:
|
||||
# https://github.com/giampaolo/psutil/issues/392
|
||||
# https://github.com/giampaolo/psutil/issues/645
|
||||
# if not WINDOWS:
|
||||
# last = psutil.cpu_times()
|
||||
# for x in range(100):
|
||||
# new = psutil.cpu_times()
|
||||
# for field in new._fields:
|
||||
# new_t = getattr(new, field)
|
||||
# last_t = getattr(last, field)
|
||||
# self.assertGreaterEqual(new_t, last_t,
|
||||
# msg="%s %s" % (new_t, last_t))
|
||||
# last = new
|
||||
|
||||
def test_cpu_times_time_increases(self):
|
||||
# Make sure time increases between calls.
|
||||
t1 = sum(psutil.cpu_times())
|
||||
stop_at = time.time() + GLOBAL_TIMEOUT
|
||||
while time.time() < stop_at:
|
||||
t2 = sum(psutil.cpu_times())
|
||||
if t2 > t1:
|
||||
return
|
||||
raise self.fail("time remained the same")
|
||||
|
||||
def test_per_cpu_times(self):
|
||||
# Check type, value >= 0, str().
|
||||
for times in psutil.cpu_times(percpu=True):
|
||||
total = 0
|
||||
sum(times)
|
||||
for cp_time in times:
|
||||
assert isinstance(cp_time, float)
|
||||
assert cp_time >= 0.0
|
||||
total += cp_time
|
||||
assert round(abs(total - sum(times)), 6) == 0
|
||||
str(times)
|
||||
assert len(psutil.cpu_times(percpu=True)[0]) == len(
|
||||
psutil.cpu_times(percpu=False)
|
||||
)
|
||||
|
||||
# Note: in theory CPU times are always supposed to increase over
|
||||
# time or remain the same but never go backwards. In practice
|
||||
# sometimes this is not the case.
|
||||
# This issue seemd to be afflict Windows:
|
||||
# https://github.com/giampaolo/psutil/issues/392
|
||||
# ...but it turns out also Linux (rarely) behaves the same.
|
||||
# last = psutil.cpu_times(percpu=True)
|
||||
# for x in range(100):
|
||||
# new = psutil.cpu_times(percpu=True)
|
||||
# for index in range(len(new)):
|
||||
# newcpu = new[index]
|
||||
# lastcpu = last[index]
|
||||
# for field in newcpu._fields:
|
||||
# new_t = getattr(newcpu, field)
|
||||
# last_t = getattr(lastcpu, field)
|
||||
# self.assertGreaterEqual(
|
||||
# new_t, last_t, msg="%s %s" % (lastcpu, newcpu))
|
||||
# last = new
|
||||
|
||||
def test_per_cpu_times_2(self):
|
||||
# Simulate some work load then make sure time have increased
|
||||
# between calls.
|
||||
tot1 = psutil.cpu_times(percpu=True)
|
||||
giveup_at = time.time() + GLOBAL_TIMEOUT
|
||||
while True:
|
||||
if time.time() >= giveup_at:
|
||||
return self.fail("timeout")
|
||||
tot2 = psutil.cpu_times(percpu=True)
|
||||
for t1, t2 in zip(tot1, tot2):
|
||||
t1, t2 = psutil._cpu_busy_time(t1), psutil._cpu_busy_time(t2)
|
||||
difference = t2 - t1
|
||||
if difference >= 0.05:
|
||||
return
|
||||
|
||||
@pytest.mark.skipif(
|
||||
CI_TESTING and OPENBSD, reason="unreliable on OPENBSD + CI"
|
||||
)
|
||||
def test_cpu_times_comparison(self):
|
||||
# Make sure the sum of all per cpu times is almost equal to
|
||||
# base "one cpu" times. On OpenBSD the sum of per-CPUs is
|
||||
# higher for some reason.
|
||||
base = psutil.cpu_times()
|
||||
per_cpu = psutil.cpu_times(percpu=True)
|
||||
summed_values = base._make([sum(num) for num in zip(*per_cpu)])
|
||||
for field in base._fields:
|
||||
with self.subTest(field=field, base=base, per_cpu=per_cpu):
|
||||
assert (
|
||||
abs(getattr(base, field) - getattr(summed_values, field))
|
||||
< 1
|
||||
)
|
||||
|
||||
def _test_cpu_percent(self, percent, last_ret, new_ret):
|
||||
try:
|
||||
assert isinstance(percent, float)
|
||||
assert percent >= 0.0
|
||||
assert percent is not -0.0
|
||||
assert percent <= 100.0 * psutil.cpu_count()
|
||||
except AssertionError as err:
|
||||
raise AssertionError(
|
||||
"\n%s\nlast=%s\nnew=%s"
|
||||
% (err, pprint.pformat(last_ret), pprint.pformat(new_ret))
|
||||
)
|
||||
|
||||
def test_cpu_percent(self):
|
||||
last = psutil.cpu_percent(interval=0.001)
|
||||
for _ in range(100):
|
||||
new = psutil.cpu_percent(interval=None)
|
||||
self._test_cpu_percent(new, last, new)
|
||||
last = new
|
||||
with pytest.raises(ValueError):
|
||||
psutil.cpu_percent(interval=-1)
|
||||
|
||||
def test_per_cpu_percent(self):
|
||||
last = psutil.cpu_percent(interval=0.001, percpu=True)
|
||||
assert len(last) == psutil.cpu_count()
|
||||
for _ in range(100):
|
||||
new = psutil.cpu_percent(interval=None, percpu=True)
|
||||
for percent in new:
|
||||
self._test_cpu_percent(percent, last, new)
|
||||
last = new
|
||||
with pytest.raises(ValueError):
|
||||
psutil.cpu_percent(interval=-1, percpu=True)
|
||||
|
||||
def test_cpu_times_percent(self):
|
||||
last = psutil.cpu_times_percent(interval=0.001)
|
||||
for _ in range(100):
|
||||
new = psutil.cpu_times_percent(interval=None)
|
||||
for percent in new:
|
||||
self._test_cpu_percent(percent, last, new)
|
||||
self._test_cpu_percent(sum(new), last, new)
|
||||
last = new
|
||||
with pytest.raises(ValueError):
|
||||
psutil.cpu_times_percent(interval=-1)
|
||||
|
||||
def test_per_cpu_times_percent(self):
|
||||
last = psutil.cpu_times_percent(interval=0.001, percpu=True)
|
||||
assert len(last) == psutil.cpu_count()
|
||||
for _ in range(100):
|
||||
new = psutil.cpu_times_percent(interval=None, percpu=True)
|
||||
for cpu in new:
|
||||
for percent in cpu:
|
||||
self._test_cpu_percent(percent, last, new)
|
||||
self._test_cpu_percent(sum(cpu), last, new)
|
||||
last = new
|
||||
|
||||
def test_per_cpu_times_percent_negative(self):
|
||||
# see: https://github.com/giampaolo/psutil/issues/645
|
||||
psutil.cpu_times_percent(percpu=True)
|
||||
zero_times = [
|
||||
x._make([0 for x in range(len(x._fields))])
|
||||
for x in psutil.cpu_times(percpu=True)
|
||||
]
|
||||
with mock.patch('psutil.cpu_times', return_value=zero_times):
|
||||
for cpu in psutil.cpu_times_percent(percpu=True):
|
||||
for percent in cpu:
|
||||
self._test_cpu_percent(percent, None, None)
|
||||
|
||||
def test_cpu_stats(self):
|
||||
# Tested more extensively in per-platform test modules.
|
||||
infos = psutil.cpu_stats()
|
||||
assert infos._fields == (
|
||||
'ctx_switches',
|
||||
'interrupts',
|
||||
'soft_interrupts',
|
||||
'syscalls',
|
||||
)
|
||||
for name in infos._fields:
|
||||
value = getattr(infos, name)
|
||||
assert value >= 0
|
||||
# on AIX, ctx_switches is always 0
|
||||
if not AIX and name in ('ctx_switches', 'interrupts'):
|
||||
assert value > 0
|
||||
|
||||
# TODO: remove this once 1892 is fixed
|
||||
@pytest.mark.skipif(
|
||||
MACOS and platform.machine() == 'arm64', reason="skipped due to #1892"
|
||||
)
|
||||
@pytest.mark.skipif(not HAS_CPU_FREQ, reason="not supported")
|
||||
def test_cpu_freq(self):
|
||||
def check_ls(ls):
|
||||
for nt in ls:
|
||||
assert nt._fields == ('current', 'min', 'max')
|
||||
if nt.max != 0.0:
|
||||
assert nt.current <= nt.max
|
||||
for name in nt._fields:
|
||||
value = getattr(nt, name)
|
||||
assert isinstance(value, (int, long, float))
|
||||
assert value >= 0
|
||||
|
||||
ls = psutil.cpu_freq(percpu=True)
|
||||
if FREEBSD and not ls:
|
||||
raise pytest.skip("returns empty list on FreeBSD")
|
||||
|
||||
assert ls, ls
|
||||
check_ls([psutil.cpu_freq(percpu=False)])
|
||||
|
||||
if LINUX:
|
||||
assert len(ls) == psutil.cpu_count()
|
||||
|
||||
@pytest.mark.skipif(not HAS_GETLOADAVG, reason="not supported")
|
||||
def test_getloadavg(self):
|
||||
loadavg = psutil.getloadavg()
|
||||
assert len(loadavg) == 3
|
||||
for load in loadavg:
|
||||
assert isinstance(load, float)
|
||||
assert load >= 0.0
|
||||
|
||||
|
||||
class TestDiskAPIs(PsutilTestCase):
|
||||
@pytest.mark.skipif(
|
||||
PYPY and not IS_64BIT, reason="unreliable on PYPY32 + 32BIT"
|
||||
)
|
||||
def test_disk_usage(self):
|
||||
usage = psutil.disk_usage(os.getcwd())
|
||||
assert usage._fields == ('total', 'used', 'free', 'percent')
|
||||
|
||||
assert usage.total > 0, usage
|
||||
assert usage.used > 0, usage
|
||||
assert usage.free > 0, usage
|
||||
assert usage.total > usage.used, usage
|
||||
assert usage.total > usage.free, usage
|
||||
assert 0 <= usage.percent <= 100, usage.percent
|
||||
if hasattr(shutil, 'disk_usage'):
|
||||
# py >= 3.3, see: http://bugs.python.org/issue12442
|
||||
shutil_usage = shutil.disk_usage(os.getcwd())
|
||||
tolerance = 5 * 1024 * 1024 # 5MB
|
||||
assert usage.total == shutil_usage.total
|
||||
assert abs(usage.free - shutil_usage.free) < tolerance
|
||||
if not MACOS_12PLUS:
|
||||
# see https://github.com/giampaolo/psutil/issues/2147
|
||||
assert abs(usage.used - shutil_usage.used) < tolerance
|
||||
|
||||
# if path does not exist OSError ENOENT is expected across
|
||||
# all platforms
|
||||
fname = self.get_testfn()
|
||||
with pytest.raises(FileNotFoundError):
|
||||
psutil.disk_usage(fname)
|
||||
|
||||
@pytest.mark.skipif(not ASCII_FS, reason="not an ASCII fs")
|
||||
def test_disk_usage_unicode(self):
|
||||
# See: https://github.com/giampaolo/psutil/issues/416
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
psutil.disk_usage(UNICODE_SUFFIX)
|
||||
|
||||
def test_disk_usage_bytes(self):
|
||||
psutil.disk_usage(b'.')
|
||||
|
||||
def test_disk_partitions(self):
|
||||
def check_ntuple(nt):
|
||||
assert isinstance(nt.device, str)
|
||||
assert isinstance(nt.mountpoint, str)
|
||||
assert isinstance(nt.fstype, str)
|
||||
assert isinstance(nt.opts, str)
|
||||
|
||||
# all = False
|
||||
ls = psutil.disk_partitions(all=False)
|
||||
assert ls
|
||||
for disk in ls:
|
||||
check_ntuple(disk)
|
||||
if WINDOWS and 'cdrom' in disk.opts:
|
||||
continue
|
||||
if not POSIX:
|
||||
assert os.path.exists(disk.device), disk
|
||||
else:
|
||||
# we cannot make any assumption about this, see:
|
||||
# http://goo.gl/p9c43
|
||||
disk.device # noqa
|
||||
# on modern systems mount points can also be files
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
assert disk.fstype, disk
|
||||
|
||||
# all = True
|
||||
ls = psutil.disk_partitions(all=True)
|
||||
assert ls
|
||||
for disk in psutil.disk_partitions(all=True):
|
||||
check_ntuple(disk)
|
||||
if not WINDOWS and disk.mountpoint:
|
||||
try:
|
||||
os.stat(disk.mountpoint)
|
||||
except OSError as err:
|
||||
if GITHUB_ACTIONS and MACOS and err.errno == errno.EIO:
|
||||
continue
|
||||
# http://mail.python.org/pipermail/python-dev/
|
||||
# 2012-June/120787.html
|
||||
if err.errno not in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
else:
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
|
||||
# ---
|
||||
|
||||
def find_mount_point(path):
|
||||
path = os.path.abspath(path)
|
||||
while not os.path.ismount(path):
|
||||
path = os.path.dirname(path)
|
||||
return path.lower()
|
||||
|
||||
mount = find_mount_point(__file__)
|
||||
mounts = [
|
||||
x.mountpoint.lower()
|
||||
for x in psutil.disk_partitions(all=True)
|
||||
if x.mountpoint
|
||||
]
|
||||
assert mount in mounts
|
||||
|
||||
@pytest.mark.skipif(
|
||||
LINUX and not os.path.exists('/proc/diskstats'),
|
||||
reason="/proc/diskstats not available on this linux version",
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
CI_TESTING and not psutil.disk_io_counters(), reason="unreliable on CI"
|
||||
) # no visible disks
|
||||
def test_disk_io_counters(self):
|
||||
def check_ntuple(nt):
|
||||
assert nt[0] == nt.read_count
|
||||
assert nt[1] == nt.write_count
|
||||
assert nt[2] == nt.read_bytes
|
||||
assert nt[3] == nt.write_bytes
|
||||
if not (OPENBSD or NETBSD):
|
||||
assert nt[4] == nt.read_time
|
||||
assert nt[5] == nt.write_time
|
||||
if LINUX:
|
||||
assert nt[6] == nt.read_merged_count
|
||||
assert nt[7] == nt.write_merged_count
|
||||
assert nt[8] == nt.busy_time
|
||||
elif FREEBSD:
|
||||
assert nt[6] == nt.busy_time
|
||||
for name in nt._fields:
|
||||
assert getattr(nt, name) >= 0, nt
|
||||
|
||||
ret = psutil.disk_io_counters(perdisk=False)
|
||||
assert ret is not None, "no disks on this system?"
|
||||
check_ntuple(ret)
|
||||
ret = psutil.disk_io_counters(perdisk=True)
|
||||
# make sure there are no duplicates
|
||||
assert len(ret) == len(set(ret))
|
||||
for key in ret:
|
||||
assert key, key
|
||||
check_ntuple(ret[key])
|
||||
|
||||
def test_disk_io_counters_no_disks(self):
|
||||
# Emulate a case where no disks are installed, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1062
|
||||
with mock.patch(
|
||||
'psutil._psplatform.disk_io_counters', return_value={}
|
||||
) as m:
|
||||
assert psutil.disk_io_counters(perdisk=False) is None
|
||||
assert psutil.disk_io_counters(perdisk=True) == {}
|
||||
assert m.called
|
||||
|
||||
|
||||
class TestNetAPIs(PsutilTestCase):
|
||||
@pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
|
||||
def test_net_io_counters(self):
|
||||
def check_ntuple(nt):
|
||||
assert nt[0] == nt.bytes_sent
|
||||
assert nt[1] == nt.bytes_recv
|
||||
assert nt[2] == nt.packets_sent
|
||||
assert nt[3] == nt.packets_recv
|
||||
assert nt[4] == nt.errin
|
||||
assert nt[5] == nt.errout
|
||||
assert nt[6] == nt.dropin
|
||||
assert nt[7] == nt.dropout
|
||||
assert nt.bytes_sent >= 0, nt
|
||||
assert nt.bytes_recv >= 0, nt
|
||||
assert nt.packets_sent >= 0, nt
|
||||
assert nt.packets_recv >= 0, nt
|
||||
assert nt.errin >= 0, nt
|
||||
assert nt.errout >= 0, nt
|
||||
assert nt.dropin >= 0, nt
|
||||
assert nt.dropout >= 0, nt
|
||||
|
||||
ret = psutil.net_io_counters(pernic=False)
|
||||
check_ntuple(ret)
|
||||
ret = psutil.net_io_counters(pernic=True)
|
||||
assert ret != []
|
||||
for key in ret:
|
||||
assert key
|
||||
assert isinstance(key, str)
|
||||
check_ntuple(ret[key])
|
||||
|
||||
@pytest.mark.skipif(not HAS_NET_IO_COUNTERS, reason="not supported")
|
||||
def test_net_io_counters_no_nics(self):
|
||||
# Emulate a case where no NICs are installed, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1062
|
||||
with mock.patch(
|
||||
'psutil._psplatform.net_io_counters', return_value={}
|
||||
) as m:
|
||||
assert psutil.net_io_counters(pernic=False) is None
|
||||
assert psutil.net_io_counters(pernic=True) == {}
|
||||
assert m.called
|
||||
|
||||
@pytest.mark.skipif(QEMU_USER, reason="QEMU user not supported")
|
||||
def test_net_if_addrs(self):
|
||||
nics = psutil.net_if_addrs()
|
||||
assert nics, nics
|
||||
|
||||
nic_stats = psutil.net_if_stats()
|
||||
|
||||
# Not reliable on all platforms (net_if_addrs() reports more
|
||||
# interfaces).
|
||||
# self.assertEqual(sorted(nics.keys()),
|
||||
# sorted(psutil.net_io_counters(pernic=True).keys()))
|
||||
|
||||
families = set([socket.AF_INET, socket.AF_INET6, psutil.AF_LINK])
|
||||
for nic, addrs in nics.items():
|
||||
assert isinstance(nic, str)
|
||||
assert len(set(addrs)) == len(addrs)
|
||||
for addr in addrs:
|
||||
assert isinstance(addr.family, int)
|
||||
assert isinstance(addr.address, str)
|
||||
assert isinstance(addr.netmask, (str, type(None)))
|
||||
assert isinstance(addr.broadcast, (str, type(None)))
|
||||
assert addr.family in families
|
||||
if PY3 and not PYPY:
|
||||
assert isinstance(addr.family, enum.IntEnum)
|
||||
if nic_stats[nic].isup:
|
||||
# Do not test binding to addresses of interfaces
|
||||
# that are down
|
||||
if addr.family == socket.AF_INET:
|
||||
s = socket.socket(addr.family)
|
||||
with contextlib.closing(s):
|
||||
s.bind((addr.address, 0))
|
||||
elif addr.family == socket.AF_INET6:
|
||||
info = socket.getaddrinfo(
|
||||
addr.address,
|
||||
0,
|
||||
socket.AF_INET6,
|
||||
socket.SOCK_STREAM,
|
||||
0,
|
||||
socket.AI_PASSIVE,
|
||||
)[0]
|
||||
af, socktype, proto, _canonname, sa = info
|
||||
s = socket.socket(af, socktype, proto)
|
||||
with contextlib.closing(s):
|
||||
s.bind(sa)
|
||||
for ip in (
|
||||
addr.address,
|
||||
addr.netmask,
|
||||
addr.broadcast,
|
||||
addr.ptp,
|
||||
):
|
||||
if ip is not None:
|
||||
# TODO: skip AF_INET6 for now because I get:
|
||||
# AddressValueError: Only hex digits permitted in
|
||||
# u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0'
|
||||
if addr.family != socket.AF_INET6:
|
||||
check_net_address(ip, addr.family)
|
||||
# broadcast and ptp addresses are mutually exclusive
|
||||
if addr.broadcast:
|
||||
assert addr.ptp is None
|
||||
elif addr.ptp:
|
||||
assert addr.broadcast is None
|
||||
|
||||
if BSD or MACOS or SUNOS:
|
||||
if hasattr(socket, "AF_LINK"):
|
||||
assert psutil.AF_LINK == socket.AF_LINK
|
||||
elif LINUX:
|
||||
assert psutil.AF_LINK == socket.AF_PACKET
|
||||
elif WINDOWS:
|
||||
assert psutil.AF_LINK == -1
|
||||
|
||||
def test_net_if_addrs_mac_null_bytes(self):
|
||||
# Simulate that the underlying C function returns an incomplete
|
||||
# MAC address. psutil is supposed to fill it with null bytes.
|
||||
# https://github.com/giampaolo/psutil/issues/786
|
||||
if POSIX:
|
||||
ret = [('em1', psutil.AF_LINK, '06:3d:29', None, None, None)]
|
||||
else:
|
||||
ret = [('em1', -1, '06-3d-29', None, None, None)]
|
||||
with mock.patch(
|
||||
'psutil._psplatform.net_if_addrs', return_value=ret
|
||||
) as m:
|
||||
addr = psutil.net_if_addrs()['em1'][0]
|
||||
assert m.called
|
||||
if POSIX:
|
||||
assert addr.address == '06:3d:29:00:00:00'
|
||||
else:
|
||||
assert addr.address == '06-3d-29-00-00-00'
|
||||
|
||||
@pytest.mark.skipif(QEMU_USER, reason="QEMU user not supported")
|
||||
def test_net_if_stats(self):
|
||||
nics = psutil.net_if_stats()
|
||||
assert nics, nics
|
||||
all_duplexes = (
|
||||
psutil.NIC_DUPLEX_FULL,
|
||||
psutil.NIC_DUPLEX_HALF,
|
||||
psutil.NIC_DUPLEX_UNKNOWN,
|
||||
)
|
||||
for name, stats in nics.items():
|
||||
assert isinstance(name, str)
|
||||
isup, duplex, speed, mtu, flags = stats
|
||||
assert isinstance(isup, bool)
|
||||
assert duplex in all_duplexes
|
||||
assert duplex in all_duplexes
|
||||
assert speed >= 0
|
||||
assert mtu >= 0
|
||||
assert isinstance(flags, str)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not (LINUX or BSD or MACOS), reason="LINUX or BSD or MACOS specific"
|
||||
)
|
||||
def test_net_if_stats_enodev(self):
|
||||
# See: https://github.com/giampaolo/psutil/issues/1279
|
||||
with mock.patch(
|
||||
'psutil._psutil_posix.net_if_mtu',
|
||||
side_effect=OSError(errno.ENODEV, ""),
|
||||
) as m:
|
||||
ret = psutil.net_if_stats()
|
||||
assert ret == {}
|
||||
assert m.called
|
||||
|
||||
|
||||
class TestSensorsAPIs(PsutilTestCase):
|
||||
@pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
temps = psutil.sensors_temperatures()
|
||||
for name, entries in temps.items():
|
||||
assert isinstance(name, str)
|
||||
for entry in entries:
|
||||
assert isinstance(entry.label, str)
|
||||
if entry.current is not None:
|
||||
assert entry.current >= 0
|
||||
if entry.high is not None:
|
||||
assert entry.high >= 0
|
||||
if entry.critical is not None:
|
||||
assert entry.critical >= 0
|
||||
|
||||
@pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
|
||||
def test_sensors_temperatures_fahreneit(self):
|
||||
d = {'coretemp': [('label', 50.0, 60.0, 70.0)]}
|
||||
with mock.patch(
|
||||
"psutil._psplatform.sensors_temperatures", return_value=d
|
||||
) as m:
|
||||
temps = psutil.sensors_temperatures(fahrenheit=True)['coretemp'][0]
|
||||
assert m.called
|
||||
assert temps.current == 122.0
|
||||
assert temps.high == 140.0
|
||||
assert temps.critical == 158.0
|
||||
|
||||
@pytest.mark.skipif(not HAS_SENSORS_BATTERY, reason="not supported")
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_sensors_battery(self):
|
||||
ret = psutil.sensors_battery()
|
||||
assert ret.percent >= 0
|
||||
assert ret.percent <= 100
|
||||
if ret.secsleft not in (
|
||||
psutil.POWER_TIME_UNKNOWN,
|
||||
psutil.POWER_TIME_UNLIMITED,
|
||||
):
|
||||
assert ret.secsleft >= 0
|
||||
else:
|
||||
if ret.secsleft == psutil.POWER_TIME_UNLIMITED:
|
||||
assert ret.power_plugged
|
||||
assert isinstance(ret.power_plugged, bool)
|
||||
|
||||
@pytest.mark.skipif(not HAS_SENSORS_FANS, reason="not supported")
|
||||
def test_sensors_fans(self):
|
||||
fans = psutil.sensors_fans()
|
||||
for name, entries in fans.items():
|
||||
assert isinstance(name, str)
|
||||
for entry in entries:
|
||||
assert isinstance(entry.label, str)
|
||||
assert isinstance(entry.current, (int, long))
|
||||
assert entry.current >= 0
|
587
env/lib/python3.12/site-packages/psutil/tests/test_testutils.py
vendored
Normal file
587
env/lib/python3.12/site-packages/psutil/tests/test_testutils.py
vendored
Normal file
@ -0,0 +1,587 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Tests for testing utils (psutil.tests namespace)."""
|
||||
|
||||
import collections
|
||||
import contextlib
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import subprocess
|
||||
import textwrap
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
import psutil
|
||||
import psutil.tests
|
||||
from psutil import FREEBSD
|
||||
from psutil import NETBSD
|
||||
from psutil import POSIX
|
||||
from psutil._common import open_binary
|
||||
from psutil._common import open_text
|
||||
from psutil._common import supports_ipv6
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import COVERAGE
|
||||
from psutil.tests import HAS_NET_CONNECTIONS_UNIX
|
||||
from psutil.tests import HERE
|
||||
from psutil.tests import PYTHON_EXE
|
||||
from psutil.tests import PYTHON_EXE_ENV
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import TestMemoryLeak
|
||||
from psutil.tests import bind_socket
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import call_until
|
||||
from psutil.tests import chdir
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import fake_pytest
|
||||
from psutil.tests import filter_proc_net_connections
|
||||
from psutil.tests import get_free_port
|
||||
from psutil.tests import is_namedtuple
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import process_namespace
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import safe_mkdir
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import system_namespace
|
||||
from psutil.tests import tcp_socketpair
|
||||
from psutil.tests import terminate
|
||||
from psutil.tests import unix_socketpair
|
||||
from psutil.tests import wait_for_file
|
||||
from psutil.tests import wait_for_pid
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- Unit tests for test utilities.
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestRetryDecorator(PsutilTestCase):
|
||||
@mock.patch('time.sleep')
|
||||
def test_retry_success(self, sleep):
|
||||
# Fail 3 times out of 5; make sure the decorated fun returns.
|
||||
|
||||
@retry(retries=5, interval=1, logfun=None)
|
||||
def foo():
|
||||
while queue:
|
||||
queue.pop()
|
||||
1 / 0 # noqa
|
||||
return 1
|
||||
|
||||
queue = list(range(3))
|
||||
assert foo() == 1
|
||||
assert sleep.call_count == 3
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_retry_failure(self, sleep):
|
||||
# Fail 6 times out of 5; th function is supposed to raise exc.
|
||||
@retry(retries=5, interval=1, logfun=None)
|
||||
def foo():
|
||||
while queue:
|
||||
queue.pop()
|
||||
1 / 0 # noqa
|
||||
return 1
|
||||
|
||||
queue = list(range(6))
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
foo()
|
||||
assert sleep.call_count == 5
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_exception_arg(self, sleep):
|
||||
@retry(exception=ValueError, interval=1)
|
||||
def foo():
|
||||
raise TypeError
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
foo()
|
||||
assert sleep.call_count == 0
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_no_interval_arg(self, sleep):
|
||||
# if interval is not specified sleep is not supposed to be called
|
||||
|
||||
@retry(retries=5, interval=None, logfun=None)
|
||||
def foo():
|
||||
1 / 0 # noqa
|
||||
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
foo()
|
||||
assert sleep.call_count == 0
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_retries_arg(self, sleep):
|
||||
@retry(retries=5, interval=1, logfun=None)
|
||||
def foo():
|
||||
1 / 0 # noqa
|
||||
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
foo()
|
||||
assert sleep.call_count == 5
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
def test_retries_and_timeout_args(self, sleep):
|
||||
with pytest.raises(ValueError):
|
||||
retry(retries=5, timeout=1)
|
||||
|
||||
|
||||
class TestSyncTestUtils(PsutilTestCase):
|
||||
def test_wait_for_pid(self):
|
||||
wait_for_pid(os.getpid())
|
||||
nopid = max(psutil.pids()) + 99999
|
||||
with mock.patch('psutil.tests.retry.__iter__', return_value=iter([0])):
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
wait_for_pid(nopid)
|
||||
|
||||
def test_wait_for_file(self):
|
||||
testfn = self.get_testfn()
|
||||
with open(testfn, 'w') as f:
|
||||
f.write('foo')
|
||||
wait_for_file(testfn)
|
||||
assert not os.path.exists(testfn)
|
||||
|
||||
def test_wait_for_file_empty(self):
|
||||
testfn = self.get_testfn()
|
||||
with open(testfn, 'w'):
|
||||
pass
|
||||
wait_for_file(testfn, empty=True)
|
||||
assert not os.path.exists(testfn)
|
||||
|
||||
def test_wait_for_file_no_file(self):
|
||||
testfn = self.get_testfn()
|
||||
with mock.patch('psutil.tests.retry.__iter__', return_value=iter([0])):
|
||||
with pytest.raises(IOError):
|
||||
wait_for_file(testfn)
|
||||
|
||||
def test_wait_for_file_no_delete(self):
|
||||
testfn = self.get_testfn()
|
||||
with open(testfn, 'w') as f:
|
||||
f.write('foo')
|
||||
wait_for_file(testfn, delete=False)
|
||||
assert os.path.exists(testfn)
|
||||
|
||||
def test_call_until(self):
|
||||
call_until(lambda: 1)
|
||||
# TODO: test for timeout
|
||||
|
||||
|
||||
class TestFSTestUtils(PsutilTestCase):
|
||||
def test_open_text(self):
|
||||
with open_text(__file__) as f:
|
||||
assert f.mode == 'r'
|
||||
|
||||
def test_open_binary(self):
|
||||
with open_binary(__file__) as f:
|
||||
assert f.mode == 'rb'
|
||||
|
||||
def test_safe_mkdir(self):
|
||||
testfn = self.get_testfn()
|
||||
safe_mkdir(testfn)
|
||||
assert os.path.isdir(testfn)
|
||||
safe_mkdir(testfn)
|
||||
assert os.path.isdir(testfn)
|
||||
|
||||
def test_safe_rmpath(self):
|
||||
# test file is removed
|
||||
testfn = self.get_testfn()
|
||||
open(testfn, 'w').close()
|
||||
safe_rmpath(testfn)
|
||||
assert not os.path.exists(testfn)
|
||||
# test no exception if path does not exist
|
||||
safe_rmpath(testfn)
|
||||
# test dir is removed
|
||||
os.mkdir(testfn)
|
||||
safe_rmpath(testfn)
|
||||
assert not os.path.exists(testfn)
|
||||
# test other exceptions are raised
|
||||
with mock.patch(
|
||||
'psutil.tests.os.stat', side_effect=OSError(errno.EINVAL, "")
|
||||
) as m:
|
||||
with pytest.raises(OSError):
|
||||
safe_rmpath(testfn)
|
||||
assert m.called
|
||||
|
||||
def test_chdir(self):
|
||||
testfn = self.get_testfn()
|
||||
base = os.getcwd()
|
||||
os.mkdir(testfn)
|
||||
with chdir(testfn):
|
||||
assert os.getcwd() == os.path.join(base, testfn)
|
||||
assert os.getcwd() == base
|
||||
|
||||
|
||||
class TestProcessUtils(PsutilTestCase):
|
||||
def test_reap_children(self):
|
||||
subp = self.spawn_testproc()
|
||||
p = psutil.Process(subp.pid)
|
||||
assert p.is_running()
|
||||
reap_children()
|
||||
assert not p.is_running()
|
||||
assert not psutil.tests._pids_started
|
||||
assert not psutil.tests._subprocesses_started
|
||||
|
||||
def test_spawn_children_pair(self):
|
||||
child, grandchild = self.spawn_children_pair()
|
||||
assert child.pid != grandchild.pid
|
||||
assert child.is_running()
|
||||
assert grandchild.is_running()
|
||||
children = psutil.Process().children()
|
||||
assert children == [child]
|
||||
children = psutil.Process().children(recursive=True)
|
||||
assert len(children) == 2
|
||||
assert child in children
|
||||
assert grandchild in children
|
||||
assert child.ppid() == os.getpid()
|
||||
assert grandchild.ppid() == child.pid
|
||||
|
||||
terminate(child)
|
||||
assert not child.is_running()
|
||||
assert grandchild.is_running()
|
||||
|
||||
terminate(grandchild)
|
||||
assert not grandchild.is_running()
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_spawn_zombie(self):
|
||||
_parent, zombie = self.spawn_zombie()
|
||||
assert zombie.status() == psutil.STATUS_ZOMBIE
|
||||
|
||||
def test_terminate(self):
|
||||
# by subprocess.Popen
|
||||
p = self.spawn_testproc()
|
||||
terminate(p)
|
||||
self.assertPidGone(p.pid)
|
||||
terminate(p)
|
||||
# by psutil.Process
|
||||
p = psutil.Process(self.spawn_testproc().pid)
|
||||
terminate(p)
|
||||
self.assertPidGone(p.pid)
|
||||
terminate(p)
|
||||
# by psutil.Popen
|
||||
cmd = [
|
||||
PYTHON_EXE,
|
||||
"-c",
|
||||
"import time; [time.sleep(0.1) for x in range(100)];",
|
||||
]
|
||||
p = psutil.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=PYTHON_EXE_ENV,
|
||||
)
|
||||
terminate(p)
|
||||
self.assertPidGone(p.pid)
|
||||
terminate(p)
|
||||
# by PID
|
||||
pid = self.spawn_testproc().pid
|
||||
terminate(pid)
|
||||
self.assertPidGone(p.pid)
|
||||
terminate(pid)
|
||||
# zombie
|
||||
if POSIX:
|
||||
parent, zombie = self.spawn_zombie()
|
||||
terminate(parent)
|
||||
terminate(zombie)
|
||||
self.assertPidGone(parent.pid)
|
||||
self.assertPidGone(zombie.pid)
|
||||
|
||||
|
||||
class TestNetUtils(PsutilTestCase):
|
||||
def bind_socket(self):
|
||||
port = get_free_port()
|
||||
with contextlib.closing(bind_socket(addr=('', port))) as s:
|
||||
assert s.getsockname()[1] == port
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_bind_unix_socket(self):
|
||||
name = self.get_testfn()
|
||||
sock = bind_unix_socket(name)
|
||||
with contextlib.closing(sock):
|
||||
assert sock.family == socket.AF_UNIX
|
||||
assert sock.type == socket.SOCK_STREAM
|
||||
assert sock.getsockname() == name
|
||||
assert os.path.exists(name)
|
||||
assert stat.S_ISSOCK(os.stat(name).st_mode)
|
||||
# UDP
|
||||
name = self.get_testfn()
|
||||
sock = bind_unix_socket(name, type=socket.SOCK_DGRAM)
|
||||
with contextlib.closing(sock):
|
||||
assert sock.type == socket.SOCK_DGRAM
|
||||
|
||||
def tcp_tcp_socketpair(self):
|
||||
addr = ("127.0.0.1", get_free_port())
|
||||
server, client = tcp_socketpair(socket.AF_INET, addr=addr)
|
||||
with contextlib.closing(server):
|
||||
with contextlib.closing(client):
|
||||
# Ensure they are connected and the positions are
|
||||
# correct.
|
||||
assert server.getsockname() == addr
|
||||
assert client.getpeername() == addr
|
||||
assert client.getsockname() != addr
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@pytest.mark.skipif(
|
||||
NETBSD or FREEBSD, reason="/var/run/log UNIX socket opened by default"
|
||||
)
|
||||
def test_unix_socketpair(self):
|
||||
p = psutil.Process()
|
||||
num_fds = p.num_fds()
|
||||
assert (
|
||||
filter_proc_net_connections(p.net_connections(kind='unix')) == []
|
||||
)
|
||||
name = self.get_testfn()
|
||||
server, client = unix_socketpair(name)
|
||||
try:
|
||||
assert os.path.exists(name)
|
||||
assert stat.S_ISSOCK(os.stat(name).st_mode)
|
||||
assert p.num_fds() - num_fds == 2
|
||||
assert (
|
||||
len(
|
||||
filter_proc_net_connections(p.net_connections(kind='unix'))
|
||||
)
|
||||
== 2
|
||||
)
|
||||
assert server.getsockname() == name
|
||||
assert client.getpeername() == name
|
||||
finally:
|
||||
client.close()
|
||||
server.close()
|
||||
|
||||
def test_create_sockets(self):
|
||||
with create_sockets() as socks:
|
||||
fams = collections.defaultdict(int)
|
||||
types = collections.defaultdict(int)
|
||||
for s in socks:
|
||||
fams[s.family] += 1
|
||||
# work around http://bugs.python.org/issue30204
|
||||
types[s.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE)] += 1
|
||||
assert fams[socket.AF_INET] >= 2
|
||||
if supports_ipv6():
|
||||
assert fams[socket.AF_INET6] >= 2
|
||||
if POSIX and HAS_NET_CONNECTIONS_UNIX:
|
||||
assert fams[socket.AF_UNIX] >= 2
|
||||
assert types[socket.SOCK_STREAM] >= 2
|
||||
assert types[socket.SOCK_DGRAM] >= 2
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="serial")
|
||||
class TestMemLeakClass(TestMemoryLeak):
|
||||
@retry_on_failure()
|
||||
def test_times(self):
|
||||
def fun():
|
||||
cnt['cnt'] += 1
|
||||
|
||||
cnt = {'cnt': 0}
|
||||
self.execute(fun, times=10, warmup_times=15)
|
||||
assert cnt['cnt'] == 26
|
||||
|
||||
def test_param_err(self):
|
||||
with pytest.raises(ValueError):
|
||||
self.execute(lambda: 0, times=0)
|
||||
with pytest.raises(ValueError):
|
||||
self.execute(lambda: 0, times=-1)
|
||||
with pytest.raises(ValueError):
|
||||
self.execute(lambda: 0, warmup_times=-1)
|
||||
with pytest.raises(ValueError):
|
||||
self.execute(lambda: 0, tolerance=-1)
|
||||
with pytest.raises(ValueError):
|
||||
self.execute(lambda: 0, retries=-1)
|
||||
|
||||
@retry_on_failure()
|
||||
@pytest.mark.skipif(CI_TESTING, reason="skipped on CI")
|
||||
@pytest.mark.skipif(COVERAGE, reason="skipped during test coverage")
|
||||
def test_leak_mem(self):
|
||||
ls = []
|
||||
|
||||
def fun(ls=ls):
|
||||
ls.append("x" * 248 * 1024)
|
||||
|
||||
try:
|
||||
# will consume around 60M in total
|
||||
with pytest.raises(AssertionError, match="extra-mem"):
|
||||
self.execute(fun, times=100)
|
||||
finally:
|
||||
del ls
|
||||
|
||||
def test_unclosed_files(self):
|
||||
def fun():
|
||||
f = open(__file__)
|
||||
self.addCleanup(f.close)
|
||||
box.append(f)
|
||||
|
||||
box = []
|
||||
kind = "fd" if POSIX else "handle"
|
||||
with pytest.raises(AssertionError, match="unclosed " + kind):
|
||||
self.execute(fun)
|
||||
|
||||
def test_tolerance(self):
|
||||
def fun():
|
||||
ls.append("x" * 24 * 1024)
|
||||
|
||||
ls = []
|
||||
times = 100
|
||||
self.execute(
|
||||
fun, times=times, warmup_times=0, tolerance=200 * 1024 * 1024
|
||||
)
|
||||
assert len(ls) == times + 1
|
||||
|
||||
def test_execute_w_exc(self):
|
||||
def fun_1():
|
||||
1 / 0 # noqa
|
||||
|
||||
self.execute_w_exc(ZeroDivisionError, fun_1)
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
self.execute_w_exc(OSError, fun_1)
|
||||
|
||||
def fun_2():
|
||||
pass
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
self.execute_w_exc(ZeroDivisionError, fun_2)
|
||||
|
||||
|
||||
class TestFakePytest(PsutilTestCase):
|
||||
def run_test_class(self, klass):
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(klass)
|
||||
runner = unittest.TextTestRunner()
|
||||
result = runner.run(suite)
|
||||
return result
|
||||
|
||||
def test_raises(self):
|
||||
with fake_pytest.raises(ZeroDivisionError) as cm:
|
||||
1 / 0 # noqa
|
||||
assert isinstance(cm.value, ZeroDivisionError)
|
||||
|
||||
with fake_pytest.raises(ValueError, match="foo") as cm:
|
||||
raise ValueError("foo")
|
||||
|
||||
try:
|
||||
with fake_pytest.raises(ValueError, match="foo") as cm:
|
||||
raise ValueError("bar")
|
||||
except AssertionError as err:
|
||||
assert str(err) == '"foo" does not match "bar"'
|
||||
else:
|
||||
raise self.fail("exception not raised")
|
||||
|
||||
def test_mark(self):
|
||||
@fake_pytest.mark.xdist_group(name="serial")
|
||||
def foo():
|
||||
return 1
|
||||
|
||||
assert foo() == 1
|
||||
|
||||
@fake_pytest.mark.xdist_group(name="serial")
|
||||
class Foo:
|
||||
def bar(self):
|
||||
return 1
|
||||
|
||||
assert Foo().bar() == 1
|
||||
|
||||
def test_skipif(self):
|
||||
class TestCase(unittest.TestCase):
|
||||
@fake_pytest.mark.skipif(True, reason="reason")
|
||||
def foo(self):
|
||||
assert 1 == 1 # noqa
|
||||
|
||||
result = self.run_test_class(TestCase("foo"))
|
||||
assert result.wasSuccessful()
|
||||
assert len(result.skipped) == 1
|
||||
assert result.skipped[0][1] == "reason"
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
@fake_pytest.mark.skipif(False, reason="reason")
|
||||
def foo(self):
|
||||
assert 1 == 1 # noqa
|
||||
|
||||
result = self.run_test_class(TestCase("foo"))
|
||||
assert result.wasSuccessful()
|
||||
assert len(result.skipped) == 0
|
||||
|
||||
@pytest.mark.skipif(not PY3, reason="not PY3")
|
||||
def test_skip(self):
|
||||
class TestCase(unittest.TestCase):
|
||||
def foo(self):
|
||||
fake_pytest.skip("reason")
|
||||
assert 1 == 0 # noqa
|
||||
|
||||
result = self.run_test_class(TestCase("foo"))
|
||||
assert result.wasSuccessful()
|
||||
assert len(result.skipped) == 1
|
||||
assert result.skipped[0][1] == "reason"
|
||||
|
||||
def test_main(self):
|
||||
tmpdir = self.get_testfn(dir=HERE)
|
||||
os.mkdir(tmpdir)
|
||||
with open(os.path.join(tmpdir, "__init__.py"), "w"):
|
||||
pass
|
||||
with open(os.path.join(tmpdir, "test_file.py"), "w") as f:
|
||||
f.write(textwrap.dedent("""\
|
||||
import unittest
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
def test_passed(self):
|
||||
pass
|
||||
""").lstrip())
|
||||
with mock.patch.object(psutil.tests, "HERE", tmpdir):
|
||||
with self.assertWarnsRegex(
|
||||
UserWarning, "Fake pytest module was used"
|
||||
):
|
||||
suite = fake_pytest.main()
|
||||
assert suite.countTestCases() == 1
|
||||
|
||||
def test_warns(self):
|
||||
# success
|
||||
with fake_pytest.warns(UserWarning):
|
||||
warnings.warn("foo", UserWarning, stacklevel=1)
|
||||
|
||||
# failure
|
||||
try:
|
||||
with fake_pytest.warns(UserWarning):
|
||||
warnings.warn("foo", DeprecationWarning, stacklevel=1)
|
||||
except AssertionError:
|
||||
pass
|
||||
else:
|
||||
raise self.fail("exception not raised")
|
||||
|
||||
# match success
|
||||
with fake_pytest.warns(UserWarning, match="foo"):
|
||||
warnings.warn("foo", UserWarning, stacklevel=1)
|
||||
|
||||
# match failure
|
||||
try:
|
||||
with fake_pytest.warns(UserWarning, match="foo"):
|
||||
warnings.warn("bar", UserWarning, stacklevel=1)
|
||||
except AssertionError:
|
||||
pass
|
||||
else:
|
||||
raise self.fail("exception not raised")
|
||||
|
||||
|
||||
class TestTestingUtils(PsutilTestCase):
|
||||
def test_process_namespace(self):
|
||||
p = psutil.Process()
|
||||
ns = process_namespace(p)
|
||||
ns.test()
|
||||
fun = [x for x in ns.iter(ns.getters) if x[1] == 'ppid'][0][0]
|
||||
assert fun() == p.ppid()
|
||||
|
||||
def test_system_namespace(self):
|
||||
ns = system_namespace()
|
||||
fun = [x for x in ns.iter(ns.getters) if x[1] == 'net_if_addrs'][0][0]
|
||||
assert fun() == psutil.net_if_addrs()
|
||||
|
||||
|
||||
class TestOtherUtils(PsutilTestCase):
|
||||
def test_is_namedtuple(self):
|
||||
assert is_namedtuple(collections.namedtuple('foo', 'a b c')(1, 2, 3))
|
||||
assert not is_namedtuple(tuple())
|
369
env/lib/python3.12/site-packages/psutil/tests/test_unicode.py
vendored
Normal file
369
env/lib/python3.12/site-packages/psutil/tests/test_unicode.py
vendored
Normal file
@ -0,0 +1,369 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Notes about unicode handling in psutil
|
||||
======================================.
|
||||
|
||||
Starting from version 5.3.0 psutil adds unicode support, see:
|
||||
https://github.com/giampaolo/psutil/issues/1040
|
||||
The notes below apply to *any* API returning a string such as
|
||||
process exe(), cwd() or username():
|
||||
|
||||
* all strings are encoded by using the OS filesystem encoding
|
||||
(sys.getfilesystemencoding()) which varies depending on the platform
|
||||
(e.g. "UTF-8" on macOS, "mbcs" on Win)
|
||||
* no API call is supposed to crash with UnicodeDecodeError
|
||||
* instead, in case of badly encoded data returned by the OS, the
|
||||
following error handlers are used to replace the corrupted characters in
|
||||
the string:
|
||||
* Python 3: sys.getfilesystemencodeerrors() (PY 3.6+) or
|
||||
"surrogatescape" on POSIX and "replace" on Windows
|
||||
* Python 2: "replace"
|
||||
* on Python 2 all APIs return bytes (str type), never unicode
|
||||
* on Python 2, you can go back to unicode by doing:
|
||||
|
||||
>>> unicode(p.exe(), sys.getdefaultencoding(), errors="replace")
|
||||
|
||||
For a detailed explanation of how psutil handles unicode see #1040.
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
List of APIs returning or dealing with a string:
|
||||
('not tested' means they are not tested to deal with non-ASCII strings):
|
||||
|
||||
* Process.cmdline()
|
||||
* Process.cwd()
|
||||
* Process.environ()
|
||||
* Process.exe()
|
||||
* Process.memory_maps()
|
||||
* Process.name()
|
||||
* Process.net_connections('unix')
|
||||
* Process.open_files()
|
||||
* Process.username() (not tested)
|
||||
|
||||
* disk_io_counters() (not tested)
|
||||
* disk_partitions() (not tested)
|
||||
* disk_usage(str)
|
||||
* net_connections('unix')
|
||||
* net_if_addrs() (not tested)
|
||||
* net_if_stats() (not tested)
|
||||
* net_io_counters() (not tested)
|
||||
* sensors_fans() (not tested)
|
||||
* sensors_temperatures() (not tested)
|
||||
* users() (not tested)
|
||||
|
||||
* WindowsService.binpath() (not tested)
|
||||
* WindowsService.description() (not tested)
|
||||
* WindowsService.display_name() (not tested)
|
||||
* WindowsService.name() (not tested)
|
||||
* WindowsService.status() (not tested)
|
||||
* WindowsService.username() (not tested)
|
||||
|
||||
In here we create a unicode path with a funky non-ASCII name and (where
|
||||
possible) make psutil return it back (e.g. on name(), exe(), open_files(),
|
||||
etc.) and make sure that:
|
||||
|
||||
* psutil never crashes with UnicodeDecodeError
|
||||
* the returned path matches
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import traceback
|
||||
import warnings
|
||||
from contextlib import closing
|
||||
|
||||
import psutil
|
||||
from psutil import BSD
|
||||
from psutil import POSIX
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import PY3
|
||||
from psutil._compat import super
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import ASCII_FS
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import HAS_ENVIRON
|
||||
from psutil.tests import HAS_MEMORY_MAPS
|
||||
from psutil.tests import HAS_NET_CONNECTIONS_UNIX
|
||||
from psutil.tests import INVALID_UNICODE_SUFFIX
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import TESTFN_PREFIX
|
||||
from psutil.tests import UNICODE_SUFFIX
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import chdir
|
||||
from psutil.tests import copyload_shared_lib
|
||||
from psutil.tests import create_py_exe
|
||||
from psutil.tests import get_testfn
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import safe_mkdir
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import terminate
|
||||
|
||||
|
||||
if APPVEYOR:
|
||||
|
||||
def safe_rmpath(path): # NOQA
|
||||
# TODO - this is quite random and I'm not sure why it happens,
|
||||
# nor I can reproduce it locally:
|
||||
# https://ci.appveyor.com/project/giampaolo/psutil/build/job/
|
||||
# jiq2cgd6stsbtn60
|
||||
# safe_rmpath() happens after reap_children() so this is weird
|
||||
# Perhaps wait_procs() on Windows is broken? Maybe because
|
||||
# of STILL_ACTIVE?
|
||||
# https://github.com/giampaolo/psutil/blob/
|
||||
# 68c7a70728a31d8b8b58f4be6c4c0baa2f449eda/psutil/arch/
|
||||
# windows/process_info.c#L146
|
||||
from psutil.tests import safe_rmpath as rm
|
||||
|
||||
try:
|
||||
return rm(path)
|
||||
except WindowsError:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def try_unicode(suffix):
|
||||
"""Return True if both the fs and the subprocess module can
|
||||
deal with a unicode file name.
|
||||
"""
|
||||
sproc = None
|
||||
testfn = get_testfn(suffix=suffix)
|
||||
try:
|
||||
safe_rmpath(testfn)
|
||||
create_py_exe(testfn)
|
||||
sproc = spawn_testproc(cmd=[testfn])
|
||||
shutil.copyfile(testfn, testfn + '-2')
|
||||
safe_rmpath(testfn + '-2')
|
||||
except (UnicodeEncodeError, IOError):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
finally:
|
||||
if sproc is not None:
|
||||
terminate(sproc)
|
||||
safe_rmpath(testfn)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# FS APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class BaseUnicodeTest(PsutilTestCase):
|
||||
funky_suffix = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.skip_tests = False
|
||||
cls.funky_name = None
|
||||
if cls.funky_suffix is not None:
|
||||
if not try_unicode(cls.funky_suffix):
|
||||
cls.skip_tests = True
|
||||
else:
|
||||
cls.funky_name = get_testfn(suffix=cls.funky_suffix)
|
||||
create_py_exe(cls.funky_name)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
if self.skip_tests:
|
||||
raise pytest.skip("can't handle unicode str")
|
||||
|
||||
|
||||
@pytest.mark.xdist_group(name="serial")
|
||||
@pytest.mark.skipif(ASCII_FS, reason="ASCII fs")
|
||||
@pytest.mark.skipif(PYPY and not PY3, reason="too much trouble on PYPY2")
|
||||
class TestFSAPIs(BaseUnicodeTest):
|
||||
"""Test FS APIs with a funky, valid, UTF8 path name."""
|
||||
|
||||
funky_suffix = UNICODE_SUFFIX
|
||||
|
||||
def expect_exact_path_match(self):
|
||||
# Do not expect psutil to correctly handle unicode paths on
|
||||
# Python 2 if os.listdir() is not able either.
|
||||
here = '.' if isinstance(self.funky_name, str) else u'.'
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
return self.funky_name in os.listdir(here)
|
||||
|
||||
# ---
|
||||
|
||||
def test_proc_exe(self):
|
||||
cmd = [
|
||||
self.funky_name,
|
||||
"-c",
|
||||
"import time; [time.sleep(0.1) for x in range(100)]",
|
||||
]
|
||||
subp = self.spawn_testproc(cmd)
|
||||
p = psutil.Process(subp.pid)
|
||||
exe = p.exe()
|
||||
assert isinstance(exe, str)
|
||||
if self.expect_exact_path_match():
|
||||
assert os.path.normcase(exe) == os.path.normcase(self.funky_name)
|
||||
|
||||
def test_proc_name(self):
|
||||
cmd = [
|
||||
self.funky_name,
|
||||
"-c",
|
||||
"import time; [time.sleep(0.1) for x in range(100)]",
|
||||
]
|
||||
subp = self.spawn_testproc(cmd)
|
||||
name = psutil.Process(subp.pid).name()
|
||||
assert isinstance(name, str)
|
||||
if self.expect_exact_path_match():
|
||||
assert name == os.path.basename(self.funky_name)
|
||||
|
||||
def test_proc_cmdline(self):
|
||||
cmd = [
|
||||
self.funky_name,
|
||||
"-c",
|
||||
"import time; [time.sleep(0.1) for x in range(100)]",
|
||||
]
|
||||
subp = self.spawn_testproc(cmd)
|
||||
p = psutil.Process(subp.pid)
|
||||
cmdline = p.cmdline()
|
||||
for part in cmdline:
|
||||
assert isinstance(part, str)
|
||||
if self.expect_exact_path_match():
|
||||
assert cmdline == cmd
|
||||
|
||||
def test_proc_cwd(self):
|
||||
dname = self.funky_name + "2"
|
||||
self.addCleanup(safe_rmpath, dname)
|
||||
safe_mkdir(dname)
|
||||
with chdir(dname):
|
||||
p = psutil.Process()
|
||||
cwd = p.cwd()
|
||||
assert isinstance(p.cwd(), str)
|
||||
if self.expect_exact_path_match():
|
||||
assert cwd == dname
|
||||
|
||||
@pytest.mark.skipif(PYPY and WINDOWS, reason="fails on PYPY + WINDOWS")
|
||||
def test_proc_open_files(self):
|
||||
p = psutil.Process()
|
||||
start = set(p.open_files())
|
||||
with open(self.funky_name, 'rb'):
|
||||
new = set(p.open_files())
|
||||
path = (new - start).pop().path
|
||||
assert isinstance(path, str)
|
||||
if BSD and not path:
|
||||
# XXX - see https://github.com/giampaolo/psutil/issues/595
|
||||
raise pytest.skip("open_files on BSD is broken")
|
||||
if self.expect_exact_path_match():
|
||||
assert os.path.normcase(path) == os.path.normcase(self.funky_name)
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
def test_proc_net_connections(self):
|
||||
name = self.get_testfn(suffix=self.funky_suffix)
|
||||
try:
|
||||
sock = bind_unix_socket(name)
|
||||
except UnicodeEncodeError:
|
||||
if PY3:
|
||||
raise
|
||||
else:
|
||||
raise pytest.skip("not supported")
|
||||
with closing(sock):
|
||||
conn = psutil.Process().net_connections('unix')[0]
|
||||
assert isinstance(conn.laddr, str)
|
||||
assert conn.laddr == name
|
||||
|
||||
@pytest.mark.skipif(not POSIX, reason="POSIX only")
|
||||
@pytest.mark.skipif(
|
||||
not HAS_NET_CONNECTIONS_UNIX, reason="can't list UNIX sockets"
|
||||
)
|
||||
@skip_on_access_denied()
|
||||
def test_net_connections(self):
|
||||
def find_sock(cons):
|
||||
for conn in cons:
|
||||
if os.path.basename(conn.laddr).startswith(TESTFN_PREFIX):
|
||||
return conn
|
||||
raise ValueError("connection not found")
|
||||
|
||||
name = self.get_testfn(suffix=self.funky_suffix)
|
||||
try:
|
||||
sock = bind_unix_socket(name)
|
||||
except UnicodeEncodeError:
|
||||
if PY3:
|
||||
raise
|
||||
else:
|
||||
raise pytest.skip("not supported")
|
||||
with closing(sock):
|
||||
cons = psutil.net_connections(kind='unix')
|
||||
conn = find_sock(cons)
|
||||
assert isinstance(conn.laddr, str)
|
||||
assert conn.laddr == name
|
||||
|
||||
def test_disk_usage(self):
|
||||
dname = self.funky_name + "2"
|
||||
self.addCleanup(safe_rmpath, dname)
|
||||
safe_mkdir(dname)
|
||||
psutil.disk_usage(dname)
|
||||
|
||||
@pytest.mark.skipif(not HAS_MEMORY_MAPS, reason="not supported")
|
||||
@pytest.mark.skipif(
|
||||
not PY3, reason="ctypes does not support unicode on PY2"
|
||||
)
|
||||
@pytest.mark.skipif(PYPY, reason="unstable on PYPY")
|
||||
def test_memory_maps(self):
|
||||
# XXX: on Python 2, using ctypes.CDLL with a unicode path
|
||||
# opens a message box which blocks the test run.
|
||||
with copyload_shared_lib(suffix=self.funky_suffix) as funky_path:
|
||||
|
||||
def normpath(p):
|
||||
return os.path.realpath(os.path.normcase(p))
|
||||
|
||||
libpaths = [
|
||||
normpath(x.path) for x in psutil.Process().memory_maps()
|
||||
]
|
||||
# ...just to have a clearer msg in case of failure
|
||||
libpaths = [x for x in libpaths if TESTFN_PREFIX in x]
|
||||
assert normpath(funky_path) in libpaths
|
||||
for path in libpaths:
|
||||
assert isinstance(path, str)
|
||||
|
||||
|
||||
@pytest.mark.skipif(CI_TESTING, reason="unreliable on CI")
|
||||
class TestFSAPIsWithInvalidPath(TestFSAPIs):
|
||||
"""Test FS APIs with a funky, invalid path name."""
|
||||
|
||||
funky_suffix = INVALID_UNICODE_SUFFIX
|
||||
|
||||
def expect_exact_path_match(self):
|
||||
# Invalid unicode names are supposed to work on Python 2.
|
||||
return True
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Non fs APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestNonFSAPIS(BaseUnicodeTest):
|
||||
"""Unicode tests for non fs-related APIs."""
|
||||
|
||||
funky_suffix = UNICODE_SUFFIX if PY3 else 'è'
|
||||
|
||||
@pytest.mark.skipif(not HAS_ENVIRON, reason="not supported")
|
||||
@pytest.mark.skipif(PYPY and WINDOWS, reason="segfaults on PYPY + WINDOWS")
|
||||
def test_proc_environ(self):
|
||||
# Note: differently from others, this test does not deal
|
||||
# with fs paths. On Python 2 subprocess module is broken as
|
||||
# it's not able to handle with non-ASCII env vars, so
|
||||
# we use "è", which is part of the extended ASCII table
|
||||
# (unicode point <= 255).
|
||||
env = os.environ.copy()
|
||||
env['FUNNY_ARG'] = self.funky_suffix
|
||||
sproc = self.spawn_testproc(env=env)
|
||||
p = psutil.Process(sproc.pid)
|
||||
env = p.environ()
|
||||
for k, v in env.items():
|
||||
assert isinstance(k, str)
|
||||
assert isinstance(v, str)
|
||||
assert env['FUNNY_ARG'] == self.funky_suffix
|
934
env/lib/python3.12/site-packages/psutil/tests/test_windows.py
vendored
Normal file
934
env/lib/python3.12/site-packages/psutil/tests/test_windows.py
vendored
Normal file
@ -0,0 +1,934 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Windows specific tests."""
|
||||
|
||||
import datetime
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
|
||||
import psutil
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil._compat import super
|
||||
from psutil._compat import which
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import GITHUB_ACTIONS
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import IS_64BIT
|
||||
from psutil.tests import PY3
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import TOLERANCE_DISK_USAGE
|
||||
from psutil.tests import TOLERANCE_SYS_MEM
|
||||
from psutil.tests import PsutilTestCase
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import pytest
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import spawn_testproc
|
||||
from psutil.tests import terminate
|
||||
|
||||
|
||||
if WINDOWS and not PYPY:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
import win32api # requires "pip install pywin32"
|
||||
import win32con
|
||||
import win32process
|
||||
import wmi # requires "pip install wmi" / "make install-pydeps-test"
|
||||
|
||||
if WINDOWS:
|
||||
from psutil._pswindows import convert_oserror
|
||||
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
@pytest.mark.skipif(PYPY, reason="pywin32 not available on PYPY")
|
||||
# https://github.com/giampaolo/psutil/pull/1762#issuecomment-632892692
|
||||
@pytest.mark.skipif(
|
||||
GITHUB_ACTIONS and not PY3, reason="pywin32 broken on GITHUB + PY2"
|
||||
)
|
||||
class WindowsTestCase(PsutilTestCase):
|
||||
pass
|
||||
|
||||
|
||||
def powershell(cmd):
|
||||
"""Currently not used, but available just in case. Usage:
|
||||
|
||||
>>> powershell(
|
||||
"Get-CIMInstance Win32_PageFileUsage | Select AllocatedBaseSize")
|
||||
"""
|
||||
if not which("powershell.exe"):
|
||||
raise pytest.skip("powershell.exe not available")
|
||||
cmdline = (
|
||||
'powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive '
|
||||
+ '-NoProfile -WindowStyle Hidden -Command "%s"' % cmd
|
||||
)
|
||||
return sh(cmdline)
|
||||
|
||||
|
||||
def wmic(path, what, converter=int):
|
||||
"""Currently not used, but available just in case. Usage:
|
||||
|
||||
>>> wmic("Win32_OperatingSystem", "FreePhysicalMemory")
|
||||
2134124534
|
||||
"""
|
||||
out = sh("wmic path %s get %s" % (path, what)).strip()
|
||||
data = "".join(out.splitlines()[1:]).strip() # get rid of the header
|
||||
if converter is not None:
|
||||
if "," in what:
|
||||
return tuple([converter(x) for x in data.split()])
|
||||
else:
|
||||
return converter(data)
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# System APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestCpuAPIs(WindowsTestCase):
|
||||
@pytest.mark.skipif(
|
||||
'NUMBER_OF_PROCESSORS' not in os.environ,
|
||||
reason="NUMBER_OF_PROCESSORS env var is not available",
|
||||
)
|
||||
def test_cpu_count_vs_NUMBER_OF_PROCESSORS(self):
|
||||
# Will likely fail on many-cores systems:
|
||||
# https://stackoverflow.com/questions/31209256
|
||||
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
assert num_cpus == psutil.cpu_count()
|
||||
|
||||
def test_cpu_count_vs_GetSystemInfo(self):
|
||||
# Will likely fail on many-cores systems:
|
||||
# https://stackoverflow.com/questions/31209256
|
||||
sys_value = win32api.GetSystemInfo()[5]
|
||||
psutil_value = psutil.cpu_count()
|
||||
assert sys_value == psutil_value
|
||||
|
||||
def test_cpu_count_logical_vs_wmi(self):
|
||||
w = wmi.WMI()
|
||||
procs = sum(
|
||||
proc.NumberOfLogicalProcessors for proc in w.Win32_Processor()
|
||||
)
|
||||
assert psutil.cpu_count() == procs
|
||||
|
||||
def test_cpu_count_cores_vs_wmi(self):
|
||||
w = wmi.WMI()
|
||||
cores = sum(proc.NumberOfCores for proc in w.Win32_Processor())
|
||||
assert psutil.cpu_count(logical=False) == cores
|
||||
|
||||
def test_cpu_count_vs_cpu_times(self):
|
||||
assert psutil.cpu_count() == len(psutil.cpu_times(percpu=True))
|
||||
|
||||
def test_cpu_freq(self):
|
||||
w = wmi.WMI()
|
||||
proc = w.Win32_Processor()[0]
|
||||
assert proc.CurrentClockSpeed == psutil.cpu_freq().current
|
||||
assert proc.MaxClockSpeed == psutil.cpu_freq().max
|
||||
|
||||
|
||||
class TestSystemAPIs(WindowsTestCase):
|
||||
def test_nic_names(self):
|
||||
out = sh('ipconfig /all')
|
||||
nics = psutil.net_io_counters(pernic=True).keys()
|
||||
for nic in nics:
|
||||
if "pseudo-interface" in nic.replace(' ', '-').lower():
|
||||
continue
|
||||
if nic not in out:
|
||||
raise self.fail(
|
||||
"%r nic wasn't found in 'ipconfig /all' output" % nic
|
||||
)
|
||||
|
||||
def test_total_phymem(self):
|
||||
w = wmi.WMI().Win32_ComputerSystem()[0]
|
||||
assert int(w.TotalPhysicalMemory) == psutil.virtual_memory().total
|
||||
|
||||
def test_free_phymem(self):
|
||||
w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0]
|
||||
assert (
|
||||
abs(int(w.AvailableBytes) - psutil.virtual_memory().free)
|
||||
< TOLERANCE_SYS_MEM
|
||||
)
|
||||
|
||||
def test_total_swapmem(self):
|
||||
w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0]
|
||||
assert (
|
||||
int(w.CommitLimit) - psutil.virtual_memory().total
|
||||
== psutil.swap_memory().total
|
||||
)
|
||||
if psutil.swap_memory().total == 0:
|
||||
assert psutil.swap_memory().free == 0
|
||||
assert psutil.swap_memory().used == 0
|
||||
|
||||
def test_percent_swapmem(self):
|
||||
if psutil.swap_memory().total > 0:
|
||||
w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile(Name="_Total")[0]
|
||||
# calculate swap usage to percent
|
||||
percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base)
|
||||
# exact percent may change but should be reasonable
|
||||
# assert within +/- 5% and between 0 and 100%
|
||||
assert psutil.swap_memory().percent >= 0
|
||||
assert abs(psutil.swap_memory().percent - percentSwap) < 5
|
||||
assert psutil.swap_memory().percent <= 100
|
||||
|
||||
# @pytest.mark.skipif(wmi is None, reason="wmi module is not installed")
|
||||
# def test__UPTIME(self):
|
||||
# # _UPTIME constant is not public but it is used internally
|
||||
# # as value to return for pid 0 creation time.
|
||||
# # WMI behaves the same.
|
||||
# w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
# p = psutil.Process(0)
|
||||
# wmic_create = str(w.CreationDate.split('.')[0])
|
||||
# psutil_create = time.strftime("%Y%m%d%H%M%S",
|
||||
# time.localtime(p.create_time()))
|
||||
|
||||
# Note: this test is not very reliable
|
||||
@pytest.mark.skipif(APPVEYOR, reason="test not relieable on appveyor")
|
||||
@retry_on_failure()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
w = wmi.WMI().Win32_Process()
|
||||
wmi_pids = set([x.ProcessId for x in w])
|
||||
psutil_pids = set(psutil.pids())
|
||||
assert wmi_pids == psutil_pids
|
||||
|
||||
@retry_on_failure()
|
||||
def test_disks(self):
|
||||
ps_parts = psutil.disk_partitions(all=True)
|
||||
wmi_parts = wmi.WMI().Win32_LogicalDisk()
|
||||
for ps_part in ps_parts:
|
||||
for wmi_part in wmi_parts:
|
||||
if ps_part.device.replace('\\', '') == wmi_part.DeviceID:
|
||||
if not ps_part.mountpoint:
|
||||
# this is usually a CD-ROM with no disk inserted
|
||||
break
|
||||
if 'cdrom' in ps_part.opts:
|
||||
break
|
||||
if ps_part.mountpoint.startswith('A:'):
|
||||
break # floppy
|
||||
try:
|
||||
usage = psutil.disk_usage(ps_part.mountpoint)
|
||||
except FileNotFoundError:
|
||||
# usually this is the floppy
|
||||
break
|
||||
assert usage.total == int(wmi_part.Size)
|
||||
wmi_free = int(wmi_part.FreeSpace)
|
||||
assert usage.free == wmi_free
|
||||
# 10 MB tolerance
|
||||
if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
|
||||
raise self.fail(
|
||||
"psutil=%s, wmi=%s" % (usage.free, wmi_free)
|
||||
)
|
||||
break
|
||||
else:
|
||||
raise self.fail("can't find partition %s" % repr(ps_part))
|
||||
|
||||
@retry_on_failure()
|
||||
def test_disk_usage(self):
|
||||
for disk in psutil.disk_partitions():
|
||||
if 'cdrom' in disk.opts:
|
||||
continue
|
||||
sys_value = win32api.GetDiskFreeSpaceEx(disk.mountpoint)
|
||||
psutil_value = psutil.disk_usage(disk.mountpoint)
|
||||
assert abs(sys_value[0] - psutil_value.free) < TOLERANCE_DISK_USAGE
|
||||
assert (
|
||||
abs(sys_value[1] - psutil_value.total) < TOLERANCE_DISK_USAGE
|
||||
)
|
||||
assert psutil_value.used == psutil_value.total - psutil_value.free
|
||||
|
||||
def test_disk_partitions(self):
|
||||
sys_value = [
|
||||
x + '\\'
|
||||
for x in win32api.GetLogicalDriveStrings().split("\\\x00")
|
||||
if x and not x.startswith('A:')
|
||||
]
|
||||
psutil_value = [
|
||||
x.mountpoint
|
||||
for x in psutil.disk_partitions(all=True)
|
||||
if not x.mountpoint.startswith('A:')
|
||||
]
|
||||
assert sys_value == psutil_value
|
||||
|
||||
def test_net_if_stats(self):
|
||||
ps_names = set(cext.net_if_stats())
|
||||
wmi_adapters = wmi.WMI().Win32_NetworkAdapter()
|
||||
wmi_names = set()
|
||||
for wmi_adapter in wmi_adapters:
|
||||
wmi_names.add(wmi_adapter.Name)
|
||||
wmi_names.add(wmi_adapter.NetConnectionID)
|
||||
assert ps_names & wmi_names, "no common entries in %s, %s" % (
|
||||
ps_names,
|
||||
wmi_names,
|
||||
)
|
||||
|
||||
def test_boot_time(self):
|
||||
wmi_os = wmi.WMI().Win32_OperatingSystem()
|
||||
wmi_btime_str = wmi_os[0].LastBootUpTime.split('.')[0]
|
||||
wmi_btime_dt = datetime.datetime.strptime(
|
||||
wmi_btime_str, "%Y%m%d%H%M%S"
|
||||
)
|
||||
psutil_dt = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||
diff = abs((wmi_btime_dt - psutil_dt).total_seconds())
|
||||
assert diff <= 5
|
||||
|
||||
def test_boot_time_fluctuation(self):
|
||||
# https://github.com/giampaolo/psutil/issues/1007
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=5):
|
||||
assert psutil.boot_time() == 5
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=4):
|
||||
assert psutil.boot_time() == 5
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=6):
|
||||
assert psutil.boot_time() == 5
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=333):
|
||||
assert psutil.boot_time() == 333
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# sensors_battery()
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestSensorsBattery(WindowsTestCase):
|
||||
def test_has_battery(self):
|
||||
if win32api.GetPwrCapabilities()['SystemBatteriesPresent']:
|
||||
assert psutil.sensors_battery() is not None
|
||||
else:
|
||||
assert psutil.sensors_battery() is None
|
||||
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_percent(self):
|
||||
w = wmi.WMI()
|
||||
battery_wmi = w.query('select * from Win32_Battery')[0]
|
||||
battery_psutil = psutil.sensors_battery()
|
||||
assert (
|
||||
abs(battery_psutil.percent - battery_wmi.EstimatedChargeRemaining)
|
||||
< 1
|
||||
)
|
||||
|
||||
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
|
||||
def test_power_plugged(self):
|
||||
w = wmi.WMI()
|
||||
battery_wmi = w.query('select * from Win32_Battery')[0]
|
||||
battery_psutil = psutil.sensors_battery()
|
||||
# Status codes:
|
||||
# https://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx
|
||||
assert battery_psutil.power_plugged == (battery_wmi.BatteryStatus == 2)
|
||||
|
||||
def test_emulate_no_battery(self):
|
||||
with mock.patch(
|
||||
"psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(0, 128, 0, 0),
|
||||
) as m:
|
||||
assert psutil.sensors_battery() is None
|
||||
assert m.called
|
||||
|
||||
def test_emulate_power_connected(self):
|
||||
with mock.patch(
|
||||
"psutil._pswindows.cext.sensors_battery", return_value=(1, 0, 0, 0)
|
||||
) as m:
|
||||
assert (
|
||||
psutil.sensors_battery().secsleft
|
||||
== psutil.POWER_TIME_UNLIMITED
|
||||
)
|
||||
assert m.called
|
||||
|
||||
def test_emulate_power_charging(self):
|
||||
with mock.patch(
|
||||
"psutil._pswindows.cext.sensors_battery", return_value=(0, 8, 0, 0)
|
||||
) as m:
|
||||
assert (
|
||||
psutil.sensors_battery().secsleft
|
||||
== psutil.POWER_TIME_UNLIMITED
|
||||
)
|
||||
assert m.called
|
||||
|
||||
def test_emulate_secs_left_unknown(self):
|
||||
with mock.patch(
|
||||
"psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(0, 0, 0, -1),
|
||||
) as m:
|
||||
assert (
|
||||
psutil.sensors_battery().secsleft == psutil.POWER_TIME_UNKNOWN
|
||||
)
|
||||
assert m.called
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Process APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestProcess(WindowsTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
def test_issue_24(self):
|
||||
p = psutil.Process(0)
|
||||
with pytest.raises(psutil.AccessDenied):
|
||||
p.kill()
|
||||
|
||||
def test_special_pid(self):
|
||||
p = psutil.Process(4)
|
||||
assert p.name() == 'System'
|
||||
# use __str__ to access all common Process properties to check
|
||||
# that nothing strange happens
|
||||
str(p)
|
||||
p.username()
|
||||
assert p.create_time() >= 0.0
|
||||
try:
|
||||
rss, _vms = p.memory_info()[:2]
|
||||
except psutil.AccessDenied:
|
||||
# expected on Windows Vista and Windows 7
|
||||
if platform.uname()[1] not in ('vista', 'win-7', 'win7'):
|
||||
raise
|
||||
else:
|
||||
assert rss > 0
|
||||
|
||||
def test_send_signal(self):
|
||||
p = psutil.Process(self.pid)
|
||||
with pytest.raises(ValueError):
|
||||
p.send_signal(signal.SIGINT)
|
||||
|
||||
def test_num_handles_increment(self):
|
||||
p = psutil.Process(os.getpid())
|
||||
before = p.num_handles()
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, os.getpid()
|
||||
)
|
||||
after = p.num_handles()
|
||||
assert after == before + 1
|
||||
win32api.CloseHandle(handle)
|
||||
assert p.num_handles() == before
|
||||
|
||||
def test_ctrl_signals(self):
|
||||
p = psutil.Process(self.spawn_testproc().pid)
|
||||
p.send_signal(signal.CTRL_C_EVENT)
|
||||
p.send_signal(signal.CTRL_BREAK_EVENT)
|
||||
p.kill()
|
||||
p.wait()
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
p.send_signal(signal.CTRL_C_EVENT)
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
p.send_signal(signal.CTRL_BREAK_EVENT)
|
||||
|
||||
def test_username(self):
|
||||
name = win32api.GetUserNameEx(win32con.NameSamCompatible)
|
||||
if name.endswith('$'):
|
||||
# When running as a service account (most likely to be
|
||||
# NetworkService), these user name calculations don't produce the
|
||||
# same result, causing the test to fail.
|
||||
raise pytest.skip('running as service account')
|
||||
assert psutil.Process().username() == name
|
||||
|
||||
def test_cmdline(self):
|
||||
sys_value = re.sub('[ ]+', ' ', win32api.GetCommandLine()).strip()
|
||||
psutil_value = ' '.join(psutil.Process().cmdline())
|
||||
if sys_value[0] == '"' != psutil_value[0]:
|
||||
# The PyWin32 command line may retain quotes around argv[0] if they
|
||||
# were used unnecessarily, while psutil will omit them. So remove
|
||||
# the first 2 quotes from sys_value if not in psutil_value.
|
||||
# A path to an executable will not contain quotes, so this is safe.
|
||||
sys_value = sys_value.replace('"', '', 2)
|
||||
assert sys_value == psutil_value
|
||||
|
||||
# XXX - occasional failures
|
||||
|
||||
# def test_cpu_times(self):
|
||||
# handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
# win32con.FALSE, os.getpid())
|
||||
# self.addCleanup(win32api.CloseHandle, handle)
|
||||
# sys_value = win32process.GetProcessTimes(handle)
|
||||
# psutil_value = psutil.Process().cpu_times()
|
||||
# self.assertAlmostEqual(
|
||||
# psutil_value.user, sys_value['UserTime'] / 10000000.0,
|
||||
# delta=0.2)
|
||||
# self.assertAlmostEqual(
|
||||
# psutil_value.user, sys_value['KernelTime'] / 10000000.0,
|
||||
# delta=0.2)
|
||||
|
||||
def test_nice(self):
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, os.getpid()
|
||||
)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetPriorityClass(handle)
|
||||
psutil_value = psutil.Process().nice()
|
||||
assert psutil_value == sys_value
|
||||
|
||||
def test_memory_info(self):
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, self.pid
|
||||
)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetProcessMemoryInfo(handle)
|
||||
psutil_value = psutil.Process(self.pid).memory_info()
|
||||
assert sys_value['PeakWorkingSetSize'] == psutil_value.peak_wset
|
||||
assert sys_value['WorkingSetSize'] == psutil_value.wset
|
||||
assert (
|
||||
sys_value['QuotaPeakPagedPoolUsage']
|
||||
== psutil_value.peak_paged_pool
|
||||
)
|
||||
assert sys_value['QuotaPagedPoolUsage'] == psutil_value.paged_pool
|
||||
assert (
|
||||
sys_value['QuotaPeakNonPagedPoolUsage']
|
||||
== psutil_value.peak_nonpaged_pool
|
||||
)
|
||||
assert (
|
||||
sys_value['QuotaNonPagedPoolUsage'] == psutil_value.nonpaged_pool
|
||||
)
|
||||
assert sys_value['PagefileUsage'] == psutil_value.pagefile
|
||||
assert sys_value['PeakPagefileUsage'] == psutil_value.peak_pagefile
|
||||
|
||||
assert psutil_value.rss == psutil_value.wset
|
||||
assert psutil_value.vms == psutil_value.pagefile
|
||||
|
||||
def test_wait(self):
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, self.pid
|
||||
)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
p = psutil.Process(self.pid)
|
||||
p.terminate()
|
||||
psutil_value = p.wait()
|
||||
sys_value = win32process.GetExitCodeProcess(handle)
|
||||
assert psutil_value == sys_value
|
||||
|
||||
def test_cpu_affinity(self):
|
||||
def from_bitmask(x):
|
||||
return [i for i in range(64) if (1 << i) & x]
|
||||
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, self.pid
|
||||
)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = from_bitmask(
|
||||
win32process.GetProcessAffinityMask(handle)[0]
|
||||
)
|
||||
psutil_value = psutil.Process(self.pid).cpu_affinity()
|
||||
assert psutil_value == sys_value
|
||||
|
||||
def test_io_counters(self):
|
||||
handle = win32api.OpenProcess(
|
||||
win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, os.getpid()
|
||||
)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetProcessIoCounters(handle)
|
||||
psutil_value = psutil.Process().io_counters()
|
||||
assert psutil_value.read_count == sys_value['ReadOperationCount']
|
||||
assert psutil_value.write_count == sys_value['WriteOperationCount']
|
||||
assert psutil_value.read_bytes == sys_value['ReadTransferCount']
|
||||
assert psutil_value.write_bytes == sys_value['WriteTransferCount']
|
||||
assert psutil_value.other_count == sys_value['OtherOperationCount']
|
||||
assert psutil_value.other_bytes == sys_value['OtherTransferCount']
|
||||
|
||||
def test_num_handles(self):
|
||||
import ctypes
|
||||
import ctypes.wintypes
|
||||
|
||||
PROCESS_QUERY_INFORMATION = 0x400
|
||||
handle = ctypes.windll.kernel32.OpenProcess(
|
||||
PROCESS_QUERY_INFORMATION, 0, self.pid
|
||||
)
|
||||
self.addCleanup(ctypes.windll.kernel32.CloseHandle, handle)
|
||||
|
||||
hndcnt = ctypes.wintypes.DWORD()
|
||||
ctypes.windll.kernel32.GetProcessHandleCount(
|
||||
handle, ctypes.byref(hndcnt)
|
||||
)
|
||||
sys_value = hndcnt.value
|
||||
psutil_value = psutil.Process(self.pid).num_handles()
|
||||
assert psutil_value == sys_value
|
||||
|
||||
def test_error_partial_copy(self):
|
||||
# https://github.com/giampaolo/psutil/issues/875
|
||||
exc = WindowsError()
|
||||
exc.winerror = 299
|
||||
with mock.patch("psutil._psplatform.cext.proc_cwd", side_effect=exc):
|
||||
with mock.patch("time.sleep") as m:
|
||||
p = psutil.Process()
|
||||
with pytest.raises(psutil.AccessDenied):
|
||||
p.cwd()
|
||||
assert m.call_count >= 5
|
||||
|
||||
def test_exe(self):
|
||||
# NtQuerySystemInformation succeeds if process is gone. Make sure
|
||||
# it raises NSP for a non existent pid.
|
||||
pid = psutil.pids()[-1] + 99999
|
||||
proc = psutil._psplatform.Process(pid)
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
proc.exe()
|
||||
|
||||
|
||||
class TestProcessWMI(WindowsTestCase):
|
||||
"""Compare Process API results with WMI."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
def test_name(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
assert p.name() == w.Caption
|
||||
|
||||
# This fail on github because using virtualenv for test environment
|
||||
@pytest.mark.skipif(
|
||||
GITHUB_ACTIONS, reason="unreliable path on GITHUB_ACTIONS"
|
||||
)
|
||||
def test_exe(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
# Note: wmi reports the exe as a lower case string.
|
||||
# Being Windows paths case-insensitive we ignore that.
|
||||
assert p.exe().lower() == w.ExecutablePath.lower()
|
||||
|
||||
def test_cmdline(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
assert ' '.join(p.cmdline()) == w.CommandLine.replace('"', '')
|
||||
|
||||
def test_username(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
domain, _, username = w.GetOwner()
|
||||
username = "%s\\%s" % (domain, username)
|
||||
assert p.username() == username
|
||||
|
||||
@retry_on_failure()
|
||||
def test_memory_rss(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
rss = p.memory_info().rss
|
||||
assert rss == int(w.WorkingSetSize)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_memory_vms(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
vms = p.memory_info().vms
|
||||
# http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx
|
||||
# ...claims that PageFileUsage is represented in Kilo
|
||||
# bytes but funnily enough on certain platforms bytes are
|
||||
# returned instead.
|
||||
wmi_usage = int(w.PageFileUsage)
|
||||
if vms not in (wmi_usage, wmi_usage * 1024):
|
||||
raise self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
|
||||
|
||||
def test_create_time(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
wmic_create = str(w.CreationDate.split('.')[0])
|
||||
psutil_create = time.strftime(
|
||||
"%Y%m%d%H%M%S", time.localtime(p.create_time())
|
||||
)
|
||||
assert wmic_create == psutil_create
|
||||
|
||||
|
||||
# ---
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
class TestDualProcessImplementation(PsutilTestCase):
|
||||
"""Certain APIs on Windows have 2 internal implementations, one
|
||||
based on documented Windows APIs, another one based
|
||||
NtQuerySystemInformation() which gets called as fallback in
|
||||
case the first fails because of limited permission error.
|
||||
Here we test that the two methods return the exact same value,
|
||||
see:
|
||||
https://github.com/giampaolo/psutil/issues/304.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = spawn_testproc().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
terminate(cls.pid)
|
||||
|
||||
def test_memory_info(self):
|
||||
mem_1 = psutil.Process(self.pid).memory_info()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.proc_memory_info",
|
||||
side_effect=OSError(errno.EPERM, "msg"),
|
||||
) as fun:
|
||||
mem_2 = psutil.Process(self.pid).memory_info()
|
||||
assert len(mem_1) == len(mem_2)
|
||||
for i in range(len(mem_1)):
|
||||
assert mem_1[i] >= 0
|
||||
assert mem_2[i] >= 0
|
||||
assert abs(mem_1[i] - mem_2[i]) < 512
|
||||
assert fun.called
|
||||
|
||||
def test_create_time(self):
|
||||
ctime = psutil.Process(self.pid).create_time()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.proc_times",
|
||||
side_effect=OSError(errno.EPERM, "msg"),
|
||||
) as fun:
|
||||
assert psutil.Process(self.pid).create_time() == ctime
|
||||
assert fun.called
|
||||
|
||||
def test_cpu_times(self):
|
||||
cpu_times_1 = psutil.Process(self.pid).cpu_times()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.proc_times",
|
||||
side_effect=OSError(errno.EPERM, "msg"),
|
||||
) as fun:
|
||||
cpu_times_2 = psutil.Process(self.pid).cpu_times()
|
||||
assert fun.called
|
||||
assert abs(cpu_times_1.user - cpu_times_2.user) < 0.01
|
||||
assert abs(cpu_times_1.system - cpu_times_2.system) < 0.01
|
||||
|
||||
def test_io_counters(self):
|
||||
io_counters_1 = psutil.Process(self.pid).io_counters()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.proc_io_counters",
|
||||
side_effect=OSError(errno.EPERM, "msg"),
|
||||
) as fun:
|
||||
io_counters_2 = psutil.Process(self.pid).io_counters()
|
||||
for i in range(len(io_counters_1)):
|
||||
assert abs(io_counters_1[i] - io_counters_2[i]) < 5
|
||||
assert fun.called
|
||||
|
||||
def test_num_handles(self):
|
||||
num_handles = psutil.Process(self.pid).num_handles()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.proc_num_handles",
|
||||
side_effect=OSError(errno.EPERM, "msg"),
|
||||
) as fun:
|
||||
assert psutil.Process(self.pid).num_handles() == num_handles
|
||||
assert fun.called
|
||||
|
||||
def test_cmdline(self):
|
||||
for pid in psutil.pids():
|
||||
try:
|
||||
a = cext.proc_cmdline(pid, use_peb=True)
|
||||
b = cext.proc_cmdline(pid, use_peb=False)
|
||||
except OSError as err:
|
||||
err = convert_oserror(err)
|
||||
if not isinstance(
|
||||
err, (psutil.AccessDenied, psutil.NoSuchProcess)
|
||||
):
|
||||
raise
|
||||
else:
|
||||
assert a == b
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
class RemoteProcessTestCase(PsutilTestCase):
|
||||
"""Certain functions require calling ReadProcessMemory.
|
||||
This trivially works when called on the current process.
|
||||
Check that this works on other processes, especially when they
|
||||
have a different bitness.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def find_other_interpreter():
|
||||
# find a python interpreter that is of the opposite bitness from us
|
||||
code = "import sys; sys.stdout.write(str(sys.maxsize > 2**32))"
|
||||
|
||||
# XXX: a different and probably more stable approach might be to access
|
||||
# the registry but accessing 64 bit paths from a 32 bit process
|
||||
for filename in glob.glob(r"C:\Python*\python.exe"):
|
||||
proc = subprocess.Popen(
|
||||
args=[filename, "-c", code],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
output, _ = proc.communicate()
|
||||
proc.wait()
|
||||
if output == str(not IS_64BIT):
|
||||
return filename
|
||||
|
||||
test_args = ["-c", "import sys; sys.stdin.read()"]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
other_python = self.find_other_interpreter()
|
||||
if other_python is None:
|
||||
raise pytest.skip(
|
||||
"could not find interpreter with opposite bitness"
|
||||
)
|
||||
if IS_64BIT:
|
||||
self.python64 = sys.executable
|
||||
self.python32 = other_python
|
||||
else:
|
||||
self.python64 = other_python
|
||||
self.python32 = sys.executable
|
||||
|
||||
env = os.environ.copy()
|
||||
env["THINK_OF_A_NUMBER"] = str(os.getpid())
|
||||
self.proc32 = self.spawn_testproc(
|
||||
[self.python32] + self.test_args, env=env, stdin=subprocess.PIPE
|
||||
)
|
||||
self.proc64 = self.spawn_testproc(
|
||||
[self.python64] + self.test_args, env=env, stdin=subprocess.PIPE
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
self.proc32.communicate()
|
||||
self.proc64.communicate()
|
||||
|
||||
def test_cmdline_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
assert len(p.cmdline()) == 3
|
||||
assert p.cmdline()[1:] == self.test_args
|
||||
|
||||
def test_cmdline_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
assert len(p.cmdline()) == 3
|
||||
assert p.cmdline()[1:] == self.test_args
|
||||
|
||||
def test_cwd_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
assert p.cwd() == os.getcwd()
|
||||
|
||||
def test_cwd_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
assert p.cwd() == os.getcwd()
|
||||
|
||||
def test_environ_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
e = p.environ()
|
||||
assert "THINK_OF_A_NUMBER" in e
|
||||
assert e["THINK_OF_A_NUMBER"] == str(os.getpid())
|
||||
|
||||
def test_environ_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
try:
|
||||
p.environ()
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Windows services
|
||||
# ===================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
|
||||
class TestServices(PsutilTestCase):
|
||||
def test_win_service_iter(self):
|
||||
valid_statuses = set([
|
||||
"running",
|
||||
"paused",
|
||||
"start",
|
||||
"pause",
|
||||
"continue",
|
||||
"stop",
|
||||
"stopped",
|
||||
])
|
||||
valid_start_types = set(["automatic", "manual", "disabled"])
|
||||
valid_statuses = set([
|
||||
"running",
|
||||
"paused",
|
||||
"start_pending",
|
||||
"pause_pending",
|
||||
"continue_pending",
|
||||
"stop_pending",
|
||||
"stopped",
|
||||
])
|
||||
for serv in psutil.win_service_iter():
|
||||
data = serv.as_dict()
|
||||
assert isinstance(data['name'], str)
|
||||
assert data['name'].strip()
|
||||
assert isinstance(data['display_name'], str)
|
||||
assert isinstance(data['username'], str)
|
||||
assert data['status'] in valid_statuses
|
||||
if data['pid'] is not None:
|
||||
psutil.Process(data['pid'])
|
||||
assert isinstance(data['binpath'], str)
|
||||
assert isinstance(data['username'], str)
|
||||
assert isinstance(data['start_type'], str)
|
||||
assert data['start_type'] in valid_start_types
|
||||
assert data['status'] in valid_statuses
|
||||
assert isinstance(data['description'], str)
|
||||
pid = serv.pid()
|
||||
if pid is not None:
|
||||
p = psutil.Process(pid)
|
||||
assert p.is_running()
|
||||
# win_service_get
|
||||
s = psutil.win_service_get(serv.name())
|
||||
# test __eq__
|
||||
assert serv == s
|
||||
|
||||
def test_win_service_get(self):
|
||||
ERROR_SERVICE_DOES_NOT_EXIST = (
|
||||
psutil._psplatform.cext.ERROR_SERVICE_DOES_NOT_EXIST
|
||||
)
|
||||
ERROR_ACCESS_DENIED = psutil._psplatform.cext.ERROR_ACCESS_DENIED
|
||||
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
with pytest.raises(psutil.NoSuchProcess) as cm:
|
||||
psutil.win_service_get(name + '???')
|
||||
assert cm.value.name == name + '???'
|
||||
|
||||
# test NoSuchProcess
|
||||
service = psutil.win_service_get(name)
|
||||
if PY3:
|
||||
args = (0, "msg", 0, ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
else:
|
||||
args = (ERROR_SERVICE_DOES_NOT_EXIST, "msg")
|
||||
exc = WindowsError(*args)
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.winservice_query_status", side_effect=exc
|
||||
):
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
service.status()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.winservice_query_config", side_effect=exc
|
||||
):
|
||||
with pytest.raises(psutil.NoSuchProcess):
|
||||
service.username()
|
||||
|
||||
# test AccessDenied
|
||||
if PY3:
|
||||
args = (0, "msg", 0, ERROR_ACCESS_DENIED)
|
||||
else:
|
||||
args = (ERROR_ACCESS_DENIED, "msg")
|
||||
exc = WindowsError(*args)
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.winservice_query_status", side_effect=exc
|
||||
):
|
||||
with pytest.raises(psutil.AccessDenied):
|
||||
service.status()
|
||||
with mock.patch(
|
||||
"psutil._psplatform.cext.winservice_query_config", side_effect=exc
|
||||
):
|
||||
with pytest.raises(psutil.AccessDenied):
|
||||
service.username()
|
||||
|
||||
# test __str__ and __repr__
|
||||
assert service.name() in str(service)
|
||||
assert service.display_name() in str(service)
|
||||
assert service.name() in repr(service)
|
||||
assert service.display_name() in repr(service)
|
Reference in New Issue
Block a user