1
0

test_process.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. # -*- coding: utf-8 -*-
  2. # Import python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import datetime
  5. import functools
  6. import io
  7. import multiprocessing
  8. import os
  9. import signal
  10. import sys
  11. import threading
  12. import time
  13. import warnings
  14. import psutil
  15. import pytest
  16. # Import salt libs
  17. import salt.utils.platform
  18. import salt.utils.process
  19. # Import 3rd-party libs
  20. from salt.ext import six
  21. from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
  22. from salt.utils.versions import warn_until_date
  23. from tests.support.mock import patch
  24. # Import Salt Testing libs
  25. from tests.support.unit import TestCase, skipIf
  26. def die(func):
  27. """
  28. Add proc title
  29. """
  30. @functools.wraps(func)
  31. def wrapper(self):
  32. # Strip off the "test_" from the function name
  33. name = func.__name__[5:]
  34. def _die():
  35. salt.utils.process.appendproctitle("test_{0}".format(name))
  36. attrname = "die_" + name
  37. setattr(self, attrname, _die)
  38. self.addCleanup(delattr, self, attrname)
  39. return wrapper
  40. def incr(func):
  41. """
  42. Increment counter
  43. """
  44. @functools.wraps(func)
  45. def wrapper(self):
  46. # Strip off the "test_" from the function name
  47. name = func.__name__[5:]
  48. def _incr(counter, num):
  49. salt.utils.process.appendproctitle("test_{0}".format(name))
  50. for _ in range(0, num):
  51. counter.value += 1
  52. attrname = "incr_" + name
  53. setattr(self, attrname, _incr)
  54. self.addCleanup(delattr, self, attrname)
  55. return wrapper
  56. def spin(func):
  57. """
  58. Spin indefinitely
  59. """
  60. @functools.wraps(func)
  61. def wrapper(self):
  62. # Strip off the "test_" from the function name
  63. name = func.__name__[5:]
  64. def _spin():
  65. salt.utils.process.appendproctitle("test_{0}".format(name))
  66. while True:
  67. time.sleep(1)
  68. attrname = "spin_" + name
  69. setattr(self, attrname, _spin)
  70. self.addCleanup(delattr, self, attrname)
  71. return wrapper
  72. class TestProcessManager(TestCase):
  73. @spin
  74. def test_basic(self):
  75. """
  76. Make sure that the process is alive 2s later
  77. """
  78. process_manager = salt.utils.process.ProcessManager()
  79. process_manager.add_process(self.spin_basic)
  80. initial_pid = next(six.iterkeys(process_manager._process_map))
  81. time.sleep(2)
  82. process_manager.check_children()
  83. try:
  84. assert initial_pid == next(six.iterkeys(process_manager._process_map))
  85. finally:
  86. process_manager.stop_restarting()
  87. process_manager.kill_children()
  88. time.sleep(0.5)
  89. # Are there child processes still running?
  90. if process_manager._process_map.keys():
  91. process_manager.send_signal_to_processes(signal.SIGKILL)
  92. process_manager.stop_restarting()
  93. process_manager.kill_children()
  94. @spin
  95. def test_kill(self):
  96. process_manager = salt.utils.process.ProcessManager()
  97. process_manager.add_process(self.spin_kill)
  98. initial_pid = next(six.iterkeys(process_manager._process_map))
  99. # kill the child
  100. if salt.utils.platform.is_windows():
  101. os.kill(initial_pid, signal.SIGTERM)
  102. else:
  103. os.kill(initial_pid, signal.SIGKILL)
  104. # give the OS time to give the signal...
  105. time.sleep(0.1)
  106. process_manager.check_children()
  107. try:
  108. assert initial_pid != next(six.iterkeys(process_manager._process_map))
  109. finally:
  110. process_manager.stop_restarting()
  111. process_manager.kill_children()
  112. time.sleep(0.5)
  113. # Are there child processes still running?
  114. if process_manager._process_map.keys():
  115. process_manager.send_signal_to_processes(signal.SIGKILL)
  116. process_manager.stop_restarting()
  117. process_manager.kill_children()
  118. @die
  119. def test_restarting(self):
  120. """
  121. Make sure that the process is alive 2s later
  122. """
  123. process_manager = salt.utils.process.ProcessManager()
  124. process_manager.add_process(self.die_restarting)
  125. initial_pid = next(six.iterkeys(process_manager._process_map))
  126. time.sleep(2)
  127. process_manager.check_children()
  128. try:
  129. assert initial_pid != next(six.iterkeys(process_manager._process_map))
  130. finally:
  131. process_manager.stop_restarting()
  132. process_manager.kill_children()
  133. time.sleep(0.5)
  134. # Are there child processes still running?
  135. if process_manager._process_map.keys():
  136. process_manager.send_signal_to_processes(signal.SIGKILL)
  137. process_manager.stop_restarting()
  138. process_manager.kill_children()
  139. @skipIf(sys.version_info < (2, 7), "Needs > Py 2.7 due to bug in stdlib")
  140. @incr
  141. def test_counter(self):
  142. counter = multiprocessing.Value("i", 0)
  143. process_manager = salt.utils.process.ProcessManager()
  144. process_manager.add_process(self.incr_counter, args=(counter, 2))
  145. time.sleep(1)
  146. process_manager.check_children()
  147. time.sleep(1)
  148. # we should have had 2 processes go at it
  149. try:
  150. assert counter.value == 4
  151. finally:
  152. process_manager.stop_restarting()
  153. process_manager.kill_children()
  154. time.sleep(0.5)
  155. # Are there child processes still running?
  156. if process_manager._process_map.keys():
  157. process_manager.send_signal_to_processes(signal.SIGKILL)
  158. process_manager.stop_restarting()
  159. process_manager.kill_children()
  160. class TestThreadPool(TestCase):
  161. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  162. def test_basic(self):
  163. """
  164. Make sure the threadpool can do things
  165. """
  166. def incr_counter(counter):
  167. counter.value += 1
  168. counter = multiprocessing.Value("i", 0)
  169. pool = salt.utils.process.ThreadPool()
  170. sent = pool.fire_async(incr_counter, args=(counter,))
  171. self.assertTrue(sent)
  172. time.sleep(1) # Sleep to let the threads do things
  173. self.assertEqual(counter.value, 1)
  174. self.assertEqual(pool._job_queue.qsize(), 0)
  175. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  176. def test_full_queue(self):
  177. """
  178. Make sure that a full threadpool acts as we expect
  179. """
  180. def incr_counter(counter):
  181. counter.value += 1
  182. counter = multiprocessing.Value("i", 0)
  183. # Create a pool with no workers and 1 queue size
  184. pool = salt.utils.process.ThreadPool(0, 1)
  185. # make sure we can put the one item in
  186. sent = pool.fire_async(incr_counter, args=(counter,))
  187. self.assertTrue(sent)
  188. # make sure we can't put more in
  189. sent = pool.fire_async(incr_counter, args=(counter,))
  190. self.assertFalse(sent)
  191. time.sleep(1) # Sleep to let the threads do things
  192. # make sure no one updated the counter
  193. self.assertEqual(counter.value, 0)
  194. # make sure the queue is still full
  195. self.assertEqual(pool._job_queue.qsize(), 1)
  196. class TestProcess(TestCase):
  197. def test_daemonize_if(self):
  198. # pylint: disable=assignment-from-none
  199. with patch("sys.argv", ["salt-call"]):
  200. ret = salt.utils.process.daemonize_if({})
  201. self.assertEqual(None, ret)
  202. ret = salt.utils.process.daemonize_if({"multiprocessing": False})
  203. self.assertEqual(None, ret)
  204. with patch("sys.platform", "win"):
  205. ret = salt.utils.process.daemonize_if({})
  206. self.assertEqual(None, ret)
  207. with patch("salt.utils.process.daemonize"), patch("sys.platform", "linux2"):
  208. salt.utils.process.daemonize_if({})
  209. self.assertTrue(salt.utils.process.daemonize.called)
  210. # pylint: enable=assignment-from-none
  211. class TestProcessCallbacks(TestCase):
  212. @staticmethod
  213. def process_target(evt):
  214. evt.set()
  215. def test_callbacks(self):
  216. "Validate Process call after fork and finalize methods"
  217. teardown_to_mock = "salt.log.setup.shutdown_multiprocessing_logging"
  218. log_to_mock = "salt.utils.process.Process._setup_process_logging"
  219. with patch(teardown_to_mock) as ma, patch(log_to_mock) as mb:
  220. evt = multiprocessing.Event()
  221. proc = salt.utils.process.Process(target=self.process_target, args=(evt,))
  222. proc.run()
  223. assert evt.is_set()
  224. mb.assert_called()
  225. ma.assert_called()
  226. def test_callbacks_called_when_run_overriden(self):
  227. "Validate Process sub classes call after fork and finalize methods when run is overridden"
  228. class MyProcess(salt.utils.process.Process):
  229. def __init__(self):
  230. super(MyProcess, self).__init__()
  231. self.evt = multiprocessing.Event()
  232. def run(self):
  233. self.evt.set()
  234. teardown_to_mock = "salt.log.setup.shutdown_multiprocessing_logging"
  235. log_to_mock = "salt.utils.process.Process._setup_process_logging"
  236. with patch(teardown_to_mock) as ma, patch(log_to_mock) as mb:
  237. proc = MyProcess()
  238. proc.run()
  239. assert proc.evt.is_set()
  240. ma.assert_called()
  241. mb.assert_called()
  242. class TestSignalHandlingProcess(TestCase):
  243. @classmethod
  244. def Process(cls, pid):
  245. raise psutil.NoSuchProcess(pid)
  246. @classmethod
  247. def target(cls):
  248. os.kill(os.getpid(), signal.SIGTERM)
  249. @classmethod
  250. def children(cls, *args, **kwargs):
  251. raise psutil.NoSuchProcess(1)
  252. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  253. def test_process_does_not_exist(self):
  254. try:
  255. with patch("psutil.Process", self.Process):
  256. proc = salt.utils.process.SignalHandlingProcess(target=self.target)
  257. proc.start()
  258. except psutil.NoSuchProcess:
  259. assert False, "psutil.NoSuchProcess raised"
  260. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  261. def test_process_children_do_not_exist(self):
  262. try:
  263. with patch("psutil.Process.children", self.children):
  264. proc = salt.utils.process.SignalHandlingProcess(target=self.target)
  265. proc.start()
  266. except psutil.NoSuchProcess:
  267. assert False, "psutil.NoSuchProcess raised"
  268. @staticmethod
  269. def run_forever_sub_target(evt):
  270. "Used by run_forever_target to create a sub-process"
  271. while not evt.is_set():
  272. time.sleep(1)
  273. @staticmethod
  274. def run_forever_target(sub_target, evt):
  275. "A target that will run forever or until an event is set"
  276. p = multiprocessing.Process(target=sub_target, args=(evt,))
  277. p.start()
  278. p.join()
  279. @staticmethod
  280. def kill_target_sub_proc():
  281. pid = os.fork()
  282. if pid == 0:
  283. return
  284. pid = os.fork()
  285. if pid == 0:
  286. return
  287. time.sleep(0.1)
  288. try:
  289. os.kill(os.getpid(), signal.SIGINT)
  290. except KeyboardInterrupt:
  291. pass
  292. @skipIf(sys.platform.startswith("win"), "No os.fork on Windows")
  293. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  294. def test_signal_processing_regression_test(self):
  295. evt = multiprocessing.Event()
  296. sh_proc = salt.utils.process.SignalHandlingProcess(
  297. target=self.run_forever_target, args=(self.run_forever_sub_target, evt)
  298. )
  299. sh_proc.start()
  300. proc = multiprocessing.Process(target=self.kill_target_sub_proc)
  301. proc.start()
  302. proc.join()
  303. # When the bug exists, the kill_target_sub_proc signal will kill both
  304. # processes. sh_proc will be alive if the bug is fixed
  305. try:
  306. assert sh_proc.is_alive()
  307. finally:
  308. evt.set()
  309. sh_proc.join()
  310. @staticmethod
  311. def no_op_target():
  312. pass
  313. @staticmethod
  314. def pid_setting_target(sub_target, val, evt):
  315. val.value = os.getpid()
  316. p = multiprocessing.Process(target=sub_target, args=(evt,))
  317. p.start()
  318. p.join()
  319. @skipIf(sys.platform.startswith("win"), "Required signals not supported on windows")
  320. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  321. def test_signal_processing_handle_signals_called(self):
  322. "Validate SignalHandlingProcess handles signals"
  323. # Gloobal event to stop all processes we're creating
  324. evt = multiprocessing.Event()
  325. # Create a process to test signal handler
  326. val = multiprocessing.Value("i", 0)
  327. proc = salt.utils.process.SignalHandlingProcess(
  328. target=self.pid_setting_target,
  329. args=(self.run_forever_sub_target, val, evt),
  330. )
  331. proc.start()
  332. # Create a second process that should not respond to SIGINT or SIGTERM
  333. proc2 = multiprocessing.Process(
  334. target=self.run_forever_target, args=(self.run_forever_sub_target, evt),
  335. )
  336. proc2.start()
  337. # Wait for the sub process to set it's pid
  338. while not val.value:
  339. time.sleep(0.3)
  340. assert not proc.signal_handled()
  341. # Send a signal that should get handled by the subprocess
  342. os.kill(val.value, signal.SIGTERM)
  343. # wait up to 10 seconds for signal handler:
  344. start = time.time()
  345. while time.time() - start < 10:
  346. if proc.signal_handled():
  347. break
  348. time.sleep(0.3)
  349. try:
  350. # Allow some time for the signal handler to do it's thing
  351. assert proc.signal_handled()
  352. # Reap the signaled process
  353. proc.join(1)
  354. assert proc2.is_alive()
  355. finally:
  356. evt.set()
  357. proc2.join(30)
  358. proc.join(30)
  359. class TestSignalHandlingProcessCallbacks(TestCase):
  360. @staticmethod
  361. def process_target(evt):
  362. evt.set()
  363. def test_callbacks(self):
  364. "Validate SignalHandlingProcess call after fork and finalize methods"
  365. teardown_to_mock = "salt.log.setup.shutdown_multiprocessing_logging"
  366. log_to_mock = "salt.utils.process.Process._setup_process_logging"
  367. sig_to_mock = "salt.utils.process.SignalHandlingProcess._setup_signals"
  368. # Mock _setup_signals so we do not register one for this process.
  369. evt = multiprocessing.Event()
  370. with patch(sig_to_mock):
  371. with patch(teardown_to_mock) as ma, patch(log_to_mock) as mb:
  372. sh_proc = salt.utils.process.SignalHandlingProcess(
  373. target=self.process_target, args=(evt,)
  374. )
  375. sh_proc.run()
  376. assert evt.is_set()
  377. ma.assert_called()
  378. mb.assert_called()
  379. def test_callbacks_called_when_run_overriden(self):
  380. "Validate SignalHandlingProcess sub classes call after fork and finalize methods when run is overridden"
  381. class MyProcess(salt.utils.process.SignalHandlingProcess):
  382. def __init__(self):
  383. super(MyProcess, self).__init__()
  384. self.evt = multiprocessing.Event()
  385. def run(self):
  386. self.evt.set()
  387. teardown_to_mock = "salt.log.setup.shutdown_multiprocessing_logging"
  388. log_to_mock = "salt.utils.process.Process._setup_process_logging"
  389. sig_to_mock = "salt.utils.process.SignalHandlingProcess._setup_signals"
  390. # Mock _setup_signals so we do not register one for this process.
  391. with patch(sig_to_mock):
  392. with patch(teardown_to_mock) as ma, patch(log_to_mock) as mb:
  393. sh_proc = MyProcess()
  394. sh_proc.run()
  395. assert sh_proc.evt.is_set()
  396. ma.assert_called()
  397. mb.assert_called()
  398. class TestDup2(TestCase):
  399. def test_dup2_no_fileno(self):
  400. "The dup2 method does not fail on streams without fileno support"
  401. f1 = io.StringIO("some initial text data")
  402. f2 = io.StringIO("some initial other text data")
  403. with self.assertRaises(io.UnsupportedOperation):
  404. f1.fileno()
  405. with patch("os.dup2") as dup_mock:
  406. try:
  407. salt.utils.process.dup2(f1, f2)
  408. except io.UnsupportedOperation:
  409. assert False, "io.UnsupportedOperation was raised"
  410. assert not dup_mock.called
  411. def null_target():
  412. pass
  413. def event_target(event):
  414. while True:
  415. if event.wait(5):
  416. break
  417. class TestProcessList(TestCase):
  418. @staticmethod
  419. def wait_for_proc(proc, timeout=10):
  420. start = time.time()
  421. while proc.is_alive():
  422. if time.time() - start > timeout:
  423. raise Exception("Process did not finishe before timeout")
  424. time.sleep(0.3)
  425. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  426. def test_process_list_process(self):
  427. plist = salt.utils.process.SubprocessList()
  428. proc = multiprocessing.Process(target=null_target)
  429. proc.start()
  430. plist.add(proc)
  431. assert proc in plist.processes
  432. self.wait_for_proc(proc)
  433. assert not proc.is_alive()
  434. plist.cleanup()
  435. assert proc not in plist.processes
  436. def test_process_list_thread(self):
  437. plist = salt.utils.process.SubprocessList()
  438. thread = threading.Thread(target=null_target)
  439. thread.start()
  440. plist.add(thread)
  441. assert thread in plist.processes
  442. self.wait_for_proc(thread)
  443. assert not thread.is_alive()
  444. plist.cleanup()
  445. assert thread not in plist.processes
  446. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  447. def test_process_list_cleanup(self):
  448. plist = salt.utils.process.SubprocessList()
  449. event = multiprocessing.Event()
  450. proc = multiprocessing.Process(target=event_target, args=[event])
  451. proc.start()
  452. plist.add(proc)
  453. assert proc in plist.processes
  454. plist.cleanup()
  455. event.set()
  456. assert proc in plist.processes
  457. self.wait_for_proc(proc)
  458. assert not proc.is_alive()
  459. plist.cleanup()
  460. assert proc not in plist.processes
  461. class TestDeprecatedClassNames(TestCase):
  462. @staticmethod
  463. def process_target():
  464. pass
  465. @staticmethod
  466. def patched_warn_until_date(current_date):
  467. def _patched_warn_until_date(
  468. date,
  469. message,
  470. category=DeprecationWarning,
  471. stacklevel=None,
  472. _current_date=current_date,
  473. _dont_call_warnings=False,
  474. ):
  475. # Because we add another function in between, the stacklevel
  476. # set in salt.utils.process, 3, needs to now be 4
  477. stacklevel = 4
  478. return warn_until_date(
  479. date,
  480. message,
  481. category=category,
  482. stacklevel=stacklevel,
  483. _current_date=_current_date,
  484. _dont_call_warnings=_dont_call_warnings,
  485. )
  486. return _patched_warn_until_date
  487. def test_multiprocessing_process_warning(self):
  488. # We *always* want *all* warnings thrown on this module
  489. warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  490. fake_utcnow = datetime.date(2021, 1, 1)
  491. proc = None
  492. try:
  493. with patch(
  494. "salt.utils.versions.warn_until_date",
  495. self.patched_warn_until_date(fake_utcnow),
  496. ):
  497. # Test warning
  498. with warnings.catch_warnings(record=True) as recorded_warnings:
  499. proc = salt.utils.process.MultiprocessingProcess(
  500. target=self.process_target
  501. )
  502. self.assertEqual(
  503. "Please stop using 'salt.utils.process.MultiprocessingProcess' "
  504. "and instead use 'salt.utils.process.Process'. "
  505. "'salt.utils.process.MultiprocessingProcess' will go away "
  506. "after 2022-01-01.",
  507. six.text_type(recorded_warnings[0].message),
  508. )
  509. finally:
  510. if proc is not None:
  511. del proc
  512. def test_multiprocessing_process_runtime_error(self):
  513. fake_utcnow = datetime.date(2022, 1, 1)
  514. proc = None
  515. try:
  516. with patch(
  517. "salt.utils.versions.warn_until_date",
  518. self.patched_warn_until_date(fake_utcnow),
  519. ):
  520. with self.assertRaisesRegex(
  521. RuntimeError,
  522. r"Please stop using 'salt.utils.process.MultiprocessingProcess' "
  523. r"and instead use 'salt.utils.process.Process'. "
  524. r"'salt.utils.process.MultiprocessingProcess' will go away "
  525. r"after 2022-01-01. "
  526. r"This warning\(now exception\) triggered on "
  527. r"filename '(.*)test_process.py', line number ([\d]+), is "
  528. r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
  529. r"Please remove the warning.",
  530. ):
  531. proc = salt.utils.process.MultiprocessingProcess(
  532. target=self.process_target
  533. )
  534. finally:
  535. if proc is not None:
  536. del proc
  537. def test_signal_handling_multiprocessing_process_warning(self):
  538. # We *always* want *all* warnings thrown on this module
  539. warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  540. fake_utcnow = datetime.date(2021, 1, 1)
  541. proc = None
  542. try:
  543. with patch(
  544. "salt.utils.versions.warn_until_date",
  545. self.patched_warn_until_date(fake_utcnow),
  546. ):
  547. # Test warning
  548. with warnings.catch_warnings(record=True) as recorded_warnings:
  549. proc = salt.utils.process.SignalHandlingMultiprocessingProcess(
  550. target=self.process_target
  551. )
  552. self.assertEqual(
  553. "Please stop using 'salt.utils.process.SignalHandlingMultiprocessingProcess' "
  554. "and instead use 'salt.utils.process.SignalHandlingProcess'. "
  555. "'salt.utils.process.SignalHandlingMultiprocessingProcess' will go away "
  556. "after 2022-01-01.",
  557. six.text_type(recorded_warnings[0].message),
  558. )
  559. finally:
  560. if proc is not None:
  561. del proc
  562. def test_signal_handling_multiprocessing_process_runtime_error(self):
  563. fake_utcnow = datetime.date(2022, 1, 1)
  564. proc = None
  565. try:
  566. with patch(
  567. "salt.utils.versions.warn_until_date",
  568. self.patched_warn_until_date(fake_utcnow),
  569. ):
  570. with self.assertRaisesRegex(
  571. RuntimeError,
  572. r"Please stop using 'salt.utils.process.SignalHandlingMultiprocessingProcess' "
  573. r"and instead use 'salt.utils.process.SignalHandlingProcess'. "
  574. r"'salt.utils.process.SignalHandlingMultiprocessingProcess' will go away "
  575. r"after 2022-01-01. "
  576. r"This warning\(now exception\) triggered on "
  577. r"filename '(.*)test_process.py', line number ([\d]+), is "
  578. r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
  579. r"Please remove the warning.",
  580. ):
  581. proc = salt.utils.process.SignalHandlingMultiprocessingProcess(
  582. target=self.process_target
  583. )
  584. finally:
  585. if proc is not None:
  586. del proc