runtests.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. """
  2. :codeauthor: Pedro Algarvio (pedro@algarvio.me)
  3. .. _runtime_vars:
  4. Runtime Variables
  5. -----------------
  6. :command:`salt-runtests` provides a variable, :py:attr:`RUNTIME_VARS` which has some common paths defined at
  7. startup:
  8. .. autoattribute:: tests.support.runtests.RUNTIME_VARS
  9. :annotation:
  10. :TMP: Tests suite temporary directory
  11. :TMP_CONF_DIR: Configuration directory from where the daemons that :command:`salt-runtests` starts get their
  12. configuration files.
  13. :TMP_CONF_MASTER_INCLUDES: Salt Master configuration files includes directory. See
  14. :salt_conf_master:`default_include`.
  15. :TMP_CONF_MINION_INCLUDES: Salt Minion configuration files includes directory. Seei
  16. :salt_conf_minion:`include`.
  17. :TMP_CONF_CLOUD_INCLUDES: Salt cloud configuration files includes directory. The same as the salt master and
  18. minion includes configuration, though under a different directory name.
  19. :TMP_CONF_CLOUD_PROFILE_INCLUDES: Salt cloud profiles configuration files includes directory. Same as above.
  20. :TMP_CONF_CLOUD_PROVIDER_INCLUDES: Salt cloud providers configuration files includes directory. Same as above.
  21. :TMP_SCRIPT_DIR: Temporary scripts directory from where the Salt CLI tools will be called when running tests.
  22. :TMP_SALT_INTEGRATION_FILES: Temporary directory from where Salt's test suite integration files are copied to.
  23. :TMP_BASEENV_STATE_TREE: Salt master's **base** environment state tree directory
  24. :TMP_PRODENV_STATE_TREE: Salt master's **production** environment state tree directory
  25. :TMP_BASEENV_PILLAR_TREE: Salt master's **base** environment pillar tree directory
  26. :TMP_PRODENV_PILLAR_TREE: Salt master's **production** environment pillar tree directory
  27. Use it on your test case in case of need. As simple as:
  28. .. code-block:: python
  29. import os
  30. from tests.support.runtests import RUNTIME_VARS
  31. # Path to the testing minion configuration file
  32. minion_config_path = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, 'minion')
  33. .. _`pytest`: http://pytest.org
  34. """
  35. import logging
  36. import os
  37. import shutil
  38. import salt.utils.path
  39. import salt.utils.platform
  40. import tests.support.paths as paths
  41. try:
  42. import pwd
  43. except ImportError:
  44. import salt.utils.win_functions
  45. log = logging.getLogger(__name__)
  46. def this_user():
  47. """
  48. Get the user associated with the current process.
  49. """
  50. if salt.utils.platform.is_windows():
  51. return salt.utils.win_functions.get_current_user(with_domain=False)
  52. return pwd.getpwuid(os.getuid())[0]
  53. class RootsDict(dict):
  54. def merge(self, data):
  55. for key, values in data.items():
  56. if key not in self:
  57. self[key] = values
  58. continue
  59. for value in values:
  60. if value not in self[key]:
  61. self[key].append(value)
  62. return self
  63. def to_dict(self):
  64. return dict(self)
  65. def recursive_copytree(source, destination, overwrite=False):
  66. for root, dirs, files in os.walk(source):
  67. for item in dirs:
  68. src_path = os.path.join(root, item)
  69. dst_path = os.path.join(
  70. destination, src_path.replace(source, "").lstrip(os.sep)
  71. )
  72. if not os.path.exists(dst_path):
  73. log.debug("Creating directory: %s", dst_path)
  74. os.makedirs(dst_path)
  75. for item in files:
  76. src_path = os.path.join(root, item)
  77. dst_path = os.path.join(
  78. destination, src_path.replace(source, "").lstrip(os.sep)
  79. )
  80. if os.path.exists(dst_path) and not overwrite:
  81. if os.stat(src_path).st_mtime > os.stat(dst_path).st_mtime:
  82. log.debug("Copying %s to %s", src_path, dst_path)
  83. shutil.copy2(src_path, dst_path)
  84. else:
  85. if not os.path.isdir(os.path.dirname(dst_path)):
  86. log.debug("Creating directory: %s", os.path.dirname(dst_path))
  87. os.makedirs(os.path.dirname(dst_path))
  88. log.debug("Copying %s to %s", src_path, dst_path)
  89. shutil.copy2(src_path, dst_path)
  90. class RuntimeVars:
  91. __self_attributes__ = ("_vars", "_locked", "lock")
  92. def __init__(self, **kwargs):
  93. self._vars = kwargs
  94. self._locked = False
  95. def lock(self):
  96. # Late import
  97. from salt.utils.immutabletypes import freeze
  98. frozen_vars = freeze(self._vars.copy())
  99. self._vars = frozen_vars
  100. self._locked = True
  101. def __iter__(self):
  102. yield from self._vars.items()
  103. def __getattribute__(self, name):
  104. if name in object.__getattribute__(self, "_vars"):
  105. return object.__getattribute__(self, "_vars")[name]
  106. return object.__getattribute__(self, name)
  107. def __setattr__(self, name, value):
  108. if getattr(self, "_locked", False) is True:
  109. raise RuntimeError(
  110. "After {} is locked, no additional data can be added to it".format(
  111. self.__class__.__name__
  112. )
  113. )
  114. if name in object.__getattribute__(self, "__self_attributes__"):
  115. object.__setattr__(self, name, value)
  116. return
  117. self._vars[name] = value
  118. # <---- Helper Methods -----------------------------------------------------------------------------------------------
  119. # ----- Global Variables -------------------------------------------------------------------------------------------->
  120. XML_OUTPUT_DIR = os.environ.get(
  121. "SALT_XML_TEST_REPORTS_DIR", os.path.join(paths.TMP, "xml-test-reports")
  122. )
  123. # <---- Global Variables ---------------------------------------------------------------------------------------------
  124. # ----- Tests Runtime Variables ------------------------------------------------------------------------------------->
  125. RUNTIME_VARS = RuntimeVars(
  126. TMP=paths.TMP,
  127. SYS_TMP_DIR=paths.SYS_TMP_DIR,
  128. FILES=paths.FILES,
  129. CONF_DIR=paths.CONF_DIR,
  130. PILLAR_DIR=paths.PILLAR_DIR,
  131. ENGINES_DIR=paths.ENGINES_DIR,
  132. LOG_HANDLERS_DIR=paths.LOG_HANDLERS_DIR,
  133. TMP_ROOT_DIR=paths.TMP_ROOT_DIR,
  134. TMP_CONF_DIR=paths.TMP_CONF_DIR,
  135. TMP_MINION_CONF_DIR=paths.TMP_MINION_CONF_DIR,
  136. TMP_CONF_MASTER_INCLUDES=os.path.join(paths.TMP_CONF_DIR, "master.d"),
  137. TMP_CONF_MINION_INCLUDES=os.path.join(paths.TMP_CONF_DIR, "minion.d"),
  138. TMP_CONF_PROXY_INCLUDES=os.path.join(paths.TMP_CONF_DIR, "proxy.d"),
  139. TMP_CONF_CLOUD_INCLUDES=os.path.join(paths.TMP_CONF_DIR, "cloud.conf.d"),
  140. TMP_CONF_CLOUD_PROFILE_INCLUDES=os.path.join(
  141. paths.TMP_CONF_DIR, "cloud.profiles.d"
  142. ),
  143. TMP_CONF_CLOUD_PROVIDER_INCLUDES=os.path.join(
  144. paths.TMP_CONF_DIR, "cloud.providers.d"
  145. ),
  146. TMP_SUB_MINION_CONF_DIR=paths.TMP_SUB_MINION_CONF_DIR,
  147. TMP_SYNDIC_MASTER_CONF_DIR=paths.TMP_SYNDIC_MASTER_CONF_DIR,
  148. TMP_SYNDIC_MINION_CONF_DIR=paths.TMP_SYNDIC_MINION_CONF_DIR,
  149. TMP_PROXY_CONF_DIR=paths.TMP_PROXY_CONF_DIR,
  150. TMP_SSH_CONF_DIR=paths.TMP_SSH_CONF_DIR,
  151. TMP_SCRIPT_DIR=paths.TMP_SCRIPT_DIR,
  152. TMP_STATE_TREE=paths.TMP_STATE_TREE,
  153. TMP_BASEENV_STATE_TREE=paths.TMP_STATE_TREE,
  154. TMP_PILLAR_TREE=paths.TMP_PILLAR_TREE,
  155. TMP_BASEENV_PILLAR_TREE=paths.TMP_PILLAR_TREE,
  156. TMP_PRODENV_STATE_TREE=paths.TMP_PRODENV_STATE_TREE,
  157. TMP_PRODENV_PILLAR_TREE=paths.TMP_PRODENV_PILLAR_TREE,
  158. SHELL_TRUE_PATH=salt.utils.path.which("true")
  159. if not salt.utils.platform.is_windows()
  160. else "cmd /c exit 0 > nul",
  161. SHELL_FALSE_PATH=salt.utils.path.which("false")
  162. if not salt.utils.platform.is_windows()
  163. else "cmd /c exit 1 > nul",
  164. RUNNING_TESTS_USER=this_user(),
  165. RUNTIME_CONFIGS={},
  166. CODE_DIR=paths.CODE_DIR,
  167. SALT_CODE_DIR=paths.SALT_CODE_DIR,
  168. BASE_FILES=paths.BASE_FILES,
  169. PROD_FILES=paths.PROD_FILES,
  170. TESTS_DIR=paths.TESTS_DIR,
  171. PYTEST_SESSION="PYTEST_SESSION" in os.environ,
  172. )
  173. # <---- Tests Runtime Variables --------------------------------------------------------------------------------------