conftest.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Pedro Algarvio (pedro@algarvio.me)
  4. tests.conftest
  5. ~~~~~~~~~~~~~~
  6. Prepare py.test for our test suite
  7. '''
  8. # Import python libs
  9. from __future__ import absolute_import
  10. import os
  11. import sys
  12. import stat
  13. import socket
  14. import logging
  15. from collections import namedtuple
  16. TESTS_DIR = os.path.dirname(
  17. os.path.normpath(os.path.abspath(__file__))
  18. )
  19. CODE_DIR = os.path.dirname(TESTS_DIR)
  20. os.chdir(CODE_DIR)
  21. try:
  22. # If we have a system-wide salt module imported, unload it
  23. import salt
  24. for module in list(sys.modules):
  25. if module.startswith(('salt',)):
  26. try:
  27. if not sys.modules[module].__file__.startswith(CODE_DIR):
  28. sys.modules.pop(module)
  29. except AttributeError:
  30. continue
  31. sys.path.insert(0, CODE_DIR)
  32. except ImportError:
  33. sys.path.insert(0, CODE_DIR)
  34. # Import test libs
  35. import tests.support.paths # pylint: disable=unused-import
  36. from tests.integration import TestDaemon
  37. # Import pytest libs
  38. import pytest
  39. from _pytest.terminal import TerminalReporter
  40. # Import 3rd-party libs
  41. import psutil
  42. from salt.ext import six
  43. # Import salt libs
  44. import salt.utils.files
  45. import salt.utils.path
  46. import salt.log.setup
  47. from salt.utils.odict import OrderedDict
  48. # Define the pytest plugins we rely on
  49. pytest_plugins = ['tempdir', 'helpers_namespace', 'salt-from-filenames'] # pylint: disable=invalid-name
  50. # Define where not to collect tests from
  51. collect_ignore = ['setup.py']
  52. log = logging.getLogger('salt.testsuite')
  53. # Reset logging root handlers
  54. for handler in logging.root.handlers:
  55. logging.root.removeHandler(handler)
  56. def pytest_tempdir_basename():
  57. '''
  58. Return the temporary directory basename for the salt test suite.
  59. '''
  60. return 'salt-tests-tmp'
  61. # ----- CLI Options Setup ------------------------------------------------------------------------------------------->
  62. def pytest_addoption(parser):
  63. '''
  64. register argparse-style options and ini-style config values.
  65. '''
  66. parser.addoption(
  67. '--sysinfo',
  68. default=False,
  69. action='store_true',
  70. help='Print some system information.'
  71. )
  72. parser.addoption(
  73. '--transport',
  74. default='zeromq',
  75. choices=('zeromq', 'raet', 'tcp'),
  76. help=('Select which transport to run the integration tests with, '
  77. 'zeromq, raet, or tcp. Default: %default')
  78. )
  79. test_selection_group = parser.getgroup('Tests Selection')
  80. test_selection_group.addoption(
  81. '--ssh',
  82. '--ssh-tests',
  83. dest='ssh',
  84. action='store_true',
  85. default=False,
  86. help='Run salt-ssh tests. These tests will spin up a temporary '
  87. 'SSH server on your machine. In certain environments, this '
  88. 'may be insecure! Default: False'
  89. )
  90. test_selection_group.addoption(
  91. '--proxy',
  92. '--proxy-tests',
  93. dest='proxy',
  94. action='store_true',
  95. default=False,
  96. help='Run proxy tests'
  97. )
  98. test_selection_group.addoption(
  99. '--run-destructive',
  100. action='store_true',
  101. default=False,
  102. help='Run destructive tests. These tests can include adding '
  103. 'or removing users from your system for example. '
  104. 'Default: False'
  105. )
  106. test_selection_group.addoption(
  107. '--run-expensive',
  108. action='store_true',
  109. default=False,
  110. help='Run expensive tests. These tests usually involve costs '
  111. 'like for example bootstrapping a cloud VM. '
  112. 'Default: False'
  113. )
  114. output_options_group = parser.getgroup('Output Options')
  115. output_options_group.addoption(
  116. '--output-columns',
  117. default=80,
  118. type=int,
  119. help='Number of maximum columns to use on the output'
  120. )
  121. output_options_group.addoption(
  122. '--no-colors',
  123. '--no-colours',
  124. default=False,
  125. action='store_true',
  126. help='Disable colour printing.'
  127. )
  128. # <---- CLI Options Setup --------------------------------------------------------------------------------------------
  129. # ----- CLI Terminal Reporter --------------------------------------------------------------------------------------->
  130. class SaltTerminalReporter(TerminalReporter):
  131. def __init__(self, config):
  132. TerminalReporter.__init__(self, config)
  133. @pytest.hookimpl(trylast=True)
  134. def pytest_sessionstart(self, session):
  135. TerminalReporter.pytest_sessionstart(self, session)
  136. self._session = session
  137. def pytest_runtest_logreport(self, report):
  138. TerminalReporter.pytest_runtest_logreport(self, report)
  139. if self.verbosity <= 0:
  140. return
  141. if report.when != 'call':
  142. return
  143. if self.config.getoption('--sys-stats') is False:
  144. return
  145. test_daemon = getattr(self._session, 'test_daemon', None)
  146. if self.verbosity == 1:
  147. line = ' [CPU:{0}%|MEM:{1}%]'.format(psutil.cpu_percent(),
  148. psutil.virtual_memory().percent)
  149. self._tw.write(line)
  150. return
  151. else:
  152. self.ensure_newline()
  153. template = ' {} - CPU: {:6.2f} % MEM: {:6.2f} % SWAP: {:6.2f} %\n'
  154. self._tw.write(
  155. template.format(
  156. ' System',
  157. psutil.cpu_percent(),
  158. psutil.virtual_memory().percent,
  159. psutil.swap_memory().percent
  160. )
  161. )
  162. for name, psproc in self._session.stats_processes.items():
  163. with psproc.oneshot():
  164. cpu = psproc.cpu_percent()
  165. mem = psproc.memory_percent('vms')
  166. swap = psproc.memory_percent('swap')
  167. self._tw.write(template.format(name, cpu, mem, swap))
  168. def pytest_sessionstart(session):
  169. session.stats_processes = OrderedDict((
  170. #('Log Server', test_daemon.log_server),
  171. (' Test Suite Run', psutil.Process(os.getpid())),
  172. ))
  173. # <---- CLI Terminal Reporter ----------------------------------------------------------------------------------------
  174. # ----- Register Markers -------------------------------------------------------------------------------------------->
  175. @pytest.mark.trylast
  176. def pytest_configure(config):
  177. '''
  178. called after command line options have been parsed
  179. and all plugins and initial conftest files been loaded.
  180. '''
  181. config.addinivalue_line('norecursedirs', os.path.join(CODE_DIR, 'templates'))
  182. config.addinivalue_line(
  183. 'markers',
  184. 'destructive_test: Run destructive tests. These tests can include adding '
  185. 'or removing users from your system for example.'
  186. )
  187. config.addinivalue_line(
  188. 'markers',
  189. 'skip_if_not_root: Skip if the current user is not `root`.'
  190. )
  191. config.addinivalue_line(
  192. 'markers',
  193. 'skip_if_binaries_missing(*binaries, check_all=False, message=None): Skip if '
  194. 'any of the passed binaries are not found in path. If \'check_all\' is '
  195. '\'True\', then all binaries must be found.'
  196. )
  197. config.addinivalue_line(
  198. 'markers',
  199. 'requires_network(only_local_network=False): Skip if no networking is set up. '
  200. 'If \'only_local_network\' is \'True\', only the local network is checked.'
  201. )
  202. # Register our terminal reporter
  203. if not getattr(config, 'slaveinput', None):
  204. standard_reporter = config.pluginmanager.getplugin('terminalreporter')
  205. salt_reporter = SaltTerminalReporter(standard_reporter.config)
  206. config.pluginmanager.unregister(standard_reporter)
  207. config.pluginmanager.register(salt_reporter, 'terminalreporter')
  208. # Transplant configuration
  209. TestDaemon.transplant_configs(transport=config.getoption('--transport'))
  210. # <---- Register Markers ---------------------------------------------------------------------------------------------
  211. # ----- Test Setup -------------------------------------------------------------------------------------------------->
  212. @pytest.hookimpl(tryfirst=True)
  213. def pytest_runtest_setup(item):
  214. '''
  215. Fixtures injection based on markers or test skips based on CLI arguments
  216. '''
  217. destructive_tests_marker = item.get_marker('destructive_test')
  218. if destructive_tests_marker is not None:
  219. if item.config.getoption('--run-destructive') is False:
  220. pytest.skip('Destructive tests are disabled')
  221. os.environ['DESTRUCTIVE_TESTS'] = six.text_type(item.config.getoption('--run-destructive'))
  222. expensive_tests_marker = item.get_marker('expensive_test')
  223. if expensive_tests_marker is not None:
  224. if item.config.getoption('--run-expensive') is False:
  225. pytest.skip('Expensive tests are disabled')
  226. os.environ['EXPENSIVE_TESTS'] = six.text_type(item.config.getoption('--run-expensive'))
  227. skip_if_not_root_marker = item.get_marker('skip_if_not_root')
  228. if skip_if_not_root_marker is not None:
  229. if os.getuid() != 0:
  230. pytest.skip('You must be logged in as root to run this test')
  231. skip_if_binaries_missing_marker = item.get_marker('skip_if_binaries_missing')
  232. if skip_if_binaries_missing_marker is not None:
  233. binaries = skip_if_binaries_missing_marker.args
  234. if len(binaries) == 1:
  235. if isinstance(binaries[0], (list, tuple, set, frozenset)):
  236. binaries = binaries[0]
  237. check_all = skip_if_binaries_missing_marker.kwargs.get('check_all', False)
  238. message = skip_if_binaries_missing_marker.kwargs.get('message', None)
  239. if check_all:
  240. for binary in binaries:
  241. if salt.utils.path.which(binary) is None:
  242. pytest.skip(
  243. '{0}The "{1}" binary was not found'.format(
  244. message and '{0}. '.format(message) or '',
  245. binary
  246. )
  247. )
  248. elif salt.utils.path.which_bin(binaries) is None:
  249. pytest.skip(
  250. '{0}None of the following binaries was found: {1}'.format(
  251. message and '{0}. '.format(message) or '',
  252. ', '.join(binaries)
  253. )
  254. )
  255. requires_network_marker = item.get_marker('requires_network')
  256. if requires_network_marker is not None:
  257. only_local_network = requires_network_marker.kwargs.get('only_local_network', False)
  258. has_local_network = False
  259. # First lets try if we have a local network. Inspired in verify_socket
  260. try:
  261. pubsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  262. retsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  263. pubsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  264. pubsock.bind(('', 18000))
  265. pubsock.close()
  266. retsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  267. retsock.bind(('', 18001))
  268. retsock.close()
  269. has_local_network = True
  270. except socket.error:
  271. # I wonder if we just have IPV6 support?
  272. try:
  273. pubsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  274. retsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  275. pubsock.setsockopt(
  276. socket.SOL_SOCKET, socket.SO_REUSEADDR, 1
  277. )
  278. pubsock.bind(('', 18000))
  279. pubsock.close()
  280. retsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  281. retsock.bind(('', 18001))
  282. retsock.close()
  283. has_local_network = True
  284. except socket.error:
  285. # Let's continue
  286. pass
  287. if only_local_network is True:
  288. if has_local_network is False:
  289. # Since we're only supposed to check local network, and no
  290. # local network was detected, skip the test
  291. pytest.skip('No local network was detected')
  292. # We are using the google.com DNS records as numerical IPs to avoid
  293. # DNS lookups which could greatly slow down this check
  294. for addr in ('173.194.41.198', '173.194.41.199', '173.194.41.200',
  295. '173.194.41.201', '173.194.41.206', '173.194.41.192',
  296. '173.194.41.193', '173.194.41.194', '173.194.41.195',
  297. '173.194.41.196', '173.194.41.197'):
  298. try:
  299. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  300. sock.settimeout(0.25)
  301. sock.connect((addr, 80))
  302. sock.close()
  303. # We connected? Stop the loop
  304. break
  305. except socket.error:
  306. # Let's check the next IP
  307. continue
  308. else:
  309. pytest.skip('No internet network connection was detected')
  310. # <---- Test Setup ---------------------------------------------------------------------------------------------------
  311. # ----- Automatic Markers Setup ------------------------------------------------------------------------------------->
  312. def pytest_collection_modifyitems(items):
  313. '''
  314. Automatically add markers to tests based on directory layout
  315. '''
  316. for item in items:
  317. fspath = str(item.fspath)
  318. if '/integration/' in fspath:
  319. if 'test_daemon' not in item.fixturenames:
  320. item.fixturenames.append('test_daemon')
  321. item.add_marker(pytest.mark.integration)
  322. for kind in ('cli', 'client', 'cloud', 'fileserver', 'loader', 'minion', 'modules',
  323. 'netapi', 'output', 'reactor', 'renderers', 'runners', 'sdb', 'shell',
  324. 'ssh', 'states', 'utils', 'wheel'):
  325. if '/{0}/'.format(kind) in fspath:
  326. item.add_marker(getattr(pytest.mark, kind))
  327. break
  328. if '/unit/' in fspath:
  329. item.add_marker(pytest.mark.unit)
  330. for kind in ('acl', 'beacons', 'cli', 'cloud', 'config', 'grains', 'modules', 'netapi',
  331. 'output', 'pillar', 'renderers', 'runners', 'serializers', 'states',
  332. 'templates', 'transport', 'utils'):
  333. if '/{0}/'.format(kind) in fspath:
  334. item.add_marker(getattr(pytest.mark, kind))
  335. break
  336. # <---- Automatic Markers Setup --------------------------------------------------------------------------------------
  337. # ----- Pytest Helpers ---------------------------------------------------------------------------------------------->
  338. if six.PY2:
  339. # backport mock_open from the python 3 unittest.mock library so that we can
  340. # mock read, readline, readlines, and file iteration properly
  341. file_spec = None
  342. def _iterate_read_data(read_data):
  343. # Helper for mock_open:
  344. # Retrieve lines from read_data via a generator so that separate calls to
  345. # readline, read, and readlines are properly interleaved
  346. data_as_list = ['{0}\n'.format(l) for l in read_data.split('\n')]
  347. if data_as_list[-1] == '\n':
  348. # If the last line ended in a newline, the list comprehension will have an
  349. # extra entry that's just a newline. Remove this.
  350. data_as_list = data_as_list[:-1]
  351. else:
  352. # If there wasn't an extra newline by itself, then the file being
  353. # emulated doesn't have a newline to end the last line remove the
  354. # newline that our naive format() added
  355. data_as_list[-1] = data_as_list[-1][:-1]
  356. for line in data_as_list:
  357. yield line
  358. @pytest.helpers.mock.register
  359. def mock_open(mock=None, read_data=''):
  360. """
  361. A helper function to create a mock to replace the use of `open`. It works
  362. for `open` called directly or used as a context manager.
  363. The `mock` argument is the mock object to configure. If `None` (the
  364. default) then a `MagicMock` will be created for you, with the API limited
  365. to methods or attributes available on standard file handles.
  366. `read_data` is a string for the `read` methoddline`, and `readlines` of the
  367. file handle to return. This is an empty string by default.
  368. """
  369. _mock = pytest.importorskip('mock', minversion='2.0.0')
  370. def _readlines_side_effect(*args, **kwargs):
  371. if handle.readlines.return_value is not None:
  372. return handle.readlines.return_value
  373. return list(_data)
  374. def _read_side_effect(*args, **kwargs):
  375. if handle.read.return_value is not None:
  376. return handle.read.return_value
  377. return ''.join(_data)
  378. def _readline_side_effect():
  379. if handle.readline.return_value is not None:
  380. while True:
  381. yield handle.readline.return_value
  382. for line in _data:
  383. yield line
  384. global file_spec
  385. if file_spec is None:
  386. file_spec = file # pylint: disable=undefined-variable
  387. if mock is None:
  388. mock = _mock.MagicMock(name='open', spec=open)
  389. handle = _mock.MagicMock(spec=file_spec)
  390. handle.__enter__.return_value = handle
  391. _data = _iterate_read_data(read_data)
  392. handle.write.return_value = None
  393. handle.read.return_value = None
  394. handle.readline.return_value = None
  395. handle.readlines.return_value = None
  396. handle.read.side_effect = _read_side_effect
  397. handle.readline.side_effect = _readline_side_effect()
  398. handle.readlines.side_effect = _readlines_side_effect
  399. mock.return_value = handle
  400. return mock
  401. else:
  402. @pytest.helpers.mock.register
  403. def mock_open(mock=None, read_data=''):
  404. _mock = pytest.importorskip('mock', minversion='2.0.0')
  405. return _mock.mock_open(mock=mock, read_data=read_data)
  406. # <---- Pytest Helpers -----------------------------------------------------------------------------------------------
  407. # ----- Fixtures Overrides ------------------------------------------------------------------------------------------>
  408. # ----- Generate CLI Scripts ---------------------------------------------------------------------------------------->
  409. @pytest.fixture(scope='session')
  410. def cli_master_script_name():
  411. '''
  412. Return the CLI script basename
  413. '''
  414. return 'cli_salt_master'
  415. @pytest.fixture(scope='session')
  416. def cli_minion_script_name():
  417. '''
  418. Return the CLI script basename
  419. '''
  420. return 'cli_salt_minion'
  421. @pytest.fixture(scope='session')
  422. def cli_salt_script_name():
  423. '''
  424. Return the CLI script basename
  425. '''
  426. return 'cli_salt'
  427. @pytest.fixture(scope='session')
  428. def cli_run_script_name():
  429. '''
  430. Return the CLI script basename
  431. '''
  432. return 'cli_salt_run'
  433. @pytest.fixture(scope='session')
  434. def cli_key_script_name():
  435. '''
  436. Return the CLI script basename
  437. '''
  438. return 'cli_salt_key'
  439. @pytest.fixture(scope='session')
  440. def cli_call_script_name():
  441. '''
  442. Return the CLI script basename
  443. '''
  444. return 'cli_salt_call'
  445. @pytest.fixture(scope='session')
  446. def cli_syndic_script_name():
  447. '''
  448. Return the CLI script basename
  449. '''
  450. return 'cli_salt_syndic'
  451. @pytest.fixture(scope='session')
  452. def cli_ssh_script_name():
  453. '''
  454. Return the CLI script basename
  455. '''
  456. return 'cli_salt_ssh'
  457. @pytest.fixture(scope='session')
  458. def cli_bin_dir(tempdir,
  459. request,
  460. python_executable_path,
  461. cli_master_script_name,
  462. cli_minion_script_name,
  463. cli_salt_script_name,
  464. cli_call_script_name,
  465. cli_key_script_name,
  466. cli_run_script_name,
  467. cli_ssh_script_name):
  468. '''
  469. Return the path to the CLI script directory to use
  470. '''
  471. tmp_cli_scripts_dir = tempdir.join('cli-scrips-bin')
  472. tmp_cli_scripts_dir.ensure(dir=True)
  473. cli_bin_dir_path = tmp_cli_scripts_dir.strpath
  474. # Now that we have the CLI directory created, lets generate the required CLI scripts to run salt's test suite
  475. script_templates = {
  476. 'salt': [
  477. 'from salt.scripts import salt_main\n',
  478. 'if __name__ == \'__main__\':\n'
  479. ' salt_main()'
  480. ],
  481. 'salt-api': [
  482. 'import salt.cli\n',
  483. 'def main():\n',
  484. ' sapi = salt.cli.SaltAPI()',
  485. ' sapi.run()\n',
  486. 'if __name__ == \'__main__\':',
  487. ' main()'
  488. ],
  489. 'common': [
  490. 'from salt.scripts import salt_{0}\n',
  491. 'if __name__ == \'__main__\':\n',
  492. ' salt_{0}()'
  493. ]
  494. }
  495. for script_name in (cli_master_script_name,
  496. cli_minion_script_name,
  497. cli_call_script_name,
  498. cli_key_script_name,
  499. cli_run_script_name,
  500. cli_salt_script_name,
  501. cli_ssh_script_name):
  502. original_script_name = script_name.split('cli_')[-1].replace('_', '-')
  503. script_path = os.path.join(cli_bin_dir_path, script_name)
  504. if not os.path.isfile(script_path):
  505. log.info('Generating {0}'.format(script_path))
  506. with salt.utils.files.fopen(script_path, 'w') as sfh:
  507. script_template = script_templates.get(original_script_name, None)
  508. if script_template is None:
  509. script_template = script_templates.get('common', None)
  510. if script_template is None:
  511. raise RuntimeError(
  512. 'Salt\'s test suite does not know how to handle the "{0}" script'.format(
  513. original_script_name
  514. )
  515. )
  516. sfh.write(
  517. '#!{0}\n\n'.format(python_executable_path) +
  518. 'import sys\n' +
  519. 'CODE_DIR="{0}"\n'.format(request.config.startdir.realpath().strpath) +
  520. 'if CODE_DIR not in sys.path:\n' +
  521. ' sys.path.insert(0, CODE_DIR)\n\n' +
  522. '\n'.join(script_template).format(original_script_name.replace('salt-', ''))
  523. )
  524. fst = os.stat(script_path)
  525. os.chmod(script_path, fst.st_mode | stat.S_IEXEC)
  526. # Return the CLI bin dir value
  527. return cli_bin_dir_path
  528. # <---- Generate CLI Scripts -----------------------------------------------------------------------------------------
  529. # ----- Salt Configuration ------------------------------------------------------------------------------------------>
  530. @pytest.fixture(scope='session')
  531. def session_integration_files_dir(request):
  532. '''
  533. Fixture which returns the salt integration files directory path.
  534. Creates the directory if it does not yet exist.
  535. '''
  536. return request.config.startdir.join('tests').join('integration').join('files')
  537. @pytest.fixture(scope='session')
  538. def session_state_tree_root_dir(session_integration_files_dir):
  539. '''
  540. Fixture which returns the salt state tree root directory path.
  541. Creates the directory if it does not yet exist.
  542. '''
  543. return session_integration_files_dir.join('file')
  544. @pytest.fixture(scope='session')
  545. def session_pillar_tree_root_dir(session_integration_files_dir):
  546. '''
  547. Fixture which returns the salt pillar tree root directory path.
  548. Creates the directory if it does not yet exist.
  549. '''
  550. return session_integration_files_dir.join('pillar')
  551. # <---- Salt Configuration -------------------------------------------------------------------------------------------
  552. # <---- Fixtures Overrides -------------------------------------------------------------------------------------------
  553. # ----- Custom Fixtures Definitions --------------------------------------------------------------------------------->
  554. @pytest.fixture(scope='session')
  555. def test_daemon(request):
  556. values = (('transport', request.config.getoption('--transport')),
  557. ('sysinfo', request.config.getoption('--sysinfo')),
  558. ('no_colors', request.config.getoption('--no-colors')),
  559. ('output_columns', request.config.getoption('--output-columns')),
  560. ('ssh', request.config.getoption('--ssh')),
  561. ('proxy', request.config.getoption('--proxy')))
  562. options = namedtuple('options', [n for n, v in values])(*[v for n, v in values])
  563. fake_parser = namedtuple('parser', 'options')(options)
  564. test_daemon = TestDaemon(fake_parser)
  565. with test_daemon as test_daemon_running:
  566. request.session.test_daemon = test_daemon_running
  567. request.session.stats_processes.update(OrderedDict((
  568. (' Salt Master', psutil.Process(test_daemon.master_process.pid)),
  569. (' Salt Minion', psutil.Process(test_daemon.minion_process.pid)),
  570. (' Salt Sub Minion', psutil.Process(test_daemon.sub_minion_process.pid)),
  571. ('Salt Syndic Master', psutil.Process(test_daemon.smaster_process.pid)),
  572. (' Salt Syndic', psutil.Process(test_daemon.syndic_process.pid)),
  573. )).items())
  574. yield
  575. TestDaemon.clean()
  576. # <---- Custom Fixtures Definitions ----------------------------------------------------------------------------------