Bug 783727 - Part 4: Add psutil Python package; r=glandium
Version 0.6.1 obtained from https://psutil.googlecode.com/files/psutil-0.6.1.tar.gz
This commit is contained in:
200
python/psutil/test/_bsd.py
Normal file
200
python/psutil/test/_bsd.py
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: _bsd.py 1498 2012-07-24 21:41:28Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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.
|
||||
|
||||
"""BSD specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import unittest
|
||||
import subprocess
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3
|
||||
from test_psutil import DEVNULL
|
||||
from test_psutil import (reap_children, get_test_subprocess, sh, which,
|
||||
skipUnless)
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
TOLERANCE = 200 * 1024 # 200 KB
|
||||
MUSE_AVAILABLE = which('muse')
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
result = sh("sysctl " + cmdline)
|
||||
result = result[result.find(": ") + 2:]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
def muse(field):
|
||||
"""Thin wrapper around 'muse' cmdline utility."""
|
||||
out = sh('muse', stderr=DEVNULL)
|
||||
for line in out.split('\n'):
|
||||
if line.startswith(field):
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(line.split()[1])
|
||||
|
||||
|
||||
class BSDSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pid = get_test_subprocess().pid
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def assert_eq_w_tol(self, first, second, tolerance):
|
||||
difference = abs(first - second)
|
||||
if difference <= tolerance:
|
||||
return
|
||||
msg = '%r != %r within %r delta (%r difference)' \
|
||||
% (first, second, tolerance, difference)
|
||||
raise AssertionError(msg)
|
||||
|
||||
def test_BOOT_TIME(self):
|
||||
s = sysctl('sysctl kern.boottime')
|
||||
s = s[s.find(" sec = ") + 7:]
|
||||
s = s[:s.find(',')]
|
||||
btime = int(s)
|
||||
self.assertEqual(btime, psutil.BOOT_TIME)
|
||||
|
||||
def test_process_create_time(self):
|
||||
cmdline = "ps -o lstart -p %s" %self.pid
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0]
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
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))
|
||||
self.assertEqual(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)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
def test_memory_maps(self):
|
||||
out = sh('procstat -v %s' % self.pid)
|
||||
maps = psutil.Process(self.pid).get_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()
|
||||
self.assertEqual("%s-%s" % (start, stop), map.addr)
|
||||
self.assertEqual(int(res), map.rss)
|
||||
if not map.path.startswith('['):
|
||||
self.assertEqual(fields[10], map.path)
|
||||
|
||||
# --- virtual_memory(); tests against sysctl
|
||||
|
||||
def test_vmem_total(self):
|
||||
syst = sysctl("sysctl vm.stats.vm.v_page_count") * PAGESIZE
|
||||
self.assertEqual(psutil.virtual_memory().total, syst)
|
||||
|
||||
def test_vmem_active(self):
|
||||
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().active, syst, TOLERANCE)
|
||||
|
||||
def test_vmem_inactive(self):
|
||||
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().inactive, syst, TOLERANCE)
|
||||
|
||||
def test_vmem_wired(self):
|
||||
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().wired, syst, TOLERANCE)
|
||||
|
||||
def test_vmem_cached(self):
|
||||
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().cached, syst, TOLERANCE)
|
||||
|
||||
def test_vmem_free(self):
|
||||
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().free, syst, TOLERANCE)
|
||||
|
||||
def test_vmem_buffers(self):
|
||||
syst = sysctl("vfs.bufspace")
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().buffers, syst, TOLERANCE)
|
||||
|
||||
# --- virtual_memory(); tests against muse
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_total(self):
|
||||
num = muse('Total')
|
||||
self.assertEqual(psutil.virtual_memory().total, num)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_active(self):
|
||||
num = muse('Active')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().active, num, TOLERANCE)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_inactive(self):
|
||||
num = muse('Inactive')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().inactive, num, TOLERANCE)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_wired(self):
|
||||
num = muse('Wired')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().wired, num, TOLERANCE)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_cached(self):
|
||||
num = muse('Cache')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().cached, num, TOLERANCE)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_free(self):
|
||||
num = muse('Free')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().free, num, TOLERANCE)
|
||||
|
||||
@skipUnless(MUSE_AVAILABLE)
|
||||
def test_buffers(self):
|
||||
num = muse('Buffer')
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().buffers, num, TOLERANCE)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
122
python/psutil/test/_linux.py
Normal file
122
python/psutil/test/_linux.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: _linux.py 1498 2012-07-24 21:41:28Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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.
|
||||
|
||||
"""Linux specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
from __future__ import division
|
||||
import unittest
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
|
||||
from test_psutil import sh, get_test_subprocess
|
||||
from psutil._compat import PY3
|
||||
import psutil
|
||||
|
||||
|
||||
TOLERANCE = 200 * 1024 # 200 KB
|
||||
|
||||
|
||||
class LinuxSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def assert_eq_w_tol(self, first, second, tolerance):
|
||||
difference = abs(first - second)
|
||||
if difference <= tolerance:
|
||||
return
|
||||
msg = '%r != %r within %r delta (%r difference)' \
|
||||
% (first, second, tolerance, difference)
|
||||
raise AssertionError(msg)
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -P -B 1 "%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, used, free = int(total), int(used), int(free)
|
||||
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)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
def test_memory_maps(self):
|
||||
sproc = get_test_subprocess()
|
||||
time.sleep(1)
|
||||
p = psutil.Process(sproc.pid)
|
||||
maps = p.get_memory_maps(grouped=False)
|
||||
pmap = sh('pmap -x %s' % p.pid).split('\n')
|
||||
del pmap[0]; del pmap[0] # get rid of header
|
||||
while maps and pmap:
|
||||
this = maps.pop(0)
|
||||
other = pmap.pop(0)
|
||||
addr, _, rss, dirty, mode, path = other.split(None, 5)
|
||||
if not path.startswith('[') and not path.endswith(']'):
|
||||
self.assertEqual(path, os.path.basename(this.path))
|
||||
self.assertEqual(int(rss) * 1024, this.rss)
|
||||
# test only rwx chars, ignore 's' and 'p'
|
||||
self.assertEqual(mode[:3], this.perms[:3])
|
||||
|
||||
def test_vmem_total(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
total = int(lines[0].split()[1]) * 1024
|
||||
self.assertEqual(total, psutil.virtual_memory().total)
|
||||
|
||||
def test_vmem_used(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
used = int(lines[0].split()[2]) * 1024
|
||||
self.assert_eq_w_tol(used, psutil.virtual_memory().used, TOLERANCE)
|
||||
|
||||
def test_vmem_free(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
free = int(lines[0].split()[3]) * 1024
|
||||
self.assert_eq_w_tol(free, psutil.virtual_memory().free, TOLERANCE)
|
||||
|
||||
def test_vmem_buffers(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
buffers = int(lines[0].split()[5]) * 1024
|
||||
self.assert_eq_w_tol(buffers, psutil.virtual_memory().buffers, TOLERANCE)
|
||||
|
||||
def test_vmem_cached(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
cached = int(lines[0].split()[6]) * 1024
|
||||
self.assert_eq_w_tol(cached, psutil.virtual_memory().cached, TOLERANCE)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
total = int(lines[2].split()[1]) * 1024
|
||||
self.assertEqual(total, psutil.swap_memory().total)
|
||||
|
||||
def test_swapmem_used(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
used = int(lines[2].split()[2]) * 1024
|
||||
self.assert_eq_w_tol(used, psutil.swap_memory().used, TOLERANCE)
|
||||
|
||||
def test_swapmem_free(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
free = int(lines[2].split()[3]) * 1024
|
||||
self.assert_eq_w_tol(free, psutil.swap_memory().free, TOLERANCE)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
154
python/psutil/test/_osx.py
Normal file
154
python/psutil/test/_osx.py
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: _osx.py 1498 2012-07-24 21:41:28Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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.
|
||||
|
||||
"""OSX specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import unittest
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3
|
||||
from test_psutil import reap_children, get_test_subprocess, sh
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
TOLERANCE = 200 * 1024 # 200 KB
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0].strip().split()[1]
|
||||
if PY3:
|
||||
result = str(result, sys.stdout.encoding)
|
||||
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('\d+', line).group(0)) * PAGESIZE
|
||||
|
||||
|
||||
class OSXSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pid = get_test_subprocess().pid
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def assert_eq_w_tol(self, first, second, tolerance):
|
||||
difference = abs(first - second)
|
||||
if difference <= tolerance:
|
||||
return
|
||||
msg = '%r != %r within %r delta (%r difference)' \
|
||||
% (first, second, tolerance, difference)
|
||||
raise AssertionError(msg)
|
||||
|
||||
def test_process_create_time(self):
|
||||
cmdline = "ps -o lstart -p %s" %self.pid
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0]
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
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))
|
||||
self.assertEqual(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)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.free, free)
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.used, used)
|
||||
|
||||
# --- virtual mem
|
||||
|
||||
def test_vmem_total(self):
|
||||
sysctl_hwphymem = sysctl('sysctl hw.memsize')
|
||||
self.assertEqual(sysctl_hwphymem, psutil.TOTAL_PHYMEM)
|
||||
|
||||
def test_vmem_free(self):
|
||||
num = vm_stat("free")
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().free, num, TOLERANCE)
|
||||
|
||||
def test_vmem_active(self):
|
||||
num = vm_stat("active")
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().active, num, TOLERANCE)
|
||||
|
||||
def test_vmem_inactive(self):
|
||||
num = vm_stat("inactive")
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().inactive, num, TOLERANCE)
|
||||
|
||||
def test_vmem_wired(self):
|
||||
num = vm_stat("wired")
|
||||
self.assert_eq_w_tol(psutil.virtual_memory().wired, num, TOLERANCE)
|
||||
|
||||
# --- swap mem
|
||||
|
||||
def test_swapmem_sin(self):
|
||||
num = vm_stat("Pageins")
|
||||
self.assertEqual(psutil.swap_memory().sin, num)
|
||||
|
||||
def test_swapmem_sout(self):
|
||||
num = vm_stat("Pageouts")
|
||||
self.assertEqual(psutil.swap_memory().sout, num)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
tot1 = psutil.swap_memory().total
|
||||
tot2 = 0
|
||||
# OSX uses multiple cache files:
|
||||
# http://en.wikipedia.org/wiki/Paging#OS_X
|
||||
for name in os.listdir("/var/vm/"):
|
||||
file = os.path.join("/var/vm", name)
|
||||
if os.path.isfile(file):
|
||||
tot2 += os.path.getsize(file)
|
||||
self.assertEqual(tot1, tot2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
183
python/psutil/test/_posix.py
Executable file
183
python/psutil/test/_posix.py
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: _posix.py 1386 2012-06-27 15:44:36Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import unittest
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import datetime
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3
|
||||
from test_psutil import (get_test_subprocess, reap_children, PYTHON, LINUX, OSX,
|
||||
BSD, ignore_access_denied, sh, skipIf)
|
||||
|
||||
|
||||
def ps(cmd):
|
||||
"""Expects a ps command with a -o argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
if not LINUX:
|
||||
cmd = cmd.replace(" --no-headers ", " ")
|
||||
p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
if not LINUX:
|
||||
output = output.split('\n')[1]
|
||||
try:
|
||||
return int(output)
|
||||
except ValueError:
|
||||
return output
|
||||
|
||||
|
||||
class PosixSpecificTestCase(unittest.TestCase):
|
||||
"""Compare psutil results against 'ps' command line utility."""
|
||||
|
||||
# for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps
|
||||
|
||||
def setUp(self):
|
||||
self.pid = get_test_subprocess([PYTHON, "-E", "-O"],
|
||||
stdin=subprocess.PIPE).pid
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def test_process_parent_pid(self):
|
||||
ppid_ps = ps("ps --no-headers -o ppid -p %s" %self.pid)
|
||||
ppid_psutil = psutil.Process(self.pid).ppid
|
||||
self.assertEqual(ppid_ps, ppid_psutil)
|
||||
|
||||
def test_process_uid(self):
|
||||
uid_ps = ps("ps --no-headers -o uid -p %s" %self.pid)
|
||||
uid_psutil = psutil.Process(self.pid).uids.real
|
||||
self.assertEqual(uid_ps, uid_psutil)
|
||||
|
||||
def test_process_gid(self):
|
||||
gid_ps = ps("ps --no-headers -o rgid -p %s" %self.pid)
|
||||
gid_psutil = psutil.Process(self.pid).gids.real
|
||||
self.assertEqual(gid_ps, gid_psutil)
|
||||
|
||||
def test_process_username(self):
|
||||
username_ps = ps("ps --no-headers -o user -p %s" %self.pid)
|
||||
username_psutil = psutil.Process(self.pid).username
|
||||
self.assertEqual(username_ps, username_psutil)
|
||||
|
||||
@ignore_access_denied
|
||||
def test_process_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("ps --no-headers -o rss -p %s" %self.pid)
|
||||
rss_psutil = psutil.Process(self.pid).get_memory_info()[0] / 1024
|
||||
self.assertEqual(rss_ps, rss_psutil)
|
||||
|
||||
@ignore_access_denied
|
||||
def test_process_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("ps --no-headers -o vsz -p %s" %self.pid)
|
||||
vsz_psutil = psutil.Process(self.pid).get_memory_info()[1] / 1024
|
||||
self.assertEqual(vsz_ps, vsz_psutil)
|
||||
|
||||
def test_process_name(self):
|
||||
# use command + arg since "comm" keyword not supported on all platforms
|
||||
name_ps = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
|
||||
# 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()
|
||||
self.assertEqual(name_ps, name_psutil)
|
||||
|
||||
@skipIf(OSX or BSD)
|
||||
def test_process_create_time(self):
|
||||
time_ps = ps("ps --no-headers -o start -p %s" %self.pid).split(' ')[0]
|
||||
time_psutil = psutil.Process(self.pid).create_time
|
||||
time_psutil = datetime.datetime.fromtimestamp(
|
||||
time_psutil).strftime("%H:%M:%S")
|
||||
self.assertEqual(time_ps, time_psutil)
|
||||
|
||||
def test_process_exe(self):
|
||||
ps_pathname = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
|
||||
psutil_pathname = psutil.Process(self.pid).exe
|
||||
try:
|
||||
self.assertEqual(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)]
|
||||
self.assertEqual(ps_pathname, adjusted_ps_pathname)
|
||||
|
||||
def test_process_cmdline(self):
|
||||
ps_cmdline = ps("ps --no-headers -o command -p %s" %self.pid)
|
||||
psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline)
|
||||
self.assertEqual(ps_cmdline, psutil_cmdline)
|
||||
|
||||
def test_get_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
p = get_test_subprocess(["ps", "ax", "-o", "pid"], stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
output = output.replace('PID', '')
|
||||
p.wait()
|
||||
pids_ps = []
|
||||
for pid in output.split('\n'):
|
||||
if pid:
|
||||
pids_ps.append(int(pid.strip()))
|
||||
# remove ps subprocess pid which is supposed to be dead in meantime
|
||||
pids_ps.remove(p.pid)
|
||||
pids_psutil = psutil.get_pid_list()
|
||||
pids_ps.sort()
|
||||
pids_psutil.sort()
|
||||
|
||||
# on OSX ps doesn't show pid 0
|
||||
if OSX and 0 not in pids_ps:
|
||||
pids_ps.insert(0, 0)
|
||||
|
||||
if pids_ps != pids_psutil:
|
||||
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]
|
||||
self.fail("difference: " + str(difference))
|
||||
|
||||
def test_nic_names(self):
|
||||
p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
for nic in psutil.network_io_counters(pernic=True).keys():
|
||||
for line in output.split():
|
||||
if line.startswith(nic):
|
||||
break
|
||||
else:
|
||||
self.fail("couldn't find %s nic in 'ifconfig -a' output" % nic)
|
||||
|
||||
def test_get_users(self):
|
||||
out = sh("who")
|
||||
lines = out.split('\n')
|
||||
users = [x.split()[0] for x in lines]
|
||||
self.assertEqual(len(users), len(psutil.get_users()))
|
||||
terminals = [x.split()[1] for x in lines]
|
||||
for u in psutil.get_users():
|
||||
self.assertTrue(u.name in users, u.name)
|
||||
self.assertTrue(u.terminal in terminals, u.terminal)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
368
python/psutil/test/_windows.py
Normal file
368
python/psutil/test/_windows.py
Normal file
@@ -0,0 +1,368 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: _windows.py 1453 2012-07-13 19:55:11Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import platform
|
||||
import signal
|
||||
import time
|
||||
import warnings
|
||||
import atexit
|
||||
import sys
|
||||
import subprocess
|
||||
import errno
|
||||
import traceback
|
||||
|
||||
import psutil
|
||||
import _psutil_mswindows
|
||||
from psutil._compat import PY3, callable, long
|
||||
from test_psutil import reap_children, get_test_subprocess, wait_for_pid, warn
|
||||
try:
|
||||
import wmi
|
||||
except ImportError:
|
||||
err = sys.exc_info()[1]
|
||||
atexit.register(warn, "Couldn't run wmi tests: %s" % str(err))
|
||||
wmi = None
|
||||
try:
|
||||
import win32api
|
||||
import win32con
|
||||
except ImportError:
|
||||
err = sys.exc_info()[1]
|
||||
atexit.register(warn, "Couldn't run pywin32 tests: %s" % str(err))
|
||||
win32api = None
|
||||
|
||||
|
||||
|
||||
class WindowsSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
sproc = get_test_subprocess()
|
||||
wait_for_pid(sproc.pid)
|
||||
self.pid = sproc.pid
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def test_issue_24(self):
|
||||
p = psutil.Process(0)
|
||||
self.assertRaises(psutil.AccessDenied, p.kill)
|
||||
|
||||
def test_special_pid(self):
|
||||
p = psutil.Process(4)
|
||||
self.assertEqual(p.name, 'System')
|
||||
# use __str__ to access all common Process properties to check
|
||||
# that nothing strange happens
|
||||
str(p)
|
||||
p.username
|
||||
self.assertTrue(p.create_time >= 0.0)
|
||||
try:
|
||||
rss, vms = p.get_memory_info()
|
||||
except psutil.AccessDenied:
|
||||
# expected on Windows Vista and Windows 7
|
||||
if not platform.uname()[1] in ('vista', 'win-7', 'win7'):
|
||||
raise
|
||||
else:
|
||||
self.assertTrue(rss > 0)
|
||||
|
||||
def test_signal(self):
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertRaises(ValueError, p.send_signal, signal.SIGINT)
|
||||
|
||||
def test_nic_names(self):
|
||||
p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE)
|
||||
out = p.communicate()[0]
|
||||
if PY3:
|
||||
out = str(out, sys.stdout.encoding)
|
||||
nics = psutil.network_io_counters(pernic=True).keys()
|
||||
for nic in nics:
|
||||
if "pseudo-interface" in nic.replace(' ', '-').lower():
|
||||
continue
|
||||
if nic not in out:
|
||||
self.fail("%r nic wasn't found in 'ipconfig /all' output" % nic)
|
||||
|
||||
def test_exe(self):
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
self.assertEqual(os.path.basename(p.exe), p.name)
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
if wmi is not None:
|
||||
|
||||
# --- Process class tests
|
||||
|
||||
def test_process_name(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(p.name, w.Caption)
|
||||
|
||||
def test_process_exe(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(p.exe, w.ExecutablePath)
|
||||
|
||||
def test_process_cmdline(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(' '.join(p.cmdline), w.CommandLine.replace('"', ''))
|
||||
|
||||
def test_process_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)
|
||||
self.assertEqual(p.username, username)
|
||||
|
||||
def test_process_rss_memory(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
rss = p.get_memory_info().rss
|
||||
self.assertEqual(rss, int(w.WorkingSetSize))
|
||||
|
||||
def test_process_vms_memory(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
vms = p.get_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 != wmi_usage) and (vms != wmi_usage * 1024):
|
||||
self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
|
||||
|
||||
def test_process_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))
|
||||
self.assertEqual(wmic_create, psutil_create)
|
||||
|
||||
|
||||
# --- psutil namespace functions and constants tests
|
||||
|
||||
def test_NUM_CPUS(self):
|
||||
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
self.assertEqual(num_cpus, psutil.NUM_CPUS)
|
||||
|
||||
def test_TOTAL_PHYMEM(self):
|
||||
w = wmi.WMI().Win32_ComputerSystem()[0]
|
||||
self.assertEqual(int(w.TotalPhysicalMemory), psutil.TOTAL_PHYMEM)
|
||||
|
||||
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))
|
||||
# XXX - ? no actual test here
|
||||
|
||||
def test_get_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 = [x.ProcessId for x in w]
|
||||
wmi_pids.sort()
|
||||
psutil_pids = psutil.get_pid_list()
|
||||
psutil_pids.sort()
|
||||
if wmi_pids != psutil_pids:
|
||||
difference = filter(lambda x:x not in wmi_pids, psutil_pids) + \
|
||||
filter(lambda x:x not in psutil_pids, wmi_pids)
|
||||
self.fail("difference: " + str(difference))
|
||||
|
||||
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
|
||||
try:
|
||||
usage = psutil.disk_usage(ps_part.mountpoint)
|
||||
except OSError:
|
||||
err = sys.exc_info()[1]
|
||||
if err.errno == errno.ENOENT:
|
||||
# usually this is the floppy
|
||||
break
|
||||
else:
|
||||
raise
|
||||
self.assertEqual(usage.total, int(wmi_part.Size))
|
||||
wmi_free = int(wmi_part.FreeSpace)
|
||||
self.assertEqual(usage.free, wmi_free)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, wmi=%s" % usage.free, wmi_free)
|
||||
break
|
||||
else:
|
||||
self.fail("can't find partition %s" % repr(ps_part))
|
||||
|
||||
if win32api is not None:
|
||||
|
||||
def test_get_num_handles(self):
|
||||
p = psutil.Process(os.getpid())
|
||||
before = p.get_num_handles()
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, os.getpid())
|
||||
after = p.get_num_handles()
|
||||
self.assertEqual(after, before+1)
|
||||
win32api.CloseHandle(handle)
|
||||
self.assertEqual(p.get_num_handles(), before)
|
||||
|
||||
def test_get_num_handles_2(self):
|
||||
# Note: this fails from time to time; I'm keen on thinking
|
||||
# it doesn't mean something is broken
|
||||
def call(p, attr):
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
ret = attr()
|
||||
else:
|
||||
ret = attr
|
||||
|
||||
p = psutil.Process(self.pid)
|
||||
attrs = []
|
||||
failures = []
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith('_') \
|
||||
or name.startswith('set_') \
|
||||
or name in ('terminate', 'kill', 'suspend', 'resume', 'nice',
|
||||
'send_signal', 'wait', 'get_children', 'as_dict'):
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
call(p, name)
|
||||
num1 = p.get_num_handles()
|
||||
call(p, name)
|
||||
num2 = p.get_num_handles()
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
else:
|
||||
if num2 > num1:
|
||||
fail = "failure while processing Process.%s method " \
|
||||
"(before=%s, after=%s)" % (name, num1, num2)
|
||||
failures.append(fail)
|
||||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
|
||||
import _psutil_mswindows
|
||||
from psutil._psmswindows import ACCESS_DENIED_SET
|
||||
|
||||
def wrap_exceptions(callable):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return callable(self, *args, **kwargs)
|
||||
except OSError:
|
||||
err = sys.exc_info()[1]
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
raise psutil.AccessDenied(None, None)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise psutil.NoSuchProcess(None, None)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
class TestDualProcessImplementation(unittest.TestCase):
|
||||
fun_names = [
|
||||
# function name tolerance
|
||||
('get_process_cpu_times', 0.2),
|
||||
('get_process_create_time', 0.5),
|
||||
('get_process_num_handles', 1), # 1 because impl #1 opens a handle
|
||||
('get_process_io_counters', 0),
|
||||
('get_process_memory_info', 1024), # KB
|
||||
]
|
||||
|
||||
def test_compare_values(self):
|
||||
# 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:
|
||||
# http://code.google.com/p/psutil/issues/detail?id=304
|
||||
def assert_ge_0(obj):
|
||||
if isinstance(obj, tuple):
|
||||
for value in obj:
|
||||
assert value >= 0, value
|
||||
elif isinstance(obj, (int, long, float)):
|
||||
assert obj >= 0, obj
|
||||
else:
|
||||
assert 0 # case not handled which needs to be fixed
|
||||
|
||||
def compare_with_tolerance(ret1, ret2, tolerance):
|
||||
if ret1 == ret2:
|
||||
return
|
||||
else:
|
||||
if isinstance(ret2, (int, long, float)):
|
||||
diff = abs(ret1 - ret2)
|
||||
assert diff <= tolerance, diff
|
||||
elif isinstance(ret2, tuple):
|
||||
for a, b in zip(ret1, ret2):
|
||||
diff = abs(a - b)
|
||||
assert diff <= tolerance, diff
|
||||
|
||||
failures = []
|
||||
for name, tolerance in self.fun_names:
|
||||
meth1 = wrap_exceptions(getattr(_psutil_mswindows, name))
|
||||
meth2 = wrap_exceptions(getattr(_psutil_mswindows, name + '_2'))
|
||||
for p in psutil.process_iter():
|
||||
#
|
||||
try:
|
||||
ret1 = meth1(p.pid)
|
||||
except psutil.NoSuchProcess:
|
||||
continue
|
||||
except psutil.AccessDenied:
|
||||
ret1 = None
|
||||
#
|
||||
try:
|
||||
ret2 = meth2(p.pid)
|
||||
except psutil.NoSuchProcess:
|
||||
# this is supposed to fail only in case of zombie process
|
||||
# never for permission error
|
||||
continue
|
||||
|
||||
# compare values
|
||||
try:
|
||||
if ret1 is None:
|
||||
assert_ge_0(ret2)
|
||||
else:
|
||||
compare_with_tolerance(ret1, ret2, tolerance)
|
||||
assert_ge_0(ret1)
|
||||
assert_ge_0(ret2)
|
||||
except AssertionError:
|
||||
err = sys.exc_info()[1]
|
||||
trace = traceback.format_exc()
|
||||
msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' \
|
||||
% (trace, p.pid, name, ret1, ret2)
|
||||
failures.append(msg)
|
||||
break
|
||||
if failures:
|
||||
self.fail('\n\n'.join(failures))
|
||||
|
||||
def test_zombies(self):
|
||||
# test that NPS is raised by the 2nd implementation in case a
|
||||
# process no longer exists
|
||||
ZOMBIE_PID = max(psutil.get_pid_list()) + 5000
|
||||
for name, _ in self.fun_names:
|
||||
meth = wrap_exceptions(getattr(_psutil_mswindows, name))
|
||||
self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase))
|
||||
test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
325
python/psutil/test/test_memory_leaks.py
Normal file
325
python/psutil/test/test_memory_leaks.py
Normal file
@@ -0,0 +1,325 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: test_memory_leaks.py 1499 2012-07-25 12:42:31Z g.rodola $
|
||||
#
|
||||
# Copyright (c) 2009, Jay Loden, 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.
|
||||
|
||||
"""
|
||||
A test script which attempts to detect memory leaks by calling C
|
||||
functions many times and compare process memory usage before and
|
||||
after the calls. It might produce false positives.
|
||||
"""
|
||||
|
||||
import os
|
||||
import gc
|
||||
import unittest
|
||||
import time
|
||||
import socket
|
||||
import threading
|
||||
import types
|
||||
|
||||
import psutil
|
||||
import psutil._common
|
||||
from psutil._compat import PY3, callable, xrange
|
||||
from test_psutil import POSIX, LINUX, WINDOWS, OSX, BSD, TESTFN
|
||||
from test_psutil import (reap_children, skipUnless, skipIf, supports_ipv6,
|
||||
safe_remove, get_test_subprocess)
|
||||
|
||||
# disable cache for Process class properties
|
||||
psutil._common.cached_property.enabled = False
|
||||
|
||||
LOOPS = 1000
|
||||
TOLERANCE = 4096
|
||||
|
||||
|
||||
class Base(unittest.TestCase):
|
||||
|
||||
proc = psutil.Process(os.getpid())
|
||||
|
||||
def execute(self, function, *args, **kwargs):
|
||||
def call_many_times():
|
||||
for x in xrange(LOOPS - 1):
|
||||
self.call(function, *args, **kwargs)
|
||||
del x
|
||||
gc.collect()
|
||||
return self.get_mem()
|
||||
|
||||
self.call(function, *args, **kwargs)
|
||||
self.assertEqual(gc.garbage, [])
|
||||
self.assertEqual(threading.active_count(), 1)
|
||||
|
||||
# RSS comparison
|
||||
# step 1
|
||||
rss1 = call_many_times()
|
||||
# step 2
|
||||
rss2 = call_many_times()
|
||||
|
||||
difference = rss2 - rss1
|
||||
if difference > TOLERANCE:
|
||||
# This doesn't necessarily mean we have a leak yet.
|
||||
# At this point we assume that after having called the
|
||||
# function so many times the memory usage is stabilized
|
||||
# and if there are no leaks it should not increase any
|
||||
# more.
|
||||
# Let's keep calling fun for 3 more seconds and fail if
|
||||
# we notice any difference.
|
||||
stop_at = time.time() + 3
|
||||
while 1:
|
||||
self.call(function, *args, **kwargs)
|
||||
if time.time() >= stop_at:
|
||||
break
|
||||
del stop_at
|
||||
gc.collect()
|
||||
rss3 = self.get_mem()
|
||||
difference = rss3 - rss2
|
||||
if rss3 > rss2:
|
||||
self.fail("rss2=%s, rss3=%s, difference=%s" \
|
||||
% (rss2, rss3, difference))
|
||||
|
||||
def get_mem(self):
|
||||
return psutil.Process(os.getpid()).get_memory_info()[0]
|
||||
|
||||
def call(self, *args, **kwargs):
|
||||
raise NotImplementedError("must be implemented in subclass")
|
||||
|
||||
|
||||
class TestProcessObjectLeaks(Base):
|
||||
"""Test leaks of Process class methods and properties"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Base.__init__(self, *args, **kwargs)
|
||||
# skip tests which are not supported by Process API
|
||||
supported_attrs = dir(psutil.Process)
|
||||
for attr in [x for x in dir(self) if x.startswith('test')]:
|
||||
if attr[5:] not in supported_attrs:
|
||||
meth = getattr(self, attr)
|
||||
@skipIf(True)
|
||||
def test_(self):
|
||||
pass
|
||||
setattr(self, attr, types.MethodType(test_, self))
|
||||
|
||||
def setUp(self):
|
||||
gc.collect()
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
try:
|
||||
obj = getattr(self.proc, function)
|
||||
if callable(obj):
|
||||
obj(*args, **kwargs)
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
def test_name(self):
|
||||
self.execute('name')
|
||||
|
||||
def test_cmdline(self):
|
||||
self.execute('cmdline')
|
||||
|
||||
def test_exe(self):
|
||||
self.execute('exe')
|
||||
|
||||
def test_ppid(self):
|
||||
self.execute('ppid')
|
||||
|
||||
def test_uids(self):
|
||||
self.execute('uids')
|
||||
|
||||
def test_gids(self):
|
||||
self.execute('gids')
|
||||
|
||||
def test_status(self):
|
||||
self.execute('status')
|
||||
|
||||
def test_get_nice(self):
|
||||
self.execute('get_nice')
|
||||
|
||||
def test_set_nice(self):
|
||||
niceness = psutil.Process(os.getpid()).get_nice()
|
||||
self.execute('set_nice', niceness)
|
||||
|
||||
def test_get_io_counters(self):
|
||||
self.execute('get_io_counters')
|
||||
|
||||
def test_get_ionice(self):
|
||||
self.execute('get_ionice')
|
||||
|
||||
def test_set_ionice(self):
|
||||
self.execute('set_ionice', psutil.IOPRIO_CLASS_NONE)
|
||||
|
||||
def test_username(self):
|
||||
self.execute('username')
|
||||
|
||||
def test_create_time(self):
|
||||
self.execute('create_time')
|
||||
|
||||
def test_get_num_threads(self):
|
||||
self.execute('get_num_threads')
|
||||
|
||||
def test_get_num_handles(self):
|
||||
self.execute('get_num_handles')
|
||||
|
||||
def test_get_num_fds(self):
|
||||
self.execute('get_num_fds')
|
||||
|
||||
def test_get_threads(self):
|
||||
self.execute('get_threads')
|
||||
|
||||
def test_get_cpu_times(self):
|
||||
self.execute('get_cpu_times')
|
||||
|
||||
def test_get_memory_info(self):
|
||||
self.execute('get_memory_info')
|
||||
|
||||
def test_get_ext_memory_info(self):
|
||||
self.execute('get_ext_memory_info')
|
||||
|
||||
def test_terminal(self):
|
||||
self.execute('terminal')
|
||||
|
||||
@skipUnless(WINDOWS)
|
||||
def test_resume(self):
|
||||
self.execute('resume')
|
||||
|
||||
def test_getcwd(self):
|
||||
self.execute('getcwd')
|
||||
|
||||
def test_get_cpu_affinity(self):
|
||||
self.execute('get_cpu_affinity')
|
||||
|
||||
def test_set_cpu_affinity(self):
|
||||
affinity = psutil.Process(os.getpid()).get_cpu_affinity()
|
||||
self.execute('set_cpu_affinity', affinity)
|
||||
|
||||
def test_get_open_files(self):
|
||||
safe_remove(TESTFN) # needed after UNIX socket test has run
|
||||
f = open(TESTFN, 'w')
|
||||
try:
|
||||
self.execute('get_open_files')
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
# OSX implementation is unbelievably slow
|
||||
@skipIf(OSX)
|
||||
def test_get_memory_maps(self):
|
||||
self.execute('get_memory_maps')
|
||||
|
||||
# Linux implementation is pure python so since it's slow we skip it
|
||||
@skipIf(LINUX)
|
||||
def test_get_connections(self):
|
||||
def create_socket(family, type):
|
||||
sock = socket.socket(family, type)
|
||||
sock.bind(('', 0))
|
||||
if type == socket.SOCK_STREAM:
|
||||
sock.listen(1)
|
||||
return sock
|
||||
|
||||
socks = []
|
||||
socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM))
|
||||
socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM))
|
||||
if supports_ipv6():
|
||||
socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM))
|
||||
socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM))
|
||||
if hasattr(socket, 'AF_UNIX'):
|
||||
safe_remove(TESTFN)
|
||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
s.bind(TESTFN)
|
||||
s.listen(1)
|
||||
socks.append(s)
|
||||
try:
|
||||
self.execute('get_connections', kind='all')
|
||||
finally:
|
||||
for s in socks:
|
||||
s.close()
|
||||
|
||||
|
||||
p = get_test_subprocess()
|
||||
DEAD_PROC = psutil.Process(p.pid)
|
||||
DEAD_PROC.kill()
|
||||
DEAD_PROC.wait()
|
||||
del p
|
||||
|
||||
class TestProcessObjectLeaksZombie(TestProcessObjectLeaks):
|
||||
"""Same as above but looks for leaks occurring when dealing with
|
||||
zombie processes raising NoSuchProcess exception.
|
||||
"""
|
||||
proc = DEAD_PROC
|
||||
|
||||
if not POSIX:
|
||||
def test_kill(self):
|
||||
self.execute('kill')
|
||||
|
||||
def test_terminate(self):
|
||||
self.execute('terminate')
|
||||
|
||||
def test_suspend(self):
|
||||
self.execute('suspend')
|
||||
|
||||
def test_resume(self):
|
||||
self.execute('resume')
|
||||
|
||||
def test_wait(self):
|
||||
self.execute('wait')
|
||||
|
||||
|
||||
class TestModuleFunctionsLeaks(Base):
|
||||
"""Test leaks of psutil module functions."""
|
||||
|
||||
def setUp(self):
|
||||
gc.collect()
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
obj = getattr(psutil, function)
|
||||
if callable(obj):
|
||||
retvalue = obj(*args, **kwargs)
|
||||
|
||||
@skipIf(POSIX)
|
||||
def test_pid_exists(self):
|
||||
self.execute('pid_exists', os.getpid())
|
||||
|
||||
def test_virtual_memory(self):
|
||||
self.execute('virtual_memory')
|
||||
|
||||
def test_swap_memory(self):
|
||||
self.execute('swap_memory')
|
||||
|
||||
def test_cpu_times(self):
|
||||
self.execute('cpu_times')
|
||||
|
||||
def test_per_cpu_times(self):
|
||||
self.execute('cpu_times', percpu=True)
|
||||
|
||||
@skipUnless(WINDOWS)
|
||||
def test_disk_usage(self):
|
||||
self.execute('disk_usage', '.')
|
||||
|
||||
def test_disk_partitions(self):
|
||||
self.execute('disk_partitions')
|
||||
|
||||
def test_network_io_counters(self):
|
||||
self.execute('network_io_counters')
|
||||
|
||||
def test_disk_io_counters(self):
|
||||
self.execute('disk_io_counters')
|
||||
|
||||
# XXX - on Windows this produces a false positive
|
||||
@skipIf(WINDOWS)
|
||||
def test_get_users(self):
|
||||
self.execute('get_users')
|
||||
|
||||
|
||||
def test_main():
|
||||
test_suite = unittest.TestSuite()
|
||||
tests = [TestProcessObjectLeaksZombie,
|
||||
TestProcessObjectLeaks,
|
||||
TestModuleFunctionsLeaks,]
|
||||
for test in tests:
|
||||
test_suite.addTest(unittest.makeSuite(test))
|
||||
unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_main()
|
||||
1946
python/psutil/test/test_psutil.py
Normal file
1946
python/psutil/test/test_psutil.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user