| Viewing file:  test_testutils.py (14.28 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
#!/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 unittest
 
 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.tests import CI_TESTING
 from psutil.tests import COVERAGE
 from psutil.tests import HAS_CONNECTIONS_UNIX
 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 get_free_port
 from psutil.tests import is_namedtuple
 from psutil.tests import mock
 from psutil.tests import process_namespace
 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 serialrun
 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
 return 1
 
 queue = list(range(3))
 self.assertEqual(foo(), 1)
 self.assertEqual(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
 return 1
 
 queue = list(range(6))
 self.assertRaises(ZeroDivisionError, foo)
 self.assertEqual(sleep.call_count, 5)
 
 @mock.patch('time.sleep')
 def test_exception_arg(self, sleep):
 @retry(exception=ValueError, interval=1)
 def foo():
 raise TypeError
 
 self.assertRaises(TypeError, foo)
 self.assertEqual(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
 
 self.assertRaises(ZeroDivisionError, foo)
 self.assertEqual(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
 
 self.assertRaises(ZeroDivisionError, foo)
 self.assertEqual(sleep.call_count, 5)
 
 @mock.patch('time.sleep')
 def test_retries_and_timeout_args(self, sleep):
 self.assertRaises(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])):
 self.assertRaises(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])):
 self.assertRaises(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):
 ret = call_until(lambda: 1, "ret == 1")
 self.assertEqual(ret, 1)
 
 
 class TestFSTestUtils(PsutilTestCase):
 
 def test_open_text(self):
 with open_text(__file__) as f:
 self.assertEqual(f.mode, 'rt')
 
 def test_open_binary(self):
 with open_binary(__file__) as f:
 self.assertEqual(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 self.assertRaises(OSError):
 safe_rmpath(testfn)
 assert m.called
 
 def test_chdir(self):
 testfn = self.get_testfn()
 base = os.getcwd()
 os.mkdir(testfn)
 with chdir(testfn):
 self.assertEqual(os.getcwd(), os.path.join(base, testfn))
 self.assertEqual(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()
 self.assertNotEqual(child.pid, grandchild.pid)
 assert child.is_running()
 assert grandchild.is_running()
 children = psutil.Process().children()
 self.assertEqual(children, [child])
 children = psutil.Process().children(recursive=True)
 self.assertEqual(len(children), 2)
 self.assertIn(child, children)
 self.assertIn(grandchild, children)
 self.assertEqual(child.ppid(), os.getpid())
 self.assertEqual(grandchild.ppid(), child.pid)
 
 terminate(child)
 assert not child.is_running()
 assert grandchild.is_running()
 
 terminate(grandchild)
 assert not grandchild.is_running()
 
 @unittest.skipIf(not POSIX, "POSIX only")
 def test_spawn_zombie(self):
 parent, zombie = self.spawn_zombie()
 self.assertEqual(zombie.status(), psutil.STATUS_ZOMBIE)
 
 def test_terminate(self):
 # by subprocess.Popen
 p = self.spawn_testproc()
 terminate(p)
 self.assertProcessGone(p)
 terminate(p)
 # by psutil.Process
 p = psutil.Process(self.spawn_testproc().pid)
 terminate(p)
 self.assertProcessGone(p)
 terminate(p)
 # by psutil.Popen
 cmd = [PYTHON_EXE, "-c", "import time; time.sleep(60);"]
 p = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
 env=PYTHON_EXE_ENV)
 terminate(p)
 self.assertProcessGone(p)
 terminate(p)
 # by PID
 pid = self.spawn_testproc().pid
 terminate(pid)
 self.assertProcessGone(p)
 terminate(pid)
 # zombie
 if POSIX:
 parent, zombie = self.spawn_zombie()
 terminate(parent)
 terminate(zombie)
 self.assertProcessGone(parent)
 self.assertProcessGone(zombie)
 
 
 class TestNetUtils(PsutilTestCase):
 
 def bind_socket(self):
 port = get_free_port()
 with contextlib.closing(bind_socket(addr=('', port))) as s:
 self.assertEqual(s.getsockname()[1], port)
 
 @unittest.skipIf(not POSIX, "POSIX only")
 def test_bind_unix_socket(self):
 name = self.get_testfn()
 sock = bind_unix_socket(name)
 with contextlib.closing(sock):
 self.assertEqual(sock.family, socket.AF_UNIX)
 self.assertEqual(sock.type, socket.SOCK_STREAM)
 self.assertEqual(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):
 self.assertEqual(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.
 self.assertEqual(server.getsockname(), addr)
 self.assertEqual(client.getpeername(), addr)
 self.assertNotEqual(client.getsockname(), addr)
 
 @unittest.skipIf(not POSIX, "POSIX only")
 @unittest.skipIf(NETBSD or FREEBSD,
 "/var/run/log UNIX socket opened by default")
 def test_unix_socketpair(self):
 p = psutil.Process()
 num_fds = p.num_fds()
 assert not p.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)
 self.assertEqual(p.num_fds() - num_fds, 2)
 self.assertEqual(len(p.connections(kind='unix')), 2)
 self.assertEqual(server.getsockname(), name)
 self.assertEqual(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
 self.assertGreaterEqual(fams[socket.AF_INET], 2)
 if supports_ipv6():
 self.assertGreaterEqual(fams[socket.AF_INET6], 2)
 if POSIX and HAS_CONNECTIONS_UNIX:
 self.assertGreaterEqual(fams[socket.AF_UNIX], 2)
 self.assertGreaterEqual(types[socket.SOCK_STREAM], 2)
 self.assertGreaterEqual(types[socket.SOCK_DGRAM], 2)
 
 
 @serialrun
 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)
 self.assertEqual(cnt['cnt'], 26)
 
 def test_param_err(self):
 self.assertRaises(ValueError, self.execute, lambda: 0, times=0)
 self.assertRaises(ValueError, self.execute, lambda: 0, times=-1)
 self.assertRaises(ValueError, self.execute, lambda: 0, warmup_times=-1)
 self.assertRaises(ValueError, self.execute, lambda: 0, tolerance=-1)
 self.assertRaises(ValueError, self.execute, lambda: 0, retries=-1)
 
 @retry_on_failure()
 @unittest.skipIf(CI_TESTING, "skipped on CI")
 @unittest.skipIf(COVERAGE, "skipped during test coverage")
 def test_leak_mem(self):
 ls = []
 
 def fun(ls=ls):
 ls.append("x" * 24 * 1024)
 
 try:
 # will consume around 3M in total
 self.assertRaisesRegex(AssertionError, "extra-mem",
 self.execute, fun, times=50)
 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"
 self.assertRaisesRegex(AssertionError, "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)
 self.assertEqual(len(ls), times + 1)
 
 def test_execute_w_exc(self):
 def fun_1():
 1 / 0
 self.execute_w_exc(ZeroDivisionError, fun_1)
 with self.assertRaises(ZeroDivisionError):
 self.execute_w_exc(OSError, fun_1)
 
 def fun_2():
 pass
 with self.assertRaises(AssertionError):
 self.execute_w_exc(ZeroDivisionError, fun_2)
 
 
 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]
 self.assertEqual(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]
 self.assertEqual(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())
 
 
 if __name__ == '__main__':
 from psutil.tests.runner import run_from_name
 run_from_name(__file__)
 
 |