case.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #
  2. # Copyright (C) 2013-2017 Intel Corporation
  3. #
  4. # SPDX-License-Identifier: MIT
  5. #
  6. import sys
  7. import os
  8. import shutil
  9. import glob
  10. import errno
  11. from unittest.util import safe_repr
  12. import oeqa.utils.ftools as ftools
  13. from oeqa.utils.commands import runCmd, bitbake, get_bb_var
  14. from oeqa.core.case import OETestCase
  15. import bb.utils
  16. class OESelftestTestCase(OETestCase):
  17. def __init__(self, methodName="runTest"):
  18. self._extra_tear_down_commands = []
  19. super(OESelftestTestCase, self).__init__(methodName)
  20. @classmethod
  21. def setUpClass(cls):
  22. super(OESelftestTestCase, cls).setUpClass()
  23. cls.testlayer_path = cls.tc.config_paths['testlayer_path']
  24. cls.builddir = cls.tc.config_paths['builddir']
  25. cls.localconf_path = cls.tc.config_paths['localconf']
  26. cls.localconf_backup = cls.tc.config_paths['localconf_class_backup']
  27. cls.local_bblayers_path = cls.tc.config_paths['bblayers']
  28. cls.local_bblayers_backup = cls.tc.config_paths['bblayers_class_backup']
  29. cls.testinc_path = os.path.join(cls.tc.config_paths['builddir'],
  30. "conf/selftest.inc")
  31. cls.testinc_bblayers_path = os.path.join(cls.tc.config_paths['builddir'],
  32. "conf/bblayers.inc")
  33. cls.machineinc_path = os.path.join(cls.tc.config_paths['builddir'],
  34. "conf/machine.inc")
  35. cls._track_for_cleanup = [
  36. cls.testinc_path, cls.testinc_bblayers_path,
  37. cls.machineinc_path, cls.localconf_backup,
  38. cls.local_bblayers_backup]
  39. cls.add_include()
  40. @classmethod
  41. def tearDownClass(cls):
  42. cls.remove_include()
  43. cls.remove_inc_files()
  44. super(OESelftestTestCase, cls).tearDownClass()
  45. @classmethod
  46. def add_include(cls):
  47. if "#include added by oe-selftest" \
  48. not in ftools.read_file(os.path.join(cls.builddir, "conf/local.conf")):
  49. cls.logger.info("Adding: \"include selftest.inc\" in %s" % os.path.join(cls.builddir, "conf/local.conf"))
  50. ftools.append_file(os.path.join(cls.builddir, "conf/local.conf"), \
  51. "\n#include added by oe-selftest\ninclude machine.inc\ninclude selftest.inc")
  52. if "#include added by oe-selftest" \
  53. not in ftools.read_file(os.path.join(cls.builddir, "conf/bblayers.conf")):
  54. cls.logger.info("Adding: \"include bblayers.inc\" in bblayers.conf")
  55. ftools.append_file(os.path.join(cls.builddir, "conf/bblayers.conf"), \
  56. "\n#include added by oe-selftest\ninclude bblayers.inc")
  57. @classmethod
  58. def remove_include(cls):
  59. if "#include added by oe-selftest.py" \
  60. in ftools.read_file(os.path.join(cls.builddir, "conf/local.conf")):
  61. cls.logger.info("Removing the include from local.conf")
  62. ftools.remove_from_file(os.path.join(cls.builddir, "conf/local.conf"), \
  63. "\n#include added by oe-selftest.py\ninclude machine.inc\ninclude selftest.inc")
  64. if "#include added by oe-selftest.py" \
  65. in ftools.read_file(os.path.join(cls.builddir, "conf/bblayers.conf")):
  66. cls.logger.info("Removing the include from bblayers.conf")
  67. ftools.remove_from_file(os.path.join(cls.builddir, "conf/bblayers.conf"), \
  68. "\n#include added by oe-selftest.py\ninclude bblayers.inc")
  69. @classmethod
  70. def remove_inc_files(cls):
  71. try:
  72. os.remove(os.path.join(cls.builddir, "conf/selftest.inc"))
  73. for root, _, files in os.walk(cls.testlayer_path):
  74. for f in files:
  75. if f == 'test_recipe.inc':
  76. os.remove(os.path.join(root, f))
  77. except OSError as e:
  78. pass
  79. for incl_file in ['conf/bblayers.inc', 'conf/machine.inc']:
  80. try:
  81. os.remove(os.path.join(cls.builddir, incl_file))
  82. except:
  83. pass
  84. def setUp(self):
  85. super(OESelftestTestCase, self).setUp()
  86. os.chdir(self.builddir)
  87. # Check if local.conf or bblayers.conf files backup exists
  88. # from a previous failed test and restore them
  89. if os.path.isfile(self.localconf_backup) or os.path.isfile(
  90. self.local_bblayers_backup):
  91. self.logger.debug("\
  92. Found a local.conf and/or bblayers.conf backup from a previously aborted test.\
  93. Restoring these files now, but tests should be re-executed from a clean environment\
  94. to ensure accurate results.")
  95. try:
  96. shutil.copyfile(self.localconf_backup, self.localconf_path)
  97. except OSError as e:
  98. if e.errno != errno.ENOENT:
  99. raise
  100. try:
  101. shutil.copyfile(self.local_bblayers_backup,
  102. self.local_bblayers_path)
  103. except OSError as e:
  104. if e.errno != errno.ENOENT:
  105. raise
  106. else:
  107. # backup local.conf and bblayers.conf
  108. shutil.copyfile(self.localconf_path, self.localconf_backup)
  109. shutil.copyfile(self.local_bblayers_path, self.local_bblayers_backup)
  110. self.logger.debug("Creating local.conf and bblayers.conf backups.")
  111. # we don't know what the previous test left around in config or inc files
  112. # if it failed so we need a fresh start
  113. try:
  114. os.remove(self.testinc_path)
  115. except OSError as e:
  116. if e.errno != errno.ENOENT:
  117. raise
  118. for root, _, files in os.walk(self.testlayer_path):
  119. for f in files:
  120. if f == 'test_recipe.inc':
  121. os.remove(os.path.join(root, f))
  122. for incl_file in [self.testinc_bblayers_path, self.machineinc_path]:
  123. try:
  124. os.remove(incl_file)
  125. except OSError as e:
  126. if e.errno != errno.ENOENT:
  127. raise
  128. if self.tc.custommachine:
  129. machine_conf = 'MACHINE ??= "%s"\n' % self.tc.custommachine
  130. self.set_machine_config(machine_conf)
  131. # tests might need their own setup
  132. # but if they overwrite this one they have to call
  133. # super each time, so let's give them an alternative
  134. self.setUpLocal()
  135. def setUpLocal(self):
  136. pass
  137. def tearDown(self):
  138. if self._extra_tear_down_commands:
  139. failed_extra_commands = []
  140. for command in self._extra_tear_down_commands:
  141. result = runCmd(command, ignore_status=True)
  142. if not result.status == 0:
  143. failed_extra_commands.append(command)
  144. if failed_extra_commands:
  145. self.logger.warning("tearDown commands have failed: %s" % ', '.join(map(str, failed_extra_commands)))
  146. self.logger.debug("Trying to move on.")
  147. self._extra_tear_down_commands = []
  148. if self._track_for_cleanup:
  149. for path in self._track_for_cleanup:
  150. if os.path.isdir(path):
  151. bb.utils.remove(path, recurse=True)
  152. if os.path.isfile(path):
  153. os.remove(path)
  154. self._track_for_cleanup = []
  155. self.tearDownLocal()
  156. super(OESelftestTestCase, self).tearDown()
  157. def tearDownLocal(self):
  158. pass
  159. def add_command_to_tearDown(self, command):
  160. """Add test specific commands to the tearDown method"""
  161. self.logger.debug("Adding command '%s' to tearDown for this test." % command)
  162. self._extra_tear_down_commands.append(command)
  163. def track_for_cleanup(self, path):
  164. """Add test specific files or directories to be removed in the tearDown method"""
  165. self.logger.debug("Adding path '%s' to be cleaned up when test is over" % path)
  166. self._track_for_cleanup.append(path)
  167. def write_config(self, data, multiconfig=None):
  168. """Write to config file"""
  169. if multiconfig:
  170. multiconfigdir = "%s/conf/multiconfig" % self.builddir
  171. os.makedirs(multiconfigdir, exist_ok=True)
  172. dest_path = '%s/%s.conf' % (multiconfigdir, multiconfig)
  173. self.track_for_cleanup(dest_path)
  174. else:
  175. dest_path = self.testinc_path
  176. self.logger.debug("Writing to: %s\n%s\n" % (dest_path, data))
  177. ftools.write_file(dest_path, data)
  178. if not multiconfig and self.tc.custommachine and 'MACHINE' in data:
  179. machine = get_bb_var('MACHINE')
  180. self.logger.warning('MACHINE overridden: %s' % machine)
  181. def append_config(self, data):
  182. """Append to <builddir>/conf/selftest.inc"""
  183. self.logger.debug("Appending to: %s\n%s\n" % (self.testinc_path, data))
  184. ftools.append_file(self.testinc_path, data)
  185. if self.tc.custommachine and 'MACHINE' in data:
  186. machine = get_bb_var('MACHINE')
  187. self.logger.warning('MACHINE overridden: %s' % machine)
  188. def remove_config(self, data):
  189. """Remove data from <builddir>/conf/selftest.inc"""
  190. self.logger.debug("Removing from: %s\n%s\n" % (self.testinc_path, data))
  191. ftools.remove_from_file(self.testinc_path, data)
  192. def recipeinc(self, recipe):
  193. """Return absolute path of meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
  194. return os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
  195. def write_recipeinc(self, recipe, data):
  196. """Write to meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
  197. inc_file = self.recipeinc(recipe)
  198. self.logger.debug("Writing to: %s\n%s\n" % (inc_file, data))
  199. ftools.write_file(inc_file, data)
  200. return inc_file
  201. def append_recipeinc(self, recipe, data):
  202. """Append data to meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
  203. inc_file = self.recipeinc(recipe)
  204. self.logger.debug("Appending to: %s\n%s\n" % (inc_file, data))
  205. ftools.append_file(inc_file, data)
  206. return inc_file
  207. def remove_recipeinc(self, recipe, data):
  208. """Remove data from meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
  209. inc_file = self.recipeinc(recipe)
  210. self.logger.debug("Removing from: %s\n%s\n" % (inc_file, data))
  211. ftools.remove_from_file(inc_file, data)
  212. def delete_recipeinc(self, recipe):
  213. """Delete meta-selftest/recipes-test/<recipe>/test_recipe.inc file"""
  214. inc_file = self.recipeinc(recipe)
  215. self.logger.debug("Deleting file: %s" % inc_file)
  216. try:
  217. os.remove(inc_file)
  218. except OSError as e:
  219. if e.errno != errno.ENOENT:
  220. raise
  221. def write_bblayers_config(self, data):
  222. """Write to <builddir>/conf/bblayers.inc"""
  223. self.logger.debug("Writing to: %s\n%s\n" % (self.testinc_bblayers_path, data))
  224. ftools.write_file(self.testinc_bblayers_path, data)
  225. def append_bblayers_config(self, data):
  226. """Append to <builddir>/conf/bblayers.inc"""
  227. self.logger.debug("Appending to: %s\n%s\n" % (self.testinc_bblayers_path, data))
  228. ftools.append_file(self.testinc_bblayers_path, data)
  229. def remove_bblayers_config(self, data):
  230. """Remove data from <builddir>/conf/bblayers.inc"""
  231. self.logger.debug("Removing from: %s\n%s\n" % (self.testinc_bblayers_path, data))
  232. ftools.remove_from_file(self.testinc_bblayers_path, data)
  233. def set_machine_config(self, data):
  234. """Write to <builddir>/conf/machine.inc"""
  235. self.logger.debug("Writing to: %s\n%s\n" % (self.machineinc_path, data))
  236. ftools.write_file(self.machineinc_path, data)
  237. # check does path exist
  238. def assertExists(self, expr, msg=None):
  239. if not os.path.exists(expr):
  240. msg = self._formatMessage(msg, "%s does not exist" % safe_repr(expr))
  241. raise self.failureException(msg)
  242. # check does path not exist
  243. def assertNotExists(self, expr, msg=None):
  244. if os.path.exists(expr):
  245. msg = self._formatMessage(msg, "%s exists when it should not" % safe_repr(expr))
  246. raise self.failureException(msg)