blob: 0990ec104965d777ec55358df7519da29da6ab21 [file] [edit]
#!/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.
"""Test various scripts."""
import ast
import os
import pathlib
import stat
import pytest
from psutil import LINUX
from psutil import POSIX
from psutil import WINDOWS
from . import CI_TESTING
from . import HAS_BATTERY
from . import HAS_PROC_MEMORY_FOOTPRINT
from . import HAS_PROC_MEMORY_MAPS
from . import HAS_SENSORS_BATTERY
from . import HAS_SENSORS_FANS
from . import HAS_SENSORS_TEMPERATURES
from . import PYTHON_EXE
from . import PYTHON_EXE_ENV
from . import ROOT_DIR
from . import PsutilTestCase
from . import import_module_by_path
from . import psutil
from . import sh
SCRIPTS_DIR = pathlib.Path(ROOT_DIR) / "scripts"
INTERNAL_SCRIPTS_DIR = SCRIPTS_DIR / "internal"
class ScriptsTestCase(PsutilTestCase):
scripts_dir = SCRIPTS_DIR
def assert_stdout(self, exe, *args):
"""Execute the script, make sure it doesn't crash and prints
something.
"""
exe = os.path.join(self.scripts_dir, exe)
env = PYTHON_EXE_ENV.copy()
env.pop("PSUTIL_DEBUG", None) # avoid spamming to stderr
cmd = [PYTHON_EXE, exe, *args]
try:
out = sh(cmd, env=env).strip()
except RuntimeError as err:
if 'AccessDenied' in str(err):
return str(err)
else:
raise
assert out, out
return out
def assert_syntax(self, exe):
"""Check script's syntax without executing it."""
exe = os.path.join(self.scripts_dir, exe)
with open(exe, encoding="utf8") as f:
src = f.read()
ast.parse(src)
# ===================================================================
# --- Tests scripts in scripts/ directory
# ===================================================================
@pytest.mark.skipif(
CI_TESTING and not os.path.exists(SCRIPTS_DIR),
reason="can't find scripts/ directory",
)
class TestExampleScripts(ScriptsTestCase):
def test_coverage(self):
# make sure all example scripts have a test method defined
meths = dir(self)
for name in os.listdir(SCRIPTS_DIR):
if name.endswith('.py') and not name.startswith("_"):
if 'test_' + os.path.splitext(name)[0] not in meths:
# self.assert_stdout(name)
return pytest.fail(
"no test defined for"
f" {os.path.join(SCRIPTS_DIR, name)!r} script"
)
@pytest.mark.skipif(not POSIX, reason="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]:
return pytest.fail(f"{path!r} is not executable")
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()))
@pytest.mark.skipif(CI_TESTING and not psutil.users(), reason="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')
def test_ifconfig(self):
self.assert_stdout('ifconfig.py')
@pytest.mark.skipif(not HAS_PROC_MEMORY_MAPS, reason="not supported")
def test_pmap(self):
self.assert_stdout('pmap.py', str(os.getpid()))
@pytest.mark.skipif(not HAS_PROC_MEMORY_FOOTPRINT, reason="not supported")
def test_procsmem(self):
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())
assert str(os.getpid()) in output
@pytest.mark.skipif(not WINDOWS, reason="WINDOWS only")
def test_winservices(self):
self.assert_stdout('winservices.py')
def test_cpu_distribution(self):
self.assert_syntax('cpu_distribution.py')
@pytest.mark.skipif(not HAS_SENSORS_TEMPERATURES, reason="not supported")
def test_temperatures(self):
if not psutil.sensors_temperatures():
return pytest.skip("no temperatures")
self.assert_stdout('temperatures.py')
@pytest.mark.skipif(not HAS_SENSORS_FANS, reason="not supported")
def test_fans(self):
if not psutil.sensors_fans():
return pytest.skip("no fans")
self.assert_stdout('fans.py')
@pytest.mark.skipif(not HAS_SENSORS_BATTERY, reason="not supported")
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
def test_battery(self):
self.assert_stdout('battery.py')
@pytest.mark.skipif(not HAS_SENSORS_BATTERY, reason="not supported")
@pytest.mark.skipif(not HAS_BATTERY, reason="no battery")
def test_sensors(self):
self.assert_stdout('sensors.py')
# ===================================================================
# --- Tests scripts in scripts/internal/ directory
# ===================================================================
@pytest.mark.skipif(
CI_TESTING and not os.path.exists(INTERNAL_SCRIPTS_DIR),
reason="can't find scripts/internal/ directory",
)
class TestInternalScripts(ScriptsTestCase):
scripts_dir = INTERNAL_SCRIPTS_DIR
@staticmethod
def ls():
for name in os.listdir(INTERNAL_SCRIPTS_DIR):
if name.endswith(".py"):
yield os.path.join(INTERNAL_SCRIPTS_DIR, name)
def test_syntax_all(self):
for path in self.ls():
with open(path, encoding="utf8") as f:
data = f.read()
ast.parse(data)
# don't care about other platforms, this is really just for myself
@pytest.mark.skipif(not LINUX, reason="not on LINUX")
@pytest.mark.skipif(CI_TESTING, reason="not on CI")
def test_import_all(self):
for path in self.ls():
try:
import_module_by_path(path)
except SystemExit:
pass
def test_print_api_speed(self):
self.assert_stdout("print_api_speed.py", "-t", "2")
def test_print_sysinfo(self):
self.assert_stdout("print_sysinfo.py")