ya.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import os
  2. import sys
  3. import logging
  4. import json
  5. from .tools import to_str
  6. from .external import ExternalDataInfo
  7. TESTING_OUT_DIR_NAME = "testing_out_stuff" # XXX import from test.const
  8. yatest_logger = logging.getLogger("ya.test")
  9. class RunMode(object):
  10. Run = "run"
  11. List = "list"
  12. class TestMisconfigurationException(Exception):
  13. pass
  14. class Ya(object):
  15. """
  16. Adds integration with ya, helps in finding dependencies
  17. """
  18. def __init__(
  19. self,
  20. mode=None,
  21. source_root=None,
  22. build_root=None,
  23. dep_roots=None,
  24. output_dir=None,
  25. test_params=None,
  26. context=None,
  27. python_path=None,
  28. valgrind_path=None,
  29. gdb_path=None,
  30. data_root=None,
  31. ):
  32. context_file_path = os.environ.get("YA_TEST_CONTEXT_FILE", None)
  33. if context_file_path:
  34. with open(context_file_path, 'r') as afile:
  35. test_context = json.load(afile)
  36. context_runtime = test_context["runtime"]
  37. context_internal = test_context.get("internal", {})
  38. context_build = test_context.get("build", {})
  39. else:
  40. context_runtime = {}
  41. context_internal = {}
  42. context_build = {}
  43. self._mode = mode
  44. self._build_root = to_str(context_runtime.get("build_root", "")) or build_root
  45. self._source_root = to_str(context_runtime.get("source_root", "")) or source_root or self._detect_source_root()
  46. self._output_dir = to_str(context_runtime.get("output_path", "")) or output_dir or self._detect_output_root()
  47. if not self._output_dir:
  48. raise Exception("Run ya make -t before running test binary")
  49. if not self._source_root:
  50. logging.warning("Source root was not set neither determined, use --source-root to set it explicitly")
  51. if not self._build_root:
  52. if self._source_root:
  53. self._build_root = self._source_root
  54. else:
  55. logging.warning("Build root was not set neither determined, use --build-root to set it explicitly")
  56. if data_root:
  57. self._data_root = data_root
  58. elif self._source_root:
  59. self._data_root = os.path.abspath(os.path.join(self._source_root, "..", "arcadia_tests_data"))
  60. self._dep_roots = dep_roots
  61. self._python_path = to_str(context_runtime.get("python_bin", "")) or python_path
  62. self._valgrind_path = valgrind_path
  63. self._gdb_path = to_str(context_runtime.get("gdb_bin", "")) or gdb_path
  64. self._test_params = {}
  65. self._context = {}
  66. self._test_item_node_id = None
  67. ram_drive_path = to_str(context_runtime.get("ram_drive_path", ""))
  68. if ram_drive_path:
  69. self._test_params["ram_drive_path"] = ram_drive_path
  70. if test_params:
  71. self._test_params.update(dict(x.split('=', 1) for x in test_params))
  72. self._test_params.update(context_runtime.get("test_params", {}))
  73. self._context["project_path"] = context_runtime.get("project_path")
  74. self._context["modulo"] = context_runtime.get("split_count", 1)
  75. self._context["modulo_index"] = context_runtime.get("split_index", 0)
  76. self._context["work_path"] = context_runtime.get("work_path")
  77. self._context["sanitize"] = context_build.get("sanitizer")
  78. self._context["ya_trace_path"] = context_internal.get("trace_file")
  79. self._env_file = context_internal.get("env_file")
  80. if context:
  81. self._context.update(context)
  82. @property
  83. def source_root(self):
  84. return self._source_root
  85. @property
  86. def data_root(self):
  87. return self._data_root
  88. @property
  89. def build_root(self):
  90. return self._build_root
  91. @property
  92. def dep_roots(self):
  93. return self._dep_roots
  94. @property
  95. def output_dir(self):
  96. return self._output_dir
  97. @property
  98. def python_path(self):
  99. return self._python_path or sys.executable
  100. @property
  101. def valgrind_path(self):
  102. if not self._valgrind_path:
  103. raise ValueError("path to valgrind was not pass correctly, use --valgrind-path to fix it")
  104. return self._valgrind_path
  105. @property
  106. def gdb_path(self):
  107. return self._gdb_path
  108. @property
  109. def env_file(self):
  110. return self._env_file
  111. def get_binary(self, *path):
  112. assert self._build_root, "Build root was not set neither determined, use --build-root to set it explicitly"
  113. path = list(path)
  114. if os.name == "nt":
  115. if not path[-1].endswith(".exe"):
  116. path[-1] += ".exe"
  117. target_dirs = [self.build_root]
  118. # Search for binaries within PATH dirs to be able to get path to the binaries specified by basename for exectests
  119. if 'PATH' in os.environ:
  120. target_dirs += os.environ['PATH'].split(':')
  121. for target_dir in target_dirs:
  122. binary_path = os.path.join(target_dir, *path)
  123. if os.path.exists(binary_path):
  124. yatest_logger.debug("Binary was found by %s", binary_path)
  125. return binary_path
  126. error_message = "Cannot find binary '{binary}': make sure it was added in the DEPENDS section".format(binary=path)
  127. yatest_logger.debug(error_message)
  128. if self._mode == RunMode.Run:
  129. raise TestMisconfigurationException(error_message)
  130. def file(self, path, diff_tool=None, local=False, diff_file_name=None, diff_tool_timeout=None):
  131. return ExternalDataInfo.serialize_file(path, diff_tool=diff_tool, local=local, diff_file_name=diff_file_name, diff_tool_timeout=diff_tool_timeout)
  132. def get_param(self, key, default=None):
  133. return self._test_params.get(key, default)
  134. def get_param_dict_copy(self):
  135. return dict(self._test_params)
  136. def get_context(self, key):
  137. return self._context.get(key)
  138. def _detect_source_root(self):
  139. root = None
  140. try:
  141. import library.python.find_root
  142. # try to determine source root from cwd
  143. cwd = os.getcwd()
  144. root = library.python.find_root.detect_root(cwd)
  145. if not root:
  146. # try to determine root pretending we are in the test work dir made from --keep-temps run
  147. env_subdir = os.path.join("environment", "arcadia")
  148. root = library.python.find_root.detect_root(cwd, detector=lambda p: os.path.exists(os.path.join(p, env_subdir)))
  149. except ImportError:
  150. logging.warning("Unable to import library.python.find_root")
  151. return root
  152. def _detect_output_root(self):
  153. # if run from kept test working dir
  154. if os.path.exists(TESTING_OUT_DIR_NAME):
  155. return TESTING_OUT_DIR_NAME
  156. # if run from source dir
  157. if sys.version_info.major == 3:
  158. test_results_dir = "py3test"
  159. else:
  160. test_results_dir = "pytest"
  161. test_results_output_path = os.path.join("test-results", test_results_dir, TESTING_OUT_DIR_NAME)
  162. if os.path.exists(test_results_output_path):
  163. return test_results_output_path
  164. if os.path.exists(os.path.dirname(test_results_output_path)):
  165. os.mkdir(test_results_output_path)
  166. return test_results_output_path
  167. return None
  168. def set_test_item_node_id(self, node_id):
  169. self._test_item_node_id = node_id
  170. def get_test_item_node_id(self):
  171. assert self._test_item_node_id
  172. return self._test_item_node_id
  173. @property
  174. def pytest_config(self):
  175. if not hasattr(self, "_pytest_config"):
  176. import library.python.pytest.plugins.ya as ya_plugin
  177. self._pytest_config = ya_plugin.pytest_config
  178. return self._pytest_config
  179. def set_metric_value(self, name, val):
  180. node_id = self.get_test_item_node_id()
  181. if node_id not in self.pytest_config.test_metrics:
  182. self.pytest_config.test_metrics[node_id] = {}
  183. self.pytest_config.test_metrics[node_id][name] = val
  184. def get_metric_value(self, name, default=None):
  185. res = self.pytest_config.test_metrics.get(self.get_test_item_node_id(), {}).get(name)
  186. if res is None:
  187. return default
  188. return res