test_connections.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Tests for net_connections() and Process.connections() APIs."""
  6. import contextlib
  7. import errno
  8. import os
  9. import socket
  10. import textwrap
  11. from contextlib import closing
  12. from socket import AF_INET
  13. from socket import AF_INET6
  14. from socket import SOCK_DGRAM
  15. from socket import SOCK_STREAM
  16. import psutil
  17. from psutil import FREEBSD
  18. from psutil import LINUX
  19. from psutil import MACOS
  20. from psutil import NETBSD
  21. from psutil import OPENBSD
  22. from psutil import POSIX
  23. from psutil import SUNOS
  24. from psutil import WINDOWS
  25. from psutil._common import supports_ipv6
  26. from psutil._compat import PY3
  27. from psutil.tests import AF_UNIX
  28. from psutil.tests import bind_socket
  29. from psutil.tests import bind_unix_socket
  30. from psutil.tests import check_net_address
  31. from psutil.tests import CIRRUS
  32. from psutil.tests import create_sockets
  33. from psutil.tests import enum
  34. from psutil.tests import get_free_port
  35. from psutil.tests import HAS_CONNECTIONS_UNIX
  36. from psutil.tests import PsutilTestCase
  37. from psutil.tests import reap_children
  38. from psutil.tests import retry_on_failure
  39. from psutil.tests import serialrun
  40. from psutil.tests import skip_on_access_denied
  41. from psutil.tests import SKIP_SYSCONS
  42. from psutil.tests import tcp_socketpair
  43. from psutil.tests import TRAVIS
  44. from psutil.tests import unittest
  45. from psutil.tests import unix_socketpair
  46. from psutil.tests import wait_for_file
  47. thisproc = psutil.Process()
  48. SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
  49. @serialrun
  50. class _ConnTestCase(PsutilTestCase):
  51. def setUp(self):
  52. if not (NETBSD or FREEBSD):
  53. # process opens a UNIX socket to /var/log/run.
  54. cons = thisproc.connections(kind='all')
  55. assert not cons, cons
  56. def tearDown(self):
  57. if not (FREEBSD or NETBSD):
  58. # Make sure we closed all resources.
  59. # NetBSD opens a UNIX socket to /var/log/run.
  60. cons = thisproc.connections(kind='all')
  61. assert not cons, cons
  62. def compare_procsys_connections(self, pid, proc_cons, kind='all'):
  63. """Given a process PID and its list of connections compare
  64. those against system-wide connections retrieved via
  65. psutil.net_connections.
  66. """
  67. try:
  68. sys_cons = psutil.net_connections(kind=kind)
  69. except psutil.AccessDenied:
  70. # On MACOS, system-wide connections are retrieved by iterating
  71. # over all processes
  72. if MACOS:
  73. return
  74. else:
  75. raise
  76. # Filter for this proc PID and exlucde PIDs from the tuple.
  77. sys_cons = [c[:-1] for c in sys_cons if c.pid == pid]
  78. sys_cons.sort()
  79. proc_cons.sort()
  80. self.assertEqual(proc_cons, sys_cons)
  81. def check_connection_ntuple(self, conn):
  82. """Check validity of a connection namedtuple."""
  83. def check_ntuple(conn):
  84. has_pid = len(conn) == 7
  85. self.assertIn(len(conn), (6, 7))
  86. self.assertEqual(conn[0], conn.fd)
  87. self.assertEqual(conn[1], conn.family)
  88. self.assertEqual(conn[2], conn.type)
  89. self.assertEqual(conn[3], conn.laddr)
  90. self.assertEqual(conn[4], conn.raddr)
  91. self.assertEqual(conn[5], conn.status)
  92. if has_pid:
  93. self.assertEqual(conn[6], conn.pid)
  94. def check_family(conn):
  95. self.assertIn(conn.family, (AF_INET, AF_INET6, AF_UNIX))
  96. if enum is not None:
  97. assert isinstance(conn.family, enum.IntEnum), conn
  98. else:
  99. assert isinstance(conn.family, int), conn
  100. if conn.family == AF_INET:
  101. # actually try to bind the local socket; ignore IPv6
  102. # sockets as their address might be represented as
  103. # an IPv4-mapped-address (e.g. "::127.0.0.1")
  104. # and that's rejected by bind()
  105. s = socket.socket(conn.family, conn.type)
  106. with contextlib.closing(s):
  107. try:
  108. s.bind((conn.laddr[0], 0))
  109. except socket.error as err:
  110. if err.errno != errno.EADDRNOTAVAIL:
  111. raise
  112. elif conn.family == AF_UNIX:
  113. self.assertEqual(conn.status, psutil.CONN_NONE)
  114. def check_type(conn):
  115. # SOCK_SEQPACKET may happen in case of AF_UNIX socks
  116. self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
  117. if enum is not None:
  118. assert isinstance(conn.type, enum.IntEnum), conn
  119. else:
  120. assert isinstance(conn.type, int), conn
  121. if conn.type == SOCK_DGRAM:
  122. self.assertEqual(conn.status, psutil.CONN_NONE)
  123. def check_addrs(conn):
  124. # check IP address and port sanity
  125. for addr in (conn.laddr, conn.raddr):
  126. if conn.family in (AF_INET, AF_INET6):
  127. self.assertIsInstance(addr, tuple)
  128. if not addr:
  129. continue
  130. self.assertIsInstance(addr.port, int)
  131. assert 0 <= addr.port <= 65535, addr.port
  132. check_net_address(addr.ip, conn.family)
  133. elif conn.family == AF_UNIX:
  134. self.assertIsInstance(addr, str)
  135. def check_status(conn):
  136. self.assertIsInstance(conn.status, str)
  137. valids = [getattr(psutil, x) for x in dir(psutil)
  138. if x.startswith('CONN_')]
  139. self.assertIn(conn.status, valids)
  140. if conn.family in (AF_INET, AF_INET6) and conn.type == SOCK_STREAM:
  141. self.assertNotEqual(conn.status, psutil.CONN_NONE)
  142. else:
  143. self.assertEqual(conn.status, psutil.CONN_NONE)
  144. check_ntuple(conn)
  145. check_family(conn)
  146. check_type(conn)
  147. check_addrs(conn)
  148. check_status(conn)
  149. class TestBasicOperations(_ConnTestCase):
  150. @unittest.skipIf(SKIP_SYSCONS, "requires root")
  151. def test_system(self):
  152. with create_sockets():
  153. for conn in psutil.net_connections(kind='all'):
  154. self.check_connection_ntuple(conn)
  155. def test_process(self):
  156. with create_sockets():
  157. for conn in psutil.Process().connections(kind='all'):
  158. self.check_connection_ntuple(conn)
  159. def test_invalid_kind(self):
  160. self.assertRaises(ValueError, thisproc.connections, kind='???')
  161. self.assertRaises(ValueError, psutil.net_connections, kind='???')
  162. @serialrun
  163. class TestUnconnectedSockets(_ConnTestCase):
  164. """Tests sockets which are open but not connected to anything."""
  165. def get_conn_from_sock(self, sock):
  166. cons = thisproc.connections(kind='all')
  167. smap = dict([(c.fd, c) for c in cons])
  168. if NETBSD or FREEBSD:
  169. # NetBSD opens a UNIX socket to /var/log/run
  170. # so there may be more connections.
  171. return smap[sock.fileno()]
  172. else:
  173. self.assertEqual(len(cons), 1)
  174. if cons[0].fd != -1:
  175. self.assertEqual(smap[sock.fileno()].fd, sock.fileno())
  176. return cons[0]
  177. def check_socket(self, sock):
  178. """Given a socket, makes sure it matches the one obtained
  179. via psutil. It assumes this process created one connection
  180. only (the one supposed to be checked).
  181. """
  182. conn = self.get_conn_from_sock(sock)
  183. self.check_connection_ntuple(conn)
  184. # fd, family, type
  185. if conn.fd != -1:
  186. self.assertEqual(conn.fd, sock.fileno())
  187. self.assertEqual(conn.family, sock.family)
  188. # see: http://bugs.python.org/issue30204
  189. self.assertEqual(
  190. conn.type, sock.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE))
  191. # local address
  192. laddr = sock.getsockname()
  193. if not laddr and PY3 and isinstance(laddr, bytes):
  194. # See: http://bugs.python.org/issue30205
  195. laddr = laddr.decode()
  196. if sock.family == AF_INET6:
  197. laddr = laddr[:2]
  198. if sock.family == AF_UNIX and OPENBSD:
  199. # No addresses are set for UNIX sockets on OpenBSD.
  200. pass
  201. else:
  202. self.assertEqual(conn.laddr, laddr)
  203. # XXX Solaris can't retrieve system-wide UNIX sockets
  204. if sock.family == AF_UNIX and HAS_CONNECTIONS_UNIX:
  205. cons = thisproc.connections(kind='all')
  206. self.compare_procsys_connections(os.getpid(), cons, kind='all')
  207. return conn
  208. def test_tcp_v4(self):
  209. addr = ("127.0.0.1", get_free_port())
  210. with closing(bind_socket(AF_INET, SOCK_STREAM, addr=addr)) as sock:
  211. conn = self.check_socket(sock)
  212. assert not conn.raddr
  213. self.assertEqual(conn.status, psutil.CONN_LISTEN)
  214. @unittest.skipIf(not supports_ipv6(), "IPv6 not supported")
  215. def test_tcp_v6(self):
  216. addr = ("::1", get_free_port())
  217. with closing(bind_socket(AF_INET6, SOCK_STREAM, addr=addr)) as sock:
  218. conn = self.check_socket(sock)
  219. assert not conn.raddr
  220. self.assertEqual(conn.status, psutil.CONN_LISTEN)
  221. def test_udp_v4(self):
  222. addr = ("127.0.0.1", get_free_port())
  223. with closing(bind_socket(AF_INET, SOCK_DGRAM, addr=addr)) as sock:
  224. conn = self.check_socket(sock)
  225. assert not conn.raddr
  226. self.assertEqual(conn.status, psutil.CONN_NONE)
  227. @unittest.skipIf(not supports_ipv6(), "IPv6 not supported")
  228. def test_udp_v6(self):
  229. addr = ("::1", get_free_port())
  230. with closing(bind_socket(AF_INET6, SOCK_DGRAM, addr=addr)) as sock:
  231. conn = self.check_socket(sock)
  232. assert not conn.raddr
  233. self.assertEqual(conn.status, psutil.CONN_NONE)
  234. @unittest.skipIf(not POSIX, 'POSIX only')
  235. def test_unix_tcp(self):
  236. testfn = self.get_testfn()
  237. with closing(bind_unix_socket(testfn, type=SOCK_STREAM)) as sock:
  238. conn = self.check_socket(sock)
  239. assert not conn.raddr
  240. self.assertEqual(conn.status, psutil.CONN_NONE)
  241. @unittest.skipIf(not POSIX, 'POSIX only')
  242. def test_unix_udp(self):
  243. testfn = self.get_testfn()
  244. with closing(bind_unix_socket(testfn, type=SOCK_STREAM)) as sock:
  245. conn = self.check_socket(sock)
  246. assert not conn.raddr
  247. self.assertEqual(conn.status, psutil.CONN_NONE)
  248. @serialrun
  249. class TestConnectedSocket(_ConnTestCase):
  250. """Test socket pairs which are are actually connected to
  251. each other.
  252. """
  253. # On SunOS, even after we close() it, the server socket stays around
  254. # in TIME_WAIT state.
  255. @unittest.skipIf(SUNOS, "unreliable on SUONS")
  256. def test_tcp(self):
  257. addr = ("127.0.0.1", get_free_port())
  258. assert not thisproc.connections(kind='tcp4')
  259. server, client = tcp_socketpair(AF_INET, addr=addr)
  260. try:
  261. cons = thisproc.connections(kind='tcp4')
  262. self.assertEqual(len(cons), 2)
  263. self.assertEqual(cons[0].status, psutil.CONN_ESTABLISHED)
  264. self.assertEqual(cons[1].status, psutil.CONN_ESTABLISHED)
  265. # May not be fast enough to change state so it stays
  266. # commenteed.
  267. # client.close()
  268. # cons = thisproc.connections(kind='all')
  269. # self.assertEqual(len(cons), 1)
  270. # self.assertEqual(cons[0].status, psutil.CONN_CLOSE_WAIT)
  271. finally:
  272. server.close()
  273. client.close()
  274. @unittest.skipIf(not POSIX, 'POSIX only')
  275. def test_unix(self):
  276. testfn = self.get_testfn()
  277. server, client = unix_socketpair(testfn)
  278. try:
  279. cons = thisproc.connections(kind='unix')
  280. assert not (cons[0].laddr and cons[0].raddr)
  281. assert not (cons[1].laddr and cons[1].raddr)
  282. if NETBSD or FREEBSD:
  283. # On NetBSD creating a UNIX socket will cause
  284. # a UNIX connection to /var/run/log.
  285. cons = [c for c in cons if c.raddr != '/var/run/log']
  286. if CIRRUS:
  287. cons = [c for c in cons if c.fd in
  288. (server.fileno(), client.fileno())]
  289. self.assertEqual(len(cons), 2, msg=cons)
  290. if LINUX or FREEBSD or SUNOS:
  291. # remote path is never set
  292. self.assertEqual(cons[0].raddr, "")
  293. self.assertEqual(cons[1].raddr, "")
  294. # one local address should though
  295. self.assertEqual(testfn, cons[0].laddr or cons[1].laddr)
  296. elif OPENBSD:
  297. # No addresses whatsoever here.
  298. for addr in (cons[0].laddr, cons[0].raddr,
  299. cons[1].laddr, cons[1].raddr):
  300. self.assertEqual(addr, "")
  301. else:
  302. # On other systems either the laddr or raddr
  303. # of both peers are set.
  304. self.assertEqual(cons[0].laddr or cons[1].laddr, testfn)
  305. self.assertEqual(cons[0].raddr or cons[1].raddr, testfn)
  306. finally:
  307. server.close()
  308. client.close()
  309. class TestFilters(_ConnTestCase):
  310. def test_filters(self):
  311. def check(kind, families, types):
  312. for conn in thisproc.connections(kind=kind):
  313. self.assertIn(conn.family, families)
  314. self.assertIn(conn.type, types)
  315. if not SKIP_SYSCONS:
  316. for conn in psutil.net_connections(kind=kind):
  317. self.assertIn(conn.family, families)
  318. self.assertIn(conn.type, types)
  319. with create_sockets():
  320. check('all',
  321. [AF_INET, AF_INET6, AF_UNIX],
  322. [SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET])
  323. check('inet',
  324. [AF_INET, AF_INET6],
  325. [SOCK_STREAM, SOCK_DGRAM])
  326. check('inet4',
  327. [AF_INET],
  328. [SOCK_STREAM, SOCK_DGRAM])
  329. check('tcp',
  330. [AF_INET, AF_INET6],
  331. [SOCK_STREAM])
  332. check('tcp4',
  333. [AF_INET],
  334. [SOCK_STREAM])
  335. check('tcp6',
  336. [AF_INET6],
  337. [SOCK_STREAM])
  338. check('udp',
  339. [AF_INET, AF_INET6],
  340. [SOCK_DGRAM])
  341. check('udp4',
  342. [AF_INET],
  343. [SOCK_DGRAM])
  344. check('udp6',
  345. [AF_INET6],
  346. [SOCK_DGRAM])
  347. if HAS_CONNECTIONS_UNIX:
  348. check('unix',
  349. [AF_UNIX],
  350. [SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET])
  351. @skip_on_access_denied(only_if=MACOS)
  352. def test_combos(self):
  353. reap_children()
  354. def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
  355. all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4",
  356. "tcp6", "udp", "udp4", "udp6")
  357. self.check_connection_ntuple(conn)
  358. self.assertEqual(conn.family, family)
  359. self.assertEqual(conn.type, type)
  360. self.assertEqual(conn.laddr, laddr)
  361. self.assertEqual(conn.raddr, raddr)
  362. self.assertEqual(conn.status, status)
  363. for kind in all_kinds:
  364. cons = proc.connections(kind=kind)
  365. if kind in kinds:
  366. assert cons
  367. else:
  368. assert not cons, cons
  369. # compare against system-wide connections
  370. # XXX Solaris can't retrieve system-wide UNIX
  371. # sockets.
  372. if HAS_CONNECTIONS_UNIX:
  373. self.compare_procsys_connections(proc.pid, [conn])
  374. tcp_template = textwrap.dedent("""
  375. import socket, time
  376. s = socket.socket({family}, socket.SOCK_STREAM)
  377. s.bind(('{addr}', 0))
  378. s.listen(5)
  379. with open('{testfn}', 'w') as f:
  380. f.write(str(s.getsockname()[:2]))
  381. time.sleep(60)
  382. """)
  383. udp_template = textwrap.dedent("""
  384. import socket, time
  385. s = socket.socket({family}, socket.SOCK_DGRAM)
  386. s.bind(('{addr}', 0))
  387. with open('{testfn}', 'w') as f:
  388. f.write(str(s.getsockname()[:2]))
  389. time.sleep(60)
  390. """)
  391. # must be relative on Windows
  392. testfile = os.path.basename(self.get_testfn(dir=os.getcwd()))
  393. tcp4_template = tcp_template.format(
  394. family=int(AF_INET), addr="127.0.0.1", testfn=testfile)
  395. udp4_template = udp_template.format(
  396. family=int(AF_INET), addr="127.0.0.1", testfn=testfile)
  397. tcp6_template = tcp_template.format(
  398. family=int(AF_INET6), addr="::1", testfn=testfile)
  399. udp6_template = udp_template.format(
  400. family=int(AF_INET6), addr="::1", testfn=testfile)
  401. # launch various subprocess instantiating a socket of various
  402. # families and types to enrich psutil results
  403. tcp4_proc = self.pyrun(tcp4_template)
  404. tcp4_addr = eval(wait_for_file(testfile, delete=True))
  405. udp4_proc = self.pyrun(udp4_template)
  406. udp4_addr = eval(wait_for_file(testfile, delete=True))
  407. if supports_ipv6():
  408. tcp6_proc = self.pyrun(tcp6_template)
  409. tcp6_addr = eval(wait_for_file(testfile, delete=True))
  410. udp6_proc = self.pyrun(udp6_template)
  411. udp6_addr = eval(wait_for_file(testfile, delete=True))
  412. else:
  413. tcp6_proc = None
  414. udp6_proc = None
  415. tcp6_addr = None
  416. udp6_addr = None
  417. for p in thisproc.children():
  418. cons = p.connections()
  419. self.assertEqual(len(cons), 1)
  420. for conn in cons:
  421. # TCP v4
  422. if p.pid == tcp4_proc.pid:
  423. check_conn(p, conn, AF_INET, SOCK_STREAM, tcp4_addr, (),
  424. psutil.CONN_LISTEN,
  425. ("all", "inet", "inet4", "tcp", "tcp4"))
  426. # UDP v4
  427. elif p.pid == udp4_proc.pid:
  428. check_conn(p, conn, AF_INET, SOCK_DGRAM, udp4_addr, (),
  429. psutil.CONN_NONE,
  430. ("all", "inet", "inet4", "udp", "udp4"))
  431. # TCP v6
  432. elif p.pid == getattr(tcp6_proc, "pid", None):
  433. check_conn(p, conn, AF_INET6, SOCK_STREAM, tcp6_addr, (),
  434. psutil.CONN_LISTEN,
  435. ("all", "inet", "inet6", "tcp", "tcp6"))
  436. # UDP v6
  437. elif p.pid == getattr(udp6_proc, "pid", None):
  438. check_conn(p, conn, AF_INET6, SOCK_DGRAM, udp6_addr, (),
  439. psutil.CONN_NONE,
  440. ("all", "inet", "inet6", "udp", "udp6"))
  441. def test_count(self):
  442. with create_sockets():
  443. # tcp
  444. cons = thisproc.connections(kind='tcp')
  445. self.assertEqual(len(cons), 2 if supports_ipv6() else 1)
  446. for conn in cons:
  447. self.assertIn(conn.family, (AF_INET, AF_INET6))
  448. self.assertEqual(conn.type, SOCK_STREAM)
  449. # tcp4
  450. cons = thisproc.connections(kind='tcp4')
  451. self.assertEqual(len(cons), 1)
  452. self.assertEqual(cons[0].family, AF_INET)
  453. self.assertEqual(cons[0].type, SOCK_STREAM)
  454. # tcp6
  455. if supports_ipv6():
  456. cons = thisproc.connections(kind='tcp6')
  457. self.assertEqual(len(cons), 1)
  458. self.assertEqual(cons[0].family, AF_INET6)
  459. self.assertEqual(cons[0].type, SOCK_STREAM)
  460. # udp
  461. cons = thisproc.connections(kind='udp')
  462. self.assertEqual(len(cons), 2 if supports_ipv6() else 1)
  463. for conn in cons:
  464. self.assertIn(conn.family, (AF_INET, AF_INET6))
  465. self.assertEqual(conn.type, SOCK_DGRAM)
  466. # udp4
  467. cons = thisproc.connections(kind='udp4')
  468. self.assertEqual(len(cons), 1)
  469. self.assertEqual(cons[0].family, AF_INET)
  470. self.assertEqual(cons[0].type, SOCK_DGRAM)
  471. # udp6
  472. if supports_ipv6():
  473. cons = thisproc.connections(kind='udp6')
  474. self.assertEqual(len(cons), 1)
  475. self.assertEqual(cons[0].family, AF_INET6)
  476. self.assertEqual(cons[0].type, SOCK_DGRAM)
  477. # inet
  478. cons = thisproc.connections(kind='inet')
  479. self.assertEqual(len(cons), 4 if supports_ipv6() else 2)
  480. for conn in cons:
  481. self.assertIn(conn.family, (AF_INET, AF_INET6))
  482. self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
  483. # inet6
  484. if supports_ipv6():
  485. cons = thisproc.connections(kind='inet6')
  486. self.assertEqual(len(cons), 2)
  487. for conn in cons:
  488. self.assertEqual(conn.family, AF_INET6)
  489. self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
  490. # Skipped on BSD becayse by default the Python process
  491. # creates a UNIX socket to '/var/run/log'.
  492. if HAS_CONNECTIONS_UNIX and not (FREEBSD or NETBSD):
  493. cons = thisproc.connections(kind='unix')
  494. self.assertEqual(len(cons), 3)
  495. for conn in cons:
  496. self.assertEqual(conn.family, AF_UNIX)
  497. self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
  498. @unittest.skipIf(SKIP_SYSCONS, "requires root")
  499. class TestSystemWideConnections(_ConnTestCase):
  500. """Tests for net_connections()."""
  501. def test_it(self):
  502. def check(cons, families, types_):
  503. for conn in cons:
  504. self.assertIn(conn.family, families, msg=conn)
  505. if conn.family != AF_UNIX:
  506. self.assertIn(conn.type, types_, msg=conn)
  507. self.check_connection_ntuple(conn)
  508. with create_sockets():
  509. from psutil._common import conn_tmap
  510. for kind, groups in conn_tmap.items():
  511. # XXX: SunOS does not retrieve UNIX sockets.
  512. if kind == 'unix' and not HAS_CONNECTIONS_UNIX:
  513. continue
  514. families, types_ = groups
  515. cons = psutil.net_connections(kind)
  516. self.assertEqual(len(cons), len(set(cons)))
  517. check(cons, families, types_)
  518. # See: https://travis-ci.org/giampaolo/psutil/jobs/237566297
  519. @unittest.skipIf(MACOS and TRAVIS, "unreliable on MACOS + TRAVIS")
  520. @retry_on_failure()
  521. def test_multi_sockets_procs(self):
  522. # Creates multiple sub processes, each creating different
  523. # sockets. For each process check that proc.connections()
  524. # and net_connections() return the same results.
  525. # This is done mainly to check whether net_connections()'s
  526. # pid is properly set, see:
  527. # https://github.com/giampaolo/psutil/issues/1013
  528. with create_sockets() as socks:
  529. expected = len(socks)
  530. pids = []
  531. times = 10
  532. fnames = []
  533. for i in range(times):
  534. fname = self.get_testfn()
  535. fnames.append(fname)
  536. src = textwrap.dedent("""\
  537. import time, os
  538. from psutil.tests import create_sockets
  539. with create_sockets():
  540. with open(r'%s', 'w') as f:
  541. f.write("hello")
  542. time.sleep(60)
  543. """ % fname)
  544. sproc = self.pyrun(src)
  545. pids.append(sproc.pid)
  546. # sync
  547. for fname in fnames:
  548. wait_for_file(fname)
  549. syscons = [x for x in psutil.net_connections(kind='all') if x.pid
  550. in pids]
  551. for pid in pids:
  552. self.assertEqual(len([x for x in syscons if x.pid == pid]),
  553. expected)
  554. p = psutil.Process(pid)
  555. self.assertEqual(len(p.connections('all')), expected)
  556. class TestMisc(PsutilTestCase):
  557. def test_connection_constants(self):
  558. ints = []
  559. strs = []
  560. for name in dir(psutil):
  561. if name.startswith('CONN_'):
  562. num = getattr(psutil, name)
  563. str_ = str(num)
  564. assert str_.isupper(), str_
  565. self.assertNotIn(str, strs)
  566. self.assertNotIn(num, ints)
  567. ints.append(num)
  568. strs.append(str_)
  569. if SUNOS:
  570. psutil.CONN_IDLE
  571. psutil.CONN_BOUND
  572. if WINDOWS:
  573. psutil.CONN_DELETE_TCB
  574. if __name__ == '__main__':
  575. from psutil.tests.runner import run_from_name
  576. run_from_name(__file__)