diff options
Diffstat (limited to 'import-layers/yocto-poky/meta/lib/oeqa/selftest')
33 files changed, 2390 insertions, 807 deletions
diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/_toaster.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/_toaster.py deleted file mode 100644 index 15ea9df9e..000000000 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/_toaster.py +++ /dev/null @@ -1,320 +0,0 @@ -import unittest -import os -import sys -import shlex, subprocess -import urllib.request, urllib.parse, urllib.error, subprocess, time, getpass, re, json, shlex - -import oeqa.utils.ftools as ftools -from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd - -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../', 'bitbake/lib/toaster'))) -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toastermain.settings") - -import toastermain.settings -from django.db.models import Q -from orm.models import * -from oeqa.utils.decorators import testcase - -class ToasterSetup(oeSelfTest): - - def recipe_parse(self, file_path, var): - for line in open(file_path,'r'): - if line.find(var) > -1: - val = line.split(" = ")[1].replace("\"", "").strip() - return val - - def fix_file_path(self, file_path): - if ":" in file_path: - file_path=file_path.split(":")[2] - return file_path - -class Toaster_DB_Tests(ToasterSetup): - - # Check if build name is unique - tc_id=795 - @testcase(795) - def test_Build_Unique_Name(self): - all_builds = Build.objects.all().count() - distinct_builds = Build.objects.values('id').distinct().count() - self.assertEqual(distinct_builds, all_builds, msg = 'Build name is not unique') - - # Check if build coocker log path is unique - tc_id=819 - @testcase(819) - def test_Build_Unique_Cooker_Log_Path(self): - distinct_path = Build.objects.values('cooker_log_path').distinct().count() - total_builds = Build.objects.values('id').count() - self.assertEqual(distinct_path, total_builds, msg = 'Build coocker log path is not unique') - - # Check if task order is unique for one build - tc=824 - @testcase(824) - def test_Task_Unique_Order(self): - builds = Build.objects.values('id') - cnt_err = [] - for build in builds: - total_task_order = Task.objects.filter(build = build['id']).values('order').count() - distinct_task_order = Task.objects.filter(build = build['id']).values('order').distinct().count() - if (total_task_order != distinct_task_order): - cnt_err.append(build['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for build id: %s' % cnt_err) - - # Check task order sequence for one build - tc=825 - @testcase(825) - def test_Task_Order_Sequence(self): - builds = builds = Build.objects.values('id') - cnt_err = [] - for build in builds: - tasks = Task.objects.filter(Q(build = build['id']), ~Q(order = None), ~Q(task_name__contains = '_setscene')).values('id', 'order').order_by("order") - cnt_tasks = 0 - for task in tasks: - cnt_tasks += 1 - if (task['order'] != cnt_tasks): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if disk_io matches the difference between EndTimeIO and StartTimeIO in build stats - tc=828 - ### this needs to be updated ### - #def test_Task_Disk_IO_TC828(self): - - # Check if outcome = 2 (SSTATE) then sstate_result must be 3 (RESTORED) - tc=832 - @testcase(832) - def test_Task_If_Outcome_2_Sstate_Result_Must_Be_3(self): - tasks = Task.objects.filter(outcome = 2).values('id', 'sstate_result') - cnt_err = [] - for task in tasks: - if (row['sstate_result'] != 3): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if outcome = 1 (COVERED) or 3 (EXISTING) then sstate_result must be 0 (SSTATE_NA) - tc=833 - @testcase(833) - def test_Task_If_Outcome_1_3_Sstate_Result_Must_Be_0(self): - tasks = Task.objects.filter(outcome__in = (1, 3)).values('id', 'sstate_result') - cnt_err = [] - for task in tasks: - if (task['sstate_result'] != 0): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if outcome is 0 (SUCCESS) or 4 (FAILED) then sstate_result must be 0 (NA), 1 (MISS) or 2 (FAILED) - tc=834 - @testcase(834) - def test_Task_If_Outcome_0_4_Sstate_Result_Must_Be_0_1_2(self): - tasks = Task.objects.filter(outcome__in = (0, 4)).values('id', 'sstate_result') - cnt_err = [] - for task in tasks: - if (task['sstate_result'] not in [0, 1, 2]): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if task_executed = TRUE (1), script_type must be 0 (CODING_NA), 2 (CODING_PYTHON), 3 (CODING_SHELL) - tc=891 - @testcase(891) - def test_Task_If_Task_Executed_True_Script_Type_0_2_3(self): - tasks = Task.objects.filter(task_executed = 1).values('id', 'script_type') - cnt_err = [] - for task in tasks: - if (task['script_type'] not in [0, 2, 3]): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if task_executed = TRUE (1), outcome must be 0 (SUCCESS) or 4 (FAILED) - tc=836 - @testcase(836) - def test_Task_If_Task_Executed_True_Outcome_0_4(self): - tasks = Task.objects.filter(task_executed = 1).values('id', 'outcome') - cnt_err = [] - for task in tasks: - if (task['outcome'] not in [0, 4]): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if task_executed = FALSE (0), script_type must be 0 - tc=890 - @testcase(890) - def test_Task_If_Task_Executed_False_Script_Type_0(self): - tasks = Task.objects.filter(task_executed = 0).values('id', 'script_type') - cnt_err = [] - for task in tasks: - if (task['script_type'] != 0): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Check if task_executed = FALSE (0) and build outcome = SUCCEEDED (0), task outcome must be 1 (COVERED), 2 (CACHED), 3 (PREBUILT), 5 (EMPTY) - tc=837 - @testcase(837) - def test_Task_If_Task_Executed_False_Outcome_1_2_3_5(self): - builds = Build.objects.filter(outcome = 0).values('id') - cnt_err = [] - for build in builds: - tasks = Task.objects.filter(build = build['id'], task_executed = 0).values('id', 'outcome') - for task in tasks: - if (task['outcome'] not in [1, 2, 3, 5]): - cnt_err.append(task['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err) - - # Key verification - tc=888 - @testcase(888) - def test_Target_Installed_Package(self): - rows = Target_Installed_Package.objects.values('id', 'target_id', 'package_id') - cnt_err = [] - for row in rows: - target = Target.objects.filter(id = row['target_id']).values('id') - package = Package.objects.filter(id = row['package_id']).values('id') - if (not target or not package): - cnt_err.append(row['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for target installed package id: %s' % cnt_err) - - # Key verification - tc=889 - @testcase(889) - def test_Task_Dependency(self): - rows = Task_Dependency.objects.values('id', 'task_id', 'depends_on_id') - cnt_err = [] - for row in rows: - task_id = Task.objects.filter(id = row['task_id']).values('id') - depends_on_id = Task.objects.filter(id = row['depends_on_id']).values('id') - if (not task_id or not depends_on_id): - cnt_err.append(row['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for task dependency id: %s' % cnt_err) - - # Check if build target file_name is populated only if is_image=true AND orm_build.outcome=0 then if the file exists and its size matches the file_size value - ### Need to add the tc in the test run - @testcase(1037) - def test_Target_File_Name_Populated(self): - builds = Build.objects.filter(outcome = 0).values('id') - for build in builds: - targets = Target.objects.filter(build_id = build['id'], is_image = 1).values('id') - for target in targets: - target_files = Target_Image_File.objects.filter(target_id = target['id']).values('id', 'file_name', 'file_size') - cnt_err = [] - for file_info in target_files: - target_id = file_info['id'] - target_file_name = file_info['file_name'] - target_file_size = file_info['file_size'] - if (not target_file_name or not target_file_size): - cnt_err.append(target_id) - else: - if (not os.path.exists(target_file_name)): - cnt_err.append(target_id) - else: - if (os.path.getsize(target_file_name) != target_file_size): - cnt_err.append(target_id) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for target image file id: %s' % cnt_err) - - # Key verification - tc=884 - @testcase(884) - def test_Package_Dependency(self): - cnt_err = [] - deps = Package_Dependency.objects.values('id', 'package_id', 'depends_on_id') - for dep in deps: - if (dep['package_id'] == dep['depends_on_id']): - cnt_err.append(dep['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package dependency id: %s' % cnt_err) - - # Recipe key verification, recipe name does not depends on a recipe having the same name - tc=883 - @testcase(883) - def test_Recipe_Dependency(self): - deps = Recipe_Dependency.objects.values('id', 'recipe_id', 'depends_on_id') - cnt_err = [] - for dep in deps: - if (not dep['recipe_id'] or not dep['depends_on_id']): - cnt_err.append(dep['id']) - else: - name = Recipe.objects.filter(id = dep['recipe_id']).values('name') - dep_name = Recipe.objects.filter(id = dep['depends_on_id']).values('name') - if (name == dep_name): - cnt_err.append(dep['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe dependency id: %s' % cnt_err) - - # Check if package name does not start with a number (0-9) - tc=846 - @testcase(846) - def test_Package_Name_For_Number(self): - packages = Package.objects.filter(~Q(size = -1)).values('id', 'name') - cnt_err = [] - for package in packages: - if (package['name'][0].isdigit() is True): - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check if package version starts with a number (0-9) - tc=847 - @testcase(847) - def test_Package_Version_Starts_With_Number(self): - packages = Package.objects.filter(~Q(size = -1)).values('id', 'version') - cnt_err = [] - for package in packages: - if (package['version'][0].isdigit() is False): - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check if package revision starts with 'r' - tc=848 - @testcase(848) - def test_Package_Revision_Starts_With_r(self): - packages = Package.objects.filter(~Q(size = -1)).values('id', 'revision') - cnt_err = [] - for package in packages: - if (package['revision'][0].startswith("r") is False): - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check the validity of the package build_id - ### TC must be added in test run - @testcase(1038) - def test_Package_Build_Id(self): - packages = Package.objects.filter(~Q(size = -1)).values('id', 'build_id') - cnt_err = [] - for package in packages: - build_id = Build.objects.filter(id = package['build_id']).values('id') - if (not build_id): - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check the validity of package recipe_id - ### TC must be added in test run - @testcase(1039) - def test_Package_Recipe_Id(self): - packages = Package.objects.filter(~Q(size = -1)).values('id', 'recipe_id') - cnt_err = [] - for package in packages: - recipe_id = Recipe.objects.filter(id = package['recipe_id']).values('id') - if (not recipe_id): - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check if package installed_size field is not null - ### TC must be aded in test run - @testcase(1040) - def test_Package_Installed_Size_Not_NULL(self): - packages = Package.objects.filter(installed_size__isnull = True).values('id') - cnt_err = [] - for package in packages: - cnt_err.append(package['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err) - - # Check if all layers requests return exit code is 200 - tc=843 - @testcase(843) - def test_Layers_Requests_Exit_Code(self): - layers = Layer.objects.values('id', 'layer_index_url') - cnt_err = [] - for layer in layers: - resp = urllib.request.urlopen(layer['layer_index_url']) - if (resp.getcode() != 200): - cnt_err.append(layer['id']) - self.assertEqual(len(cnt_err), 0, msg = 'Errors for layer id: %s' % cnt_err) - - # Check if django server starts regardless of the timezone set on the machine - tc=905 - @testcase(905) - def test_Start_Django_Timezone(self): - current_path = os.getcwd() - zonefilelist = [] - ZONEINFOPATH = '/usr/share/zoneinfo/' - os.chdir("../bitbake/lib/toaster/") - cnt_err = 0 - for filename in os.listdir(ZONEINFOPATH): - if os.path.isfile(os.path.join(ZONEINFOPATH, filename)): - zonefilelist.append(filename) - for k in range(len(zonefilelist)): - if k <= 5: - files = zonefilelist[k] - os.system("export TZ="+str(files)+"; python manage.py runserver > /dev/null 2>&1 &") - time.sleep(3) - pid = subprocess.check_output("ps aux | grep '[/u]sr/bin/python manage.py runserver' | awk '{print $2}'", shell = True) - if pid: - os.system("kill -9 "+str(pid)) - else: - cnt_err.append(zonefilelist[k]) - self.assertEqual(cnt_err, 0, msg = 'Errors django server does not start with timezone: %s' % cnt_err) - os.chdir(current_path) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/archiver.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/archiver.py index f2030c446..7f01c36d4 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/archiver.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/archiver.py @@ -1,5 +1,5 @@ from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import bitbake, get_bb_var +from oeqa.utils.commands import bitbake, get_bb_vars from oeqa.utils.decorators import testcase import glob import os @@ -26,25 +26,94 @@ class Archiver(oeSelfTest): features += 'ARCHIVER_MODE[src] = "original"\n' features += 'COPYLEFT_PN_INCLUDE = "%s"\n' % include_recipe features += 'COPYLEFT_PN_EXCLUDE = "%s"\n' % exclude_recipe - - # Update local.conf self.write_config(features) - tmp_dir = get_bb_var('TMPDIR') - deploy_dir_src = get_bb_var('DEPLOY_DIR_SRC') - target_sys = get_bb_var('TARGET_SYS') - src_path = os.path.join(deploy_dir_src, target_sys) - - # Delete tmp directory - shutil.rmtree(tmp_dir) + bitbake('-c clean %s %s' % (include_recipe, exclude_recipe)) + bitbake("-c deploy_archives %s %s" % (include_recipe, exclude_recipe)) - # Build core-image-minimal - bitbake('core-image-minimal') + bb_vars = get_bb_vars(['DEPLOY_DIR_SRC', 'TARGET_SYS']) + src_path = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['TARGET_SYS']) # Check that include_recipe was included - is_included = len(glob.glob(src_path + '/%s*' % include_recipe)) - self.assertEqual(1, is_included, 'Recipe %s was not included.' % include_recipe) + included_present = len(glob.glob(src_path + '/%s-*' % include_recipe)) + self.assertTrue(included_present, 'Recipe %s was not included.' % include_recipe) # Check that exclude_recipe was excluded - is_excluded = len(glob.glob(src_path + '/%s*' % exclude_recipe)) - self.assertEqual(0, is_excluded, 'Recipe %s was not excluded.' % exclude_recipe) + excluded_present = len(glob.glob(src_path + '/%s-*' % exclude_recipe)) + self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % exclude_recipe) + + + def test_archiver_filters_by_type(self): + """ + Summary: The archiver is documented to filter on the recipe type. + Expected: 1. included recipe type (target) should be included + 2. other types should be excluded + Product: oe-core + Author: André Draszik <adraszik@tycoint.com> + """ + + target_recipe = 'initscripts' + native_recipe = 'zlib-native' + + features = 'INHERIT += "archiver"\n' + features += 'ARCHIVER_MODE[src] = "original"\n' + features += 'COPYLEFT_RECIPE_TYPES = "target"\n' + self.write_config(features) + + bitbake('-c clean %s %s' % (target_recipe, native_recipe)) + bitbake("%s -c deploy_archives %s" % (target_recipe, native_recipe)) + + bb_vars = get_bb_vars(['DEPLOY_DIR_SRC', 'TARGET_SYS', 'BUILD_SYS']) + src_path_target = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['TARGET_SYS']) + src_path_native = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['BUILD_SYS']) + + # Check that target_recipe was included + included_present = len(glob.glob(src_path_target + '/%s-*' % target_recipe)) + self.assertTrue(included_present, 'Recipe %s was not included.' % target_recipe) + + # Check that native_recipe was excluded + excluded_present = len(glob.glob(src_path_native + '/%s-*' % native_recipe)) + self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % native_recipe) + + def test_archiver_filters_by_type_and_name(self): + """ + Summary: Test that the archiver archives by recipe type, taking the + recipe name into account. + Expected: 1. included recipe type (target) should be included + 2. other types should be excluded + 3. recipe by name should be included / excluded, + overriding previous decision by type + Product: oe-core + Author: André Draszik <adraszik@tycoint.com> + """ + + target_recipes = [ 'initscripts', 'zlib' ] + native_recipes = [ 'update-rc.d-native', 'zlib-native' ] + + features = 'INHERIT += "archiver"\n' + features += 'ARCHIVER_MODE[src] = "original"\n' + features += 'COPYLEFT_RECIPE_TYPES = "target"\n' + features += 'COPYLEFT_PN_INCLUDE = "%s"\n' % native_recipes[1] + features += 'COPYLEFT_PN_EXCLUDE = "%s"\n' % target_recipes[1] + self.write_config(features) + + bitbake('-c clean %s %s' % (' '.join(target_recipes), ' '.join(native_recipes))) + bitbake('-c deploy_archives %s %s' % (' '.join(target_recipes), ' '.join(native_recipes))) + + bb_vars = get_bb_vars(['DEPLOY_DIR_SRC', 'TARGET_SYS', 'BUILD_SYS']) + src_path_target = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['TARGET_SYS']) + src_path_native = os.path.join(bb_vars['DEPLOY_DIR_SRC'], bb_vars['BUILD_SYS']) + + # Check that target_recipe[0] and native_recipes[1] were included + included_present = len(glob.glob(src_path_target + '/%s-*' % target_recipes[0])) + self.assertTrue(included_present, 'Recipe %s was not included.' % target_recipes[0]) + + included_present = len(glob.glob(src_path_native + '/%s-*' % native_recipes[1])) + self.assertTrue(included_present, 'Recipe %s was not included.' % native_recipes[1]) + + # Check that native_recipes[0] and target_recipes[1] were excluded + excluded_present = len(glob.glob(src_path_native + '/%s-*' % native_recipes[0])) + self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % native_recipes[0]) + + excluded_present = len(glob.glob(src_path_target + '/%s-*' % target_recipes[1])) + self.assertFalse(excluded_present, 'Recipe %s was not excluded.' % target_recipes[1]) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/base.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/base.py index 26c93f905..47a8ea827 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/base.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/base.py @@ -163,7 +163,7 @@ be re-executed from a clean environment to ensure accurate results.") # remove data from <builddir>/conf/selftest.inc def remove_config(self, data): - self.log.debug("Removing from: %s\n\%s\n" % (self.testinc_path, data)) + self.log.debug("Removing from: %s\n%s\n" % (self.testinc_path, data)) ftools.remove_from_file(self.testinc_path, data) # write to meta-sefltest/recipes-test/<recipe>/test_recipe.inc @@ -206,7 +206,7 @@ be re-executed from a clean environment to ensure accurate results.") # remove data from <builddir>/conf/bblayers.inc def remove_bblayers_config(self, data): - self.log.debug("Removing from: %s\n\%s\n" % (self.testinc_bblayers_path, data)) + self.log.debug("Removing from: %s\n%s\n" % (self.testinc_bblayers_path, data)) ftools.remove_from_file(self.testinc_bblayers_path, data) # write to <builddir>/conf/machine.inc diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/bblayers.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/bblayers.py index d23675e84..cd658c5d4 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/bblayers.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/bblayers.py @@ -71,17 +71,12 @@ class BitbakeLayers(oeSelfTest): result = runCmd('bitbake-layers show-recipes') self.assertIn('aspell:', result.output) self.assertIn('mtd-utils:', result.output) - self.assertIn('linux-yocto:', result.output) self.assertIn('core-image-minimal:', result.output) result = runCmd('bitbake-layers show-recipes mtd-utils') self.assertIn('mtd-utils:', result.output) self.assertNotIn('aspell:', result.output) - result = runCmd('bitbake-layers show-recipes -i kernel') - self.assertIn('linux-yocto:', result.output) - self.assertNotIn('mtd-utils:', result.output) result = runCmd('bitbake-layers show-recipes -i image') self.assertIn('core-image-minimal', result.output) - self.assertNotIn('linux-yocto:', result.output) self.assertNotIn('mtd-utils:', result.output) result = runCmd('bitbake-layers show-recipes -i cmake,pkgconfig') self.assertIn('libproxy:', result.output) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/bbtests.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/bbtests.py index 4ce935fc1..46e09f509 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/bbtests.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/bbtests.py @@ -3,7 +3,7 @@ import re import oeqa.utils.ftools as ftools from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars from oeqa.utils.decorators import testcase class BitbakeTests(oeSelfTest): @@ -78,9 +78,10 @@ class BitbakeTests(oeSelfTest): # test 1 from bug 5875 test_recipe = 'zlib' test_data = "Microsoft Made No Profit From Anyone's Zunes Yo" - image_dir = get_bb_var('D', test_recipe) - pkgsplit_dir = get_bb_var('PKGDEST', test_recipe) - man_dir = get_bb_var('mandir', test_recipe) + bb_vars = get_bb_vars(['D', 'PKGDEST', 'mandir'], test_recipe) + image_dir = bb_vars['D'] + pkgsplit_dir = bb_vars['PKGDEST'] + man_dir = bb_vars['mandir'] bitbake('-c clean %s' % test_recipe) bitbake('-c package -f %s' % test_recipe) @@ -112,17 +113,18 @@ class BitbakeTests(oeSelfTest): @testcase(167) def test_bitbake_g(self): - result = bitbake('-g core-image-full-cmdline') - for f in ['pn-buildlist', 'pn-depends.dot', 'package-depends.dot', 'task-depends.dot']: + result = bitbake('-g core-image-minimal') + for f in ['pn-buildlist', 'recipe-depends.dot', 'task-depends.dot']: self.addCleanup(os.remove, f) - self.assertTrue('NOTE: PN build list saved to \'pn-buildlist\'' in result.output, msg = "No dependency \"pn-buildlist\" file was generated for the given task target. bitbake output: %s" % result.output) - self.assertTrue('openssh' in ftools.read_file(os.path.join(self.builddir, 'pn-buildlist')), msg = "No \"openssh\" dependency found in pn-buildlist file.") + self.assertTrue('Task dependencies saved to \'task-depends.dot\'' in result.output, msg = "No task dependency \"task-depends.dot\" file was generated for the given task target. bitbake output: %s" % result.output) + self.assertTrue('busybox' in ftools.read_file(os.path.join(self.builddir, 'task-depends.dot')), msg = "No \"busybox\" dependency found in task-depends.dot file.") @testcase(899) def test_image_manifest(self): bitbake('core-image-minimal') - deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal") - imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal") + bb_vars = get_bb_vars(["DEPLOY_DIR_IMAGE", "IMAGE_LINK_NAME"], "core-image-minimal") + deploydir = bb_vars["DEPLOY_DIR_IMAGE"] + imagename = bb_vars["IMAGE_LINK_NAME"] manifest = os.path.join(deploydir, imagename + ".manifest") self.assertTrue(os.path.islink(manifest), msg="No manifest file created for image. It should have been created in %s" % manifest) @@ -149,19 +151,21 @@ doesn't exist, yet fetcher didn't report any error. bitbake output: %s" % result @testcase(171) def test_rename_downloaded_file(self): + # TODO unique dldir instead of using cleanall + # TODO: need to set sstatedir? self.write_config("""DL_DIR = \"${TOPDIR}/download-selftest\" SSTATE_DIR = \"${TOPDIR}/download-selftest\" """) self.track_for_cleanup(os.path.join(self.builddir, "download-selftest")) - data = 'SRC_URI_append = ";downloadfilename=test-aspell.tar.gz"' + data = 'SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz;downloadfilename=test-aspell.tar.gz"' self.write_recipeinc('aspell', data) - bitbake('-ccleanall aspell') - result = bitbake('-c fetch aspell', ignore_status=True) + result = bitbake('-f -c fetch aspell', ignore_status=True) self.delete_recipeinc('aspell') self.assertEqual(result.status, 0, msg = "Couldn't fetch aspell. %s" % result.output) - self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz')), msg = "File rename failed. No corresponding test-aspell.tar.gz file found under %s" % str(get_bb_var("DL_DIR"))) - self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz.done')), "File rename failed. No corresponding test-aspell.tar.gz.done file found under %s" % str(get_bb_var("DL_DIR"))) + dl_dir = get_bb_var("DL_DIR") + self.assertTrue(os.path.isfile(os.path.join(dl_dir, 'test-aspell.tar.gz')), msg = "File rename failed. No corresponding test-aspell.tar.gz file found under %s" % dl_dir) + self.assertTrue(os.path.isfile(os.path.join(dl_dir, 'test-aspell.tar.gz.done')), "File rename failed. No corresponding test-aspell.tar.gz.done file found under %s" % dl_dir) @testcase(1028) def test_environment(self): @@ -227,14 +231,12 @@ INHERIT_remove = \"report-error\" @testcase(1119) def test_non_gplv3(self): - data = 'INCOMPATIBLE_LICENSE = "GPLv3"' - conf = os.path.join(self.builddir, 'conf/local.conf') - ftools.append_file(conf ,data) - self.addCleanup(ftools.remove_from_file, conf ,data) - result = bitbake('readline', ignore_status=True) + self.write_config('INCOMPATIBLE_LICENSE = "GPLv3"') + result = bitbake('selftest-ed', ignore_status=True) self.assertEqual(result.status, 0, "Bitbake failed, exit code %s, output %s" % (result.status, result.output)) - self.assertFalse(os.path.isfile(os.path.join(self.builddir, 'tmp/deploy/licenses/readline/generic_GPLv3'))) - self.assertTrue(os.path.isfile(os.path.join(self.builddir, 'tmp/deploy/licenses/readline/generic_GPLv2'))) + lic_dir = get_bb_var('LICENSE_DIRECTORY') + self.assertFalse(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPLv3'))) + self.assertTrue(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPLv2'))) @testcase(1422) def test_setscene_only(self): @@ -255,8 +257,9 @@ INHERIT_remove = \"report-error\" def test_bbappend_order(self): """ Bitbake should bbappend to recipe in a predictable order """ test_recipe = 'ed' - test_recipe_summary_before = get_bb_var('SUMMARY', test_recipe) - test_recipe_pv = get_bb_var('PV', test_recipe) + bb_vars = get_bb_vars(['SUMMARY', 'PV'], test_recipe) + test_recipe_summary_before = bb_vars['SUMMARY'] + test_recipe_pv = bb_vars['PV'] recipe_append_file = test_recipe + '_' + test_recipe_pv + '.bbappend' expected_recipe_summary = test_recipe_summary_before diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildhistory.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildhistory.py index 674da6205..008c39c95 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildhistory.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildhistory.py @@ -3,14 +3,15 @@ import re import datetime from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import bitbake, get_bb_var +from oeqa.utils.commands import bitbake, get_bb_vars from oeqa.utils.decorators import testcase class BuildhistoryBase(oeSelfTest): def config_buildhistory(self, tmp_bh_location=False): - if (not 'buildhistory' in get_bb_var('USER_CLASSES')) and (not 'buildhistory' in get_bb_var('INHERIT')): + bb_vars = get_bb_vars(['USER_CLASSES', 'INHERIT']) + if (not 'buildhistory' in bb_vars['USER_CLASSES']) and (not 'buildhistory' in bb_vars['INHERIT']): add_buildhistory_config = 'INHERIT += "buildhistory"\nBUILDHISTORY_COMMIT = "1"' self.append_config(add_buildhistory_config) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py index 47549550c..a6e0203f5 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/buildoptions.py @@ -5,7 +5,7 @@ import shutil import tempfile from oeqa.selftest.base import oeSelfTest from oeqa.selftest.buildhistory import BuildhistoryBase -from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars import oeqa.utils.ftools as ftools from oeqa.utils.decorators import testcase @@ -16,32 +16,38 @@ class ImageOptionsTests(oeSelfTest): image_pkgtype = get_bb_var("IMAGE_PKGTYPE") if image_pkgtype != 'rpm': self.skipTest('Not using RPM as main package format') - bitbake("-c cleanall core-image-minimal") + bitbake("-c clean core-image-minimal") self.write_config('INC_RPM_IMAGE_GEN = "1"') self.append_config('IMAGE_FEATURES += "ssh-server-openssh"') bitbake("core-image-minimal") log_data_file = os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs") log_data_created = ftools.read_file(log_data_file) - incremental_created = re.search("NOTE: load old install solution for incremental install\nNOTE: old install solution not exist\nNOTE: creating new install solution for incremental install(\n.*)*NOTE: Installing the following packages:.*packagegroup-core-ssh-openssh", log_data_created) + incremental_created = re.search("Installing : packagegroup-core-ssh-openssh", log_data_created) self.remove_config('IMAGE_FEATURES += "ssh-server-openssh"') self.assertTrue(incremental_created, msg = "Match failed in:\n%s" % log_data_created) bitbake("core-image-minimal") log_data_removed = ftools.read_file(log_data_file) - incremental_removed = re.search("NOTE: load old install solution for incremental install\nNOTE: creating new install solution for incremental install(\n.*)*NOTE: incremental removed:.*openssh-sshd-.*", log_data_removed) + incremental_removed = re.search("Erasing : packagegroup-core-ssh-openssh", log_data_removed) self.assertTrue(incremental_removed, msg = "Match failed in:\n%s" % log_data_removed) @testcase(286) def test_ccache_tool(self): bitbake("ccache-native") - self.assertTrue(os.path.isfile(os.path.join(get_bb_var('STAGING_BINDIR_NATIVE', 'ccache-native'), "ccache")), msg = "No ccache found under %s" % str(get_bb_var('STAGING_BINDIR_NATIVE', 'ccache-native'))) + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'ccache-native') + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "ccache" + self.assertTrue(os.path.isfile(p), msg = "No ccache found (%s)" % p) self.write_config('INHERIT += "ccache"') self.add_command_to_tearDown('bitbake -c clean m4') bitbake("m4 -f -c compile") - res = runCmd("grep ccache %s" % (os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")), ignore_status=True) - self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile. For further details: %s" % os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")) + log_compile = os.path.join(get_bb_var("WORKDIR","m4"), "temp/log.do_compile") + res = runCmd("grep ccache %s" % log_compile, ignore_status=True) + self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile. For further details: %s" % log_compile) @testcase(1435) def test_read_only_image(self): + distro_features = get_bb_var('DISTRO_FEATURES') + if not ('x11' in distro_features and 'opengl' in distro_features): + self.skipTest('core-image-sato requires x11 and opengl in distro features') self.write_config('IMAGE_FEATURES += "read-only-rootfs"') bitbake("core-image-sato") # do_image will fail if there are any pending postinsts @@ -157,7 +163,6 @@ class BuildhistoryTests(BuildhistoryBase): @testcase(294) def test_buildhistory_buildtime_pr_backwards(self): - self.add_command_to_tearDown('cleanup-workdir') target = 'xcursor-transparent-theme' error = "ERROR:.*QA Issue: Package version for package %s went backwards which would break package feeds from (.*-r1.* to .*-r0.*)" % target self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True) @@ -169,11 +174,11 @@ class ArchiverTest(oeSelfTest): """ Test for archiving the work directory and exporting the source files. """ - self.add_command_to_tearDown('cleanup-workdir') self.write_config("INHERIT += \"archiver\"\nARCHIVER_MODE[src] = \"original\"\nARCHIVER_MODE[srpm] = \"1\"") res = bitbake("xcursor-transparent-theme", ignore_status=True) self.assertEqual(res.status, 0, "\nCouldn't build xcursortransparenttheme.\nbitbake output %s" % res.output) - pkgs_path = g.glob(str(self.builddir) + "/tmp/deploy/sources/allarch*/xcurs*") + deploy_dir_src = get_bb_var('DEPLOY_DIR_SRC') + pkgs_path = g.glob(str(deploy_dir_src) + "/allarch*/xcurs*") src_file_glob = str(pkgs_path[0]) + "/xcursor*.src.rpm" tar_file_glob = str(pkgs_path[0]) + "/xcursor*.tar.gz" - self.assertTrue((g.glob(src_file_glob) and g.glob(tar_file_glob)), "Couldn't find .src.rpm and .tar.gz files under tmp/deploy/sources/allarch*/xcursor*") + self.assertTrue((g.glob(src_file_glob) and g.glob(tar_file_glob)), "Couldn't find .src.rpm and .tar.gz files under %s/allarch*/xcursor*" % deploy_dir_src) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/containerimage.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/containerimage.py new file mode 100644 index 000000000..def481f14 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/containerimage.py @@ -0,0 +1,83 @@ +import os + +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import bitbake, get_bb_vars, runCmd + +# This test builds an image with using the "container" IMAGE_FSTYPE, and +# ensures that then files in the image are only the ones expected. +# +# The only package added to the image is container_image_testpkg, which +# contains one file. However, due to some other things not cleaning up during +# rootfs creation, there is some cruft. Ideally bugs will be filed and the +# cruft removed, but for now we whitelist some known set. +# +# Also for performance reasons we're only checking the cruft when using ipk. +# When using deb, and rpm it is a bit different and we could test all +# of them, but this test is more to catch if other packages get added by +# default other than what is in ROOTFS_BOOTSTRAP_INSTALL. +# +class ContainerImageTests(oeSelfTest): + + # Verify that when specifying a IMAGE_TYPEDEP_ of the form "foo.bar" that + # the conversion type bar gets added as a dep as well + def test_expected_files(self): + + def get_each_path_part(path): + if path: + part = [ '.' + path + '/' ] + result = get_each_path_part(path.rsplit('/', 1)[0]) + if result: + return part + result + else: + return part + else: + return None + + self.write_config("""PREFERRED_PROVIDER_virtual/kernel = "linux-dummy" +IMAGE_FSTYPES = "container" +PACKAGE_CLASSES = "package_ipk" +IMAGE_FEATURES = "" +""") + + bbvars = get_bb_vars(['bindir', 'sysconfdir', 'localstatedir', + 'DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], + target='container-test-image') + expected_files = [ + './', + '.{bindir}/theapp', + '.{sysconfdir}/default/', + '.{sysconfdir}/default/postinst', + '.{sysconfdir}/ld.so.cache', + '.{sysconfdir}/timestamp', + '.{sysconfdir}/version', + './run/', + '.{localstatedir}/cache/', + '.{localstatedir}/cache/ldconfig/', + '.{localstatedir}/cache/ldconfig/aux-cache', + '.{localstatedir}/cache/opkg/', + '.{localstatedir}/lib/', + '.{localstatedir}/lib/opkg/' + ] + + expected_files = [ x.format(bindir=bbvars['bindir'], + sysconfdir=bbvars['sysconfdir'], + localstatedir=bbvars['localstatedir']) + for x in expected_files ] + + # Since tar lists all directories individually, make sure each element + # from bindir, sysconfdir, etc is added + expected_files += get_each_path_part(bbvars['bindir']) + expected_files += get_each_path_part(bbvars['sysconfdir']) + expected_files += get_each_path_part(bbvars['localstatedir']) + + expected_files = sorted(expected_files) + + # Build the image of course + bitbake('container-test-image') + + image = os.path.join(bbvars['DEPLOY_DIR_IMAGE'], + bbvars['IMAGE_LINK_NAME'] + '.tar.bz2') + + # Ensure the files in the image are what we expect + result = runCmd("tar tf {} | sort".format(image), shell=True) + self.assertEqual(result.output.split('\n'), expected_files) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/devtool.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/devtool.py index 302ec5d42..57048665c 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/devtool.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/devtool.py @@ -45,9 +45,12 @@ class DevtoolBase(oeSelfTest): if var and var in checkvars: needvalue = checkvars.pop(var) if needvalue is None: - self.fail('Variable %s should not appear in recipe') + self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value)) if isinstance(needvalue, set): - value = set(value.split()) + if var == 'LICENSE': + value = set(value.split(' & ')) + else: + value = set(value.split()) self.assertEqual(value, needvalue, 'values for %s do not match' % var) @@ -210,9 +213,10 @@ class DevtoolTests(DevtoolBase): bitbake('pv -c cleansstate') # Test devtool build result = runCmd('devtool build pv') - installdir = get_bb_var('D', 'pv') + bb_vars = get_bb_vars(['D', 'bindir'], 'pv') + installdir = bb_vars['D'] self.assertTrue(installdir, 'Could not query installdir variable') - bindir = get_bb_var('bindir', 'pv') + bindir = bb_vars['bindir'] self.assertTrue(bindir, 'Could not query bindir variable') if bindir[0] == '/': bindir = bindir[1:] @@ -260,8 +264,6 @@ class DevtoolTests(DevtoolBase): @testcase(1162) def test_devtool_add_library(self): - # We don't have the ability to pick up this dependency automatically yet... - bitbake('libusb1') # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) @@ -290,13 +292,17 @@ class DevtoolTests(DevtoolBase): result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile) with open(recipefile, 'a') as f: f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n') + # We don't have the ability to pick up this dependency automatically yet... + f.write('\nDEPENDS += "libusb1"\n') + f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n') # Test devtool build result = runCmd('devtool build libftdi') - staging_libdir = get_bb_var('STAGING_LIBDIR', 'libftdi') - self.assertTrue(staging_libdir, 'Could not query STAGING_LIBDIR variable') + bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi') + staging_libdir = bb_vars['TESTLIBOUTPUT'] + self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable') self.assertTrue(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), "libftdi binary not found in STAGING_LIBDIR. Output of devtool build libftdi %s" % result.output) # Test devtool reset - stampprefix = get_bb_var('STAMP', 'libftdi') + stampprefix = bb_vars['STAMP'] result = runCmd('devtool reset libftdi') result = runCmd('devtool status') self.assertNotIn('libftdi', result.output) @@ -353,12 +359,11 @@ class DevtoolTests(DevtoolBase): @testcase(1161) def test_devtool_add_fetch_git(self): - # Fetch source tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) - url = 'git://git.yoctoproject.org/libmatchbox' - checkrev = '462f0652055d89c648ddd54fd7b03f175c2c6973' - testrecipe = 'libmatchbox2' + url = 'gitsm://git.yoctoproject.org/mraa' + checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d' + testrecipe = 'mraa' srcdir = os.path.join(tempdir, testrecipe) # Test devtool add self.track_for_cleanup(self.workspacedir) @@ -366,7 +371,7 @@ class DevtoolTests(DevtoolBase): self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url)) self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created: %s' % result.output) - self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure.ac in source directory') + self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory') # Test devtool status result = runCmd('devtool status') self.assertIn(testrecipe, result.output) @@ -376,7 +381,7 @@ class DevtoolTests(DevtoolBase): self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') checkvars = {} checkvars['S'] = '${WORKDIR}/git' - checkvars['PV'] = '1.12+git${SRCPV}' + checkvars['PV'] = '1.0+git${SRCPV}' checkvars['SRC_URI'] = url checkvars['SRCREV'] = '${AUTOREV}' self._test_recipe_contents(recipefile, checkvars, []) @@ -385,7 +390,7 @@ class DevtoolTests(DevtoolBase): shutil.rmtree(srcdir) url_rev = '%s;rev=%s' % (url, checkrev) result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev)) - self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure.ac in source directory') + self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory') # Test devtool status result = runCmd('devtool status') self.assertIn(testrecipe, result.output) @@ -430,9 +435,8 @@ class DevtoolTests(DevtoolBase): @testcase(1164) def test_devtool_modify(self): - # Clean up anything in the workdir/sysroot/sstate cache - bitbake('mdadm -c cleansstate') - # Try modifying a recipe + import oe.path + tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) self.track_for_cleanup(self.workspacedir) @@ -443,35 +447,95 @@ class DevtoolTests(DevtoolBase): self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend')) self.assertTrue(matches, 'bbappend not created %s' % result.output) + # Test devtool status result = runCmd('devtool status') self.assertIn('mdadm', result.output) self.assertIn(tempdir, result.output) - # Check git repo self._check_src_repo(tempdir) - # Try building - bitbake('mdadm') - # Try making (minor) modifications to the source - result = runCmd("sed -i 's!^\.TH.*!.TH MDADM 8 \"\" v9.999-custom!' %s" % os.path.join(tempdir, 'mdadm.8.in')) - bitbake('mdadm -c package') - pkgd = get_bb_var('PKGD', 'mdadm') + + bitbake('mdadm -C unpack') + + def check_line(checkfile, expected, message, present=True): + # Check for $expected, on a line on its own, in checkfile. + with open(checkfile, 'r') as f: + if present: + self.assertIn(expected + '\n', f, message) + else: + self.assertNotIn(expected + '\n', f, message) + + modfile = os.path.join(tempdir, 'mdadm.8.in') + bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm') + pkgd = bb_vars['PKGD'] self.assertTrue(pkgd, 'Could not query PKGD variable') - mandir = get_bb_var('mandir', 'mdadm') + mandir = bb_vars['mandir'] self.assertTrue(mandir, 'Could not query mandir variable') - if mandir[0] == '/': - mandir = mandir[1:] - with open(os.path.join(pkgd, mandir, 'man8', 'mdadm.8'), 'r') as f: - for line in f: - if line.startswith('.TH'): - self.assertEqual(line.rstrip(), '.TH MDADM 8 "" v9.999-custom', 'man file not modified. man searched file path: %s' % os.path.join(pkgd, mandir, 'man8', 'mdadm.8')) - # Test devtool reset - stampprefix = get_bb_var('STAMP', 'mdadm') + manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8') + + check_line(modfile, 'Linux Software RAID', 'Could not find initial string') + check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False) + + result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile) + check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)') + + bitbake('mdadm -c package') + check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile) + + result = runCmd('git checkout -- %s' % modfile, cwd=tempdir) + check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)') + + bitbake('mdadm -c package') + check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile) + result = runCmd('devtool reset mdadm') result = runCmd('devtool status') self.assertNotIn('mdadm', result.output) - self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe mdadm') - matches = glob.glob(stampprefix + '*') - self.assertFalse(matches, 'Stamp files exist for recipe mdadm that should have been cleaned') + + def test_devtool_buildclean(self): + def assertFile(path, *paths): + f = os.path.join(path, *paths) + self.assertTrue(os.path.exists(f), "%r does not exist" % f) + def assertNoFile(path, *paths): + f = os.path.join(path, *paths) + self.assertFalse(os.path.exists(os.path.join(f)), "%r exists" % f) + + # Clean up anything in the workdir/sysroot/sstate cache + bitbake('mdadm m4 -c cleansstate') + # Try modifying a recipe + tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa') + tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa') + builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir_mdadm) + self.track_for_cleanup(tempdir_m4) + self.track_for_cleanup(builddir_m4) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + self.add_command_to_tearDown('bitbake -c clean mdadm m4') + self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4) + try: + runCmd('devtool modify mdadm -x %s' % tempdir_mdadm) + runCmd('devtool modify m4 -x %s' % tempdir_m4) + assertNoFile(tempdir_mdadm, 'mdadm') + assertNoFile(builddir_m4, 'src/m4') + result = bitbake('m4 -e') + result = bitbake('mdadm m4 -c compile') + self.assertEqual(result.status, 0) + assertFile(tempdir_mdadm, 'mdadm') + assertFile(builddir_m4, 'src/m4') + # Check that buildclean task exists and does call make clean + bitbake('mdadm m4 -c buildclean') + assertNoFile(tempdir_mdadm, 'mdadm') + assertNoFile(builddir_m4, 'src/m4') + bitbake('mdadm m4 -c compile') + assertFile(tempdir_mdadm, 'mdadm') + assertFile(builddir_m4, 'src/m4') + bitbake('mdadm m4 -c clean') + # Check that buildclean task is run before clean for B == S + assertNoFile(tempdir_mdadm, 'mdadm') + # Check that buildclean task is not run before clean for B != S + assertFile(builddir_m4, 'src/m4') + finally: + self.delete_recipeinc('m4') @testcase(1166) def test_devtool_modify_invalid(self): @@ -594,8 +658,8 @@ class DevtoolTests(DevtoolBase): @testcase(1378) def test_devtool_modify_virtual(self): # Try modifying a virtual recipe - virtrecipe = 'virtual/libx11' - realrecipe = 'libx11' + virtrecipe = 'virtual/make' + realrecipe = 'make' tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) self.track_for_cleanup(self.workspacedir) @@ -618,8 +682,9 @@ class DevtoolTests(DevtoolBase): def test_devtool_update_recipe(self): # Check preconditions testrecipe = 'minicom' - recipefile = get_bb_var('FILE', testrecipe) - src_uri = get_bb_var('SRC_URI', testrecipe) + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe @@ -650,8 +715,9 @@ class DevtoolTests(DevtoolBase): def test_devtool_update_recipe_git(self): # Check preconditions testrecipe = 'mtd-utils' - recipefile = get_bb_var('FILE', testrecipe) - src_uri = get_bb_var('SRC_URI', testrecipe) + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) patches = [] for entry in src_uri.split(): @@ -670,7 +736,7 @@ class DevtoolTests(DevtoolBase): self._check_src_repo(tempdir) # Add a couple of commits # FIXME: this only tests adding, need to also test update and remove - result = runCmd('echo "# Additional line" >> Makefile', cwd=tempdir) + result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir) result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir) result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir) result = runCmd('git add devtool-new-file', cwd=tempdir) @@ -719,8 +785,9 @@ class DevtoolTests(DevtoolBase): def test_devtool_update_recipe_append(self): # Check preconditions testrecipe = 'mdadm' - recipefile = get_bb_var('FILE', testrecipe) - src_uri = get_bb_var('SRC_URI', testrecipe) + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) self._check_repo_status(os.path.dirname(recipefile), []) # First, modify a recipe @@ -787,8 +854,9 @@ class DevtoolTests(DevtoolBase): def test_devtool_update_recipe_append_git(self): # Check preconditions testrecipe = 'mtd-utils' - recipefile = get_bb_var('FILE', testrecipe) - src_uri = get_bb_var('SRC_URI', testrecipe) + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) for entry in src_uri.split(): if entry.startswith('git://'): @@ -807,7 +875,7 @@ class DevtoolTests(DevtoolBase): # Check git repo self._check_src_repo(tempsrcdir) # Add a commit - result = runCmd('echo "# Additional line" >> Makefile', cwd=tempsrcdir) + result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir) result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe)) # Create a temporary layer @@ -887,6 +955,8 @@ class DevtoolTests(DevtoolBase): result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) # Check git repo self._check_src_repo(tempdir) + # Try building just to ensure we haven't broken that + bitbake("%s" % testrecipe) # Edit / commit local source runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir) runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) @@ -943,6 +1013,78 @@ class DevtoolTests(DevtoolBase): ('??', '.*/0001-Add-new-file.patch$')] self._check_repo_status(os.path.dirname(recipefile), expected_status) + def test_devtool_update_recipe_local_files_3(self): + # First, modify the recipe + testrecipe = 'devtool-test-localonly' + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + # (don't bother with cleaning the recipe on teardown, we won't be building it) + result = runCmd('devtool modify %s' % testrecipe) + # Modify one file + runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files')) + self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) + result = runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [(' M', '.*/%s/file2$' % testrecipe)] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + + def test_devtool_update_recipe_local_patch_gz(self): + # First, modify the recipe + testrecipe = 'devtool-test-patch-gz' + if get_bb_var('DISTRO') == 'poky-tiny': + self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe) + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + # (don't bother with cleaning the recipe on teardown, we won't be building it) + result = runCmd('devtool modify %s' % testrecipe) + # Modify one file + srctree = os.path.join(self.workspacedir, 'sources', testrecipe) + runCmd('echo "Another line" >> README', cwd=srctree) + runCmd('git commit -a --amend --no-edit', cwd=srctree) + self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) + result = runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz') + result = runCmd('file %s' % patch_gz) + if 'gzip compressed data' not in result.output: + self.fail('New patch file is not gzipped - file reports:\n%s' % result.output) + + def test_devtool_update_recipe_local_files_subdir(self): + # Try devtool extract on a recipe that has a file with subdir= set in + # SRC_URI such that it overwrites a file that was in an archive that + # was also in SRC_URI + # First, modify the recipe + testrecipe = 'devtool-test-subdir' + bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) + recipefile = bb_vars['FILE'] + src_uri = bb_vars['SRC_URI'] + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + # (don't bother with cleaning the recipe on teardown, we won't be building it) + result = runCmd('devtool modify %s' % testrecipe) + testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile') + self.assertTrue(os.path.exists(testfile), 'Extracted source could not be found') + with open(testfile, 'r') as f: + contents = f.read().rstrip() + self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been') + # Test devtool update-recipe without modifying any files + self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) + result = runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + @testcase(1163) def test_devtool_extract(self): tempdir = tempfile.mkdtemp(prefix='devtoolqa') @@ -960,7 +1102,7 @@ class DevtoolTests(DevtoolBase): tempdir = tempfile.mkdtemp(prefix='devtoolqa') # Try devtool extract self.track_for_cleanup(tempdir) - result = runCmd('devtool extract virtual/libx11 %s' % tempdir) + result = runCmd('devtool extract virtual/make %s' % tempdir) self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') # devtool extract shouldn't create the workspace self.assertFalse(os.path.exists(self.workspacedir)) @@ -1054,9 +1196,10 @@ class DevtoolTests(DevtoolBase): result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand)) # Check if it deployed all of the files with the right ownership/perms # First look on the host - need to do this under pseudo to get the correct ownership/perms - installdir = get_bb_var('D', testrecipe) - fakerootenv = get_bb_var('FAKEROOTENV', testrecipe) - fakerootcmd = get_bb_var('FAKEROOTCMD', testrecipe) + bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe) + installdir = bb_vars['D'] + fakerootenv = bb_vars['FAKEROOTENV'] + fakerootcmd = bb_vars['FAKEROOTCMD'] result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir) filelist1 = self._process_ls_output(result.output) @@ -1207,6 +1350,49 @@ class DevtoolTests(DevtoolBase): result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s) self.assertEqual(result.output, s[::-1]) + def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths): + dstdir = basedstdir + self.assertTrue(os.path.exists(dstdir)) + for p in paths: + dstdir = os.path.join(dstdir, p) + if not os.path.exists(dstdir): + os.makedirs(dstdir) + self.track_for_cleanup(dstdir) + dstfile = os.path.join(dstdir, os.path.basename(srcfile)) + if srcfile != dstfile: + shutil.copy(srcfile, dstfile) + self.track_for_cleanup(dstfile) + + def test_devtool_load_plugin(self): + """Test that devtool loads only the first found plugin in BBPATH.""" + + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + + devtool = runCmd("which devtool") + fromname = runCmd("devtool --quiet pluginfile") + srcfile = fromname.output + bbpath = get_bb_var('BBPATH') + searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)] + plugincontent = [] + with open(srcfile) as fh: + plugincontent = fh.readlines() + try: + self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found') + for path in searchpath: + self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool') + result = runCmd("devtool --quiet count") + self.assertEqual(result.output, '1') + result = runCmd("devtool --quiet multiloaded") + self.assertEqual(result.output, "no") + for path in searchpath: + result = runCmd("devtool --quiet bbdir") + self.assertEqual(result.output, path) + os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py')) + finally: + with open(srcfile, 'w') as fh: + fh.writelines(plugincontent) + def _setup_test_devtool_finish_upgrade(self): # Check preconditions self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') @@ -1362,3 +1548,149 @@ class DevtoolTests(DevtoolBase): files.remove(foundpatch) if files: self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files)) + + def test_devtool_rename(self): + # Check preconditions + self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + + # First run devtool add + # We already have this recipe in OE-Core, but that doesn't matter + recipename = 'i2c-tools' + recipever = '3.1.2' + recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever)) + url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever + def add_recipe(): + result = runCmd('devtool add %s' % url) + self.assertTrue(os.path.exists(recipefile), 'Expected recipe file not created') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', recipename)), 'Source directory not created') + checkvars = {} + checkvars['S'] = None + checkvars['SRC_URI'] = url.replace(recipever, '${PV}') + self._test_recipe_contents(recipefile, checkvars, []) + add_recipe() + # Now rename it - change both name and version + newrecipename = 'mynewrecipe' + newrecipever = '456' + newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever)) + result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever)) + self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') + self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipename)), 'Old recipe directory still exists') + newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename) + self.assertTrue(os.path.exists(newsrctree), 'Source directory not renamed') + checkvars = {} + checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever) + checkvars['SRC_URI'] = url + self._test_recipe_contents(newrecipefile, checkvars, []) + # Try again - change just name this time + result = runCmd('devtool reset -n %s' % newrecipename) + shutil.rmtree(newsrctree) + add_recipe() + newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever)) + result = runCmd('devtool rename %s %s' % (recipename, newrecipename)) + self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') + self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipename)), 'Old recipe directory still exists') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', newrecipename)), 'Source directory not renamed') + checkvars = {} + checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename + checkvars['SRC_URI'] = url.replace(recipever, '${PV}') + self._test_recipe_contents(newrecipefile, checkvars, []) + # Try again - change just version this time + result = runCmd('devtool reset -n %s' % newrecipename) + shutil.rmtree(newsrctree) + add_recipe() + newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever)) + result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever)) + self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') + self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', recipename)), 'Source directory no longer exists') + checkvars = {} + checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever + checkvars['SRC_URI'] = url + self._test_recipe_contents(newrecipefile, checkvars, []) + + @testcase(1577) + def test_devtool_virtual_kernel_modify(self): + """ + Summary: The purpose of this test case is to verify that + devtool modify works correctly when building + the kernel. + Dependencies: NA + Steps: 1. Build kernel with bitbake. + 2. Save the config file generated. + 3. Clean the environment. + 4. Use `devtool modify virtual/kernel` to validate following: + 4.1 The source is checked out correctly. + 4.2 The resulting configuration is the same as + what was get on step 2. + 4.3 The Kernel can be build correctly. + 4.4 Changes made on the source are reflected on the + subsequent builds. + 4.5 Changes on the configuration are reflected on the + subsequent builds + Expected: devtool modify is able to checkout the source of the kernel + and modification to the source and configurations are reflected + when building the kernel. + """ + #Set machine to qemxu86 to be able to modify the kernel and + #verify the modification. + features = 'MACHINE = "qemux86"\n' + self.write_config(features) + kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel') + # Clean up the enviroment + bitbake('%s -c clean' % kernel_provider) + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider) + #Step 1 + #Here is just generated the config file instead of all the kernel to optimize the + #time of executing this test case. + bitbake('%s -c configure' % kernel_provider) + bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config') + buildir= get_bb_var('TOPDIR') + #Step 2 + runCmd('cp %s %s' % (bbconfig, buildir)) + self.assertTrue(os.path.exists(os.path.join(buildir, '.config')), + 'Could not copy .config file from kernel') + + tmpconfig = os.path.join(buildir, '.config') + #Step 3 + bitbake('%s -c clean' % kernel_provider) + #Step 4.1 + runCmd('devtool modify virtual/kernel -x %s' % tempdir) + self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), + 'Extracted source could not be found') + #Step 4.2 + configfile = os.path.join(tempdir,'.config') + diff = runCmd('diff %s %s' % (tmpconfig, configfile)) + self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool') + #Step 4.3 + #NOTE: virtual/kernel is mapped to kernel_provider + result = runCmd('devtool build %s' % kernel_provider) + self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`') + kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux') + self.assertTrue(os.path.exists(kernelfile),'Kernel was not build correctly') + + #Modify the kernel source, this is specific for qemux86 + modfile = os.path.join(tempdir,'arch/x86/boot/header.S') + modstring = "use a boot loader - Devtool kernel testing" + modapplied = runCmd("sed -i 's/boot loader/%s/' %s" % (modstring, modfile)) + self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile) + #Modify the configuration + codeconfigfile = os.path.join(tempdir,'.config.new') + modconfopt = "CONFIG_SG_POOL=n" + modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile)) + self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile) + #Build again kernel with devtool + rebuild = runCmd('devtool build %s' % kernel_provider) + self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config') + #Step 4.4 + bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider) + bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename) + checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile)) + self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed') + #Step 4.5 + checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile)) + self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed') diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/eSDK.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/eSDK.py index 9d5c68094..1596c6e9d 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/eSDK.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/eSDK.py @@ -6,16 +6,15 @@ import glob import logging import subprocess import oeqa.utils.ftools as ftools -from oeqa.utils.decorators import testcase +from oeqa.utils.decorators import testcase from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var -from oeqa.utils.httpserver import HTTPService +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars class oeSDKExtSelfTest(oeSelfTest): """ # Bugzilla Test Plan: 6033 # This code is planned to be part of the automation for eSDK containig - # Install libraries and headers, image generation binary feeds. + # Install libraries and headers, image generation binary feeds, sdk-update. """ @staticmethod @@ -24,7 +23,7 @@ class oeSDKExtSelfTest(oeSelfTest): # what environment load oe-selftest, i586, x86_64 pattern = os.path.join(tmpdir_eSDKQA, 'environment-setup-*') return glob.glob(pattern)[0] - + @staticmethod def run_esdk_cmd(env_eSDK, tmpdir_eSDKQA, cmd, postconfig=None, **options): if postconfig: @@ -47,53 +46,66 @@ class oeSDKExtSelfTest(oeSelfTest): def get_eSDK_toolchain(image): pn_task = '%s -c populate_sdk_ext' % image - sdk_deploy = get_bb_var('SDK_DEPLOY', pn_task) - toolchain_name = get_bb_var('TOOLCHAINEXT_OUTPUTNAME', pn_task) + bb_vars = get_bb_vars(['SDK_DEPLOY', 'TOOLCHAINEXT_OUTPUTNAME'], pn_task) + sdk_deploy = bb_vars['SDK_DEPLOY'] + toolchain_name = bb_vars['TOOLCHAINEXT_OUTPUTNAME'] return os.path.join(sdk_deploy, toolchain_name + '.sh') - - @classmethod - def setUpClass(cls): - # Start to serve sstate dir + @staticmethod + def update_configuration(cls, image, tmpdir_eSDKQA, env_eSDK, ext_sdk_path): sstate_dir = os.path.join(os.environ['BUILDDIR'], 'sstate-cache') - cls.http_service = HTTPService(sstate_dir) - cls.http_service.start() - http_url = "127.0.0.1:%d" % cls.http_service.port - - image = 'core-image-minimal' + oeSDKExtSelfTest.generate_eSDK(cls.image) + cls.ext_sdk_path = oeSDKExtSelfTest.get_eSDK_toolchain(cls.image) + runCmd("%s -y -d \"%s\"" % (cls.ext_sdk_path, cls.tmpdir_eSDKQA)) + + cls.env_eSDK = oeSDKExtSelfTest.get_esdk_environment('', cls.tmpdir_eSDKQA) + + sstate_config=""" +SDK_LOCAL_CONF_WHITELIST = "SSTATE_MIRRORS" +SSTATE_MIRRORS = "file://.* file://%s/PATH" +CORE_IMAGE_EXTRA_INSTALL = "perl" + """ % sstate_dir + + with open(os.path.join(cls.tmpdir_eSDKQA, 'conf', 'local.conf'), 'a+') as f: + f.write(sstate_config) + + @classmethod + def setUpClass(cls): cls.tmpdir_eSDKQA = tempfile.mkdtemp(prefix='eSDKQA') - oeSDKExtSelfTest.generate_eSDK(image) + + sstate_dir = get_bb_var('SSTATE_DIR') + + cls.image = 'core-image-minimal' + oeSDKExtSelfTest.generate_eSDK(cls.image) # Install eSDK - ext_sdk_path = oeSDKExtSelfTest.get_eSDK_toolchain(image) - runCmd("%s -y -d \"%s\"" % (ext_sdk_path, cls.tmpdir_eSDKQA)) + cls.ext_sdk_path = oeSDKExtSelfTest.get_eSDK_toolchain(cls.image) + runCmd("%s -y -d \"%s\"" % (cls.ext_sdk_path, cls.tmpdir_eSDKQA)) cls.env_eSDK = oeSDKExtSelfTest.get_esdk_environment('', cls.tmpdir_eSDKQA) # Configure eSDK to use sstate mirror from poky sstate_config=""" SDK_LOCAL_CONF_WHITELIST = "SSTATE_MIRRORS" -SSTATE_MIRRORS = "file://.* http://%s/PATH" - """ % http_url +SSTATE_MIRRORS = "file://.* file://%s/PATH" + """ % sstate_dir with open(os.path.join(cls.tmpdir_eSDKQA, 'conf', 'local.conf'), 'a+') as f: f.write(sstate_config) - @classmethod def tearDownClass(cls): shutil.rmtree(cls.tmpdir_eSDKQA) - cls.http_service.stop() - @testcase (1471) + @testcase (1602) def test_install_libraries_headers(self): pn_sstate = 'bc' bitbake(pn_sstate) cmd = "devtool sdk-install %s " % pn_sstate oeSDKExtSelfTest.run_esdk_cmd(self.env_eSDK, self.tmpdir_eSDKQA, cmd) - - @testcase(1472) + + @testcase(1603) def test_image_generation_binary_feeds(self): image = 'core-image-minimal' cmd = "devtool build-image %s" % image diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/image_typedep.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/image_typedep.py new file mode 100644 index 000000000..256142d25 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/image_typedep.py @@ -0,0 +1,51 @@ +import os + +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import bitbake + +class ImageTypeDepTests(oeSelfTest): + + # Verify that when specifying a IMAGE_TYPEDEP_ of the form "foo.bar" that + # the conversion type bar gets added as a dep as well + def test_conversion_typedep_added(self): + + self.write_recipeinc('emptytest', """ +# Try to empty out the default dependency list +PACKAGE_INSTALL = "" +DISTRO_EXTRA_RDEPENDS="" + +LICENSE = "MIT" +IMAGE_FSTYPES = "testfstype" + +IMAGE_TYPES_MASKED += "testfstype" +IMAGE_TYPEDEP_testfstype = "tar.bz2" + +inherit image + +""") + # First get the dependency that should exist for bz2, it will look + # like CONVERSION_DEPENDS_bz2="somedep" + result = bitbake('-e emptytest') + + for line in result.output.split('\n'): + if line.startswith('CONVERSION_DEPENDS_bz2'): + dep = line.split('=')[1].strip('"') + break + + # Now get the dependency task list and check for the expected task + # dependency + bitbake('-g emptytest') + + taskdependsfile = os.path.join(self.builddir, 'task-depends.dot') + dep = dep + ".do_populate_sysroot" + depfound = False + expectedline = '"emptytest.do_rootfs" -> "{}"'.format(dep) + + with open(taskdependsfile, "r") as f: + for line in f: + if line.strip() == expectedline: + depfound = True + break + + if not depfound: + raise AssertionError("\"{}\" not found".format(expectedline)) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py index d015c4908..76896c798 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/imagefeatures.py @@ -91,9 +91,9 @@ class ImageFeatures(oeSelfTest): AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com> """ - features = 'DISTRO_FEATURES_append = " wayland"\n' - features += 'CORE_IMAGE_EXTRA_INSTALL += "wayland weston"' - self.write_config(features) + distro_features = get_bb_var('DISTRO_FEATURES') + if not ('opengl' in distro_features and 'wayland' in distro_features): + self.skipTest('neither opengl nor wayland present on DISTRO_FEATURES so core-image-weston cannot be built') # Build a core-image-weston bitbake('core-image-weston') diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/layerappend.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/layerappend.py index 4de5034a9..37bb32cd1 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/layerappend.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/layerappend.py @@ -55,7 +55,7 @@ SRC_URI_append += "file://appendtest.txt" @testcase(1196) def test_layer_appends(self): corebase = get_bb_var("COREBASE") - stagingdir = get_bb_var("STAGING_DIR_TARGET") + for l in ["0", "1", "2"]: layer = os.path.join(corebase, "meta-layertest" + l) self.assertFalse(os.path.exists(layer)) @@ -83,6 +83,7 @@ SRC_URI_append += "file://appendtest.txt" self.layerappend = "BBLAYERS += \"{0}/meta-layertest0 {0}/meta-layertest1 {0}/meta-layertest2\"".format(corebase) ftools.append_file(self.builddir + "/conf/bblayers.conf", self.layerappend) + stagingdir = get_bb_var("SYSROOT_DESTDIR", "layerappendtest") bitbake("layerappendtest") data = ftools.read_file(stagingdir + "/appendtest.txt") self.assertEqual(data, "Layer 2 test") diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/liboe.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/liboe.py index 35131eb24..0b0301def 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/liboe.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/liboe.py @@ -1,11 +1,16 @@ from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import get_bb_var, bitbake, runCmd +from oeqa.utils.commands import get_bb_var, get_bb_vars, bitbake, runCmd import oe.path import glob import os import os.path class LibOE(oeSelfTest): + + @classmethod + def setUpClass(cls): + cls.tmp_dir = get_bb_var('TMPDIR') + def test_copy_tree_special(self): """ Summary: oe.path.copytree() should copy files with special character @@ -14,8 +19,7 @@ class LibOE(oeSelfTest): Product: OE-Core Author: Joshua Lock <joshua.g.lock@intel.com> """ - tmp_dir = get_bb_var('TMPDIR') - testloc = oe.path.join(tmp_dir, 'liboetests') + testloc = oe.path.join(self.tmp_dir, 'liboetests') src = oe.path.join(testloc, 'src') dst = oe.path.join(testloc, 'dst') bb.utils.mkdirhier(testloc) @@ -40,8 +44,7 @@ class LibOE(oeSelfTest): Product: OE-Core Author: Joshua Lock <joshua.g.lock@intel.com> """ - tmp_dir = get_bb_var('TMPDIR') - testloc = oe.path.join(tmp_dir, 'liboetests') + testloc = oe.path.join(self.tmp_dir, 'liboetests') src = oe.path.join(testloc, 'src') dst = oe.path.join(testloc, 'dst') bb.utils.mkdirhier(testloc) @@ -50,7 +53,11 @@ class LibOE(oeSelfTest): # ensure we have setfattr available bitbake("attr-native") - bindir = get_bb_var('STAGING_BINDIR_NATIVE') + + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'attr-native') + destdir = bb_vars['SYSROOT_DESTDIR'] + bindir = bb_vars['bindir'] + bindir = destdir + bindir # create a file with xattr and copy it open(oe.path.join(src, testfilename), 'w+b').close() @@ -70,8 +77,7 @@ class LibOE(oeSelfTest): Product: OE-Core Author: Joshua Lock <joshua.g.lock@intel.com> """ - tmp_dir = get_bb_var('TMPDIR') - testloc = oe.path.join(tmp_dir, 'liboetests') + testloc = oe.path.join(self.tmp_dir, 'liboetests') src = oe.path.join(testloc, 'src') dst = oe.path.join(testloc, 'dst') bb.utils.mkdirhier(testloc) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/manifest.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/manifest.py index 44d0404c5..fe6f94964 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/manifest.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/manifest.py @@ -2,7 +2,7 @@ import unittest import os from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import get_bb_var, bitbake +from oeqa.utils.commands import get_bb_var, get_bb_vars, bitbake from oeqa.utils.decorators import testcase class ManifestEntry: @@ -84,9 +84,10 @@ class VerifyManifest(oeSelfTest): try: mdir = self.get_dir_from_bb_var('SDK_DEPLOY', self.buildtarget) for k in d_target.keys(): + bb_vars = get_bb_vars(['SDK_NAME', 'SDK_VERSION'], self.buildtarget) mfilename[k] = "{}-toolchain-{}.{}.manifest".format( - get_bb_var("SDK_NAME", self.buildtarget), - get_bb_var("SDK_VERSION", self.buildtarget), + bb_vars['SDK_NAME'], + bb_vars['SDK_VERSION'], k) mpath[k] = os.path.join(mdir, mfilename[k]) if not os.path.isfile(mpath[k]): diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/__init__.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/__init__.py diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/buildhistory.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/buildhistory.py new file mode 100644 index 000000000..5ed4b026f --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/buildhistory.py @@ -0,0 +1,88 @@ +import os +import unittest +import tempfile +from git import Repo +from oeqa.utils.commands import get_bb_var +from oe.buildhistory_analysis import blob_to_dict, compare_dict_blobs + +class TestBlobParsing(unittest.TestCase): + + def setUp(self): + import time + self.repo_path = tempfile.mkdtemp(prefix='selftest-buildhistory', + dir=get_bb_var('TOPDIR')) + + self.repo = Repo.init(self.repo_path) + self.test_file = "test" + self.var_map = {} + + def tearDown(self): + import shutil + shutil.rmtree(self.repo_path) + + def commit_vars(self, to_add={}, to_remove = [], msg="A commit message"): + if len(to_add) == 0 and len(to_remove) == 0: + return + + for k in to_remove: + self.var_map.pop(x,None) + for k in to_add: + self.var_map[k] = to_add[k] + + with open(os.path.join(self.repo_path, self.test_file), 'w') as repo_file: + for k in self.var_map: + repo_file.write("%s = %s\n" % (k, self.var_map[k])) + + self.repo.git.add("--all") + self.repo.git.commit(message=msg) + + def test_blob_to_dict(self): + """ + Test convertion of git blobs to dictionary + """ + valuesmap = { "foo" : "1", "bar" : "2" } + self.commit_vars(to_add = valuesmap) + + blob = self.repo.head.commit.tree.blobs[0] + self.assertEqual(valuesmap, blob_to_dict(blob), + "commit was not translated correctly to dictionary") + + def test_compare_dict_blobs(self): + """ + Test comparisson of dictionaries extracted from git blobs + """ + changesmap = { "foo-2" : ("2", "8"), "bar" : ("","4"), "bar-2" : ("","5")} + + self.commit_vars(to_add = { "foo" : "1", "foo-2" : "2", "foo-3" : "3" }) + blob1 = self.repo.heads.master.commit.tree.blobs[0] + + self.commit_vars(to_add = { "foo-2" : "8", "bar" : "4", "bar-2" : "5" }) + blob2 = self.repo.heads.master.commit.tree.blobs[0] + + change_records = compare_dict_blobs(os.path.join(self.repo_path, self.test_file), + blob1, blob2, False, False) + + var_changes = { x.fieldname : (x.oldvalue, x.newvalue) for x in change_records} + self.assertEqual(changesmap, var_changes, "Changes not reported correctly") + + def test_compare_dict_blobs_default(self): + """ + Test default values for comparisson of git blob dictionaries + """ + defaultmap = { x : ("default", "1") for x in ["PKG", "PKGE", "PKGV", "PKGR"]} + + self.commit_vars(to_add = { "foo" : "1" }) + blob1 = self.repo.heads.master.commit.tree.blobs[0] + + self.commit_vars(to_add = { "PKG" : "1", "PKGE" : "1", "PKGV" : "1", "PKGR" : "1" }) + blob2 = self.repo.heads.master.commit.tree.blobs[0] + + change_records = compare_dict_blobs(os.path.join(self.repo_path, self.test_file), + blob1, blob2, False, False) + + var_changes = {} + for x in change_records: + oldvalue = "default" if ("default" in x.oldvalue) else x.oldvalue + var_changes[x.fieldname] = (oldvalue, x.newvalue) + + self.assertEqual(defaultmap, var_changes, "Defaults not set properly") diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/elf.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/elf.py new file mode 100644 index 000000000..1f59037ed --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/elf.py @@ -0,0 +1,21 @@ +import unittest +import oe.qa + +class TestElf(unittest.TestCase): + def test_machine_name(self): + """ + Test elf_machine_to_string() + """ + self.assertEqual(oe.qa.elf_machine_to_string(0x02), "SPARC") + self.assertEqual(oe.qa.elf_machine_to_string(0x03), "x86") + self.assertEqual(oe.qa.elf_machine_to_string(0x08), "MIPS") + self.assertEqual(oe.qa.elf_machine_to_string(0x14), "PowerPC") + self.assertEqual(oe.qa.elf_machine_to_string(0x28), "ARM") + self.assertEqual(oe.qa.elf_machine_to_string(0x2A), "SuperH") + self.assertEqual(oe.qa.elf_machine_to_string(0x32), "IA-64") + self.assertEqual(oe.qa.elf_machine_to_string(0x3E), "x86-64") + self.assertEqual(oe.qa.elf_machine_to_string(0xB7), "AArch64") + + self.assertEqual(oe.qa.elf_machine_to_string(0x00), "Unknown (0)") + self.assertEqual(oe.qa.elf_machine_to_string(0xDEADBEEF), "Unknown (3735928559)") + self.assertEqual(oe.qa.elf_machine_to_string("foobar"), "Unknown ('foobar')") diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/license.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/license.py new file mode 100644 index 000000000..c38888618 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/license.py @@ -0,0 +1,68 @@ +import unittest +import oe.license + +class SeenVisitor(oe.license.LicenseVisitor): + def __init__(self): + self.seen = [] + oe.license.LicenseVisitor.__init__(self) + + def visit_Str(self, node): + self.seen.append(node.s) + +class TestSingleLicense(unittest.TestCase): + licenses = [ + "GPLv2", + "LGPL-2.0", + "Artistic", + "MIT", + "GPLv3+", + "FOO_BAR", + ] + invalid_licenses = ["GPL/BSD"] + + @staticmethod + def parse(licensestr): + visitor = SeenVisitor() + visitor.visit_string(licensestr) + return visitor.seen + + def test_single_licenses(self): + for license in self.licenses: + licenses = self.parse(license) + self.assertListEqual(licenses, [license]) + + def test_invalid_licenses(self): + for license in self.invalid_licenses: + with self.assertRaises(oe.license.InvalidLicense) as cm: + self.parse(license) + self.assertEqual(cm.exception.license, license) + +class TestSimpleCombinations(unittest.TestCase): + tests = { + "FOO&BAR": ["FOO", "BAR"], + "BAZ & MOO": ["BAZ", "MOO"], + "ALPHA|BETA": ["ALPHA"], + "BAZ&MOO|FOO": ["FOO"], + "FOO&BAR|BAZ": ["FOO", "BAR"], + } + preferred = ["ALPHA", "FOO", "BAR"] + + def test_tests(self): + def choose(a, b): + if all(lic in self.preferred for lic in b): + return b + else: + return a + + for license, expected in self.tests.items(): + licenses = oe.license.flattened_licenses(license, choose) + self.assertListEqual(licenses, expected) + +class TestComplexCombinations(TestSimpleCombinations): + tests = { + "FOO & (BAR | BAZ)&MOO": ["FOO", "BAR", "MOO"], + "(ALPHA|(BETA&THETA)|OMEGA)&DELTA": ["OMEGA", "DELTA"], + "((ALPHA|BETA)&FOO)|BAZ": ["BETA", "FOO"], + "(GPL-2.0|Proprietary)&BSD-4-clause&MIT": ["GPL-2.0", "BSD-4-clause", "MIT"], + } + preferred = ["BAR", "OMEGA", "BETA", "GPL-2.0"] diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/path.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/path.py new file mode 100644 index 000000000..44d068143 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/path.py @@ -0,0 +1,89 @@ +import unittest +import oe, oe.path +import tempfile +import os +import errno +import shutil + +class TestRealPath(unittest.TestCase): + DIRS = [ "a", "b", "etc", "sbin", "usr", "usr/bin", "usr/binX", "usr/sbin", "usr/include", "usr/include/gdbm" ] + FILES = [ "etc/passwd", "b/file" ] + LINKS = [ + ( "bin", "/usr/bin", "/usr/bin" ), + ( "binX", "usr/binX", "/usr/binX" ), + ( "c", "broken", "/broken" ), + ( "etc/passwd-1", "passwd", "/etc/passwd" ), + ( "etc/passwd-2", "passwd-1", "/etc/passwd" ), + ( "etc/passwd-3", "/etc/passwd-1", "/etc/passwd" ), + ( "etc/shadow-1", "/etc/shadow", "/etc/shadow" ), + ( "etc/shadow-2", "/etc/shadow-1", "/etc/shadow" ), + ( "prog-A", "bin/prog-A", "/usr/bin/prog-A" ), + ( "prog-B", "/bin/prog-B", "/usr/bin/prog-B" ), + ( "usr/bin/prog-C", "../../sbin/prog-C", "/sbin/prog-C" ), + ( "usr/bin/prog-D", "/sbin/prog-D", "/sbin/prog-D" ), + ( "usr/binX/prog-E", "../sbin/prog-E", None ), + ( "usr/bin/prog-F", "../../../sbin/prog-F", "/sbin/prog-F" ), + ( "loop", "a/loop", None ), + ( "a/loop", "../loop", None ), + ( "b/test", "file/foo", "/b/file/foo" ), + ] + + LINKS_PHYS = [ + ( "./", "/", "" ), + ( "binX/prog-E", "/usr/sbin/prog-E", "/sbin/prog-E" ), + ] + + EXCEPTIONS = [ + ( "loop", errno.ELOOP ), + ( "b/test", errno.ENOENT ), + ] + + def __del__(self): + try: + #os.system("tree -F %s" % self.tmpdir) + shutil.rmtree(self.tmpdir) + except: + pass + + def setUp(self): + self.tmpdir = tempfile.mkdtemp(prefix = "oe-test_path") + self.root = os.path.join(self.tmpdir, "R") + + os.mkdir(os.path.join(self.tmpdir, "_real")) + os.symlink("_real", self.root) + + for d in self.DIRS: + os.mkdir(os.path.join(self.root, d)) + for f in self.FILES: + open(os.path.join(self.root, f), "w") + for l in self.LINKS: + os.symlink(l[1], os.path.join(self.root, l[0])) + + def __realpath(self, file, use_physdir, assume_dir = True): + return oe.path.realpath(os.path.join(self.root, file), self.root, + use_physdir, assume_dir = assume_dir) + + def test_norm(self): + for l in self.LINKS: + if l[2] == None: + continue + + target_p = self.__realpath(l[0], True) + target_l = self.__realpath(l[0], False) + + if l[2] != False: + self.assertEqual(target_p, target_l) + self.assertEqual(l[2], target_p[len(self.root):]) + + def test_phys(self): + for l in self.LINKS_PHYS: + target_p = self.__realpath(l[0], True) + target_l = self.__realpath(l[0], False) + + self.assertEqual(l[1], target_p[len(self.root):]) + self.assertEqual(l[2], target_l[len(self.root):]) + + def test_loop(self): + for e in self.EXCEPTIONS: + self.assertRaisesRegex(OSError, r'\[Errno %u\]' % e[1], + self.__realpath, e[0], False, False) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/types.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/types.py new file mode 100644 index 000000000..4fe2746a3 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/types.py @@ -0,0 +1,50 @@ +import unittest +from oe.maketype import create + +class TestBooleanType(unittest.TestCase): + def test_invalid(self): + self.assertRaises(ValueError, create, '', 'boolean') + self.assertRaises(ValueError, create, 'foo', 'boolean') + self.assertRaises(TypeError, create, object(), 'boolean') + + def test_true(self): + self.assertTrue(create('y', 'boolean')) + self.assertTrue(create('yes', 'boolean')) + self.assertTrue(create('1', 'boolean')) + self.assertTrue(create('t', 'boolean')) + self.assertTrue(create('true', 'boolean')) + self.assertTrue(create('TRUE', 'boolean')) + self.assertTrue(create('truE', 'boolean')) + + def test_false(self): + self.assertFalse(create('n', 'boolean')) + self.assertFalse(create('no', 'boolean')) + self.assertFalse(create('0', 'boolean')) + self.assertFalse(create('f', 'boolean')) + self.assertFalse(create('false', 'boolean')) + self.assertFalse(create('FALSE', 'boolean')) + self.assertFalse(create('faLse', 'boolean')) + + def test_bool_equality(self): + self.assertEqual(create('n', 'boolean'), False) + self.assertNotEqual(create('n', 'boolean'), True) + self.assertEqual(create('y', 'boolean'), True) + self.assertNotEqual(create('y', 'boolean'), False) + +class TestList(unittest.TestCase): + def assertListEqual(self, value, valid, sep=None): + obj = create(value, 'list', separator=sep) + self.assertEqual(obj, valid) + if sep is not None: + self.assertEqual(obj.separator, sep) + self.assertEqual(str(obj), obj.separator.join(obj)) + + def test_list_nosep(self): + testlist = ['alpha', 'beta', 'theta'] + self.assertListEqual('alpha beta theta', testlist) + self.assertListEqual('alpha beta\ttheta', testlist) + self.assertListEqual('alpha', ['alpha']) + + def test_list_usersep(self): + self.assertListEqual('foo:bar', ['foo', 'bar'], ':') + self.assertListEqual('foo:bar:baz', ['foo', 'bar', 'baz'], ':') diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/utils.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/utils.py new file mode 100644 index 000000000..7deb10f3c --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oelib/utils.py @@ -0,0 +1,51 @@ +import unittest +from oe.utils import packages_filter_out_system, trim_version + +class TestPackagesFilterOutSystem(unittest.TestCase): + def test_filter(self): + """ + Test that oe.utils.packages_filter_out_system works. + """ + try: + import bb + except ImportError: + self.skipTest("Cannot import bb") + + d = bb.data_smart.DataSmart() + d.setVar("PN", "foo") + + d.setVar("PACKAGES", "foo foo-doc foo-dev") + pkgs = packages_filter_out_system(d) + self.assertEqual(pkgs, []) + + d.setVar("PACKAGES", "foo foo-doc foo-data foo-dev") + pkgs = packages_filter_out_system(d) + self.assertEqual(pkgs, ["foo-data"]) + + d.setVar("PACKAGES", "foo foo-locale-en-gb") + pkgs = packages_filter_out_system(d) + self.assertEqual(pkgs, []) + + d.setVar("PACKAGES", "foo foo-data foo-locale-en-gb") + pkgs = packages_filter_out_system(d) + self.assertEqual(pkgs, ["foo-data"]) + + +class TestTrimVersion(unittest.TestCase): + def test_version_exception(self): + with self.assertRaises(TypeError): + trim_version(None, 2) + with self.assertRaises(TypeError): + trim_version((1, 2, 3), 2) + + def test_num_exception(self): + with self.assertRaises(ValueError): + trim_version("1.2.3", 0) + with self.assertRaises(ValueError): + trim_version("1.2.3", -1) + + def test_valid(self): + self.assertEqual(trim_version("1.2.3", 1), "1") + self.assertEqual(trim_version("1.2.3", 2), "1.2") + self.assertEqual(trim_version("1.2.3", 3), "1.2.3") + self.assertEqual(trim_version("1.2.3", 4), "1.2.3") diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oescripts.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oescripts.py index 28345dc6a..29547f56a 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/oescripts.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/oescripts.py @@ -10,38 +10,10 @@ from oeqa.selftest.buildhistory import BuildhistoryBase from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer from oeqa.utils.decorators import testcase -class TestScripts(oeSelfTest): - - @testcase(300) - def test_cleanup_workdir(self): - path = os.path.dirname(get_bb_var('WORKDIR', 'gzip')) - old_version_recipe = os.path.join(get_bb_var('COREBASE'), 'meta/recipes-extended/gzip/gzip_1.3.12.bb') - old_version = '1.3.12' - bitbake("-c clean gzip") - bitbake("-c clean -b %s" % old_version_recipe) - - if os.path.exists(path): - initial_contents = os.listdir(path) - else: - initial_contents = [] - - bitbake('gzip') - intermediary_contents = os.listdir(path) - bitbake("-b %s" % old_version_recipe) - runCmd('cleanup-workdir') - remaining_contents = os.listdir(path) - - expected_contents = [x for x in intermediary_contents if x not in initial_contents] - remaining_not_expected = [x for x in remaining_contents if x not in expected_contents] - self.assertFalse(remaining_not_expected, msg="Not all necessary content has been deleted from %s: %s" % (path, ', '.join(map(str, remaining_not_expected)))) - expected_not_remaining = [x for x in expected_contents if x not in remaining_contents] - self.assertFalse(expected_not_remaining, msg="The script removed extra contents from %s: %s" % (path, ', '.join(map(str, expected_not_remaining)))) - class BuildhistoryDiffTests(BuildhistoryBase): @testcase(295) def test_buildhistory_diff(self): - self.add_command_to_tearDown('cleanup-workdir') target = 'xcursor-transparent-theme' self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True) self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/pkgdata.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/pkgdata.py index 5a63f89ff..d69c3c800 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/pkgdata.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/pkgdata.py @@ -6,7 +6,7 @@ import fnmatch import oeqa.utils.ftools as ftools from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars from oeqa.utils.decorators import testcase class OePkgdataUtilTests(oeSelfTest): @@ -16,21 +16,21 @@ class OePkgdataUtilTests(oeSelfTest): # Ensure we have the right data in pkgdata logger = logging.getLogger("selftest") logger.info('Running bitbake to generate pkgdata') - bitbake('glibc busybox zlib bash') + bitbake('busybox zlib m4') @testcase(1203) def test_lookup_pkg(self): # Forward tests - result = runCmd('oe-pkgdata-util lookup-pkg "glibc busybox"') - self.assertEqual(result.output, 'libc6\nbusybox') + result = runCmd('oe-pkgdata-util lookup-pkg "zlib busybox"') + self.assertEqual(result.output, 'libz1\nbusybox') result = runCmd('oe-pkgdata-util lookup-pkg zlib-dev') self.assertEqual(result.output, 'libz-dev') result = runCmd('oe-pkgdata-util lookup-pkg nonexistentpkg', ignore_status=True) self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output) self.assertEqual(result.output, 'ERROR: The following packages could not be found: nonexistentpkg') # Reverse tests - result = runCmd('oe-pkgdata-util lookup-pkg -r "libc6 busybox"') - self.assertEqual(result.output, 'glibc\nbusybox') + result = runCmd('oe-pkgdata-util lookup-pkg -r "libz1 busybox"') + self.assertEqual(result.output, 'zlib\nbusybox') result = runCmd('oe-pkgdata-util lookup-pkg -r libz-dev') self.assertEqual(result.output, 'zlib-dev') result = runCmd('oe-pkgdata-util lookup-pkg -r nonexistentpkg', ignore_status=True) @@ -41,24 +41,26 @@ class OePkgdataUtilTests(oeSelfTest): def test_read_value(self): result = runCmd('oe-pkgdata-util read-value PN libz1') self.assertEqual(result.output, 'zlib') - result = runCmd('oe-pkgdata-util read-value PKGSIZE bash') + result = runCmd('oe-pkgdata-util read-value PKG libz1') + self.assertEqual(result.output, 'libz1') + result = runCmd('oe-pkgdata-util read-value PKGSIZE m4') pkgsize = int(result.output.strip()) self.assertGreater(pkgsize, 1, "Size should be greater than 1. %s" % result.output) @testcase(1198) def test_find_path(self): - result = runCmd('oe-pkgdata-util find-path /lib/libc.so.6') - self.assertEqual(result.output, 'glibc: /lib/libc.so.6') - result = runCmd('oe-pkgdata-util find-path /bin/bash') - self.assertEqual(result.output, 'bash: /bin/bash') + result = runCmd('oe-pkgdata-util find-path /lib/libz.so.1') + self.assertEqual(result.output, 'zlib: /lib/libz.so.1') + result = runCmd('oe-pkgdata-util find-path /usr/bin/m4') + self.assertEqual(result.output, 'm4: /usr/bin/m4') result = runCmd('oe-pkgdata-util find-path /not/exist', ignore_status=True) self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output) self.assertEqual(result.output, 'ERROR: Unable to find any package producing path /not/exist') @testcase(1204) def test_lookup_recipe(self): - result = runCmd('oe-pkgdata-util lookup-recipe "libc6-staticdev busybox"') - self.assertEqual(result.output, 'glibc\nbusybox') + result = runCmd('oe-pkgdata-util lookup-recipe "libz-staticdev busybox"') + self.assertEqual(result.output, 'zlib\nbusybox') result = runCmd('oe-pkgdata-util lookup-recipe libz-dbg') self.assertEqual(result.output, 'zlib') result = runCmd('oe-pkgdata-util lookup-recipe nonexistentpkg', ignore_status=True) @@ -70,12 +72,11 @@ class OePkgdataUtilTests(oeSelfTest): # No arguments result = runCmd('oe-pkgdata-util list-pkgs') pkglist = result.output.split() - self.assertIn('glibc-utils', pkglist, "Listed packages: %s" % result.output) + self.assertIn('zlib', pkglist, "Listed packages: %s" % result.output) self.assertIn('zlib-dev', pkglist, "Listed packages: %s" % result.output) # No pkgspec, runtime result = runCmd('oe-pkgdata-util list-pkgs -r') pkglist = result.output.split() - self.assertIn('libc6-utils', pkglist, "Listed packages: %s" % result.output) self.assertIn('libz-dev', pkglist, "Listed packages: %s" % result.output) # With recipe specified result = runCmd('oe-pkgdata-util list-pkgs -p zlib') @@ -124,10 +125,11 @@ class OePkgdataUtilTests(oeSelfTest): curpkg = line.split(':')[0] files[curpkg] = [] return files - base_libdir = get_bb_var('base_libdir') - libdir = get_bb_var('libdir') - includedir = get_bb_var('includedir') - mandir = get_bb_var('mandir') + bb_vars = get_bb_vars(['base_libdir', 'libdir', 'includedir', 'mandir']) + base_libdir = bb_vars['base_libdir'] + libdir = bb_vars['libdir'] + includedir = bb_vars['includedir'] + mandir = bb_vars['mandir'] # Test recipe-space package name result = runCmd('oe-pkgdata-util list-pkg-files zlib-dev zlib-doc') files = splitoutput(result.output) @@ -205,11 +207,10 @@ class OePkgdataUtilTests(oeSelfTest): self.track_for_cleanup(tempdir) pkglistfile = os.path.join(tempdir, 'pkglist') with open(pkglistfile, 'w') as f: - f.write('libc6\n') f.write('libz1\n') f.write('busybox\n') result = runCmd('oe-pkgdata-util glob %s "*-dev"' % pkglistfile) - desiredresult = ['libc6-dev', 'libz-dev', 'busybox-dev'] + desiredresult = ['libz-dev', 'busybox-dev'] self.assertEqual(sorted(result.output.split()), sorted(desiredresult)) # The following should not error (because when we use this during rootfs construction, sometimes the complementary package won't exist) result = runCmd('oe-pkgdata-util glob %s "*-nonexistent"' % pkglistfile) @@ -222,5 +223,5 @@ class OePkgdataUtilTests(oeSelfTest): @testcase(1206) def test_specify_pkgdatadir(self): - result = runCmd('oe-pkgdata-util -p %s lookup-pkg glibc' % get_bb_var('PKGDATA_DIR')) - self.assertEqual(result.output, 'libc6') + result = runCmd('oe-pkgdata-util -p %s lookup-pkg zlib' % get_bb_var('PKGDATA_DIR')) + self.assertEqual(result.output, 'libz1') diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/prservice.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/prservice.py index 0b2dfe649..34d419762 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/prservice.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/prservice.py @@ -12,10 +12,13 @@ from oeqa.utils.decorators import testcase from oeqa.utils.network import get_free_port class BitbakePrTests(oeSelfTest): - + + @classmethod + def setUpClass(cls): + cls.pkgdata_dir = get_bb_var('PKGDATA_DIR') + def get_pr_version(self, package_name): - pkgdata_dir = get_bb_var('PKGDATA_DIR') - package_data_file = os.path.join(pkgdata_dir, 'runtime', package_name) + package_data_file = os.path.join(self.pkgdata_dir, 'runtime', package_name) package_data = ftools.read_file(package_data_file) find_pr = re.search("PKGR: r[0-9]+\.([0-9]+)", package_data) self.assertTrue(find_pr, "No PKG revision found in %s" % package_data_file) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/recipetool.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/recipetool.py index 9b669248f..dc55a5e49 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/recipetool.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/recipetool.py @@ -1,9 +1,11 @@ import os import logging +import shutil import tempfile import urllib.parse -from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer +from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import get_bb_vars, create_temp_layer from oeqa.utils.decorators import testcase from oeqa.selftest import devtool @@ -24,6 +26,7 @@ def tearDownModule(): class RecipetoolBase(devtool.DevtoolBase): + def setUpLocal(self): self.templayerdir = templayerdir self.tempdir = tempfile.mkdtemp(prefix='recipetoolqa') @@ -64,12 +67,16 @@ class RecipetoolBase(devtool.DevtoolBase): class RecipetoolTests(RecipetoolBase): + @classmethod def setUpClass(cls): # Ensure we have the right data in shlibs/pkgdata logger = logging.getLogger("selftest") logger.info('Running bitbake to generate pkgdata') bitbake('-c packagedata base-files coreutils busybox selftest-recipetool-appendfile') + bb_vars = get_bb_vars(['COREBASE', 'BBPATH']) + cls.corebase = bb_vars['COREBASE'] + cls.bbpath = bb_vars['BBPATH'] def _try_recipetool_appendfile(self, testrecipe, destfile, newfile, options, expectedlines, expectedfiles): cmd = 'recipetool appendfile %s %s %s %s' % (self.templayerdir, destfile, newfile, options) @@ -103,9 +110,8 @@ class RecipetoolTests(RecipetoolBase): # Now try with a file we know should be an alternative # (this is very much a fake example, but one we know is reliably an alternative) self._try_recipetool_appendfile_fail('/bin/ls', self.testfile, ['ERROR: File /bin/ls is an alternative possibly provided by the following recipes:', 'coreutils', 'busybox']) - corebase = get_bb_var('COREBASE') # Need a test file - should be executable - testfile2 = os.path.join(corebase, 'oe-init-build-env') + testfile2 = os.path.join(self.corebase, 'oe-init-build-env') testfile2name = os.path.basename(testfile2) expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', '\n', @@ -134,7 +140,6 @@ class RecipetoolTests(RecipetoolBase): @testcase(1173) def test_recipetool_appendfile_add(self): - corebase = get_bb_var('COREBASE') # Try arbitrary file add to a recipe expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', '\n', @@ -147,7 +152,7 @@ class RecipetoolTests(RecipetoolBase): self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase', expectedlines, ['testfile']) # Try adding another file, this time where the source file is executable # (so we're testing that, plus modifying an existing bbappend) - testfile2 = os.path.join(corebase, 'oe-init-build-env') + testfile2 = os.path.join(self.corebase, 'oe-init-build-env') testfile2name = os.path.basename(testfile2) expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', '\n', @@ -363,20 +368,22 @@ class RecipetoolTests(RecipetoolBase): # Try adding a recipe tempsrc = os.path.join(self.tempdir, 'srctree') os.makedirs(tempsrc) - recipefile = os.path.join(self.tempdir, 'logrotate_3.8.7.bb') - srcuri = 'https://github.com/logrotate/logrotate/archive/r3-8-7.tar.gz' + recipefile = os.path.join(self.tempdir, 'logrotate_3.12.3.bb') + srcuri = 'https://github.com/logrotate/logrotate/releases/download/3.12.3/logrotate-3.12.3.tar.xz' result = runCmd('recipetool create -o %s %s -x %s' % (recipefile, srcuri, tempsrc)) self.assertTrue(os.path.isfile(recipefile)) checkvars = {} checkvars['LICENSE'] = 'GPLv2' - checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=18810669f13b87348459e611d31ab760' - checkvars['SRC_URI'] = 'https://github.com/logrotate/logrotate/archive/r3-8-7.tar.gz' - checkvars['SRC_URI[md5sum]'] = '6b1aa0e0d07eda3c9a2526520850397a' - checkvars['SRC_URI[sha256sum]'] = 'dece4bfeb9d8374a0ecafa34be139b5a697db5c926dcc69a9b8715431a22e733' + checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' + checkvars['SRC_URI'] = 'https://github.com/logrotate/logrotate/releases/download/${PV}/logrotate-${PV}.tar.xz' + checkvars['SRC_URI[md5sum]'] = 'a560c57fac87c45b2fc17406cdf79288' + checkvars['SRC_URI[sha256sum]'] = '2e6a401cac9024db2288297e3be1a8ab60e7401ba8e91225218aaf4a27e82a07' self._test_recipe_contents(recipefile, checkvars, []) @testcase(1194) def test_recipetool_create_git(self): + if 'x11' not in get_bb_var('DISTRO_FEATURES'): + self.skipTest('Test requires x11 as distro feature') # Ensure we have the right data in shlibs/pkgdata bitbake('libpng pango libx11 libxext jpeg libcheck') # Try adding a recipe @@ -480,6 +487,46 @@ class RecipetoolTests(RecipetoolBase): inherits = ['pkgconfig', 'autotools'] self._test_recipe_contents(recipefile, checkvars, inherits) + def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths): + dstdir = basedstdir + self.assertTrue(os.path.exists(dstdir)) + for p in paths: + dstdir = os.path.join(dstdir, p) + if not os.path.exists(dstdir): + os.makedirs(dstdir) + self.track_for_cleanup(dstdir) + dstfile = os.path.join(dstdir, os.path.basename(srcfile)) + if srcfile != dstfile: + shutil.copy(srcfile, dstfile) + self.track_for_cleanup(dstfile) + + def test_recipetool_load_plugin(self): + """Test that recipetool loads only the first found plugin in BBPATH.""" + + recipetool = runCmd("which recipetool") + fromname = runCmd("recipetool --quiet pluginfile") + srcfile = fromname.output + searchpath = self.bbpath.split(':') + [os.path.dirname(recipetool.output)] + plugincontent = [] + with open(srcfile) as fh: + plugincontent = fh.readlines() + try: + self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found') + for path in searchpath: + self._copy_file_with_cleanup(srcfile, path, 'lib', 'recipetool') + result = runCmd("recipetool --quiet count") + self.assertEqual(result.output, '1') + result = runCmd("recipetool --quiet multiloaded") + self.assertEqual(result.output, "no") + for path in searchpath: + result = runCmd("recipetool --quiet bbdir") + self.assertEqual(result.output, path) + os.unlink(os.path.join(result.output, 'lib', 'recipetool', 'bbpath.py')) + finally: + with open(srcfile, 'w') as fh: + fh.writelines(plugincontent) + + class RecipetoolAppendsrcBase(RecipetoolBase): def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles): cmd = 'recipetool appendsrcfile %s %s %s %s %s' % (options, self.templayerdir, testrecipe, newfile, destfile) @@ -555,20 +602,23 @@ class RecipetoolAppendsrcBase(RecipetoolBase): self._try_recipetool_appendsrcfiles(testrecipe, newfiles, expectedfiles=expectedfiles, destdir=destdir, options=options) - src_uri = get_bb_var('SRC_URI', testrecipe).split() + bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'FILESEXTRAPATHS'], testrecipe) + src_uri = bb_vars['SRC_URI'].split() for f in expectedfiles: if destdir: self.assertIn('file://%s;subdir=%s' % (f, destdir), src_uri) else: self.assertIn('file://%s' % f, src_uri) - recipefile = get_bb_var('FILE', testrecipe) + recipefile = bb_vars['FILE'] bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir) filesdir = os.path.join(os.path.dirname(bbappendfile), testrecipe) - filesextrapaths = get_bb_var('FILESEXTRAPATHS', testrecipe).split(':') + filesextrapaths = bb_vars['FILESEXTRAPATHS'].split(':') self.assertIn(filesdir, filesextrapaths) + + class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): @testcase(1273) @@ -594,8 +644,9 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): @testcase(1280) def test_recipetool_appendsrcfile_srcdir_basic(self): testrecipe = 'bash' - srcdir = get_bb_var('S', testrecipe) - workdir = get_bb_var('WORKDIR', testrecipe) + bb_vars = get_bb_vars(['S', 'WORKDIR'], testrecipe) + srcdir = bb_vars['S'] + workdir = bb_vars['WORKDIR'] subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, 'a-file', srcdir=subdir) @@ -620,8 +671,9 @@ class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase): def test_recipetool_appendsrcfile_replace_file_srcdir(self): testrecipe = 'bash' filepath = 'Makefile.in' - srcdir = get_bb_var('S', testrecipe) - workdir = get_bb_var('WORKDIR', testrecipe) + bb_vars = get_bb_vars(['S', 'WORKDIR'], testrecipe) + srcdir = bb_vars['S'] + workdir = bb_vars['WORKDIR'] subdir = os.path.relpath(srcdir, workdir) self._test_appendsrcfile(testrecipe, filepath, srcdir=subdir) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/runqemu.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/runqemu.py new file mode 100644 index 000000000..58c6f96f9 --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/runqemu.py @@ -0,0 +1,140 @@ +# +# Copyright (c) 2017 Wind River Systems, Inc. +# + +import re +import logging + +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import bitbake, runqemu, get_bb_var +from oeqa.utils.decorators import testcase + +class RunqemuTests(oeSelfTest): + """Runqemu test class""" + + image_is_ready = False + deploy_dir_image = '' + + def setUpLocal(self): + self.recipe = 'core-image-minimal' + self.machine = 'qemux86-64' + self.fstypes = "ext4 iso hddimg vmdk qcow2 vdi" + self.cmd_common = "runqemu nographic" + + # Avoid emit the same record multiple times. + mainlogger = logging.getLogger("BitBake.Main") + mainlogger.propagate = False + + self.write_config( +""" +MACHINE = "%s" +IMAGE_FSTYPES = "%s" +# 10 means 1 second +SYSLINUX_TIMEOUT = "10" +""" +% (self.machine, self.fstypes) + ) + + if not RunqemuTests.image_is_ready: + RunqemuTests.deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') + bitbake(self.recipe) + RunqemuTests.image_is_ready = True + + @testcase(2001) + def test_boot_machine(self): + """Test runqemu machine""" + cmd = "%s %s" % (self.cmd_common, self.machine) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd) + + @testcase(2002) + def test_boot_machine_ext4(self): + """Test runqemu machine ext4""" + cmd = "%s %s ext4" % (self.cmd_common, self.machine) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue('rootfs.ext4' in f.read(), "Failed: %s" % cmd) + + @testcase(2003) + def test_boot_machine_iso(self): + """Test runqemu machine iso""" + cmd = "%s %s iso" % (self.cmd_common, self.machine) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue(' -cdrom ' in f.read(), "Failed: %s" % cmd) + + @testcase(2004) + def test_boot_recipe_image(self): + """Test runqemu recipe-image""" + cmd = "%s %s" % (self.cmd_common, self.recipe) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd) + + @testcase(2005) + def test_boot_recipe_image_vmdk(self): + """Test runqemu recipe-image vmdk""" + cmd = "%s %s vmdk" % (self.cmd_common, self.recipe) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue('format=vmdk' in f.read(), "Failed: %s" % cmd) + + @testcase(2006) + def test_boot_recipe_image_vdi(self): + """Test runqemu recipe-image vdi""" + cmd = "%s %s vdi" % (self.cmd_common, self.recipe) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue('format=vdi' in f.read(), "Failed: %s" % cmd) + + @testcase(2007) + def test_boot_deploy(self): + """Test runqemu deploy_dir_image""" + cmd = "%s %s" % (self.cmd_common, self.deploy_dir_image) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd) + + @testcase(2008) + def test_boot_deploy_hddimg(self): + """Test runqemu deploy_dir_image hddimg""" + cmd = "%s %s hddimg" % (self.cmd_common, self.deploy_dir_image) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue(re.search('file=.*.hddimg', f.read()), "Failed: %s" % cmd) + + @testcase(2009) + def test_boot_machine_slirp(self): + """Test runqemu machine slirp""" + cmd = "%s slirp %s" % (self.cmd_common, self.machine) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue(' -netdev user' in f.read(), "Failed: %s" % cmd) + + @testcase(2009) + def test_boot_machine_slirp_qcow2(self): + """Test runqemu machine slirp qcow2""" + cmd = "%s slirp qcow2 %s" % (self.cmd_common, self.machine) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + with open(qemu.qemurunnerlog) as f: + self.assertTrue('format=qcow2' in f.read(), "Failed: %s" % cmd) + + @testcase(2010) + def test_boot_qemu_boot(self): + """Test runqemu /path/to/image.qemuboot.conf""" + qemuboot_conf = "%s-%s.qemuboot.conf" % (self.recipe, self.machine) + qemuboot_conf = os.path.join(self.deploy_dir_image, qemuboot_conf) + if not os.path.exists(qemuboot_conf): + self.skipTest("%s not found" % qemuboot_conf) + cmd = "%s %s" % (self.cmd_common, qemuboot_conf) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd) + + @testcase(2011) + def test_boot_rootfs(self): + """Test runqemu /path/to/rootfs.ext4""" + rootfs = "%s-%s.ext4" % (self.recipe, self.machine) + rootfs = os.path.join(self.deploy_dir_image, rootfs) + if not os.path.exists(rootfs): + self.skipTest("%s not found" % rootfs) + cmd = "%s %s" % (self.cmd_common, rootfs) + with runqemu(self.recipe, ssh=False, launch_cmd=cmd) as qemu: + self.assertTrue(qemu.runner.logged, "Failed: %s" % cmd) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/runtime-test.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/runtime-test.py index c2d5b45a4..e498d046c 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/runtime-test.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/runtime-test.py @@ -1,10 +1,15 @@ from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu from oeqa.utils.decorators import testcase import os +import re class TestExport(oeSelfTest): + @classmethod + def tearDownClass(cls): + runCmd("rm -rf /tmp/sdk") + def test_testexport_basic(self): """ Summary: Check basic testexport functionality with only ping test enabled. @@ -26,22 +31,23 @@ class TestExport(oeSelfTest): bitbake('core-image-minimal') bitbake('-c testexport core-image-minimal') - # Verify if TEST_EXPORT_DIR was created testexport_dir = get_bb_var('TEST_EXPORT_DIR', 'core-image-minimal') + + # Verify if TEST_EXPORT_DIR was created isdir = os.path.isdir(testexport_dir) self.assertEqual(True, isdir, 'Failed to create testexport dir: %s' % testexport_dir) with runqemu('core-image-minimal') as qemu: # Attempt to run runexported.py to perform ping test - runexported_path = os.path.join(testexport_dir, "runexported.py") - testdata_path = os.path.join(testexport_dir, "testdata.json") - cmd = "%s -t %s -s %s %s" % (runexported_path, qemu.ip, qemu.server_ip, testdata_path) + test_path = os.path.join(testexport_dir, "oe-test") + data_file = os.path.join(testexport_dir, 'data', 'testdata.json') + manifest = os.path.join(testexport_dir, 'data', 'manifest') + cmd = ("%s runtime --test-data-file %s --packages-manifest %s " + "--target-ip %s --server-ip %s --quiet" + % (test_path, data_file, manifest, qemu.ip, qemu.server_ip)) result = runCmd(cmd) - self.assertEqual(0, result.status, 'runexported.py returned a non 0 status') - # Verify ping test was succesful - failure = True if 'FAIL' in result.output else False - self.assertNotEqual(True, failure, 'ping test failed') + self.assertEqual(0, result.status, 'oe-test runtime returned a non 0 status') def test_testexport_sdk(self): """ @@ -60,7 +66,6 @@ class TestExport(oeSelfTest): features += 'TEST_SERVER_IP = "192.168.7.1"\n' features += 'TEST_TARGET_IP = "192.168.7.1"\n' features += 'TEST_SUITES = "ping"\n' - features += 'TEST_SUITES_TAGS = "selftest_sdk"\n' features += 'TEST_EXPORT_SDK_ENABLED = "1"\n' features += 'TEST_EXPORT_SDK_PACKAGES = "nativesdk-tar"\n' self.write_config(features) @@ -69,19 +74,31 @@ class TestExport(oeSelfTest): bitbake('core-image-minimal') bitbake('-c testexport core-image-minimal') + needed_vars = ['TEST_EXPORT_DIR', 'TEST_EXPORT_SDK_DIR', 'TEST_EXPORT_SDK_NAME'] + bb_vars = get_bb_vars(needed_vars, 'core-image-minimal') + testexport_dir = bb_vars['TEST_EXPORT_DIR'] + sdk_dir = bb_vars['TEST_EXPORT_SDK_DIR'] + sdk_name = bb_vars['TEST_EXPORT_SDK_NAME'] + # Check for SDK - testexport_dir = get_bb_var('TEST_EXPORT_DIR', 'core-image-minimal') - sdk_dir = get_bb_var('TEST_EXPORT_SDK_DIR', 'core-image-minimal') - tarball_name = "%s.sh" % get_bb_var('TEST_EXPORT_SDK_NAME', 'core-image-minimal') + tarball_name = "%s.sh" % sdk_name tarball_path = os.path.join(testexport_dir, sdk_dir, tarball_name) - self.assertEqual(os.path.isfile(tarball_path), True, "Couldn't find SDK tarball: %s" % tarball_path) + msg = "Couldn't find SDK tarball: %s" % tarball_path + self.assertEqual(os.path.isfile(tarball_path), True, msg) + + # Extract SDK and run tar from SDK + result = runCmd("%s -y -d /tmp/sdk" % tarball_path) + self.assertEqual(0, result.status, "Couldn't extract SDK") - # Run runexported.py - runexported_path = os.path.join(testexport_dir, "runexported.py") - testdata_path = os.path.join(testexport_dir, "testdata.json") - cmd = "%s %s" % (runexported_path, testdata_path) - result = runCmd(cmd) - self.assertEqual(0, result.status, 'runexported.py returned a non 0 status') + env_script = result.output.split()[-1] + result = runCmd(". %s; which tar" % env_script, shell=True) + self.assertEqual(0, result.status, "Couldn't setup SDK environment") + is_sdk_tar = True if "/tmp/sdk" in result.output else False + self.assertTrue(is_sdk_tar, "Couldn't setup SDK environment") + + tar_sdk = result.output + result = runCmd("%s --version" % tar_sdk) + self.assertEqual(0, result.status, "Couldn't run tar from SDK") class TestImage(oeSelfTest): @@ -90,16 +107,131 @@ class TestImage(oeSelfTest): """ Summary: Check install packages functionality for testimage/testexport. Expected: 1. Import tests from a directory other than meta. - 2. Check install/unistall of socat. + 2. Check install/uninstall of socat. + 3. Check that remote package feeds can be accessed Product: oe-core Author: Mariano Lopez <mariano.lopez@intel.com> + Author: Alexander Kanavin <alexander.kanavin@intel.com> """ + if get_bb_var('DISTRO') == 'poky-tiny': + self.skipTest('core-image-full-cmdline not buildable for poky-tiny') features = 'INHERIT += "testimage"\n' features += 'TEST_SUITES = "ping ssh selftest"\n' - features += 'TEST_SUITES_TAGS = "selftest_package_install"\n' + # We don't yet know what the server ip and port will be - they will be patched + # in at the start of the on-image test + features += 'PACKAGE_FEED_URIS = "http://bogus_ip:bogus_port"\n' + features += 'EXTRA_IMAGE_FEATURES += "package-management"\n' + features += 'PACKAGE_CLASSES = "package_rpm"' self.write_config(features) # Build core-image-sato and testimage bitbake('core-image-full-cmdline socat') bitbake('-c testimage core-image-full-cmdline') + +class Postinst(oeSelfTest): + @testcase(1540) + def test_verify_postinst(self): + """ + Summary: The purpose of this test is to verify the execution order of postinst Bugzilla ID: [5319] + Expected : + 1. Compile a minimal image. + 2. The compiled image will add the created layer with the recipes postinst[ abdpt] + 3. Run qemux86 + 4. Validate the task execution order + Author: Francisco Pedraza <francisco.j.pedraza.gonzalez@intel.com> + """ + features = 'INHERIT += "testimage"\n' + features += 'CORE_IMAGE_EXTRA_INSTALL += "postinst-at-rootfs \ +postinst-delayed-a \ +postinst-delayed-b \ +postinst-delayed-d \ +postinst-delayed-p \ +postinst-delayed-t \ +"\n' + self.write_config(features) + + bitbake('core-image-minimal -f ') + + postinst_list = ['100-postinst-at-rootfs', + '101-postinst-delayed-a', + '102-postinst-delayed-b', + '103-postinst-delayed-d', + '104-postinst-delayed-p', + '105-postinst-delayed-t'] + path_workdir = get_bb_var('WORKDIR','core-image-minimal') + workspacedir = 'testimage/qemu_boot_log' + workspacedir = os.path.join(path_workdir, workspacedir) + rexp = re.compile("^Running postinst .*/(?P<postinst>.*)\.\.\.$") + with runqemu('core-image-minimal') as qemu: + with open(workspacedir) as f: + found = False + idx = 0 + for line in f.readlines(): + line = line.strip().replace("^M","") + if not line: # To avoid empty lines + continue + m = rexp.search(line) + if m: + self.assertEqual(postinst_list[idx], m.group('postinst'), "Fail") + idx = idx+1 + found = True + elif found: + self.assertEqual(idx, len(postinst_list), "Not found all postinsts") + break + + @testcase(1545) + def test_postinst_rootfs_and_boot(self): + """ + Summary: The purpose of this test case is to verify Post-installation + scripts are called when rootfs is created and also test + that script can be delayed to run at first boot. + Dependencies: NA + Steps: 1. Add proper configuration to local.conf file + 2. Build a "core-image-minimal" image + 3. Verify that file created by postinst_rootfs recipe is + present on rootfs dir. + 4. Boot the image created on qemu and verify that the file + created by postinst_boot recipe is present on image. + Expected: The files are successfully created during rootfs and boot + time for 3 different package managers: rpm,ipk,deb and + for initialization managers: sysvinit and systemd. + + """ + file_rootfs_name = "this-was-created-at-rootfstime" + fileboot_name = "this-was-created-at-first-boot" + rootfs_pkg = 'postinst-at-rootfs' + boot_pkg = 'postinst-delayed-a' + #Step 1 + features = 'MACHINE = "qemux86"\n' + features += 'CORE_IMAGE_EXTRA_INSTALL += "%s %s "\n'% (rootfs_pkg, boot_pkg) + features += 'IMAGE_FEATURES += "ssh-server-openssh"\n' + for init_manager in ("sysvinit", "systemd"): + #for sysvinit no extra configuration is needed, + if (init_manager is "systemd"): + features += 'DISTRO_FEATURES_append = " systemd"\n' + features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' + features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' + features += 'VIRTUAL-RUNTIME_initscripts = ""\n' + for classes in ("package_rpm package_deb package_ipk", + "package_deb package_rpm package_ipk", + "package_ipk package_deb package_rpm"): + features += 'PACKAGE_CLASSES = "%s"\n' % classes + self.write_config(features) + + #Step 2 + bitbake('core-image-minimal') + + #Step 3 + file_rootfs_created = os.path.join(get_bb_var('IMAGE_ROOTFS',"core-image-minimal"), + file_rootfs_name) + found = os.path.isfile(file_rootfs_created) + self.assertTrue(found, "File %s was not created at rootfs time by %s" % \ + (file_rootfs_name, rootfs_pkg)) + + #Step 4 + testcommand = 'ls /etc/'+fileboot_name + with runqemu('core-image-minimal') as qemu: + sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' + result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand)) + self.assertEqual(result.status, 0, 'File %s was not created at firts boot'% fileboot_name) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/signing.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/signing.py index 606bfd3e9..0ac3d1fac 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/signing.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/signing.py @@ -1,5 +1,5 @@ from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars import os import glob import re @@ -27,15 +27,17 @@ class Signing(oeSelfTest): cls.pub_key_path = os.path.join(cls.testlayer_path, 'files', 'signing', "key.pub") cls.secret_key_path = os.path.join(cls.testlayer_path, 'files', 'signing', "key.secret") - runCmd('gpg --homedir %s --import %s %s' % (cls.gpg_dir, cls.pub_key_path, cls.secret_key_path)) + runCmd('gpg --batch --homedir %s --import %s %s' % (cls.gpg_dir, cls.pub_key_path, cls.secret_key_path)) @testcase(1362) def test_signing_packages(self): """ Summary: Test that packages can be signed in the package feed Expected: Package should be signed with the correct key + Expected: Images can be created from signed packages Product: oe-core Author: Daniel Istrate <daniel.alexandrux.istrate@intel.com> + Author: Alexander Kanavin <alexander.kanavin@intel.com> AutomatedBy: Daniel Istrate <daniel.alexandrux.istrate@intel.com> """ import oe.packagedata @@ -49,7 +51,6 @@ class Signing(oeSelfTest): feature = 'INHERIT += "sign_rpm"\n' feature += 'RPM_GPG_PASSPHRASE = "test123"\n' feature += 'RPM_GPG_NAME = "testuser"\n' - feature += 'RPM_GPG_PUBKEY = "%s"\n' % self.pub_key_path feature += 'GPG_PATH = "%s"\n' % self.gpg_dir self.write_config(feature) @@ -59,30 +60,38 @@ class Signing(oeSelfTest): self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe) - pkgdatadir = get_bb_var('PKGDATA_DIR', test_recipe) + needed_vars = ['PKGDATA_DIR', 'DEPLOY_DIR_RPM', 'PACKAGE_ARCH', 'STAGING_BINDIR_NATIVE'] + bb_vars = get_bb_vars(needed_vars, test_recipe) + pkgdatadir = bb_vars['PKGDATA_DIR'] pkgdata = oe.packagedata.read_pkgdatafile(pkgdatadir + "/runtime/ed") if 'PKGE' in pkgdata: pf = pkgdata['PN'] + "-" + pkgdata['PKGE'] + pkgdata['PKGV'] + '-' + pkgdata['PKGR'] else: pf = pkgdata['PN'] + "-" + pkgdata['PKGV'] + '-' + pkgdata['PKGR'] - deploy_dir_rpm = get_bb_var('DEPLOY_DIR_RPM', test_recipe) - package_arch = get_bb_var('PACKAGE_ARCH', test_recipe).replace('-', '_') - staging_bindir_native = get_bb_var('STAGING_BINDIR_NATIVE') + deploy_dir_rpm = bb_vars['DEPLOY_DIR_RPM'] + package_arch = bb_vars['PACKAGE_ARCH'].replace('-', '_') + staging_bindir_native = bb_vars['STAGING_BINDIR_NATIVE'] pkg_deploy = os.path.join(deploy_dir_rpm, package_arch, '.'.join((pf, package_arch, 'rpm'))) # Use a temporary rpmdb rpmdb = tempfile.mkdtemp(prefix='oeqa-rpmdb') - runCmd('%s/rpm --define "_dbpath %s" --import %s' % + runCmd('%s/rpmkeys --define "_dbpath %s" --import %s' % (staging_bindir_native, rpmdb, self.pub_key_path)) - ret = runCmd('%s/rpm --define "_dbpath %s" --checksig %s' % + ret = runCmd('%s/rpmkeys --define "_dbpath %s" --checksig %s' % (staging_bindir_native, rpmdb, pkg_deploy)) # tmp/deploy/rpm/i586/ed-1.9-r0.i586.rpm: rsa sha1 md5 OK - self.assertIn('rsa sha1 md5 OK', ret.output, 'Package signed incorrectly.') + self.assertIn('rsa sha1 (md5) pgp md5 OK', ret.output, 'Package signed incorrectly.') shutil.rmtree(rpmdb) + #Check that an image can be built from signed packages + self.add_command_to_tearDown('bitbake -c clean core-image-minimal') + bitbake('-c clean core-image-minimal') + bitbake('core-image-minimal') + + @testcase(1382) def test_signing_sstate_archive(self): """ @@ -101,13 +110,7 @@ class Signing(oeSelfTest): self.add_command_to_tearDown('bitbake -c clean %s' % test_recipe) self.add_command_to_tearDown('rm -rf %s' % sstatedir) - # Determine the pub key signature - ret = runCmd('gpg --homedir %s --list-keys' % self.gpg_dir) - pub_key = re.search(r'^pub\s+\S+/(\S+)\s+', ret.output, re.M) - self.assertIsNotNone(pub_key, 'Failed to determine the public key signature.') - pub_key = pub_key.group(1) - - feature = 'SSTATE_SIG_KEY ?= "%s"\n' % pub_key + feature = 'SSTATE_SIG_KEY ?= "testuser"\n' feature += 'SSTATE_SIG_PASSPHRASE ?= "test123"\n' feature += 'SSTATE_VERIFY_SIG ?= "1"\n' feature += 'GPG_PATH = "%s"\n' % self.gpg_dir diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstate.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstate.py index 598972443..f54bc4146 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstate.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstate.py @@ -6,16 +6,24 @@ import shutil import oeqa.utils.ftools as ftools from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer +from oeqa.utils.commands import runCmd, bitbake, get_bb_vars, get_test_layer class SStateBase(oeSelfTest): def setUpLocal(self): self.temp_sstate_location = None - self.sstate_path = get_bb_var('SSTATE_DIR') - self.distro = get_bb_var('NATIVELSBSTRING') - self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro) + needed_vars = ['SSTATE_DIR', 'NATIVELSBSTRING', 'TCLIBC', 'TUNE_ARCH', + 'TOPDIR', 'TARGET_VENDOR', 'TARGET_OS'] + bb_vars = get_bb_vars(needed_vars) + self.sstate_path = bb_vars['SSTATE_DIR'] + self.hostdistro = bb_vars['NATIVELSBSTRING'] + self.tclibc = bb_vars['TCLIBC'] + self.tune_arch = bb_vars['TUNE_ARCH'] + self.topdir = bb_vars['TOPDIR'] + self.target_vendor = bb_vars['TARGET_VENDOR'] + self.target_os = bb_vars['TARGET_OS'] + self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro) # Creates a special sstate configuration with the option to add sstate mirrors def config_sstate(self, temp_sstate_location=False, add_local_mirrors=[]): @@ -26,9 +34,10 @@ class SStateBase(oeSelfTest): config_temp_sstate = "SSTATE_DIR = \"%s\"" % temp_sstate_path self.append_config(config_temp_sstate) self.track_for_cleanup(temp_sstate_path) - self.sstate_path = get_bb_var('SSTATE_DIR') - self.distro = get_bb_var('NATIVELSBSTRING') - self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro) + bb_vars = get_bb_vars(['SSTATE_DIR', 'NATIVELSBSTRING']) + self.sstate_path = bb_vars['SSTATE_DIR'] + self.hostdistro = bb_vars['NATIVELSBSTRING'] + self.distro_specific_sstate = os.path.join(self.sstate_path, self.hostdistro) if add_local_mirrors: config_set_sstate_if_not_set = 'SSTATE_MIRRORS ?= ""' @@ -42,7 +51,7 @@ class SStateBase(oeSelfTest): def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True): result = [] for root, dirs, files in os.walk(self.sstate_path): - if distro_specific and re.search("%s/[a-z0-9]{2}$" % self.distro, root): + if distro_specific and re.search("%s/[a-z0-9]{2}$" % self.hostdistro, root): for f in files: if re.search(filename_regex, f): result.append(f) diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py index f99d74684..e35ddfff5 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/sstatetests.py @@ -41,22 +41,19 @@ class SStateTests(SStateBase): @testcase(975) def test_sstate_creation_distro_specific_pass(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) + self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) @testcase(1374) def test_sstate_creation_distro_specific_fail(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False) + self.run_test_sstate_creation(['binutils-cross-'+ self.tune_arch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False) @testcase(976) def test_sstate_creation_distro_nonspecific_pass(self): - self.run_test_sstate_creation(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) + self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) @testcase(1375) def test_sstate_creation_distro_nonspecific_fail(self): - self.run_test_sstate_creation(['glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False) - + self.run_test_sstate_creation(['linux-libc-headers'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False) # Test the sstate files deletion part of the do_cleansstate task def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True): @@ -77,17 +74,19 @@ class SStateTests(SStateBase): @testcase(977) def test_cleansstate_task_distro_specific_nonspecific(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_cleansstate_task(['binutils-cross-' + targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=True, temp_sstate_location=True) + targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native'] + targets.append('linux-libc-headers') + self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True) @testcase(1376) def test_cleansstate_task_distro_nonspecific(self): - self.run_test_cleansstate_task(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) + self.run_test_cleansstate_task(['linux-libc-headers'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True) @testcase(1377) def test_cleansstate_task_distro_specific(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_cleansstate_task(['binutils-cross-'+ targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) + targets = ['binutils-cross-'+ self.tune_arch, 'binutils-native'] + targets.append('linux-libc-headers') + self.run_test_cleansstate_task(targets, distro_specific=True, distro_nonspecific=False, temp_sstate_location=True) # Test rebuilding of distro-specific sstate files @@ -124,13 +123,11 @@ class SStateTests(SStateBase): @testcase(175) def test_rebuild_distro_specific_sstate_cross_native_targets(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch, 'binutils-native'], temp_sstate_location=True) + self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch, 'binutils-native'], temp_sstate_location=True) @testcase(1372) def test_rebuild_distro_specific_sstate_cross_target(self): - targetarch = get_bb_var('TUNE_ARCH') - self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch], temp_sstate_location=True) + self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + self.tune_arch], temp_sstate_location=True) @testcase(1373) def test_rebuild_distro_specific_sstate_native_target(self): @@ -145,10 +142,9 @@ class SStateTests(SStateBase): self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements') self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path]) - # If buildhistory is enabled, we need to disable version-going-backwards QA checks for this test. It may report errors otherwise. - if ('buildhistory' in get_bb_var('USER_CLASSES')) or ('buildhistory' in get_bb_var('INHERIT')): - remove_errors_config = 'ERROR_QA_remove = "version-going-backwards"' - self.append_config(remove_errors_config) + # If buildhistory is enabled, we need to disable version-going-backwards + # QA checks for this test. It may report errors otherwise. + self.append_config('ERROR_QA_remove = "version-going-backwards"') # For not this only checks if random sstate tasks are handled correctly as a group. # In the future we should add control over what tasks we check for. @@ -229,8 +225,6 @@ class SStateTests(SStateBase): manually and check using bitbake -S. """ - topdir = get_bb_var('TOPDIR') - targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" MACHINE = "qemux86" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" @@ -239,7 +233,7 @@ BUILD_OS = "linux" SDKMACHINE = "x86_64" PACKAGE_CLASSES = "package_rpm package_ipk package_deb" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S none") self.write_config(""" MACHINE = "qemux86" @@ -249,7 +243,7 @@ BUILD_OS = "linux" SDKMACHINE = "i686" PACKAGE_CLASSES = "package_rpm package_ipk package_deb" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S none") def get_files(d): @@ -262,9 +256,9 @@ PACKAGE_CLASSES = "package_rpm package_ipk package_deb" continue f.extend(os.path.join(root, name) for name in files) return f - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") - files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + targetvendor + "-linux", "x86_64" + targetvendor + "-linux", ) for x in files2] + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") + files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash").replace("i686-linux", "x86_64-linux").replace("i686" + self.target_vendor + "-linux", "x86_64" + self.target_vendor + "-linux", ) for x in files2] self.maxDiff = None self.assertCountEqual(files1, files2) @@ -277,18 +271,17 @@ PACKAGE_CLASSES = "package_rpm package_ipk package_deb" builds, override the variables manually and check using bitbake -S. """ - topdir = get_bb_var('TOPDIR') self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" NATIVELSBSTRING = \"DistroA\" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") bitbake("core-image-sato -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" NATIVELSBSTRING = \"DistroB\" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") bitbake("core-image-sato -S none") def get_files(d): @@ -296,8 +289,8 @@ NATIVELSBSTRING = \"DistroB\" for root, dirs, files in os.walk(d): f.extend(os.path.join(root, name) for name in files) return f - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] self.maxDiff = None self.assertCountEqual(files1, files2) @@ -346,14 +339,11 @@ MULTILIBS = \"\" def sstate_allarch_samesigs(self, configA, configB): - topdir = get_bb_var('TOPDIR') - targetos = get_bb_var('TARGET_OS') - targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(configA) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") bitbake("world meta-toolchain -S none") self.write_config(configB) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") bitbake("world meta-toolchain -S none") def get_files(d): @@ -367,15 +357,15 @@ MULTILIBS = \"\" (_, task, _, shash) = name.rsplit(".", 3) f[os.path.join(os.path.basename(root), task)] = shash return f - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/all" + targetvendor + "-" + targetos) - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/all" + targetvendor + "-" + targetos) + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/all" + self.target_vendor + "-" + self.target_os) + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/all" + self.target_vendor + "-" + self.target_os) self.maxDiff = None self.assertEqual(files1, files2) - nativesdkdir = os.path.basename(glob.glob(topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux")[0]) + nativesdkdir = os.path.basename(glob.glob(self.topdir + "/tmp-sstatesamehash/stamps/*-nativesdk*-linux")[0]) - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir) - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir) + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/" + nativesdkdir) + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/" + nativesdkdir) self.maxDiff = None self.assertEqual(files1, files2) @@ -387,9 +377,6 @@ MULTILIBS = \"\" qemux86copy machine to test this. Also include multilibs in the test. """ - topdir = get_bb_var('TOPDIR') - targetos = get_bb_var('TARGET_OS') - targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash\" MACHINE = \"qemux86\" @@ -397,7 +384,7 @@ require conf/multilib.conf MULTILIBS = "multilib:lib32" DEFAULTTUNE_virtclass-multilib-lib32 = "x86" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") bitbake("world meta-toolchain -S none") self.write_config(""" TMPDIR = \"${TOPDIR}/tmp-sstatesamehash2\" @@ -406,7 +393,7 @@ require conf/multilib.conf MULTILIBS = "multilib:lib32" DEFAULTTUNE_virtclass-multilib-lib32 = "x86" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") bitbake("world meta-toolchain -S none") def get_files(d): @@ -420,8 +407,8 @@ DEFAULTTUNE_virtclass-multilib-lib32 = "x86" if "do_build" not in name and "do_populate_sdk" not in name: f.append(os.path.join(root, name)) return f - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps") - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps") + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps") + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps") files2 = [x.replace("tmp-sstatesamehash2", "tmp-sstatesamehash") for x in files2] self.maxDiff = None self.assertCountEqual(files1, files2) @@ -433,8 +420,6 @@ DEFAULTTUNE_virtclass-multilib-lib32 = "x86" classes inherits should be the same. """ - topdir = get_bb_var('TOPDIR') - targetvendor = get_bb_var('TARGET_VENDOR') self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash" BB_NUMBER_THREADS = "1" @@ -445,8 +430,8 @@ DATE = "20161111" INHERIT_remove = "buildstats-summary buildhistory uninative" http_proxy = "" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash") - self.track_for_cleanup(topdir + "/download1") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash") + self.track_for_cleanup(self.topdir + "/download1") bitbake("world meta-toolchain -S none") self.write_config(""" TMPDIR = "${TOPDIR}/tmp-sstatesamehash2" @@ -460,8 +445,8 @@ INHERIT_remove = "uninative" INHERIT += "buildstats-summary buildhistory" http_proxy = "http://example.com/" """) - self.track_for_cleanup(topdir + "/tmp-sstatesamehash2") - self.track_for_cleanup(topdir + "/download2") + self.track_for_cleanup(self.topdir + "/tmp-sstatesamehash2") + self.track_for_cleanup(self.topdir + "/download2") bitbake("world meta-toolchain -S none") def get_files(d): @@ -473,8 +458,8 @@ http_proxy = "http://example.com/" base = os.sep.join(root.rsplit(os.sep, 2)[-2:] + [name]) f[base] = shash return f - files1 = get_files(topdir + "/tmp-sstatesamehash/stamps/") - files2 = get_files(topdir + "/tmp-sstatesamehash2/stamps/") + files1 = get_files(self.topdir + "/tmp-sstatesamehash/stamps/") + files2 = get_files(self.topdir + "/tmp-sstatesamehash2/stamps/") # Remove items that are identical in both sets for k,v in files1.items() & files2.items(): del files1[k] @@ -487,8 +472,8 @@ http_proxy = "http://example.com/" if k in files1 and k in files2: print("%s differs:" % k) print(subprocess.check_output(("bitbake-diffsigs", - topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k], - topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]))) + self.topdir + "/tmp-sstatesamehash/stamps/" + k + "." + files1[k], + self.topdir + "/tmp-sstatesamehash2/stamps/" + k + "." + files2[k]))) elif k in files1 and k not in files2: print("%s in files1" % k) elif k not in files1 and k in files2: diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/tinfoil.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/tinfoil.py new file mode 100644 index 000000000..73a0c3bac --- /dev/null +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/tinfoil.py @@ -0,0 +1,190 @@ +import unittest +import os +import re +import bb.tinfoil + +from oeqa.selftest.base import oeSelfTest +from oeqa.utils.commands import runCmd +from oeqa.utils.decorators import testcase + +class TinfoilTests(oeSelfTest): + """ Basic tests for the tinfoil API """ + + @testcase(1568) + def test_getvar(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(True) + machine = tinfoil.config_data.getVar('MACHINE') + if not machine: + self.fail('Unable to get MACHINE value - returned %s' % machine) + + @testcase(1569) + def test_expand(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(True) + expr = '${@os.getpid()}' + pid = tinfoil.config_data.expand(expr) + if not pid: + self.fail('Unable to expand "%s" - returned %s' % (expr, pid)) + + @testcase(1570) + def test_getvar_bb_origenv(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(True) + origenv = tinfoil.config_data.getVar('BB_ORIGENV', False) + if not origenv: + self.fail('Unable to get BB_ORIGENV value - returned %s' % origenv) + self.assertEqual(origenv.getVar('HOME', False), os.environ['HOME']) + + @testcase(1571) + def test_parse_recipe(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=False, quiet=2) + testrecipe = 'mdadm' + best = tinfoil.find_best_provider(testrecipe) + if not best: + self.fail('Unable to find recipe providing %s' % testrecipe) + rd = tinfoil.parse_recipe_file(best[3]) + self.assertEqual(testrecipe, rd.getVar('PN')) + + @testcase(1572) + def test_parse_recipe_copy_expand(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=False, quiet=2) + testrecipe = 'mdadm' + best = tinfoil.find_best_provider(testrecipe) + if not best: + self.fail('Unable to find recipe providing %s' % testrecipe) + rd = tinfoil.parse_recipe_file(best[3]) + # Check we can get variable values + self.assertEqual(testrecipe, rd.getVar('PN')) + # Check that expanding a value that includes a variable reference works + self.assertEqual(testrecipe, rd.getVar('BPN')) + # Now check that changing the referenced variable's value in a copy gives that + # value when expanding + localdata = bb.data.createCopy(rd) + localdata.setVar('PN', 'hello') + self.assertEqual('hello', localdata.getVar('BPN')) + + @testcase(1573) + def test_parse_recipe_initial_datastore(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=False, quiet=2) + testrecipe = 'mdadm' + best = tinfoil.find_best_provider(testrecipe) + if not best: + self.fail('Unable to find recipe providing %s' % testrecipe) + dcopy = bb.data.createCopy(tinfoil.config_data) + dcopy.setVar('MYVARIABLE', 'somevalue') + rd = tinfoil.parse_recipe_file(best[3], config_data=dcopy) + # Check we can get variable values + self.assertEqual('somevalue', rd.getVar('MYVARIABLE')) + + @testcase(1574) + def test_list_recipes(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=False, quiet=2) + # Check pkg_pn + checkpns = ['tar', 'automake', 'coreutils', 'm4-native', 'nativesdk-gcc'] + pkg_pn = tinfoil.cooker.recipecaches[''].pkg_pn + for pn in checkpns: + self.assertIn(pn, pkg_pn) + # Check pkg_fn + checkfns = {'nativesdk-gcc': '^virtual:nativesdk:.*', 'coreutils': '.*/coreutils_.*.bb'} + for fn, pn in tinfoil.cooker.recipecaches[''].pkg_fn.items(): + if pn in checkpns: + if pn in checkfns: + self.assertTrue(re.match(checkfns[pn], fn), 'Entry for %s: %s did not match %s' % (pn, fn, checkfns[pn])) + checkpns.remove(pn) + if checkpns: + self.fail('Unable to find pkg_fn entries for: %s' % ', '.join(checkpns)) + + @testcase(1575) + def test_wait_event(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=True) + # Need to drain events otherwise events that will be masked will still be in the queue + while tinfoil.wait_event(0.25): + pass + tinfoil.set_event_mask(['bb.event.FilesMatchingFound', 'bb.command.CommandCompleted']) + pattern = 'conf' + res = tinfoil.run_command('findFilesMatchingInDir', pattern, 'conf/machine') + self.assertTrue(res) + + eventreceived = False + waitcount = 5 + while waitcount > 0: + event = tinfoil.wait_event(1) + if event: + if isinstance(event, bb.command.CommandCompleted): + break + elif isinstance(event, bb.event.FilesMatchingFound): + self.assertEqual(pattern, event._pattern) + self.assertIn('qemuarm.conf', event._matches) + eventreceived = True + else: + self.fail('Unexpected event: %s' % event) + + waitcount = waitcount - 1 + + self.assertNotEqual(waitcount, 0, 'Timed out waiting for CommandCompleted event from bitbake server') + self.assertTrue(eventreceived, 'Did not receive FilesMatchingFound event from bitbake server') + + @testcase(1576) + def test_setvariable_clean(self): + # First check that setVariable affects the datastore + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=True) + tinfoil.run_command('setVariable', 'TESTVAR', 'specialvalue') + self.assertEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is not reflected in client-side getVar()') + + # Now check that the setVariable's effects are no longer present + # (this may legitimately break in future if we stop reinitialising + # the datastore, in which case we'll have to reconsider use of + # setVariable entirely) + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=True) + self.assertNotEqual(tinfoil.config_data.getVar('TESTVAR'), 'specialvalue', 'Value set using setVariable is still present!') + + # Now check that setVar on the main datastore works (uses setVariable internally) + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=True) + tinfoil.config_data.setVar('TESTVAR', 'specialvalue') + value = tinfoil.run_command('getVariable', 'TESTVAR') + self.assertEqual(value, 'specialvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()') + + def test_datastore_operations(self): + with bb.tinfoil.Tinfoil() as tinfoil: + tinfoil.prepare(config_only=True) + # Test setVarFlag() / getVarFlag() + tinfoil.config_data.setVarFlag('TESTVAR', 'flagname', 'flagval') + value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname') + self.assertEqual(value, 'flagval', 'Value set using config_data.setVarFlag() is not reflected in config_data.getVarFlag()') + # Test delVarFlag() + tinfoil.config_data.setVarFlag('TESTVAR', 'otherflag', 'othervalue') + tinfoil.config_data.delVarFlag('TESTVAR', 'flagname') + value = tinfoil.config_data.getVarFlag('TESTVAR', 'flagname') + self.assertEqual(value, None, 'Varflag deleted using config_data.delVarFlag() is not reflected in config_data.getVarFlag()') + value = tinfoil.config_data.getVarFlag('TESTVAR', 'otherflag') + self.assertEqual(value, 'othervalue', 'Varflag deleted using config_data.delVarFlag() caused unrelated flag to be removed') + # Test delVar() + tinfoil.config_data.setVar('TESTVAR', 'varvalue') + value = tinfoil.config_data.getVar('TESTVAR') + self.assertEqual(value, 'varvalue', 'Value set using config_data.setVar() is not reflected in config_data.getVar()') + tinfoil.config_data.delVar('TESTVAR') + value = tinfoil.config_data.getVar('TESTVAR') + self.assertEqual(value, None, 'Variable deleted using config_data.delVar() appears to still have a value') + # Test renameVar() + tinfoil.config_data.setVar('TESTVAROLD', 'origvalue') + tinfoil.config_data.renameVar('TESTVAROLD', 'TESTVARNEW') + value = tinfoil.config_data.getVar('TESTVAROLD') + self.assertEqual(value, None, 'Variable renamed using config_data.renameVar() still seems to exist') + value = tinfoil.config_data.getVar('TESTVARNEW') + self.assertEqual(value, 'origvalue', 'Variable renamed using config_data.renameVar() does not appear with new name') + # Test overrides + tinfoil.config_data.setVar('TESTVAR', 'original') + tinfoil.config_data.setVar('TESTVAR_overrideone', 'one') + tinfoil.config_data.setVar('TESTVAR_overridetwo', 'two') + tinfoil.config_data.appendVar('OVERRIDES', ':overrideone') + value = tinfoil.config_data.getVar('TESTVAR') + self.assertEqual(value, 'one', 'Variable overrides not functioning correctly') diff --git a/import-layers/yocto-poky/meta/lib/oeqa/selftest/wic.py b/import-layers/yocto-poky/meta/lib/oeqa/selftest/wic.py index e652fad24..726af19e9 100644 --- a/import-layers/yocto-poky/meta/lib/oeqa/selftest/wic.py +++ b/import-layers/yocto-poky/meta/lib/oeqa/selftest/wic.py @@ -24,42 +24,84 @@ """Test cases for wic.""" import os +import sys +import unittest from glob import glob from shutil import rmtree +from functools import wraps, lru_cache +from tempfile import NamedTemporaryFile from oeqa.selftest.base import oeSelfTest -from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu from oeqa.utils.decorators import testcase +@lru_cache(maxsize=32) +def get_host_arch(recipe): + """A cached call to get_bb_var('HOST_ARCH', <recipe>)""" + return get_bb_var('HOST_ARCH', recipe) + + +def only_for_arch(archs, image='core-image-minimal'): + """Decorator for wrapping test cases that can be run only for specific target + architectures. A list of compatible architectures is passed in `archs`. + Current architecture will be determined by parsing bitbake output for + `image` recipe. + """ + def wrapper(func): + @wraps(func) + def wrapped_f(*args, **kwargs): + arch = get_host_arch(image) + if archs and arch not in archs: + raise unittest.SkipTest("Testcase arch dependency not met: %s" % arch) + return func(*args, **kwargs) + wrapped_f.__name__ = func.__name__ + return wrapped_f + return wrapper + + class Wic(oeSelfTest): """Wic test class.""" - resultdir = "/var/tmp/wic/build/" + resultdir = "/var/tmp/wic.oe-selftest/" image_is_ready = False + native_sysroot = None + wicenv_cache = {} def setUpLocal(self): """This code is executed before each test method.""" - self.write_config('IMAGE_FSTYPES += " hddimg"\n' - 'MACHINE_FEATURES_append = " efi"\n' - 'WKS_FILE = "wic-image-minimal"\n') + if not self.native_sysroot: + Wic.native_sysroot = get_bb_var('STAGING_DIR_NATIVE', 'wic-tools') # Do this here instead of in setUpClass as the base setUp does some # clean up which can result in the native tools built earlier in # setUpClass being unavailable. if not Wic.image_is_ready: - bitbake('syslinux syslinux-native parted-native gptfdisk-native ' - 'dosfstools-native mtools-native bmap-tools-native') + if get_bb_var('USE_NLS') == 'yes': + bitbake('wic-tools') + else: + self.skipTest('wic-tools cannot be built due its (intltool|gettext)-native dependency and NLS disable') + bitbake('core-image-minimal') Wic.image_is_ready = True rmtree(self.resultdir, ignore_errors=True) + def tearDownLocal(self): + """Remove resultdir as it may contain images.""" + rmtree(self.resultdir, ignore_errors=True) + + @testcase(1552) + def test_version(self): + """Test wic --version""" + self.assertEqual(0, runCmd('wic --version').status) + @testcase(1208) def test_help(self): - """Test wic --help""" + """Test wic --help and wic -h""" self.assertEqual(0, runCmd('wic --help').status) + self.assertEqual(0, runCmd('wic -h').status) @testcase(1209) def test_createhelp(self): @@ -71,44 +113,15 @@ class Wic(oeSelfTest): """Test wic list --help""" self.assertEqual(0, runCmd('wic list --help').status) - @testcase(1211) - def test_build_image_name(self): - """Test wic create directdisk --image-name core-image-minimal""" - self.assertEqual(0, runCmd("wic create directdisk " - "--image-name core-image-minimal").status) - self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - - @testcase(1212) - def test_build_artifacts(self): - """Test wic create directdisk providing all artifacts.""" - bbvars = dict((var.lower(), get_bb_var(var, 'core-image-minimal')) \ - for var in ('STAGING_DATADIR', 'DEPLOY_DIR_IMAGE', - 'STAGING_DIR_NATIVE', 'IMAGE_ROOTFS')) - status = runCmd("wic create directdisk " - "-b %(staging_datadir)s " - "-k %(deploy_dir_image)s " - "-n %(staging_dir_native)s " - "-r %(image_rootfs)s" % bbvars).status - self.assertEqual(0, status) - self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - - @testcase(1157) - def test_gpt_image(self): - """Test creation of core-image-minimal with gpt table and UUID boot""" - self.assertEqual(0, runCmd("wic create directdisk-gpt " - "--image-name core-image-minimal").status) - self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) - - @testcase(1213) - def test_unsupported_subcommand(self): - """Test unsupported subcommand""" - self.assertEqual(1, runCmd('wic unsupported', - ignore_status=True).status) + @testcase(1553) + def test_help_create(self): + """Test wic help create""" + self.assertEqual(0, runCmd('wic help create').status) - @testcase(1214) - def test_no_command(self): - """Test wic without command""" - self.assertEqual(1, runCmd('wic', ignore_status=True).status) + @testcase(1554) + def test_help_list(self): + """Test wic help list""" + self.assertEqual(0, runCmd('wic help list').status) @testcase(1215) def test_help_overview(self): @@ -125,94 +138,418 @@ class Wic(oeSelfTest): """Test wic help kickstart""" self.assertEqual(0, runCmd('wic help kickstart').status) + @testcase(1555) + def test_list_images(self): + """Test wic list images""" + self.assertEqual(0, runCmd('wic list images').status) + + @testcase(1556) + def test_list_source_plugins(self): + """Test wic list source-plugins""" + self.assertEqual(0, runCmd('wic list source-plugins').status) + + @testcase(1557) + def test_listed_images_help(self): + """Test wic listed images help""" + output = runCmd('wic list images').output + imagelist = [line.split()[0] for line in output.splitlines()] + for image in imagelist: + self.assertEqual(0, runCmd('wic list %s help' % image).status) + + @testcase(1213) + def test_unsupported_subcommand(self): + """Test unsupported subcommand""" + self.assertEqual(1, runCmd('wic unsupported', + ignore_status=True).status) + + @testcase(1214) + def test_no_command(self): + """Test wic without command""" + self.assertEqual(1, runCmd('wic', ignore_status=True).status) + + @testcase(1211) + def test_build_image_name(self): + """Test wic create wictestdisk --image-name=core-image-minimal""" + cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + @testcase(1157) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_gpt_image(self): + """Test creation of core-image-minimal with gpt table and UUID boot""" + cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) + + @testcase(1346) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_iso_image(self): + """Test creation of hybrid iso image with legacy and EFI boot""" + config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\ + 'MACHINE_FEATURES_append = " efi"\n' + self.append_config(config) + bitbake('core-image-minimal') + self.remove_config(config) + cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct"))) + self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso"))) + + @testcase(1348) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_qemux86_directdisk(self): + """Test creation of qemux-86-directdisk image""" + cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "qemux86-directdisk-*direct"))) + + @testcase(1350) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_mkefidisk(self): + """Test creation of mkefidisk image""" + cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "mkefidisk-*direct"))) + + @testcase(1385) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_bootloader_config(self): + """Test creation of directdisk-bootloader-config image""" + cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "directdisk-bootloader-config-*direct"))) + + @testcase(1560) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_systemd_bootdisk(self): + """Test creation of systemd-bootdisk image""" + config = 'MACHINE_FEATURES_append = " efi"\n' + self.append_config(config) + bitbake('core-image-minimal') + self.remove_config(config) + cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "systemd-bootdisk-*direct"))) + + @testcase(1561) + def test_sdimage_bootpart(self): + """Test creation of sdimage-bootpart image""" + cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir + kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal') + self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype) + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct"))) + + @testcase(1562) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_default_output_dir(self): + """Test default output location""" + for fname in glob("directdisk-*.direct"): + os.remove(fname) + cmd = "wic create directdisk -e core-image-minimal" + self.assertEqual(0, runCmd(cmd).status) + self.assertEqual(1, len(glob("directdisk-*.direct"))) + + @testcase(1212) + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_build_artifacts(self): + """Test wic create directdisk providing all artifacts.""" + bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'], + 'wic-tools') + bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'], + 'core-image-minimal')) + bbvars = {key.lower(): value for key, value in bb_vars.items()} + bbvars['resultdir'] = self.resultdir + status = runCmd("wic create directdisk " + "-b %(staging_datadir)s " + "-k %(deploy_dir_image)s " + "-n %(recipe_sysroot_native)s " + "-r %(image_rootfs)s " + "-o %(resultdir)s" % bbvars).status + self.assertEqual(0, status) + self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct"))) + @testcase(1264) def test_compress_gzip(self): """Test compressing an image with gzip""" - self.assertEqual(0, runCmd("wic create directdisk " + self.assertEqual(0, runCmd("wic create wictestdisk " "--image-name core-image-minimal " - "-c gzip").status) - self.assertEqual(1, len(glob(self.resultdir + \ - "directdisk-*.direct.gz"))) + "-c gzip -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.gz"))) @testcase(1265) def test_compress_bzip2(self): """Test compressing an image with bzip2""" - self.assertEqual(0, runCmd("wic create directdisk " - "--image-name core-image-minimal " - "-c bzip2").status) - self.assertEqual(1, len(glob(self.resultdir + \ - "directdisk-*.direct.bz2"))) + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "-c bzip2 -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.bz2"))) @testcase(1266) def test_compress_xz(self): """Test compressing an image with xz""" - self.assertEqual(0, runCmd("wic create directdisk " - "--image-name core-image-minimal " - "-c xz").status) - self.assertEqual(1, len(glob(self.resultdir + \ - "directdisk-*.direct.xz"))) + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "--compress-with=xz -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.xz"))) @testcase(1267) def test_wrong_compressor(self): """Test how wic breaks if wrong compressor is provided""" - self.assertEqual(2, runCmd("wic create directdisk " - "--image-name core-image-minimal " - "-c wrong", ignore_status=True).status) + self.assertEqual(2, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "-c wrong -o %s" % self.resultdir, + ignore_status=True).status) + + @testcase(1558) + def test_debug_short(self): + """Test -D option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "-D -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + def test_debug_long(self): + """Test --debug option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "--debug -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + @testcase(1563) + def test_skip_build_check_short(self): + """Test -s option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "-s -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + def test_skip_build_check_long(self): + """Test --skip-build-check option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "--skip-build-check " + "--outdir %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + @testcase(1564) + def test_build_rootfs_short(self): + """Test -f option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "-f -o %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) + + def test_build_rootfs_long(self): + """Test --build-rootfs option""" + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=core-image-minimal " + "--build-rootfs " + "--outdir %s" % self.resultdir).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct"))) @testcase(1268) + @only_for_arch(['i586', 'i686', 'x86_64']) def test_rootfs_indirect_recipes(self): """Test usage of rootfs plugin with rootfs recipes""" - wks = "directdisk-multi-rootfs" - self.assertEqual(0, runCmd("wic create %s " - "--image-name core-image-minimal " - "--rootfs rootfs1=core-image-minimal " - "--rootfs rootfs2=core-image-minimal" \ - % wks).status) - self.assertEqual(1, len(glob(self.resultdir + "%s*.direct" % wks))) + status = runCmd("wic create directdisk-multi-rootfs " + "--image-name=core-image-minimal " + "--rootfs rootfs1=core-image-minimal " + "--rootfs rootfs2=core-image-minimal " + "--outdir %s" % self.resultdir).status + self.assertEqual(0, status) + self.assertEqual(1, len(glob(self.resultdir + "directdisk-multi-rootfs*.direct"))) @testcase(1269) + @only_for_arch(['i586', 'i686', 'x86_64']) def test_rootfs_artifacts(self): """Test usage of rootfs plugin with rootfs paths""" - bbvars = dict((var.lower(), get_bb_var(var, 'core-image-minimal')) \ - for var in ('STAGING_DATADIR', 'DEPLOY_DIR_IMAGE', - 'STAGING_DIR_NATIVE', 'IMAGE_ROOTFS')) + bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'], + 'wic-tools') + bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'], + 'core-image-minimal')) + bbvars = {key.lower(): value for key, value in bb_vars.items()} bbvars['wks'] = "directdisk-multi-rootfs" + bbvars['resultdir'] = self.resultdir status = runCmd("wic create %(wks)s " - "-b %(staging_datadir)s " - "-k %(deploy_dir_image)s " - "-n %(staging_dir_native)s " + "--bootimg-dir=%(staging_datadir)s " + "--kernel-dir=%(deploy_dir_image)s " + "--native-sysroot=%(recipe_sysroot_native)s " "--rootfs-dir rootfs1=%(image_rootfs)s " - "--rootfs-dir rootfs2=%(image_rootfs)s" \ - % bbvars).status + "--rootfs-dir rootfs2=%(image_rootfs)s " + "--outdir %(resultdir)s" % bbvars).status + self.assertEqual(0, status) + self.assertEqual(1, len(glob(self.resultdir + "%(wks)s-*.direct" % bbvars))) + + def test_exclude_path(self): + """Test --exclude-path wks option.""" + + oldpath = os.environ['PATH'] + os.environ['PATH'] = get_bb_var("PATH", "wic-tools") + + try: + wks_file = 'temp.wks' + with open(wks_file, 'w') as wks: + rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal') + wks.write(""" +part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr +part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr +part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr""" + % (rootfs_dir, rootfs_dir)) + self.assertEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir)).status) + + os.remove(wks_file) + wicout = glob(self.resultdir + "%s-*direct" % 'temp') + self.assertEqual(1, len(wicout)) + + wicimg = wicout[0] + + # verify partition size with wic + res = runCmd("parted -m %s unit b p 2>/dev/null" % wicimg) + self.assertEqual(0, res.status) + + # parse parted output which looks like this: + # BYT;\n + # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n + # 1:0.00MiB:200MiB:200MiB:ext4::;\n + partlns = res.output.splitlines()[2:] + + self.assertEqual(3, len(partlns)) + + for part in [1, 2, 3]: + part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) + partln = partlns[part-1].split(":") + self.assertEqual(7, len(partln)) + start = int(partln[1].rstrip("B")) / 512 + length = int(partln[3].rstrip("B")) / 512 + self.assertEqual(0, runCmd("dd if=%s of=%s skip=%d count=%d" % + (wicimg, part_file, start, length)).status) + + def extract_files(debugfs_output): + """ + extract file names from the output of debugfs -R 'ls -p', + which looks like this: + + /2/040755/0/0/.//\n + /2/040755/0/0/..//\n + /11/040700/0/0/lost+found^M//\n + /12/040755/1002/1002/run//\n + /13/040755/1002/1002/sys//\n + /14/040755/1002/1002/bin//\n + /80/040755/1002/1002/var//\n + /92/040755/1002/1002/tmp//\n + """ + # NOTE the occasional ^M in file names + return [line.split('/')[5].strip() for line in \ + debugfs_output.strip().split('/\n')] + + # Test partition 1, should contain the normal root directories, except + # /usr. + res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ + os.path.join(self.resultdir, "selftest_img.part1")) + self.assertEqual(0, res.status) + files = extract_files(res.output) + self.assertIn("etc", files) + self.assertNotIn("usr", files) + + # Partition 2, should contain common directories for /usr, not root + # directories. + res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ + os.path.join(self.resultdir, "selftest_img.part2")) + self.assertEqual(0, res.status) + files = extract_files(res.output) + self.assertNotIn("etc", files) + self.assertNotIn("usr", files) + self.assertIn("share", files) + + # Partition 3, should contain the same as partition 2, including the bin + # directory, but not the files inside it. + res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \ + os.path.join(self.resultdir, "selftest_img.part3")) + self.assertEqual(0, res.status) + files = extract_files(res.output) + self.assertNotIn("etc", files) + self.assertNotIn("usr", files) + self.assertIn("share", files) + self.assertIn("bin", files) + res = runCmd("debugfs -R 'ls -p bin' %s 2>/dev/null" % \ + os.path.join(self.resultdir, "selftest_img.part3")) + self.assertEqual(0, res.status) + files = extract_files(res.output) + self.assertIn(".", files) + self.assertIn("..", files) + self.assertEqual(2, len(files)) + + for part in [1, 2, 3]: + part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part) + os.remove(part_file) + + finally: + os.environ['PATH'] = oldpath + + def test_exclude_path_errors(self): + """Test --exclude-path wks option error handling.""" + wks_file = 'temp.wks' + + # Absolute argument. + with open(wks_file, 'w') as wks: + wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr") + self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir), ignore_status=True).status) + os.remove(wks_file) + + # Argument pointing to parent directory. + with open(wks_file, 'w') as wks: + wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..") + self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wks_file, self.resultdir), ignore_status=True).status) + os.remove(wks_file) + + @testcase(1496) + def test_bmap_short(self): + """Test generation of .bmap file -m option""" + cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir + status = runCmd(cmd).status self.assertEqual(0, status) - self.assertEqual(1, len(glob(self.resultdir + \ - "%(wks)s-*.direct" % bbvars))) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct"))) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap"))) - @testcase(1346) - def test_iso_image(self): - """Test creation of hybrid iso image with legacy and EFI boot""" - self.assertEqual(0, runCmd("wic create mkhybridiso " - "--image-name core-image-minimal").status) - self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct"))) - self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso"))) + def test_bmap_long(self): + """Test generation of .bmap file --bmap option""" + cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir + status = runCmd(cmd).status + self.assertEqual(0, status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct"))) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap"))) + + def _get_image_env_path(self, image): + """Generate and obtain the path to <image>.env""" + if image not in self.wicenv_cache: + self.assertEqual(0, bitbake('%s -c do_rootfs_wicenv' % image).status) + bb_vars = get_bb_vars(['STAGING_DIR', 'MACHINE'], image) + stdir = bb_vars['STAGING_DIR'] + machine = bb_vars['MACHINE'] + self.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata') + return self.wicenv_cache[image] @testcase(1347) def test_image_env(self): """Test generation of <image>.env files.""" image = 'core-image-minimal' - self.assertEqual(0, bitbake('%s -c do_rootfs_wicenv' % image).status) - stdir = get_bb_var('STAGING_DIR_TARGET', image) - imgdatadir = os.path.join(stdir, 'imgdata') + imgdatadir = self._get_image_env_path(image) - basename = get_bb_var('IMAGE_BASENAME', image) + bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image) + basename = bb_vars['IMAGE_BASENAME'] self.assertEqual(basename, image) path = os.path.join(imgdatadir, basename) + '.env' self.assertTrue(os.path.isfile(path)) - wicvars = set(get_bb_var('WICVARS', image).split()) + wicvars = set(bb_vars['WICVARS'].split()) # filter out optional variables - wicvars = wicvars.difference(('HDDDIR', 'IMAGE_BOOT_FILES', - 'INITRD', 'ISODIR')) + wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES', + 'INITRD', 'INITRD_LIVE', 'ISODIR')) with open(path) as envfile: content = dict(line.split("=", 1) for line in envfile) # test if variables used by wic present in the .env file @@ -220,13 +557,41 @@ class Wic(oeSelfTest): self.assertTrue(var in content, "%s is not in .env file" % var) self.assertTrue(content[var]) + @testcase(1559) + def test_image_vars_dir_short(self): + """Test image vars directory selection -v option""" + image = 'core-image-minimal' + imgenvdir = self._get_image_env_path(image) + + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=%s -v %s -o %s" + % (image, imgenvdir, self.resultdir)).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct"))) + + def test_image_vars_dir_long(self): + """Test image vars directory selection --vars option""" + image = 'core-image-minimal' + imgenvdir = self._get_image_env_path(image) + self.assertEqual(0, runCmd("wic create wictestdisk " + "--image-name=%s " + "--vars %s " + "--outdir %s" + % (image, imgenvdir, self.resultdir)).status) + self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct"))) + @testcase(1351) + @only_for_arch(['i586', 'i686', 'x86_64']) def test_wic_image_type(self): """Test building wic images by bitbake""" + config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ + 'MACHINE_FEATURES_append = " efi"\n' + self.append_config(config) self.assertEqual(0, bitbake('wic-image-minimal').status) + self.remove_config(config) - deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') - machine = get_bb_var('MACHINE') + bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE']) + deploy_dir = bb_vars['DEPLOY_DIR_IMAGE'] + machine = bb_vars['MACHINE'] prefix = os.path.join(deploy_dir, 'wic-image-minimal-%s.' % machine) # check if we have result image and manifests symlinks # pointing to existing files @@ -235,68 +600,193 @@ class Wic(oeSelfTest): self.assertTrue(os.path.islink(path)) self.assertTrue(os.path.isfile(os.path.realpath(path))) - @testcase(1348) - def test_qemux86_directdisk(self): - """Test creation of qemux-86-directdisk image""" - image = "qemux86-directdisk" - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - - @testcase(1349) - def test_mkgummidisk(self): - """Test creation of mkgummidisk image""" - image = "mkgummidisk" - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - - @testcase(1350) - def test_mkefidisk(self): - """Test creation of mkefidisk image""" - image = "mkefidisk" - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - - @testcase(1385) - def test_directdisk_bootloader_config(self): - """Test creation of directdisk-bootloader-config image""" - image = "directdisk-bootloader-config" - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - @testcase(1422) + @only_for_arch(['i586', 'i686', 'x86_64']) def test_qemu(self): """Test wic-image-minimal under qemu""" + config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\ + 'MACHINE_FEATURES_append = " efi"\n' + self.append_config(config) self.assertEqual(0, bitbake('wic-image-minimal').status) + self.remove_config(config) with runqemu('wic-image-minimal', ssh=False) as qemu: - command = "mount |grep '^/dev/' | cut -f1,3 -d ' '" - status, output = qemu.run_serial(command) - self.assertEqual(1, status, 'Failed to run command "%s": %s' % (command, output)) - self.assertEqual(output, '/dev/root /\r\n/dev/vda3 /mnt') - - def test_bmap(self): - """Test generation of .bmap file""" - image = "directdisk" - status = runCmd("wic create %s -e core-image-minimal --bmap" % image).status - self.assertEqual(0, status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct.bmap" % image))) - - def test_systemd_bootdisk(self): - """Test creation of systemd-bootdisk image""" - image = "systemd-bootdisk" - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) - - def test_sdimage_bootpart(self): - """Test creation of sdimage-bootpart image""" - image = "sdimage-bootpart" - self.write_config('IMAGE_BOOT_FILES = "bzImage"\n') - self.assertEqual(0, runCmd("wic create %s -e core-image-minimal" \ - % image).status) - self.assertEqual(1, len(glob(self.resultdir + "%s-*direct" % image))) + cmd = "mount |grep '^/dev/' | cut -f1,3 -d ' '" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '/dev/root /\r\n/dev/sda3 /mnt') + + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_qemu_efi(self): + """Test core-image-minimal efi image under qemu""" + config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n' + self.append_config(config) + self.assertEqual(0, bitbake('core-image-minimal ovmf').status) + self.remove_config(config) + + with runqemu('core-image-minimal', ssh=False, + runqemuparams='ovmf', image_fstype='wic') as qemu: + cmd = "grep sda. /proc/partitions |wc -l" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '3') + + @staticmethod + def _make_fixed_size_wks(size): + """ + Create a wks of an image with a single partition. Size of the partition is set + using --fixed-size flag. Returns a tuple: (path to wks file, wks image name) + """ + with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf: + wkspath = tempf.name + tempf.write("part " \ + "--source rootfs --ondisk hda --align 4 --fixed-size %d " + "--fstype=ext4\n" % size) + wksname = os.path.splitext(os.path.basename(wkspath))[0] + + return wkspath, wksname + + def test_fixed_size(self): + """ + Test creation of a simple image with partition size controlled through + --fixed-size flag + """ + wkspath, wksname = Wic._make_fixed_size_wks(200) + + self.assertEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wkspath, self.resultdir)).status) + os.remove(wkspath) + wicout = glob(self.resultdir + "%s-*direct" % wksname) + self.assertEqual(1, len(wicout)) + + wicimg = wicout[0] + + # verify partition size with wic + res = runCmd("parted -m %s unit mib p 2>/dev/null" % wicimg, + ignore_status=True, + native_sysroot=self.native_sysroot) + self.assertEqual(0, res.status) + + # parse parted output which looks like this: + # BYT;\n + # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n + # 1:0.00MiB:200MiB:200MiB:ext4::;\n + partlns = res.output.splitlines()[2:] + + self.assertEqual(1, len(partlns)) + self.assertEqual("1:0.00MiB:200MiB:200MiB:ext4::;", partlns[0]) + + def test_fixed_size_error(self): + """ + Test creation of a simple image with partition size controlled through + --fixed-size flag. The size of partition is intentionally set to 1MiB + in order to trigger an error in wic. + """ + wkspath, wksname = Wic._make_fixed_size_wks(1) + + self.assertEqual(1, runCmd("wic create %s -e core-image-minimal -o %s" \ + % (wkspath, self.resultdir), ignore_status=True).status) + os.remove(wkspath) + wicout = glob(self.resultdir + "%s-*direct" % wksname) + self.assertEqual(0, len(wicout)) + + @only_for_arch(['i586', 'i686', 'x86_64']) + def test_rawcopy_plugin_qemu(self): + """Test rawcopy plugin in qemu""" + # build ext4 and wic images + for fstype in ("ext4", "wic"): + config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype + self.append_config(config) + self.assertEqual(0, bitbake('core-image-minimal').status) + self.remove_config(config) + + with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu: + cmd = "grep sda. /proc/partitions |wc -l" + status, output = qemu.run_serial(cmd) + self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) + self.assertEqual(output, '2') + + def test_rawcopy_plugin(self): + """Test rawcopy plugin""" + img = 'core-image-minimal' + machine = get_bb_var('MACHINE', img) + with NamedTemporaryFile("w", suffix=".wks") as wks: + wks.writelines(['part /boot --active --source bootimg-pcbios\n', + 'part / --source rawcopy --sourceparams="file=%s-%s.ext4" --use-uuid\n'\ + % (img, machine), + 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n']) + wks.flush() + cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) + self.assertEqual(0, runCmd(cmd).status) + wksname = os.path.splitext(os.path.basename(wks.name))[0] + out = glob(self.resultdir + "%s-*direct" % wksname) + self.assertEqual(1, len(out)) + + def test_fs_types(self): + """Test filesystem types for empty and not empty partitions""" + img = 'core-image-minimal' + with NamedTemporaryFile("w", suffix=".wks") as wks: + wks.writelines(['part ext2 --fstype ext2 --source rootfs\n', + 'part btrfs --fstype btrfs --source rootfs --size 40M\n', + 'part squash --fstype squashfs --source rootfs\n', + 'part swap --fstype swap --size 1M\n', + 'part emptyvfat --fstype vfat --size 1M\n', + 'part emptymsdos --fstype msdos --size 1M\n', + 'part emptyext2 --fstype ext2 --size 1M\n', + 'part emptybtrfs --fstype btrfs --size 100M\n']) + wks.flush() + cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir) + self.assertEqual(0, runCmd(cmd).status) + wksname = os.path.splitext(os.path.basename(wks.name))[0] + out = glob(self.resultdir + "%s-*direct" % wksname) + self.assertEqual(1, len(out)) + + def test_kickstart_parser(self): + """Test wks parser options""" + with NamedTemporaryFile("w", suffix=".wks") as wks: + wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\ + '--overhead-factor 1.2 --size 100k\n']) + wks.flush() + cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir) + self.assertEqual(0, runCmd(cmd).status) + wksname = os.path.splitext(os.path.basename(wks.name))[0] + out = glob(self.resultdir + "%s-*direct" % wksname) + self.assertEqual(1, len(out)) + + def test_image_bootpart_globbed(self): + """Test globbed sources with image-bootpart plugin""" + img = "core-image-minimal" + cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir) + config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img) + self.append_config(config) + self.assertEqual(0, runCmd(cmd).status) + self.remove_config(config) + self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct"))) + + def test_sparse_copy(self): + """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs""" + libpath = os.path.join(get_bb_var('COREBASE'), 'scripts', 'lib', 'wic') + sys.path.insert(0, libpath) + from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp + with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse: + src_name = sparse.name + src_size = 1024 * 10 + sparse.truncate(src_size) + # write one byte to the file + with open(src_name, 'r+b') as sfile: + sfile.seek(1024 * 4) + sfile.write(b'\x00') + dest = sparse.name + '.out' + # copy src file to dest using different filemap APIs + for api in (FilemapFiemap, FilemapSeek, None): + if os.path.exists(dest): + os.unlink(dest) + try: + sparse_copy(sparse.name, dest, api=api) + except ErrorNotSupp: + continue # skip unsupported API + dest_stat = os.stat(dest) + self.assertEqual(dest_stat.st_size, src_size) + # 8 blocks is 4K (physical sector size) + self.assertEqual(dest_stat.st_blocks, 8) + os.unlink(dest) |