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