|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Miscellaneous tests.""" |
|
|
|
import ast |
|
import collections |
|
import errno |
|
import json |
|
import os |
|
import pickle |
|
import socket |
|
import stat |
|
import sys |
|
import unittest |
|
|
|
import psutil |
|
import psutil.tests |
|
from psutil import POSIX |
|
from psutil import WINDOWS |
|
from psutil._common import bcat |
|
from psutil._common import cat |
|
from psutil._common import debug |
|
from psutil._common import isfile_strict |
|
from psutil._common import memoize |
|
from psutil._common import memoize_when_activated |
|
from psutil._common import parse_environ_block |
|
from psutil._common import supports_ipv6 |
|
from psutil._common import wrap_numbers |
|
from psutil._compat import PY3 |
|
from psutil._compat import FileNotFoundError |
|
from psutil._compat import redirect_stderr |
|
from psutil.tests import CI_TESTING |
|
from psutil.tests import HAS_BATTERY |
|
from psutil.tests import HAS_MEMORY_MAPS |
|
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 PYTHON_EXE |
|
from psutil.tests import PYTHON_EXE_ENV |
|
from psutil.tests import QEMU_USER |
|
from psutil.tests import SCRIPTS_DIR |
|
from psutil.tests import PsutilTestCase |
|
from psutil.tests import mock |
|
from psutil.tests import process_namespace |
|
from psutil.tests import reload_module |
|
from psutil.tests import sh |
|
from psutil.tests import system_namespace |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestSpecialMethods(PsutilTestCase): |
|
def test_check_pid_range(self): |
|
with self.assertRaises(OverflowError): |
|
psutil._psplatform.cext.check_pid_range(2**128) |
|
with self.assertRaises(psutil.NoSuchProcess): |
|
psutil.Process(2**128) |
|
|
|
def test_process__repr__(self, func=repr): |
|
p = psutil.Process(self.spawn_testproc().pid) |
|
r = func(p) |
|
self.assertIn("psutil.Process", r) |
|
self.assertIn("pid=%s" % p.pid, r) |
|
self.assertIn( |
|
"name='%s'" % str(p.name()), r.replace("name=u'", "name='") |
|
) |
|
self.assertIn("status=", r) |
|
self.assertNotIn("exitcode=", r) |
|
p.terminate() |
|
p.wait() |
|
r = func(p) |
|
self.assertIn("status='terminated'", r) |
|
self.assertIn("exitcode=", r) |
|
|
|
with mock.patch.object( |
|
psutil.Process, |
|
"name", |
|
side_effect=psutil.ZombieProcess(os.getpid()), |
|
): |
|
p = psutil.Process() |
|
r = func(p) |
|
self.assertIn("pid=%s" % p.pid, r) |
|
self.assertIn("status='zombie'", r) |
|
self.assertNotIn("name=", r) |
|
with mock.patch.object( |
|
psutil.Process, |
|
"name", |
|
side_effect=psutil.NoSuchProcess(os.getpid()), |
|
): |
|
p = psutil.Process() |
|
r = func(p) |
|
self.assertIn("pid=%s" % p.pid, r) |
|
self.assertIn("terminated", r) |
|
self.assertNotIn("name=", r) |
|
with mock.patch.object( |
|
psutil.Process, |
|
"name", |
|
side_effect=psutil.AccessDenied(os.getpid()), |
|
): |
|
p = psutil.Process() |
|
r = func(p) |
|
self.assertIn("pid=%s" % p.pid, r) |
|
self.assertNotIn("name=", r) |
|
|
|
def test_process__str__(self): |
|
self.test_process__repr__(func=str) |
|
|
|
def test_error__repr__(self): |
|
self.assertEqual(repr(psutil.Error()), "psutil.Error()") |
|
|
|
def test_error__str__(self): |
|
self.assertEqual(str(psutil.Error()), "") |
|
|
|
def test_no_such_process__repr__(self): |
|
self.assertEqual( |
|
repr(psutil.NoSuchProcess(321)), |
|
"psutil.NoSuchProcess(pid=321, msg='process no longer exists')", |
|
) |
|
self.assertEqual( |
|
repr(psutil.NoSuchProcess(321, name="name", msg="msg")), |
|
"psutil.NoSuchProcess(pid=321, name='name', msg='msg')", |
|
) |
|
|
|
def test_no_such_process__str__(self): |
|
self.assertEqual( |
|
str(psutil.NoSuchProcess(321)), |
|
"process no longer exists (pid=321)", |
|
) |
|
self.assertEqual( |
|
str(psutil.NoSuchProcess(321, name="name", msg="msg")), |
|
"msg (pid=321, name='name')", |
|
) |
|
|
|
def test_zombie_process__repr__(self): |
|
self.assertEqual( |
|
repr(psutil.ZombieProcess(321)), |
|
'psutil.ZombieProcess(pid=321, msg="PID still ' |
|
'exists but it\'s a zombie")', |
|
) |
|
self.assertEqual( |
|
repr(psutil.ZombieProcess(321, name="name", ppid=320, msg="foo")), |
|
"psutil.ZombieProcess(pid=321, ppid=320, name='name', msg='foo')", |
|
) |
|
|
|
def test_zombie_process__str__(self): |
|
self.assertEqual( |
|
str(psutil.ZombieProcess(321)), |
|
"PID still exists but it's a zombie (pid=321)", |
|
) |
|
self.assertEqual( |
|
str(psutil.ZombieProcess(321, name="name", ppid=320, msg="foo")), |
|
"foo (pid=321, ppid=320, name='name')", |
|
) |
|
|
|
def test_access_denied__repr__(self): |
|
self.assertEqual( |
|
repr(psutil.AccessDenied(321)), "psutil.AccessDenied(pid=321)" |
|
) |
|
self.assertEqual( |
|
repr(psutil.AccessDenied(321, name="name", msg="msg")), |
|
"psutil.AccessDenied(pid=321, name='name', msg='msg')", |
|
) |
|
|
|
def test_access_denied__str__(self): |
|
self.assertEqual(str(psutil.AccessDenied(321)), "(pid=321)") |
|
self.assertEqual( |
|
str(psutil.AccessDenied(321, name="name", msg="msg")), |
|
"msg (pid=321, name='name')", |
|
) |
|
|
|
def test_timeout_expired__repr__(self): |
|
self.assertEqual( |
|
repr(psutil.TimeoutExpired(5)), |
|
"psutil.TimeoutExpired(seconds=5, msg='timeout after 5 seconds')", |
|
) |
|
self.assertEqual( |
|
repr(psutil.TimeoutExpired(5, pid=321, name="name")), |
|
"psutil.TimeoutExpired(pid=321, name='name', seconds=5, " |
|
"msg='timeout after 5 seconds')", |
|
) |
|
|
|
def test_timeout_expired__str__(self): |
|
self.assertEqual( |
|
str(psutil.TimeoutExpired(5)), "timeout after 5 seconds" |
|
) |
|
self.assertEqual( |
|
str(psutil.TimeoutExpired(5, pid=321, name="name")), |
|
"timeout after 5 seconds (pid=321, name='name')", |
|
) |
|
|
|
def test_process__eq__(self): |
|
p1 = psutil.Process() |
|
p2 = psutil.Process() |
|
self.assertEqual(p1, p2) |
|
p2._ident = (0, 0) |
|
self.assertNotEqual(p1, p2) |
|
self.assertNotEqual(p1, 'foo') |
|
|
|
def test_process__hash__(self): |
|
s = set([psutil.Process(), psutil.Process()]) |
|
self.assertEqual(len(s), 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMisc(PsutilTestCase): |
|
def test__all__(self): |
|
dir_psutil = dir(psutil) |
|
for name in dir_psutil: |
|
if name in ( |
|
'debug', |
|
'long', |
|
'tests', |
|
'test', |
|
'PermissionError', |
|
'ProcessLookupError', |
|
): |
|
continue |
|
if not name.startswith('_'): |
|
try: |
|
__import__(name) |
|
except ImportError: |
|
if name not in psutil.__all__: |
|
fun = getattr(psutil, name) |
|
if fun is None: |
|
continue |
|
if ( |
|
fun.__doc__ is not None |
|
and 'deprecated' not in fun.__doc__.lower() |
|
): |
|
raise self.fail('%r not in psutil.__all__' % name) |
|
|
|
|
|
|
|
|
|
|
|
for name in psutil.__all__: |
|
self.assertIn(name, dir_psutil) |
|
|
|
def test_version(self): |
|
self.assertEqual( |
|
'.'.join([str(x) for x in psutil.version_info]), psutil.__version__ |
|
) |
|
|
|
def test_process_as_dict_no_new_names(self): |
|
|
|
p = psutil.Process() |
|
p.foo = '1' |
|
self.assertNotIn('foo', p.as_dict()) |
|
|
|
def test_serialization(self): |
|
def check(ret): |
|
json.loads(json.dumps(ret)) |
|
|
|
a = pickle.dumps(ret) |
|
b = pickle.loads(a) |
|
self.assertEqual(ret, b) |
|
|
|
|
|
|
|
proc = psutil.Process() |
|
check(psutil.Process().as_dict()) |
|
|
|
ns = process_namespace(proc) |
|
for fun, name in ns.iter(ns.getters, clear_cache=True): |
|
with self.subTest(proc=proc, name=name): |
|
try: |
|
ret = fun() |
|
except psutil.Error: |
|
pass |
|
else: |
|
check(ret) |
|
|
|
|
|
|
|
ns = system_namespace() |
|
for fun, name in ns.iter(ns.getters): |
|
if name in {"win_service_iter", "win_service_get"}: |
|
continue |
|
if QEMU_USER and name == "net_if_stats": |
|
|
|
continue |
|
with self.subTest(name=name): |
|
try: |
|
ret = fun() |
|
except psutil.AccessDenied: |
|
pass |
|
else: |
|
check(ret) |
|
|
|
|
|
|
|
b = pickle.loads( |
|
pickle.dumps( |
|
psutil.NoSuchProcess(pid=4567, name='name', msg='msg') |
|
) |
|
) |
|
self.assertIsInstance(b, psutil.NoSuchProcess) |
|
self.assertEqual(b.pid, 4567) |
|
self.assertEqual(b.name, 'name') |
|
self.assertEqual(b.msg, 'msg') |
|
|
|
b = pickle.loads( |
|
pickle.dumps( |
|
psutil.ZombieProcess(pid=4567, name='name', ppid=42, msg='msg') |
|
) |
|
) |
|
self.assertIsInstance(b, psutil.ZombieProcess) |
|
self.assertEqual(b.pid, 4567) |
|
self.assertEqual(b.ppid, 42) |
|
self.assertEqual(b.name, 'name') |
|
self.assertEqual(b.msg, 'msg') |
|
|
|
b = pickle.loads( |
|
pickle.dumps(psutil.AccessDenied(pid=123, name='name', msg='msg')) |
|
) |
|
self.assertIsInstance(b, psutil.AccessDenied) |
|
self.assertEqual(b.pid, 123) |
|
self.assertEqual(b.name, 'name') |
|
self.assertEqual(b.msg, 'msg') |
|
|
|
b = pickle.loads( |
|
pickle.dumps( |
|
psutil.TimeoutExpired(seconds=33, pid=4567, name='name') |
|
) |
|
) |
|
self.assertIsInstance(b, psutil.TimeoutExpired) |
|
self.assertEqual(b.seconds, 33) |
|
self.assertEqual(b.pid, 4567) |
|
self.assertEqual(b.name, 'name') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_ad_on_process_creation(self): |
|
|
|
|
|
with mock.patch.object( |
|
psutil.Process, 'create_time', side_effect=psutil.AccessDenied |
|
) as meth: |
|
psutil.Process() |
|
assert meth.called |
|
with mock.patch.object( |
|
psutil.Process, 'create_time', side_effect=psutil.ZombieProcess(1) |
|
) as meth: |
|
psutil.Process() |
|
assert meth.called |
|
with mock.patch.object( |
|
psutil.Process, 'create_time', side_effect=ValueError |
|
) as meth: |
|
with self.assertRaises(ValueError): |
|
psutil.Process() |
|
assert meth.called |
|
|
|
def test_sanity_version_check(self): |
|
|
|
with mock.patch( |
|
"psutil._psplatform.cext.version", return_value="0.0.0" |
|
): |
|
with self.assertRaises(ImportError) as cm: |
|
reload_module(psutil) |
|
self.assertIn("version conflict", str(cm.exception).lower()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMemoizeDecorator(PsutilTestCase): |
|
def setUp(self): |
|
self.calls = [] |
|
|
|
tearDown = setUp |
|
|
|
def run_against(self, obj, expected_retval=None): |
|
|
|
for _ in range(2): |
|
ret = obj() |
|
self.assertEqual(self.calls, [((), {})]) |
|
if expected_retval is not None: |
|
self.assertEqual(ret, expected_retval) |
|
|
|
for _ in range(2): |
|
ret = obj(1) |
|
self.assertEqual(self.calls, [((), {}), ((1,), {})]) |
|
if expected_retval is not None: |
|
self.assertEqual(ret, expected_retval) |
|
|
|
for _ in range(2): |
|
ret = obj(1, bar=2) |
|
self.assertEqual( |
|
self.calls, [((), {}), ((1,), {}), ((1,), {'bar': 2})] |
|
) |
|
if expected_retval is not None: |
|
self.assertEqual(ret, expected_retval) |
|
|
|
self.assertEqual(len(self.calls), 3) |
|
obj.cache_clear() |
|
ret = obj() |
|
if expected_retval is not None: |
|
self.assertEqual(ret, expected_retval) |
|
self.assertEqual(len(self.calls), 4) |
|
|
|
self.assertEqual(obj.__doc__, "My docstring.") |
|
|
|
def test_function(self): |
|
@memoize |
|
def foo(*args, **kwargs): |
|
"""My docstring.""" |
|
baseclass.calls.append((args, kwargs)) |
|
return 22 |
|
|
|
baseclass = self |
|
self.run_against(foo, expected_retval=22) |
|
|
|
def test_class(self): |
|
@memoize |
|
class Foo: |
|
"""My docstring.""" |
|
|
|
def __init__(self, *args, **kwargs): |
|
baseclass.calls.append((args, kwargs)) |
|
|
|
def bar(self): |
|
return 22 |
|
|
|
baseclass = self |
|
self.run_against(Foo, expected_retval=None) |
|
self.assertEqual(Foo().bar(), 22) |
|
|
|
def test_class_singleton(self): |
|
|
|
@memoize |
|
class Bar: |
|
def __init__(self, *args, **kwargs): |
|
pass |
|
|
|
self.assertIs(Bar(), Bar()) |
|
self.assertEqual(id(Bar()), id(Bar())) |
|
self.assertEqual(id(Bar(1)), id(Bar(1))) |
|
self.assertEqual(id(Bar(1, foo=3)), id(Bar(1, foo=3))) |
|
self.assertNotEqual(id(Bar(1)), id(Bar(2))) |
|
|
|
def test_staticmethod(self): |
|
class Foo: |
|
@staticmethod |
|
@memoize |
|
def bar(*args, **kwargs): |
|
"""My docstring.""" |
|
baseclass.calls.append((args, kwargs)) |
|
return 22 |
|
|
|
baseclass = self |
|
self.run_against(Foo().bar, expected_retval=22) |
|
|
|
def test_classmethod(self): |
|
class Foo: |
|
@classmethod |
|
@memoize |
|
def bar(cls, *args, **kwargs): |
|
"""My docstring.""" |
|
baseclass.calls.append((args, kwargs)) |
|
return 22 |
|
|
|
baseclass = self |
|
self.run_against(Foo().bar, expected_retval=22) |
|
|
|
def test_original(self): |
|
|
|
|
|
@memoize |
|
def foo(*args, **kwargs): |
|
"""Foo docstring.""" |
|
calls.append(None) |
|
return (args, kwargs) |
|
|
|
calls = [] |
|
|
|
for _ in range(2): |
|
ret = foo() |
|
expected = ((), {}) |
|
self.assertEqual(ret, expected) |
|
self.assertEqual(len(calls), 1) |
|
|
|
for _ in range(2): |
|
ret = foo(1) |
|
expected = ((1,), {}) |
|
self.assertEqual(ret, expected) |
|
self.assertEqual(len(calls), 2) |
|
|
|
for _ in range(2): |
|
ret = foo(1, bar=2) |
|
expected = ((1,), {'bar': 2}) |
|
self.assertEqual(ret, expected) |
|
self.assertEqual(len(calls), 3) |
|
|
|
foo.cache_clear() |
|
ret = foo() |
|
expected = ((), {}) |
|
self.assertEqual(ret, expected) |
|
self.assertEqual(len(calls), 4) |
|
|
|
self.assertEqual(foo.__doc__, "Foo docstring.") |
|
|
|
|
|
class TestCommonModule(PsutilTestCase): |
|
def test_memoize_when_activated(self): |
|
class Foo: |
|
@memoize_when_activated |
|
def foo(self): |
|
calls.append(None) |
|
|
|
f = Foo() |
|
calls = [] |
|
f.foo() |
|
f.foo() |
|
self.assertEqual(len(calls), 2) |
|
|
|
|
|
calls = [] |
|
f.foo.cache_activate(f) |
|
f.foo() |
|
f.foo() |
|
self.assertEqual(len(calls), 1) |
|
|
|
|
|
calls = [] |
|
f.foo.cache_deactivate(f) |
|
f.foo() |
|
f.foo() |
|
self.assertEqual(len(calls), 2) |
|
|
|
def test_parse_environ_block(self): |
|
def k(s): |
|
return s.upper() if WINDOWS else s |
|
|
|
self.assertEqual(parse_environ_block("a=1\0"), {k("a"): "1"}) |
|
self.assertEqual( |
|
parse_environ_block("a=1\0b=2\0\0"), {k("a"): "1", k("b"): "2"} |
|
) |
|
self.assertEqual( |
|
parse_environ_block("a=1\0b=\0\0"), {k("a"): "1", k("b"): ""} |
|
) |
|
|
|
self.assertEqual( |
|
parse_environ_block("a=1\0b=2\0\0c=3\0"), |
|
{k("a"): "1", k("b"): "2"}, |
|
) |
|
|
|
self.assertEqual(parse_environ_block("xxx\0a=1\0"), {k("a"): "1"}) |
|
self.assertEqual(parse_environ_block("a=1\0=b=2\0"), {k("a"): "1"}) |
|
|
|
self.assertEqual(parse_environ_block("a=1\0b=2"), {k("a"): "1"}) |
|
|
|
def test_supports_ipv6(self): |
|
self.addCleanup(supports_ipv6.cache_clear) |
|
if supports_ipv6(): |
|
with mock.patch('psutil._common.socket') as s: |
|
s.has_ipv6 = False |
|
supports_ipv6.cache_clear() |
|
assert not supports_ipv6() |
|
|
|
supports_ipv6.cache_clear() |
|
with mock.patch( |
|
'psutil._common.socket.socket', side_effect=socket.error |
|
) as s: |
|
assert not supports_ipv6() |
|
assert s.called |
|
|
|
supports_ipv6.cache_clear() |
|
with mock.patch( |
|
'psutil._common.socket.socket', side_effect=socket.gaierror |
|
) as s: |
|
assert not supports_ipv6() |
|
supports_ipv6.cache_clear() |
|
assert s.called |
|
|
|
supports_ipv6.cache_clear() |
|
with mock.patch( |
|
'psutil._common.socket.socket.bind', |
|
side_effect=socket.gaierror, |
|
) as s: |
|
assert not supports_ipv6() |
|
supports_ipv6.cache_clear() |
|
assert s.called |
|
else: |
|
with self.assertRaises(socket.error): |
|
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) |
|
try: |
|
sock.bind(("::1", 0)) |
|
finally: |
|
sock.close() |
|
|
|
def test_isfile_strict(self): |
|
this_file = os.path.abspath(__file__) |
|
assert isfile_strict(this_file) |
|
assert not isfile_strict(os.path.dirname(this_file)) |
|
with mock.patch( |
|
'psutil._common.os.stat', side_effect=OSError(errno.EPERM, "foo") |
|
): |
|
self.assertRaises(OSError, isfile_strict, this_file) |
|
with mock.patch( |
|
'psutil._common.os.stat', side_effect=OSError(errno.EACCES, "foo") |
|
): |
|
self.assertRaises(OSError, isfile_strict, this_file) |
|
with mock.patch( |
|
'psutil._common.os.stat', side_effect=OSError(errno.ENOENT, "foo") |
|
): |
|
assert not isfile_strict(this_file) |
|
with mock.patch('psutil._common.stat.S_ISREG', return_value=False): |
|
assert not isfile_strict(this_file) |
|
|
|
def test_debug(self): |
|
if PY3: |
|
from io import StringIO |
|
else: |
|
from StringIO import StringIO |
|
|
|
with redirect_stderr(StringIO()) as f: |
|
debug("hello") |
|
sys.stderr.flush() |
|
msg = f.getvalue() |
|
assert msg.startswith("psutil-debug"), msg |
|
self.assertIn("hello", msg) |
|
self.assertIn(__file__.replace('.pyc', '.py'), msg) |
|
|
|
|
|
with redirect_stderr(StringIO()) as f: |
|
debug(ValueError("this is an error")) |
|
msg = f.getvalue() |
|
self.assertIn("ignoring ValueError", msg) |
|
self.assertIn("'this is an error'", msg) |
|
|
|
|
|
with redirect_stderr(StringIO()) as f: |
|
exc = OSError(2, "no such file") |
|
exc.filename = "/foo" |
|
debug(exc) |
|
msg = f.getvalue() |
|
self.assertIn("no such file", msg) |
|
self.assertIn("/foo", msg) |
|
|
|
def test_cat_bcat(self): |
|
testfn = self.get_testfn() |
|
with open(testfn, "w") as f: |
|
f.write("foo") |
|
self.assertEqual(cat(testfn), "foo") |
|
self.assertEqual(bcat(testfn), b"foo") |
|
self.assertRaises(FileNotFoundError, cat, testfn + '-invalid') |
|
self.assertRaises(FileNotFoundError, bcat, testfn + '-invalid') |
|
self.assertEqual(cat(testfn + '-invalid', fallback="bar"), "bar") |
|
self.assertEqual(bcat(testfn + '-invalid', fallback="bar"), "bar") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nt = collections.namedtuple('foo', 'a b c') |
|
|
|
|
|
class TestWrapNumbers(PsutilTestCase): |
|
def setUp(self): |
|
wrap_numbers.cache_clear() |
|
|
|
tearDown = setUp |
|
|
|
def test_first_call(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
def test_input_hasnt_changed(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
def test_increase_but_no_wrap(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
input = {'disk1': nt(10, 15, 20)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
input = {'disk1': nt(20, 25, 30)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
input = {'disk1': nt(20, 25, 30)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
def test_wrap(self): |
|
|
|
input = {'disk1': nt(100, 100, 100)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
input = {'disk1': nt(100, 100, 10)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(100, 100, 110)} |
|
) |
|
|
|
input = {'disk1': nt(100, 100, 10)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(100, 100, 110)} |
|
) |
|
|
|
input = {'disk1': nt(100, 100, 90)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(100, 100, 190)} |
|
) |
|
|
|
input = {'disk1': nt(100, 100, 20)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(100, 100, 210)} |
|
) |
|
|
|
input = {'disk1': nt(100, 100, 20)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(100, 100, 210)} |
|
) |
|
|
|
input = {'disk1': nt(50, 100, 20)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(150, 100, 210)} |
|
) |
|
|
|
input = {'disk1': nt(40, 100, 20)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(190, 100, 210)} |
|
) |
|
|
|
input = {'disk1': nt(40, 100, 20)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), {'disk1': nt(190, 100, 210)} |
|
) |
|
|
|
def test_changing_keys(self): |
|
|
|
|
|
|
|
input = {'disk1': nt(5, 5, 5)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
input = {'disk1': nt(5, 5, 5), 'disk2': nt(7, 7, 7)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
input = {'disk1': nt(8, 8, 8)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
def test_changing_keys_w_wrap(self): |
|
input = {'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 100)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
input = {'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 10)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), |
|
{'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 110)}, |
|
) |
|
|
|
input = {'disk1': nt(50, 50, 50)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
|
|
|
|
input = {'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 100)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
input = {'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 100)} |
|
self.assertEqual(wrap_numbers(input, 'disk_io'), input) |
|
|
|
input = {'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 10)} |
|
self.assertEqual( |
|
wrap_numbers(input, 'disk_io'), |
|
{'disk1': nt(50, 50, 50), 'disk2': nt(100, 100, 110)}, |
|
) |
|
|
|
def test_real_data(self): |
|
d = { |
|
'nvme0n1': (300, 508, 640, 1571, 5970, 1987, 2049, 451751, 47048), |
|
'nvme0n1p1': (1171, 2, 5600256, 1024, 516, 0, 0, 0, 8), |
|
'nvme0n1p2': (54, 54, 2396160, 5165056, 4, 24, 30, 1207, 28), |
|
'nvme0n1p3': (2389, 4539, 5154, 150, 4828, 1844, 2019, 398, 348), |
|
} |
|
self.assertEqual(wrap_numbers(d, 'disk_io'), d) |
|
self.assertEqual(wrap_numbers(d, 'disk_io'), d) |
|
|
|
d = { |
|
'nvme0n1': (100, 508, 640, 1571, 5970, 1987, 2049, 451751, 47048), |
|
'nvme0n1p1': (1171, 2, 5600256, 1024, 516, 0, 0, 0, 8), |
|
'nvme0n1p2': (54, 54, 2396160, 5165056, 4, 24, 30, 1207, 28), |
|
'nvme0n1p3': (2389, 4539, 5154, 150, 4828, 1844, 2019, 398, 348), |
|
} |
|
out = wrap_numbers(d, 'disk_io') |
|
self.assertEqual(out['nvme0n1'][0], 400) |
|
|
|
|
|
|
|
def test_cache_first_call(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
self.assertEqual(cache[1], {'disk_io': {}}) |
|
self.assertEqual(cache[2], {'disk_io': {}}) |
|
|
|
def test_cache_call_twice(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
wrap_numbers(input, 'disk_io') |
|
input = {'disk1': nt(10, 10, 10)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
self.assertEqual( |
|
cache[1], |
|
{'disk_io': {('disk1', 0): 0, ('disk1', 1): 0, ('disk1', 2): 0}}, |
|
) |
|
self.assertEqual(cache[2], {'disk_io': {}}) |
|
|
|
def test_cache_wrap(self): |
|
|
|
input = {'disk1': nt(100, 100, 100)} |
|
wrap_numbers(input, 'disk_io') |
|
|
|
|
|
input = {'disk1': nt(100, 100, 10)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
self.assertEqual( |
|
cache[1], |
|
{'disk_io': {('disk1', 0): 0, ('disk1', 1): 0, ('disk1', 2): 100}}, |
|
) |
|
self.assertEqual(cache[2], {'disk_io': {'disk1': set([('disk1', 2)])}}) |
|
|
|
def check_cache_info(): |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual( |
|
cache[1], |
|
{ |
|
'disk_io': { |
|
('disk1', 0): 0, |
|
('disk1', 1): 0, |
|
('disk1', 2): 100, |
|
} |
|
}, |
|
) |
|
self.assertEqual( |
|
cache[2], {'disk_io': {'disk1': set([('disk1', 2)])}} |
|
) |
|
|
|
|
|
input = {'disk1': nt(100, 100, 10)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
check_cache_info() |
|
|
|
|
|
input = {'disk1': nt(100, 100, 90)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
check_cache_info() |
|
|
|
|
|
input = {'disk1': nt(100, 100, 20)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
self.assertEqual( |
|
cache[1], |
|
{'disk_io': {('disk1', 0): 0, ('disk1', 1): 0, ('disk1', 2): 190}}, |
|
) |
|
self.assertEqual(cache[2], {'disk_io': {'disk1': set([('disk1', 2)])}}) |
|
|
|
def test_cache_changing_keys(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
wrap_numbers(input, 'disk_io') |
|
input = {'disk1': nt(5, 5, 5), 'disk2': nt(7, 7, 7)} |
|
wrap_numbers(input, 'disk_io') |
|
cache = wrap_numbers.cache_info() |
|
self.assertEqual(cache[0], {'disk_io': input}) |
|
self.assertEqual( |
|
cache[1], |
|
{'disk_io': {('disk1', 0): 0, ('disk1', 1): 0, ('disk1', 2): 0}}, |
|
) |
|
self.assertEqual(cache[2], {'disk_io': {}}) |
|
|
|
def test_cache_clear(self): |
|
input = {'disk1': nt(5, 5, 5)} |
|
wrap_numbers(input, 'disk_io') |
|
wrap_numbers(input, 'disk_io') |
|
wrap_numbers.cache_clear('disk_io') |
|
self.assertEqual(wrap_numbers.cache_info(), ({}, {}, {})) |
|
wrap_numbers.cache_clear('disk_io') |
|
wrap_numbers.cache_clear('?!?') |
|
|
|
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported') |
|
def test_cache_clear_public_apis(self): |
|
if not psutil.disk_io_counters() or not psutil.net_io_counters(): |
|
raise unittest.SkipTest("no disks or NICs available") |
|
psutil.disk_io_counters() |
|
psutil.net_io_counters() |
|
caches = wrap_numbers.cache_info() |
|
for cache in caches: |
|
self.assertIn('psutil.disk_io_counters', cache) |
|
self.assertIn('psutil.net_io_counters', cache) |
|
|
|
psutil.disk_io_counters.cache_clear() |
|
caches = wrap_numbers.cache_info() |
|
for cache in caches: |
|
self.assertIn('psutil.net_io_counters', cache) |
|
self.assertNotIn('psutil.disk_io_counters', cache) |
|
|
|
psutil.net_io_counters.cache_clear() |
|
caches = wrap_numbers.cache_info() |
|
self.assertEqual(caches, ({}, {}, {})) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf( |
|
not os.path.exists(SCRIPTS_DIR), "can't locate scripts directory" |
|
) |
|
class TestScripts(PsutilTestCase): |
|
"""Tests for scripts in the "scripts" directory.""" |
|
|
|
@staticmethod |
|
def assert_stdout(exe, *args, **kwargs): |
|
kwargs.setdefault("env", PYTHON_EXE_ENV) |
|
exe = '%s' % os.path.join(SCRIPTS_DIR, exe) |
|
cmd = [PYTHON_EXE, exe] |
|
for arg in args: |
|
cmd.append(arg) |
|
try: |
|
out = sh(cmd, **kwargs).strip() |
|
except RuntimeError as err: |
|
if 'AccessDenied' in str(err): |
|
return str(err) |
|
else: |
|
raise |
|
assert out, out |
|
return out |
|
|
|
@staticmethod |
|
def assert_syntax(exe): |
|
exe = os.path.join(SCRIPTS_DIR, exe) |
|
with open(exe, encoding="utf8") if PY3 else open(exe) as f: |
|
src = f.read() |
|
ast.parse(src) |
|
|
|
def test_coverage(self): |
|
|
|
meths = dir(self) |
|
for name in os.listdir(SCRIPTS_DIR): |
|
if name.endswith('.py'): |
|
if 'test_' + os.path.splitext(name)[0] not in meths: |
|
|
|
raise self.fail( |
|
'no test defined for %r script' |
|
% os.path.join(SCRIPTS_DIR, name) |
|
) |
|
|
|
@unittest.skipIf(not POSIX, "POSIX only") |
|
def test_executable(self): |
|
for root, dirs, files in os.walk(SCRIPTS_DIR): |
|
for file in files: |
|
if file.endswith('.py'): |
|
path = os.path.join(root, file) |
|
if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]: |
|
raise self.fail('%r is not executable' % path) |
|
|
|
def test_disk_usage(self): |
|
self.assert_stdout('disk_usage.py') |
|
|
|
def test_free(self): |
|
self.assert_stdout('free.py') |
|
|
|
def test_meminfo(self): |
|
self.assert_stdout('meminfo.py') |
|
|
|
def test_procinfo(self): |
|
self.assert_stdout('procinfo.py', str(os.getpid())) |
|
|
|
@unittest.skipIf(CI_TESTING and not psutil.users(), "no users") |
|
def test_who(self): |
|
self.assert_stdout('who.py') |
|
|
|
def test_ps(self): |
|
self.assert_stdout('ps.py') |
|
|
|
def test_pstree(self): |
|
self.assert_stdout('pstree.py') |
|
|
|
def test_netstat(self): |
|
self.assert_stdout('netstat.py') |
|
|
|
@unittest.skipIf(QEMU_USER, 'QEMU user not supported') |
|
def test_ifconfig(self): |
|
self.assert_stdout('ifconfig.py') |
|
|
|
@unittest.skipIf(not HAS_MEMORY_MAPS, "not supported") |
|
def test_pmap(self): |
|
self.assert_stdout('pmap.py', str(os.getpid())) |
|
|
|
def test_procsmem(self): |
|
if 'uss' not in psutil.Process().memory_full_info()._fields: |
|
raise unittest.SkipTest("not supported") |
|
self.assert_stdout('procsmem.py') |
|
|
|
def test_killall(self): |
|
self.assert_syntax('killall.py') |
|
|
|
def test_nettop(self): |
|
self.assert_syntax('nettop.py') |
|
|
|
def test_top(self): |
|
self.assert_syntax('top.py') |
|
|
|
def test_iotop(self): |
|
self.assert_syntax('iotop.py') |
|
|
|
def test_pidof(self): |
|
output = self.assert_stdout('pidof.py', psutil.Process().name()) |
|
self.assertIn(str(os.getpid()), output) |
|
|
|
@unittest.skipIf(not WINDOWS, "WINDOWS only") |
|
def test_winservices(self): |
|
self.assert_stdout('winservices.py') |
|
|
|
def test_cpu_distribution(self): |
|
self.assert_syntax('cpu_distribution.py') |
|
|
|
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported") |
|
def test_temperatures(self): |
|
if not psutil.sensors_temperatures(): |
|
raise unittest.SkipTest("no temperatures") |
|
self.assert_stdout('temperatures.py') |
|
|
|
@unittest.skipIf(not HAS_SENSORS_FANS, "not supported") |
|
def test_fans(self): |
|
if not psutil.sensors_fans(): |
|
raise unittest.SkipTest("no fans") |
|
self.assert_stdout('fans.py') |
|
|
|
@unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported") |
|
@unittest.skipIf(not HAS_BATTERY, "no battery") |
|
def test_battery(self): |
|
self.assert_stdout('battery.py') |
|
|
|
@unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported") |
|
@unittest.skipIf(not HAS_BATTERY, "no battery") |
|
def test_sensors(self): |
|
self.assert_stdout('sensors.py') |
|
|
|
|
|
if __name__ == '__main__': |
|
from psutil.tests.runner import run_from_name |
|
|
|
run_from_name(__file__) |
|
|