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