blob: ac3308d8a448b7f83f48f21fd67a8c8538f898c4 [file] [log] [blame]
#
# Copyright (C) 2013-2017 Intel Corporation
#
# SPDX-License-Identifier: MIT
#
import sys
import os
import shutil
import glob
import errno
from unittest.util import safe_repr
import oeqa.utils.ftools as ftools
from oeqa.utils.commands import runCmd, bitbake, get_bb_var
from oeqa.core.case import OETestCase
import bb.utils
class OESelftestTestCase(OETestCase):
def __init__(self, methodName="runTest"):
self._extra_tear_down_commands = []
super(OESelftestTestCase, self).__init__(methodName)
@classmethod
def setUpClass(cls):
super(OESelftestTestCase, cls).setUpClass()
cls.testlayer_path = cls.tc.config_paths['testlayer_path']
cls.builddir = cls.tc.config_paths['builddir']
cls.localconf_path = cls.tc.config_paths['localconf']
cls.localconf_backup = cls.tc.config_paths['localconf_class_backup']
cls.local_bblayers_path = cls.tc.config_paths['bblayers']
cls.local_bblayers_backup = cls.tc.config_paths['bblayers_class_backup']
cls.testinc_path = os.path.join(cls.tc.config_paths['builddir'],
"conf/selftest.inc")
cls.testinc_bblayers_path = os.path.join(cls.tc.config_paths['builddir'],
"conf/bblayers.inc")
cls.machineinc_path = os.path.join(cls.tc.config_paths['builddir'],
"conf/machine.inc")
cls._track_for_cleanup = [
cls.testinc_path, cls.testinc_bblayers_path,
cls.machineinc_path, cls.localconf_backup,
cls.local_bblayers_backup]
cls.add_include()
@classmethod
def tearDownClass(cls):
cls.remove_include()
cls.remove_inc_files()
super(OESelftestTestCase, cls).tearDownClass()
@classmethod
def add_include(cls):
if "#include added by oe-selftest" \
not in ftools.read_file(os.path.join(cls.builddir, "conf/local.conf")):
cls.logger.info("Adding: \"include selftest.inc\" in %s" % os.path.join(cls.builddir, "conf/local.conf"))
ftools.append_file(os.path.join(cls.builddir, "conf/local.conf"), \
"\n#include added by oe-selftest\ninclude machine.inc\ninclude selftest.inc")
if "#include added by oe-selftest" \
not in ftools.read_file(os.path.join(cls.builddir, "conf/bblayers.conf")):
cls.logger.info("Adding: \"include bblayers.inc\" in bblayers.conf")
ftools.append_file(os.path.join(cls.builddir, "conf/bblayers.conf"), \
"\n#include added by oe-selftest\ninclude bblayers.inc")
@classmethod
def remove_include(cls):
if "#include added by oe-selftest.py" \
in ftools.read_file(os.path.join(cls.builddir, "conf/local.conf")):
cls.logger.info("Removing the include from local.conf")
ftools.remove_from_file(os.path.join(cls.builddir, "conf/local.conf"), \
"\n#include added by oe-selftest.py\ninclude machine.inc\ninclude selftest.inc")
if "#include added by oe-selftest.py" \
in ftools.read_file(os.path.join(cls.builddir, "conf/bblayers.conf")):
cls.logger.info("Removing the include from bblayers.conf")
ftools.remove_from_file(os.path.join(cls.builddir, "conf/bblayers.conf"), \
"\n#include added by oe-selftest.py\ninclude bblayers.inc")
@classmethod
def remove_inc_files(cls):
try:
os.remove(os.path.join(cls.builddir, "conf/selftest.inc"))
for root, _, files in os.walk(cls.testlayer_path):
for f in files:
if f == 'test_recipe.inc':
os.remove(os.path.join(root, f))
except OSError as e:
pass
for incl_file in ['conf/bblayers.inc', 'conf/machine.inc']:
try:
os.remove(os.path.join(cls.builddir, incl_file))
except:
pass
def setUp(self):
super(OESelftestTestCase, self).setUp()
os.chdir(self.builddir)
# Check if local.conf or bblayers.conf files backup exists
# from a previous failed test and restore them
if os.path.isfile(self.localconf_backup) or os.path.isfile(
self.local_bblayers_backup):
self.logger.debug("\
Found a local.conf and/or bblayers.conf backup from a previously aborted test.\
Restoring these files now, but tests should be re-executed from a clean environment\
to ensure accurate results.")
try:
shutil.copyfile(self.localconf_backup, self.localconf_path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
try:
shutil.copyfile(self.local_bblayers_backup,
self.local_bblayers_path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
else:
# backup local.conf and bblayers.conf
shutil.copyfile(self.localconf_path, self.localconf_backup)
shutil.copyfile(self.local_bblayers_path, self.local_bblayers_backup)
self.logger.debug("Creating local.conf and bblayers.conf backups.")
# we don't know what the previous test left around in config or inc files
# if it failed so we need a fresh start
try:
os.remove(self.testinc_path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
for root, _, files in os.walk(self.testlayer_path):
for f in files:
if f == 'test_recipe.inc':
os.remove(os.path.join(root, f))
for incl_file in [self.testinc_bblayers_path, self.machineinc_path]:
try:
os.remove(incl_file)
except OSError as e:
if e.errno != errno.ENOENT:
raise
if self.tc.custommachine:
machine_conf = 'MACHINE ??= "%s"\n' % self.tc.custommachine
self.set_machine_config(machine_conf)
# tests might need their own setup
# but if they overwrite this one they have to call
# super each time, so let's give them an alternative
self.setUpLocal()
def setUpLocal(self):
pass
def tearDown(self):
if self._extra_tear_down_commands:
failed_extra_commands = []
for command in self._extra_tear_down_commands:
result = runCmd(command, ignore_status=True)
if not result.status == 0:
failed_extra_commands.append(command)
if failed_extra_commands:
self.logger.warning("tearDown commands have failed: %s" % ', '.join(map(str, failed_extra_commands)))
self.logger.debug("Trying to move on.")
self._extra_tear_down_commands = []
if self._track_for_cleanup:
for path in self._track_for_cleanup:
if os.path.isdir(path):
bb.utils.remove(path, recurse=True)
if os.path.isfile(path):
os.remove(path)
self._track_for_cleanup = []
self.tearDownLocal()
super(OESelftestTestCase, self).tearDown()
def tearDownLocal(self):
pass
def add_command_to_tearDown(self, command):
"""Add test specific commands to the tearDown method"""
self.logger.debug("Adding command '%s' to tearDown for this test." % command)
self._extra_tear_down_commands.append(command)
def track_for_cleanup(self, path):
"""Add test specific files or directories to be removed in the tearDown method"""
self.logger.debug("Adding path '%s' to be cleaned up when test is over" % path)
self._track_for_cleanup.append(path)
def write_config(self, data, multiconfig=None):
"""Write to config file"""
if multiconfig:
multiconfigdir = "%s/conf/multiconfig" % self.builddir
os.makedirs(multiconfigdir, exist_ok=True)
dest_path = '%s/%s.conf' % (multiconfigdir, multiconfig)
self.track_for_cleanup(dest_path)
else:
dest_path = self.testinc_path
self.logger.debug("Writing to: %s\n%s\n" % (dest_path, data))
ftools.write_file(dest_path, data)
if not multiconfig and self.tc.custommachine and 'MACHINE' in data:
machine = get_bb_var('MACHINE')
self.logger.warning('MACHINE overridden: %s' % machine)
def append_config(self, data):
"""Append to <builddir>/conf/selftest.inc"""
self.logger.debug("Appending to: %s\n%s\n" % (self.testinc_path, data))
ftools.append_file(self.testinc_path, data)
if self.tc.custommachine and 'MACHINE' in data:
machine = get_bb_var('MACHINE')
self.logger.warning('MACHINE overridden: %s' % machine)
def remove_config(self, data):
"""Remove data from <builddir>/conf/selftest.inc"""
self.logger.debug("Removing from: %s\n%s\n" % (self.testinc_path, data))
ftools.remove_from_file(self.testinc_path, data)
def recipeinc(self, recipe):
"""Return absolute path of meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
return os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
def write_recipeinc(self, recipe, data):
"""Write to meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
inc_file = self.recipeinc(recipe)
self.logger.debug("Writing to: %s\n%s\n" % (inc_file, data))
ftools.write_file(inc_file, data)
return inc_file
def append_recipeinc(self, recipe, data):
"""Append data to meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
inc_file = self.recipeinc(recipe)
self.logger.debug("Appending to: %s\n%s\n" % (inc_file, data))
ftools.append_file(inc_file, data)
return inc_file
def remove_recipeinc(self, recipe, data):
"""Remove data from meta-selftest/recipes-test/<recipe>/test_recipe.inc"""
inc_file = self.recipeinc(recipe)
self.logger.debug("Removing from: %s\n%s\n" % (inc_file, data))
ftools.remove_from_file(inc_file, data)
def delete_recipeinc(self, recipe):
"""Delete meta-selftest/recipes-test/<recipe>/test_recipe.inc file"""
inc_file = self.recipeinc(recipe)
self.logger.debug("Deleting file: %s" % inc_file)
try:
os.remove(inc_file)
except OSError as e:
if e.errno != errno.ENOENT:
raise
def write_bblayers_config(self, data):
"""Write to <builddir>/conf/bblayers.inc"""
self.logger.debug("Writing to: %s\n%s\n" % (self.testinc_bblayers_path, data))
ftools.write_file(self.testinc_bblayers_path, data)
def append_bblayers_config(self, data):
"""Append to <builddir>/conf/bblayers.inc"""
self.logger.debug("Appending to: %s\n%s\n" % (self.testinc_bblayers_path, data))
ftools.append_file(self.testinc_bblayers_path, data)
def remove_bblayers_config(self, data):
"""Remove data from <builddir>/conf/bblayers.inc"""
self.logger.debug("Removing from: %s\n%s\n" % (self.testinc_bblayers_path, data))
ftools.remove_from_file(self.testinc_bblayers_path, data)
def set_machine_config(self, data):
"""Write to <builddir>/conf/machine.inc"""
self.logger.debug("Writing to: %s\n%s\n" % (self.machineinc_path, data))
ftools.write_file(self.machineinc_path, data)
# check does path exist
def assertExists(self, expr, msg=None):
if not os.path.exists(expr):
msg = self._formatMessage(msg, "%s does not exist" % safe_repr(expr))
raise self.failureException(msg)
# check does path not exist
def assertNotExists(self, expr, msg=None):
if os.path.exists(expr):
msg = self._formatMessage(msg, "%s exists when it should not" % safe_repr(expr))
raise self.failureException(msg)