comparison planemo/lib/python3.7/site-packages/psutil/tests/test_memleaks.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 #!/usr/bin/env python3
2
3 # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """
8 Tests for detecting function memory leaks (typically the ones
9 implemented in C). It does so by calling a function many times and
10 checking whether process memory usage keeps increasing between
11 calls or over time.
12 Note that this may produce false positives (especially on Windows
13 for some reason).
14 PyPy appears to be completely unstable for this framework, probably
15 because of how its JIT handles memory, so tests are skipped.
16 """
17
18 from __future__ import print_function
19 import functools
20 import os
21
22 import psutil
23 import psutil._common
24 from psutil import LINUX
25 from psutil import MACOS
26 from psutil import OPENBSD
27 from psutil import POSIX
28 from psutil import SUNOS
29 from psutil import WINDOWS
30 from psutil._compat import ProcessLookupError
31 from psutil._compat import super
32 from psutil.tests import create_sockets
33 from psutil.tests import get_testfn
34 from psutil.tests import HAS_CPU_AFFINITY
35 from psutil.tests import HAS_CPU_FREQ
36 from psutil.tests import HAS_ENVIRON
37 from psutil.tests import HAS_IONICE
38 from psutil.tests import HAS_MEMORY_MAPS
39 from psutil.tests import HAS_NET_IO_COUNTERS
40 from psutil.tests import HAS_PROC_CPU_NUM
41 from psutil.tests import HAS_PROC_IO_COUNTERS
42 from psutil.tests import HAS_RLIMIT
43 from psutil.tests import HAS_SENSORS_BATTERY
44 from psutil.tests import HAS_SENSORS_FANS
45 from psutil.tests import HAS_SENSORS_TEMPERATURES
46 from psutil.tests import process_namespace
47 from psutil.tests import skip_on_access_denied
48 from psutil.tests import spawn_testproc
49 from psutil.tests import system_namespace
50 from psutil.tests import terminate
51 from psutil.tests import TestMemoryLeak
52 from psutil.tests import TRAVIS
53 from psutil.tests import unittest
54
55
56 cext = psutil._psplatform.cext
57 thisproc = psutil.Process()
58 FEW_TIMES = 5
59
60
61 def fewtimes_if_linux():
62 """Decorator for those Linux functions which are implemented in pure
63 Python, and which we want to run faster.
64 """
65 def decorator(fun):
66 @functools.wraps(fun)
67 def wrapper(self, *args, **kwargs):
68 if LINUX:
69 before = self.__class__.times
70 try:
71 self.__class__.times = FEW_TIMES
72 return fun(self, *args, **kwargs)
73 finally:
74 self.__class__.times = before
75 else:
76 return fun(self, *args, **kwargs)
77 return wrapper
78 return decorator
79
80
81 # ===================================================================
82 # Process class
83 # ===================================================================
84
85
86 class TestProcessObjectLeaks(TestMemoryLeak):
87 """Test leaks of Process class methods."""
88
89 proc = thisproc
90
91 def test_coverage(self):
92 ns = process_namespace(None)
93 ns.test_class_coverage(self, ns.getters + ns.setters)
94
95 @fewtimes_if_linux()
96 def test_name(self):
97 self.execute(self.proc.name)
98
99 @fewtimes_if_linux()
100 def test_cmdline(self):
101 self.execute(self.proc.cmdline)
102
103 @fewtimes_if_linux()
104 def test_exe(self):
105 self.execute(self.proc.exe)
106
107 @fewtimes_if_linux()
108 def test_ppid(self):
109 self.execute(self.proc.ppid)
110
111 @unittest.skipIf(not POSIX, "POSIX only")
112 @fewtimes_if_linux()
113 def test_uids(self):
114 self.execute(self.proc.uids)
115
116 @unittest.skipIf(not POSIX, "POSIX only")
117 @fewtimes_if_linux()
118 def test_gids(self):
119 self.execute(self.proc.gids)
120
121 @fewtimes_if_linux()
122 def test_status(self):
123 self.execute(self.proc.status)
124
125 def test_nice(self):
126 self.execute(self.proc.nice)
127
128 def test_nice_set(self):
129 niceness = thisproc.nice()
130 self.execute(lambda: self.proc.nice(niceness))
131
132 @unittest.skipIf(not HAS_IONICE, "not supported")
133 def test_ionice(self):
134 self.execute(self.proc.ionice)
135
136 @unittest.skipIf(not HAS_IONICE, "not supported")
137 def test_ionice_set(self):
138 if WINDOWS:
139 value = thisproc.ionice()
140 self.execute(lambda: self.proc.ionice(value))
141 else:
142 self.execute(lambda: self.proc.ionice(psutil.IOPRIO_CLASS_NONE))
143 fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0)
144 self.execute_w_exc(OSError, fun)
145
146 @unittest.skipIf(not HAS_PROC_IO_COUNTERS, "not supported")
147 @fewtimes_if_linux()
148 def test_io_counters(self):
149 self.execute(self.proc.io_counters)
150
151 @unittest.skipIf(POSIX, "worthless on POSIX")
152 def test_username(self):
153 # always open 1 handle on Windows (only once)
154 psutil.Process().username()
155 self.execute(self.proc.username)
156
157 @fewtimes_if_linux()
158 def test_create_time(self):
159 self.execute(self.proc.create_time)
160
161 @fewtimes_if_linux()
162 @skip_on_access_denied(only_if=OPENBSD)
163 def test_num_threads(self):
164 self.execute(self.proc.num_threads)
165
166 @unittest.skipIf(not WINDOWS, "WINDOWS only")
167 def test_num_handles(self):
168 self.execute(self.proc.num_handles)
169
170 @unittest.skipIf(not POSIX, "POSIX only")
171 @fewtimes_if_linux()
172 def test_num_fds(self):
173 self.execute(self.proc.num_fds)
174
175 @fewtimes_if_linux()
176 def test_num_ctx_switches(self):
177 self.execute(self.proc.num_ctx_switches)
178
179 @fewtimes_if_linux()
180 @skip_on_access_denied(only_if=OPENBSD)
181 def test_threads(self):
182 self.execute(self.proc.threads)
183
184 @fewtimes_if_linux()
185 def test_cpu_times(self):
186 self.execute(self.proc.cpu_times)
187
188 @fewtimes_if_linux()
189 @unittest.skipIf(not HAS_PROC_CPU_NUM, "not supported")
190 def test_cpu_num(self):
191 self.execute(self.proc.cpu_num)
192
193 @fewtimes_if_linux()
194 def test_memory_info(self):
195 self.execute(self.proc.memory_info)
196
197 @fewtimes_if_linux()
198 def test_memory_full_info(self):
199 self.execute(self.proc.memory_full_info)
200
201 @unittest.skipIf(not POSIX, "POSIX only")
202 @fewtimes_if_linux()
203 def test_terminal(self):
204 self.execute(self.proc.terminal)
205
206 def test_resume(self):
207 times = FEW_TIMES if POSIX else self.times
208 self.execute(self.proc.resume, times=times)
209
210 @fewtimes_if_linux()
211 def test_cwd(self):
212 self.execute(self.proc.cwd)
213
214 @unittest.skipIf(not HAS_CPU_AFFINITY, "not supported")
215 def test_cpu_affinity(self):
216 self.execute(self.proc.cpu_affinity)
217
218 @unittest.skipIf(not HAS_CPU_AFFINITY, "not supported")
219 def test_cpu_affinity_set(self):
220 affinity = thisproc.cpu_affinity()
221 self.execute(lambda: self.proc.cpu_affinity(affinity))
222 if not TRAVIS:
223 self.execute_w_exc(
224 ValueError, lambda: self.proc.cpu_affinity([-1]))
225
226 @fewtimes_if_linux()
227 def test_open_files(self):
228 with open(get_testfn(), 'w'):
229 self.execute(self.proc.open_files)
230
231 @unittest.skipIf(not HAS_MEMORY_MAPS, "not supported")
232 @fewtimes_if_linux()
233 def test_memory_maps(self):
234 self.execute(self.proc.memory_maps)
235
236 @unittest.skipIf(not LINUX, "LINUX only")
237 @unittest.skipIf(not HAS_RLIMIT, "not supported")
238 def test_rlimit(self):
239 self.execute(lambda: self.proc.rlimit(psutil.RLIMIT_NOFILE))
240
241 @unittest.skipIf(not LINUX, "LINUX only")
242 @unittest.skipIf(not HAS_RLIMIT, "not supported")
243 def test_rlimit_set(self):
244 limit = thisproc.rlimit(psutil.RLIMIT_NOFILE)
245 self.execute(lambda: self.proc.rlimit(psutil.RLIMIT_NOFILE, limit))
246 self.execute_w_exc(OSError, lambda: self.proc.rlimit(-1))
247
248 @fewtimes_if_linux()
249 # Windows implementation is based on a single system-wide
250 # function (tested later).
251 @unittest.skipIf(WINDOWS, "worthless on WINDOWS")
252 def test_connections(self):
253 # TODO: UNIX sockets are temporarily implemented by parsing
254 # 'pfiles' cmd output; we don't want that part of the code to
255 # be executed.
256 with create_sockets():
257 kind = 'inet' if SUNOS else 'all'
258 self.execute(lambda: self.proc.connections(kind))
259
260 @unittest.skipIf(not HAS_ENVIRON, "not supported")
261 def test_environ(self):
262 self.execute(self.proc.environ)
263
264 @unittest.skipIf(not WINDOWS, "WINDOWS only")
265 def test_proc_info(self):
266 self.execute(lambda: cext.proc_info(os.getpid()))
267
268
269 class TestTerminatedProcessLeaks(TestProcessObjectLeaks):
270 """Repeat the tests above looking for leaks occurring when dealing
271 with terminated processes raising NoSuchProcess exception.
272 The C functions are still invoked but will follow different code
273 paths. We'll check those code paths.
274 """
275
276 @classmethod
277 def setUpClass(cls):
278 super().setUpClass()
279 cls.subp = spawn_testproc()
280 cls.proc = psutil.Process(cls.subp.pid)
281 cls.proc.kill()
282 cls.proc.wait()
283
284 @classmethod
285 def tearDownClass(cls):
286 super().tearDownClass()
287 terminate(cls.subp)
288
289 def call(self, fun):
290 try:
291 fun()
292 except psutil.NoSuchProcess:
293 pass
294
295 if WINDOWS:
296
297 def test_kill(self):
298 self.execute(self.proc.kill)
299
300 def test_terminate(self):
301 self.execute(self.proc.terminate)
302
303 def test_suspend(self):
304 self.execute(self.proc.suspend)
305
306 def test_resume(self):
307 self.execute(self.proc.resume)
308
309 def test_wait(self):
310 self.execute(self.proc.wait)
311
312 def test_proc_info(self):
313 # test dual implementation
314 def call():
315 try:
316 return cext.proc_info(self.proc.pid)
317 except ProcessLookupError:
318 pass
319
320 self.execute(call)
321
322
323 @unittest.skipIf(not WINDOWS, "WINDOWS only")
324 class TestProcessDualImplementation(TestMemoryLeak):
325
326 def test_cmdline_peb_true(self):
327 self.execute(lambda: cext.proc_cmdline(os.getpid(), use_peb=True))
328
329 def test_cmdline_peb_false(self):
330 self.execute(lambda: cext.proc_cmdline(os.getpid(), use_peb=False))
331
332
333 # ===================================================================
334 # system APIs
335 # ===================================================================
336
337
338 class TestModuleFunctionsLeaks(TestMemoryLeak):
339 """Test leaks of psutil module functions."""
340
341 def test_coverage(self):
342 ns = system_namespace()
343 ns.test_class_coverage(self, ns.all)
344
345 # --- cpu
346
347 @fewtimes_if_linux()
348 def test_cpu_count(self): # logical
349 self.execute(lambda: psutil.cpu_count(logical=True))
350
351 @fewtimes_if_linux()
352 def test_cpu_count_physical(self):
353 self.execute(lambda: psutil.cpu_count(logical=False))
354
355 @fewtimes_if_linux()
356 def test_cpu_times(self):
357 self.execute(psutil.cpu_times)
358
359 @fewtimes_if_linux()
360 def test_per_cpu_times(self):
361 self.execute(lambda: psutil.cpu_times(percpu=True))
362
363 @fewtimes_if_linux()
364 def test_cpu_stats(self):
365 self.execute(psutil.cpu_stats)
366
367 @fewtimes_if_linux()
368 @unittest.skipIf(not HAS_CPU_FREQ, "not supported")
369 def test_cpu_freq(self):
370 self.execute(psutil.cpu_freq)
371
372 @unittest.skipIf(not WINDOWS, "WINDOWS only")
373 def test_getloadavg(self):
374 psutil.getloadavg()
375 self.execute(psutil.getloadavg)
376
377 # --- mem
378
379 def test_virtual_memory(self):
380 self.execute(psutil.virtual_memory)
381
382 # TODO: remove this skip when this gets fixed
383 @unittest.skipIf(SUNOS, "worthless on SUNOS (uses a subprocess)")
384 def test_swap_memory(self):
385 self.execute(psutil.swap_memory)
386
387 def test_pid_exists(self):
388 times = FEW_TIMES if POSIX else self.times
389 self.execute(lambda: psutil.pid_exists(os.getpid()), times=times)
390
391 # --- disk
392
393 def test_disk_usage(self):
394 times = FEW_TIMES if POSIX else self.times
395 self.execute(lambda: psutil.disk_usage('.'), times=times)
396
397 def test_disk_partitions(self):
398 self.execute(psutil.disk_partitions)
399
400 @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
401 '/proc/diskstats not available on this Linux version')
402 @fewtimes_if_linux()
403 def test_disk_io_counters(self):
404 self.execute(lambda: psutil.disk_io_counters(nowrap=False))
405
406 # --- proc
407
408 @fewtimes_if_linux()
409 def test_pids(self):
410 self.execute(psutil.pids)
411
412 # --- net
413
414 @fewtimes_if_linux()
415 @unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
416 def test_net_io_counters(self):
417 self.execute(lambda: psutil.net_io_counters(nowrap=False))
418
419 @fewtimes_if_linux()
420 @unittest.skipIf(MACOS and os.getuid() != 0, "need root access")
421 def test_net_connections(self):
422 # always opens and handle on Windows() (once)
423 psutil.net_connections(kind='all')
424 with create_sockets():
425 self.execute(lambda: psutil.net_connections(kind='all'))
426
427 def test_net_if_addrs(self):
428 # Note: verified that on Windows this was a false positive.
429 tolerance = 80 * 1024 if WINDOWS else self.tolerance
430 self.execute(psutil.net_if_addrs, tolerance=tolerance)
431
432 # @unittest.skipIf(TRAVIS, "EPERM on travis")
433 def test_net_if_stats(self):
434 self.execute(psutil.net_if_stats)
435
436 # --- sensors
437
438 @fewtimes_if_linux()
439 @unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported")
440 def test_sensors_battery(self):
441 self.execute(psutil.sensors_battery)
442
443 @fewtimes_if_linux()
444 @unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
445 def test_sensors_temperatures(self):
446 self.execute(psutil.sensors_temperatures)
447
448 @fewtimes_if_linux()
449 @unittest.skipIf(not HAS_SENSORS_FANS, "not supported")
450 def test_sensors_fans(self):
451 self.execute(psutil.sensors_fans)
452
453 # --- others
454
455 @fewtimes_if_linux()
456 def test_boot_time(self):
457 self.execute(psutil.boot_time)
458
459 def test_users(self):
460 self.execute(psutil.users)
461
462 if WINDOWS:
463
464 # --- win services
465
466 def test_win_service_iter(self):
467 self.execute(cext.winservice_enumerate)
468
469 def test_win_service_get(self):
470 pass
471
472 def test_win_service_get_config(self):
473 name = next(psutil.win_service_iter()).name()
474 self.execute(lambda: cext.winservice_query_config(name))
475
476 def test_win_service_get_status(self):
477 name = next(psutil.win_service_iter()).name()
478 self.execute(lambda: cext.winservice_query_status(name))
479
480 def test_win_service_get_description(self):
481 name = next(psutil.win_service_iter()).name()
482 self.execute(lambda: cext.winservice_query_descr(name))
483
484
485 if __name__ == '__main__':
486 from psutil.tests.runner import run_from_name
487 run_from_name(__file__)