summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/selftest
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa/selftest')
-rw-r--r--meta/lib/oeqa/selftest/__init__.py2
-rw-r--r--meta/lib/oeqa/selftest/_sstatetests_noauto.py95
-rw-r--r--meta/lib/oeqa/selftest/_toaster.py445
-rw-r--r--meta/lib/oeqa/selftest/base.py131
-rw-r--r--meta/lib/oeqa/selftest/bblayers.py43
-rw-r--r--meta/lib/oeqa/selftest/bbtests.py178
-rw-r--r--meta/lib/oeqa/selftest/buildhistory.py45
-rw-r--r--meta/lib/oeqa/selftest/buildoptions.py120
-rw-r--r--meta/lib/oeqa/selftest/oescripts.py54
-rw-r--r--meta/lib/oeqa/selftest/prservice.py121
-rw-r--r--meta/lib/oeqa/selftest/sstate.py53
-rw-r--r--meta/lib/oeqa/selftest/sstatetests.py204
12 files changed, 1491 insertions, 0 deletions
diff --git a/meta/lib/oeqa/selftest/__init__.py b/meta/lib/oeqa/selftest/__init__.py
new file mode 100644
index 0000000000..3ad9513f40
--- /dev/null
+++ b/meta/lib/oeqa/selftest/__init__.py
@@ -0,0 +1,2 @@
1from pkgutil import extend_path
2__path__ = extend_path(__path__, __name__)
diff --git a/meta/lib/oeqa/selftest/_sstatetests_noauto.py b/meta/lib/oeqa/selftest/_sstatetests_noauto.py
new file mode 100644
index 0000000000..fc9ae7efb9
--- /dev/null
+++ b/meta/lib/oeqa/selftest/_sstatetests_noauto.py
@@ -0,0 +1,95 @@
1import datetime
2import unittest
3import os
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer
10from oeqa.selftest.sstate import SStateBase
11
12
13class RebuildFromSState(SStateBase):
14
15 @classmethod
16 def setUpClass(self):
17 self.builddir = os.path.join(os.environ.get('BUILDDIR'))
18
19 def get_dep_targets(self, primary_targets):
20 found_targets = []
21 bitbake("-g " + ' '.join(map(str, primary_targets)))
22 with open(os.path.join(self.builddir, 'pn-buildlist'), 'r') as pnfile:
23 found_targets = pnfile.read().splitlines()
24 return found_targets
25
26 def configure_builddir(self, builddir):
27 os.mkdir(builddir)
28 self.track_for_cleanup(builddir)
29 os.mkdir(os.path.join(builddir, 'conf'))
30 shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/local.conf'), os.path.join(builddir, 'conf/local.conf'))
31 config = {}
32 config['default_sstate_dir'] = "SSTATE_DIR ?= \"${TOPDIR}/sstate-cache\""
33 config['null_sstate_mirrors'] = "SSTATE_MIRRORS = \"\""
34 config['default_tmp_dir'] = "TMPDIR = \"${TOPDIR}/tmp\""
35 for key in config:
36 ftools.append_file(os.path.join(builddir, 'conf/selftest.inc'), config[key])
37 shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/bblayers.conf'), os.path.join(builddir, 'conf/bblayers.conf'))
38 try:
39 shutil.copyfile(os.path.join(os.environ.get('BUILDDIR'), 'conf/auto.conf'), os.path.join(builddir, 'conf/auto.conf'))
40 except:
41 pass
42
43 def hardlink_tree(self, src, dst):
44 os.mkdir(dst)
45 self.track_for_cleanup(dst)
46 for root, dirs, files in os.walk(src):
47 if root == src:
48 continue
49 os.mkdir(os.path.join(dst, root.split(src)[1][1:]))
50 for sstate_file in files:
51 os.link(os.path.join(root, sstate_file), os.path.join(dst, root.split(src)[1][1:], sstate_file))
52
53 def run_test_sstate_rebuild(self, primary_targets, relocate=False, rebuild_dependencies=False):
54 buildA = os.path.join(self.builddir, 'buildA')
55 if relocate:
56 buildB = os.path.join(self.builddir, 'buildB')
57 else:
58 buildB = buildA
59
60 if rebuild_dependencies:
61 rebuild_targets = self.get_dep_targets(primary_targets)
62 else:
63 rebuild_targets = primary_targets
64
65 self.configure_builddir(buildA)
66 runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildA)) + 'bitbake ' + ' '.join(map(str, primary_targets)), shell=True, executable='/bin/bash')
67 self.hardlink_tree(os.path.join(buildA, 'sstate-cache'), os.path.join(self.builddir, 'sstate-cache-buildA'))
68 shutil.rmtree(buildA)
69
70 failed_rebuild = []
71 failed_cleansstate = []
72 for target in rebuild_targets:
73 self.configure_builddir(buildB)
74 self.hardlink_tree(os.path.join(self.builddir, 'sstate-cache-buildA'), os.path.join(buildB, 'sstate-cache'))
75
76 result_cleansstate = runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake -ccleansstate ' + target, ignore_status=True, shell=True, executable='/bin/bash')
77 if not result_cleansstate.status == 0:
78 failed_cleansstate.append(target)
79 shutil.rmtree(buildB)
80 continue
81
82 result_build = runCmd((". %s/oe-init-build-env %s && " % (get_bb_var('COREBASE'), buildB)) + 'bitbake ' + target, ignore_status=True, shell=True, executable='/bin/bash')
83 if not result_build.status == 0:
84 failed_rebuild.append(target)
85
86 shutil.rmtree(buildB)
87
88 self.assertFalse(failed_rebuild, msg="The following recipes have failed to rebuild: %s" % ' '.join(map(str, failed_rebuild)))
89 self.assertFalse(failed_cleansstate, msg="The following recipes have failed cleansstate(all others have passed both cleansstate and rebuild from sstate tests): %s" % ' '.join(map(str, failed_cleansstate)))
90
91 def test_sstate_relocation(self):
92 self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=True, rebuild_dependencies=True)
93
94 def test_sstate_rebuild(self):
95 self.run_test_sstate_rebuild(['core-image-sato-sdk'], relocate=False, rebuild_dependencies=True)
diff --git a/meta/lib/oeqa/selftest/_toaster.py b/meta/lib/oeqa/selftest/_toaster.py
new file mode 100644
index 0000000000..1cf28a0144
--- /dev/null
+++ b/meta/lib/oeqa/selftest/_toaster.py
@@ -0,0 +1,445 @@
1import unittest
2import os
3import sys
4import shlex, subprocess
5import urllib, commands, time, getpass, re, json, shlex
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd
10
11sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../', 'bitbake/lib/toaster')))
12os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toastermain.settings")
13
14import toastermain.settings
15from django.db.models import Q
16from orm.models import *
17from oeqa.utils.decorators import testcase
18
19class ToasterSetup(oeSelfTest):
20
21 def recipe_parse(self, file_path, var):
22 for line in open(file_path,'r'):
23 if line.find(var) > -1:
24 val = line.split(" = ")[1].replace("\"", "").strip()
25 return val
26
27 def fix_file_path(self, file_path):
28 if ":" in file_path:
29 file_path=file_path.split(":")[2]
30 return file_path
31
32class Toaster_DB_Tests(ToasterSetup):
33
34 # Check if build name is unique - tc_id=795
35 @testcase(795)
36 def test_Build_Unique_Name(self):
37 all_builds = Build.objects.all().count()
38 distinct_builds = Build.objects.values('id').distinct().count()
39 self.assertEqual(distinct_builds, all_builds, msg = 'Build name is not unique')
40
41 # Check if build coocker log path is unique - tc_id=819
42 @testcase(819)
43 def test_Build_Unique_Cooker_Log_Path(self):
44 distinct_path = Build.objects.values('cooker_log_path').distinct().count()
45 total_builds = Build.objects.values('id').count()
46 self.assertEqual(distinct_path, total_builds, msg = 'Build coocker log path is not unique')
47
48 # Check if the number of errors matches the number of orm_logmessage.level entries with value 2 - tc_id=820
49 @testcase(820)
50 def test_Build_Errors_No(self):
51 builds = Build.objects.values('id', 'errors_no')
52 cnt_err = []
53 for build in builds:
54 log_mess_err_no = LogMessage.objects.filter(build = build['id'], level = 2).count()
55 if (build['errors_no'] != log_mess_err_no):
56 cnt_err.append(build['id'])
57 self.assertEqual(len(cnt_err), 0, msg = 'Errors for build id: %s' % cnt_err)
58
59 # Check if the number of warnings matches the number of orm_logmessage.level entries with value 1 - tc=821
60 @testcase(821)
61 def test_Build_Warnings_No(self):
62 builds = Build.objects.values('id', 'warnings_no')
63 cnt_err = []
64 for build in builds:
65 log_mess_warn_no = LogMessage.objects.filter(build = build['id'], level = 1).count()
66 if (build['warnings_no'] != log_mess_warn_no):
67 cnt_err.append(build['id'])
68 self.assertEqual(len(cnt_err), 0, msg = 'Errors for build id: %s' % cnt_err)
69
70 # Check if the build succeeded then the errors_no is 0 - tc_id=822
71 @testcase(822)
72 def test_Build_Suceeded_Errors_No(self):
73 builds = Build.objects.filter(outcome = 0).values('id', 'errors_no')
74 cnt_err = []
75 for build in builds:
76 if (build['errors_no'] != 0):
77 cnt_err.append(build['id'])
78 self.assertEqual(len(cnt_err), 0, msg = 'Errors for build id: %s' % cnt_err)
79
80 # Check if task order is unique for one build - tc=824
81 @testcase(824)
82 def test_Task_Unique_Order(self):
83 builds = Build.objects.values('id')
84 cnt_err = []
85 for build in builds:
86 total_task_order = Task.objects.filter(build = build['id']).values('order').count()
87 distinct_task_order = Task.objects.filter(build = build['id']).values('order').distinct().count()
88 if (total_task_order != distinct_task_order):
89 cnt_err.append(build['id'])
90 self.assertEqual(len(cnt_err), 0, msg = 'Errors for build id: %s' % cnt_err)
91
92 # Check task order sequence for one build - tc=825
93 @testcase(825)
94 def test_Task_Order_Sequence(self):
95 builds = builds = Build.objects.values('id')
96 cnt_err = []
97 for build in builds:
98 tasks = Task.objects.filter(Q(build = build['id']), ~Q(order = None), ~Q(task_name__contains = '_setscene')).values('id', 'order').order_by("order")
99 cnt_tasks = 0
100 for task in tasks:
101 cnt_tasks += 1
102 if (task['order'] != cnt_tasks):
103 cnt_err.append(task['id'])
104 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
105
106 # Check if disk_io matches the difference between EndTimeIO and StartTimeIO in build stats - tc=828
107 ### this needs to be updated ###
108 #def test_Task_Disk_IO_TC828(self):
109
110 # Check if outcome = 2 (SSTATE) then sstate_result must be 3 (RESTORED) - tc=832
111 @testcase(832)
112 def test_Task_If_Outcome_2_Sstate_Result_Must_Be_3(self):
113 tasks = Task.objects.filter(outcome = 2).values('id', 'sstate_result')
114 cnt_err = []
115 for task in tasks:
116 if (row['sstate_result'] != 3):
117 cnt_err.append(task['id'])
118 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
119
120 # Check if outcome = 1 (COVERED) or 3 (EXISTING) then sstate_result must be 0 (SSTATE_NA) - tc=833
121 @testcase(833)
122 def test_Task_If_Outcome_1_3_Sstate_Result_Must_Be_0(self):
123 tasks = Task.objects.filter(outcome__in = (1, 3)).values('id', 'sstate_result')
124 cnt_err = []
125 for task in tasks:
126 if (task['sstate_result'] != 0):
127 cnt_err.append(task['id'])
128 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
129
130 # Check if outcome is 0 (SUCCESS) or 4 (FAILED) then sstate_result must be 0 (NA), 1 (MISS) or 2 (FAILED) - tc=834
131 @testcase(834)
132 def test_Task_If_Outcome_0_4_Sstate_Result_Must_Be_0_1_2(self):
133 tasks = Task.objects.filter(outcome__in = (0, 4)).values('id', 'sstate_result')
134 cnt_err = []
135 for task in tasks:
136 if (task['sstate_result'] not in [0, 1, 2]):
137 cnt_err.append(task['id'])
138 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
139
140 # Check if task_executed = TRUE (1), script_type must be 0 (CODING_NA), 2 (CODING_PYTHON), 3 (CODING_SHELL) - tc=891
141 @testcase(891)
142 def test_Task_If_Task_Executed_True_Script_Type_0_2_3(self):
143 tasks = Task.objects.filter(task_executed = 1).values('id', 'script_type')
144 cnt_err = []
145 for task in tasks:
146 if (task['script_type'] not in [0, 2, 3]):
147 cnt_err.append(task['id'])
148 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
149
150 # Check if task_executed = TRUE (1), outcome must be 0 (SUCCESS) or 4 (FAILED) - tc=836
151 @testcase(836)
152 def test_Task_If_Task_Executed_True_Outcome_0_4(self):
153 tasks = Task.objects.filter(task_executed = 1).values('id', 'outcome')
154 cnt_err = []
155 for task in tasks:
156 if (task['outcome'] not in [0, 4]):
157 cnt_err.append(task['id'])
158 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
159
160 # Check if task_executed = FALSE (0), script_type must be 0 - tc=890
161 @testcase(890)
162 def test_Task_If_Task_Executed_False_Script_Type_0(self):
163 tasks = Task.objects.filter(task_executed = 0).values('id', 'script_type')
164 cnt_err = []
165 for task in tasks:
166 if (task['script_type'] != 0):
167 cnt_err.append(task['id'])
168 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
169
170 # 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
171 @testcase(837)
172 def test_Task_If_Task_Executed_False_Outcome_1_2_3_5(self):
173 builds = Build.objects.filter(outcome = 0).values('id')
174 cnt_err = []
175 for build in builds:
176 tasks = Task.objects.filter(build = build['id'], task_executed = 0).values('id', 'outcome')
177 for task in tasks:
178 if (task['outcome'] not in [1, 2, 3, 5]):
179 cnt_err.append(task['id'])
180 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task id: %s' % cnt_err)
181
182 # Key verification - tc=888
183 @testcase(888)
184 def test_Target_Installed_Package(self):
185 rows = Target_Installed_Package.objects.values('id', 'target_id', 'package_id')
186 cnt_err = []
187 for row in rows:
188 target = Target.objects.filter(id = row['target_id']).values('id')
189 package = Package.objects.filter(id = row['package_id']).values('id')
190 if (not target or not package):
191 cnt_err.append(row['id'])
192 self.assertEqual(len(cnt_err), 0, msg = 'Errors for target installed package id: %s' % cnt_err)
193
194 # Key verification - tc=889
195 @testcase(889)
196 def test_Task_Dependency(self):
197 rows = Task_Dependency.objects.values('id', 'task_id', 'depends_on_id')
198 cnt_err = []
199 for row in rows:
200 task_id = Task.objects.filter(id = row['task_id']).values('id')
201 depends_on_id = Task.objects.filter(id = row['depends_on_id']).values('id')
202 if (not task_id or not depends_on_id):
203 cnt_err.append(row['id'])
204 self.assertEqual(len(cnt_err), 0, msg = 'Errors for task dependency id: %s' % cnt_err)
205
206 # 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
207 ### Need to add the tc in the test run
208 @testcase(1037)
209 def test_Target_File_Name_Populated(self):
210 builds = Build.objects.filter(outcome = 0).values('id')
211 for build in builds:
212 targets = Target.objects.filter(build_id = build['id'], is_image = 1).values('id')
213 for target in targets:
214 target_files = Target_Image_File.objects.filter(target_id = target['id']).values('id', 'file_name', 'file_size')
215 cnt_err = []
216 for file_info in target_files:
217 target_id = file_info['id']
218 target_file_name = file_info['file_name']
219 target_file_size = file_info['file_size']
220 if (not target_file_name or not target_file_size):
221 cnt_err.append(target_id)
222 else:
223 if (not os.path.exists(target_file_name)):
224 cnt_err.append(target_id)
225 else:
226 if (os.path.getsize(target_file_name) != target_file_size):
227 cnt_err.append(target_id)
228 self.assertEqual(len(cnt_err), 0, msg = 'Errors for target image file id: %s' % cnt_err)
229
230 # Key verification - tc=884
231 @testcase(884)
232 def test_Package_Dependency(self):
233 cnt_err = []
234 deps = Package_Dependency.objects.values('id', 'package_id', 'depends_on_id')
235 for dep in deps:
236 if (dep['package_id'] == dep['depends_on_id']):
237 cnt_err.append(dep['id'])
238 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package dependency id: %s' % cnt_err)
239
240 # Check if recipe name does not start with a number (0-9) - tc=838
241 @testcase(838)
242 def test_Recipe_Name(self):
243 recipes = Recipe.objects.values('id', 'name')
244 cnt_err = []
245 for recipe in recipes:
246 if (recipe['name'][0].isdigit() is True):
247 cnt_err.append(recipe['id'])
248 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe id: %s' % cnt_err)
249
250 # Check if recipe section matches the content of the SECTION variable (if set) in file_path - tc=839
251 @testcase(839)
252 def test_Recipe_DB_Section_Match_Recipe_File_Section(self):
253 recipes = Recipe.objects.values('id', 'section', 'file_path')
254 cnt_err = []
255 for recipe in recipes:
256 file_path = self.fix_file_path(recipe['file_path'])
257 file_exists = os.path.isfile(file_path)
258 if (not file_path or (file_exists is False)):
259 cnt_err.append(recipe['id'])
260 else:
261 file_section = self.recipe_parse(file_path, "SECTION = ")
262 db_section = recipe['section']
263 if file_section:
264 if (db_section != file_section):
265 cnt_err.append(recipe['id'])
266 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe id: %s' % cnt_err)
267
268 # Check if recipe license matches the content of the LICENSE variable (if set) in file_path - tc=840
269 @testcase(840)
270 def test_Recipe_DB_License_Match_Recipe_File_License(self):
271 recipes = Recipe.objects.values('id', 'license', 'file_path')
272 cnt_err = []
273 for recipe in recipes:
274 file_path = self.fix_file_path(recipe['file_path'])
275 file_exists = os.path.isfile(file_path)
276 if (not file_path or (file_exists is False)):
277 cnt_err.append(recipe['id'])
278 else:
279 file_license = self.recipe_parse(file_path, "LICENSE = ")
280 db_license = recipe['license']
281 if file_license:
282 if (db_license != file_license):
283 cnt_err.append(recipe['id'])
284 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe id: %s' % cnt_err)
285
286 # Check if recipe homepage matches the content of the HOMEPAGE variable (if set) in file_path - tc=841
287 @testcase(841)
288 def test_Recipe_DB_Homepage_Match_Recipe_File_Homepage(self):
289 recipes = Recipe.objects.values('id', 'homepage', 'file_path')
290 cnt_err = []
291 for recipe in recipes:
292 file_path = self.fix_file_path(recipe['file_path'])
293 file_exists = os.path.isfile(file_path)
294 if (not file_path or (file_exists is False)):
295 cnt_err.append(recipe['id'])
296 else:
297 file_homepage = self.recipe_parse(file_path, "HOMEPAGE = ")
298 db_homepage = recipe['homepage']
299 if file_homepage:
300 if (db_homepage != file_homepage):
301 cnt_err.append(recipe['id'])
302 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe id: %s' % cnt_err)
303
304 # Check if recipe bugtracker matches the content of the BUGTRACKER variable (if set) in file_path - tc=842
305 @testcase(842)
306 def test_Recipe_DB_Bugtracker_Match_Recipe_File_Bugtracker(self):
307 recipes = Recipe.objects.values('id', 'bugtracker', 'file_path')
308 cnt_err = []
309 for recipe in recipes:
310 file_path = self.fix_file_path(recipe['file_path'])
311 file_exists = os.path.isfile(file_path)
312 if (not file_path or (file_exists is False)):
313 cnt_err.append(recipe['id'])
314 else:
315 file_bugtracker = self.recipe_parse(file_path, "BUGTRACKER = ")
316 db_bugtracker = recipe['bugtracker']
317 if file_bugtracker:
318 if (db_bugtracker != file_bugtracker):
319 cnt_err.append(recipe['id'])
320 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe id: %s' % cnt_err)
321
322 # Recipe key verification, recipe name does not depends on a recipe having the same name - tc=883
323 @testcase(883)
324 def test_Recipe_Dependency(self):
325 deps = Recipe_Dependency.objects.values('id', 'recipe_id', 'depends_on_id')
326 cnt_err = []
327 for dep in deps:
328 if (not dep['recipe_id'] or not dep['depends_on_id']):
329 cnt_err.append(dep['id'])
330 else:
331 name = Recipe.objects.filter(id = dep['recipe_id']).values('name')
332 dep_name = Recipe.objects.filter(id = dep['depends_on_id']).values('name')
333 if (name == dep_name):
334 cnt_err.append(dep['id'])
335 self.assertEqual(len(cnt_err), 0, msg = 'Errors for recipe dependency id: %s' % cnt_err)
336
337 # Check if package name does not start with a number (0-9) - tc=846
338 @testcase(846)
339 def test_Package_Name_For_Number(self):
340 packages = Package.objects.filter(~Q(size = -1)).values('id', 'name')
341 cnt_err = []
342 for package in packages:
343 if (package['name'][0].isdigit() is True):
344 cnt_err.append(package['id'])
345 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
346
347 # Check if package version starts with a number (0-9) - tc=847
348 @testcase(847)
349 def test_Package_Version_Starts_With_Number(self):
350 packages = Package.objects.filter(~Q(size = -1)).values('id', 'version')
351 cnt_err = []
352 for package in packages:
353 if (package['version'][0].isdigit() is False):
354 cnt_err.append(package['id'])
355 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
356
357 # Check if package revision starts with 'r' - tc=848
358 @testcase(848)
359 def test_Package_Revision_Starts_With_r(self):
360 packages = Package.objects.filter(~Q(size = -1)).values('id', 'revision')
361 cnt_err = []
362 for package in packages:
363 if (package['revision'][0].startswith("r") is False):
364 cnt_err.append(package['id'])
365 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
366
367 # Check the validity of the package build_id
368 ### TC must be added in test run
369 @testcase(1038)
370 def test_Package_Build_Id(self):
371 packages = Package.objects.filter(~Q(size = -1)).values('id', 'build_id')
372 cnt_err = []
373 for package in packages:
374 build_id = Build.objects.filter(id = package['build_id']).values('id')
375 if (not build_id):
376 cnt_err.append(package['id'])
377 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
378
379 # Check the validity of package recipe_id
380 ### TC must be added in test run
381 @testcase(1039)
382 def test_Package_Recipe_Id(self):
383 packages = Package.objects.filter(~Q(size = -1)).values('id', 'recipe_id')
384 cnt_err = []
385 for package in packages:
386 recipe_id = Recipe.objects.filter(id = package['recipe_id']).values('id')
387 if (not recipe_id):
388 cnt_err.append(package['id'])
389 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
390
391 # Check if package installed_size field is not null
392 ### TC must be aded in test run
393 @testcase(1040)
394 def test_Package_Installed_Size_Not_NULL(self):
395 packages = Package.objects.filter(installed_size__isnull = True).values('id')
396 cnt_err = []
397 for package in packages:
398 cnt_err.append(package['id'])
399 self.assertEqual(len(cnt_err), 0, msg = 'Errors for package id: %s' % cnt_err)
400
401 # Check if all layers requests return exit code is 200 - tc=843
402 @testcase(843)
403 def test_Layers_Requests_Exit_Code(self):
404 layers = Layer.objects.values('id', 'layer_index_url')
405 cnt_err = []
406 for layer in layers:
407 resp = urllib.urlopen(layer['layer_index_url'])
408 if (resp.getcode() != 200):
409 cnt_err.append(layer['id'])
410 self.assertEqual(len(cnt_err), 0, msg = 'Errors for layer id: %s' % cnt_err)
411
412 # Check if the output of bitbake-layers show_layers matches the info from database - tc=895
413 @testcase(895)
414 def test_Layers_Show_Layers(self):
415 layers = Layer.objects.values('id', 'name', 'local_path')
416 cmd = commands.getoutput('bitbake-layers show_layers')
417 cnt_err = []
418 for layer in layers:
419 if (layer['name'] or layer['local_path']) not in cmd:
420 cnt_err.append(layer['id'])
421 self.assertEqual(len(cnt_err), 0, msg = 'Errors for layer id: %s' % cnt_err)
422
423 # Check if django server starts regardless of the timezone set on the machine - tc=905
424 @testcase(905)
425 def test_Start_Django_Timezone(self):
426 current_path = os.getcwd()
427 zonefilelist = []
428 ZONEINFOPATH = '/usr/share/zoneinfo/'
429 os.chdir("../bitbake/lib/toaster/")
430 cnt_err = 0
431 for filename in os.listdir(ZONEINFOPATH):
432 if os.path.isfile(os.path.join(ZONEINFOPATH, filename)):
433 zonefilelist.append(filename)
434 for k in range(len(zonefilelist)):
435 if k <= 5:
436 files = zonefilelist[k]
437 os.system("export TZ="+str(files)+"; python manage.py runserver > /dev/null 2>&1 &")
438 time.sleep(3)
439 pid = subprocess.check_output("ps aux | grep '[/u]sr/bin/python manage.py runserver' | awk '{print $2}'", shell = True)
440 if pid:
441 os.system("kill -9 "+str(pid))
442 else:
443 cnt_err.append(zonefilelist[k])
444 self.assertEqual(cnt_err, 0, msg = 'Errors django server does not start with timezone: %s' % cnt_err)
445 os.chdir(current_path)
diff --git a/meta/lib/oeqa/selftest/base.py b/meta/lib/oeqa/selftest/base.py
new file mode 100644
index 0000000000..80b9b4b312
--- /dev/null
+++ b/meta/lib/oeqa/selftest/base.py
@@ -0,0 +1,131 @@
1# Copyright (c) 2013 Intel Corporation
2#
3# Released under the MIT license (see COPYING.MIT)
4
5
6# DESCRIPTION
7# Base class inherited by test classes in meta/lib/selftest
8
9import unittest
10import os
11import sys
12import shutil
13import logging
14import errno
15
16import oeqa.utils.ftools as ftools
17from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer
18from oeqa.utils.decorators import LogResults
19
20@LogResults
21class oeSelfTest(unittest.TestCase):
22
23 log = logging.getLogger("selftest.base")
24 longMessage = True
25
26 def __init__(self, methodName="runTest"):
27 self.builddir = os.environ.get("BUILDDIR")
28 self.localconf_path = os.path.join(self.builddir, "conf/local.conf")
29 self.testinc_path = os.path.join(self.builddir, "conf/selftest.inc")
30 self.testlayer_path = oeSelfTest.testlayer_path
31 self._extra_tear_down_commands = []
32 self._track_for_cleanup = []
33 super(oeSelfTest, self).__init__(methodName)
34
35 def setUp(self):
36 os.chdir(self.builddir)
37 # we don't know what the previous test left around in config or inc files
38 # if it failed so we need a fresh start
39 try:
40 os.remove(self.testinc_path)
41 except OSError as e:
42 if e.errno != errno.ENOENT:
43 raise
44 for root, _, files in os.walk(self.testlayer_path):
45 for f in files:
46 if f == 'test_recipe.inc':
47 os.remove(os.path.join(root, f))
48 # tests might need their own setup
49 # but if they overwrite this one they have to call
50 # super each time, so let's give them an alternative
51 self.setUpLocal()
52
53 def setUpLocal(self):
54 pass
55
56 def tearDown(self):
57 if self._extra_tear_down_commands:
58 failed_extra_commands = []
59 for command in self._extra_tear_down_commands:
60 result = runCmd(command, ignore_status=True)
61 if not result.status == 0:
62 failed_extra_commands.append(command)
63 if failed_extra_commands:
64 self.log.warning("tearDown commands have failed: %s" % ', '.join(map(str, failed_extra_commands)))
65 self.log.debug("Trying to move on.")
66 self._extra_tear_down_commands = []
67
68 if self._track_for_cleanup:
69 for path in self._track_for_cleanup:
70 if os.path.isdir(path):
71 shutil.rmtree(path)
72 if os.path.isfile(path):
73 os.remove(path)
74 self._track_for_cleanup = []
75
76 self.tearDownLocal()
77
78 def tearDownLocal(self):
79 pass
80
81 # add test specific commands to the tearDown method.
82 def add_command_to_tearDown(self, command):
83 self.log.debug("Adding command '%s' to tearDown for this test." % command)
84 self._extra_tear_down_commands.append(command)
85 # add test specific files or directories to be removed in the tearDown method
86 def track_for_cleanup(self, path):
87 self.log.debug("Adding path '%s' to be cleaned up when test is over" % path)
88 self._track_for_cleanup.append(path)
89
90 # write to <builddir>/conf/selftest.inc
91 def write_config(self, data):
92 self.log.debug("Writing to: %s\n%s\n" % (self.testinc_path, data))
93 ftools.write_file(self.testinc_path, data)
94
95 # append to <builddir>/conf/selftest.inc
96 def append_config(self, data):
97 self.log.debug("Appending to: %s\n%s\n" % (self.testinc_path, data))
98 ftools.append_file(self.testinc_path, data)
99
100 # remove data from <builddir>/conf/selftest.inc
101 def remove_config(self, data):
102 self.log.debug("Removing from: %s\n\%s\n" % (self.testinc_path, data))
103 ftools.remove_from_file(self.testinc_path, data)
104
105 # write to meta-sefltest/recipes-test/<recipe>/test_recipe.inc
106 def write_recipeinc(self, recipe, data):
107 inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
108 self.log.debug("Writing to: %s\n%s\n" % (inc_file, data))
109 ftools.write_file(inc_file, data)
110
111 # append data to meta-sefltest/recipes-test/<recipe>/test_recipe.inc
112 def append_recipeinc(self, recipe, data):
113 inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
114 self.log.debug("Appending to: %s\n%s\n" % (inc_file, data))
115 ftools.append_file(inc_file, data)
116
117 # remove data from meta-sefltest/recipes-test/<recipe>/test_recipe.inc
118 def remove_recipeinc(self, recipe, data):
119 inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
120 self.log.debug("Removing from: %s\n%s\n" % (inc_file, data))
121 ftools.remove_from_file(inc_file, data)
122
123 # delete meta-sefltest/recipes-test/<recipe>/test_recipe.inc file
124 def delete_recipeinc(self, recipe):
125 inc_file = os.path.join(self.testlayer_path, 'recipes-test', recipe, 'test_recipe.inc')
126 self.log.debug("Deleting file: %s" % inc_file)
127 try:
128 os.remove(inc_file)
129 except OSError as e:
130 if e.errno != errno.ENOENT:
131 raise
diff --git a/meta/lib/oeqa/selftest/bblayers.py b/meta/lib/oeqa/selftest/bblayers.py
new file mode 100644
index 0000000000..1ead8e8671
--- /dev/null
+++ b/meta/lib/oeqa/selftest/bblayers.py
@@ -0,0 +1,43 @@
1import unittest
2import os
3import logging
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd
10from oeqa.utils.decorators import testcase
11
12class BitbakeLayers(oeSelfTest):
13
14 @testcase(756)
15 def test_bitbakelayers_showcrossdepends(self):
16 result = runCmd('bitbake-layers show-cross-depends')
17 self.assertTrue('aspell' in result.output)
18
19 @testcase(83)
20 def test_bitbakelayers_showlayers(self):
21 result = runCmd('bitbake-layers show_layers')
22 self.assertTrue('meta-selftest' in result.output)
23
24 @testcase(93)
25 def test_bitbakelayers_showappends(self):
26 result = runCmd('bitbake-layers show_appends')
27 self.assertTrue('xcursor-transparent-theme_0.1.1.bbappend' in result.output, msg='xcursor-transparent-theme_0.1.1.bbappend file was not recognised')
28
29 @testcase(90)
30 def test_bitbakelayers_showoverlayed(self):
31 result = runCmd('bitbake-layers show_overlayed')
32 self.assertTrue('aspell' in result.output, msg='xcursor-transparent-theme_0.1.1.bbappend file was not recognised')
33
34 @testcase(95)
35 def test_bitbakelayers_flatten(self):
36 self.assertFalse(os.path.isdir(os.path.join(self.builddir, 'test')))
37 result = runCmd('bitbake-layers flatten test')
38 bb_file = os.path.join(self.builddir, 'test/recipes-graphics/xcursor-transparent-theme/xcursor-transparent-theme_0.1.1.bb')
39 self.assertTrue(os.path.isfile(bb_file))
40 contents = ftools.read_file(bb_file)
41 find_in_contents = re.search("##### bbappended from meta-selftest #####\n(.*\n)*include test_recipe.inc", contents)
42 shutil.rmtree(os.path.join(self.builddir, 'test'))
43 self.assertTrue(find_in_contents)
diff --git a/meta/lib/oeqa/selftest/bbtests.py b/meta/lib/oeqa/selftest/bbtests.py
new file mode 100644
index 0000000000..68f97bd8e3
--- /dev/null
+++ b/meta/lib/oeqa/selftest/bbtests.py
@@ -0,0 +1,178 @@
1import unittest
2import os
3import logging
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd, bitbake, get_bb_var
10from oeqa.utils.decorators import testcase
11
12class BitbakeTests(oeSelfTest):
13
14 @testcase(789)
15 def test_run_bitbake_from_dir_1(self):
16 os.chdir(os.path.join(self.builddir, 'conf'))
17 bitbake('-e')
18
19 @testcase(790)
20 def test_run_bitbake_from_dir_2(self):
21 my_env = os.environ.copy()
22 my_env['BBPATH'] = my_env['BUILDDIR']
23 os.chdir(os.path.dirname(os.environ['BUILDDIR']))
24 bitbake('-e', env=my_env)
25
26 @testcase(806)
27 def test_event_handler(self):
28 self.write_config("INHERIT += \"test_events\"")
29 result = bitbake('m4-native')
30 find_build_started = re.search("NOTE: Test for bb\.event\.BuildStarted(\n.*)*NOTE: Preparing runqueue", result.output)
31 find_build_completed = re.search("Tasks Summary:.*(\n.*)*NOTE: Test for bb\.event\.BuildCompleted", result.output)
32 self.assertTrue(find_build_started, msg = "Match failed in:\n%s" % result.output)
33 self.assertTrue(find_build_completed, msg = "Match failed in:\n%s" % result.output)
34 self.assertFalse('Test for bb.event.InvalidEvent' in result.output)
35
36 @testcase(103)
37 def test_local_sstate(self):
38 bitbake('m4-native -ccleansstate')
39 bitbake('m4-native')
40 bitbake('m4-native -cclean')
41 result = bitbake('m4-native')
42 find_setscene = re.search("m4-native.*do_.*_setscene", result.output)
43 self.assertTrue(find_setscene)
44
45 @testcase(105)
46 def test_bitbake_invalid_recipe(self):
47 result = bitbake('-b asdf', ignore_status=True)
48 self.assertTrue("ERROR: Unable to find any recipe file matching 'asdf'" in result.output)
49
50 @testcase(107)
51 def test_bitbake_invalid_target(self):
52 result = bitbake('asdf', ignore_status=True)
53 self.assertTrue("ERROR: Nothing PROVIDES 'asdf'" in result.output)
54
55 @testcase(106)
56 def test_warnings_errors(self):
57 result = bitbake('-b asdf', ignore_status=True)
58 find_warnings = re.search("Summary: There w.{2,3}? [1-9][0-9]* WARNING messages* shown", result.output)
59 find_errors = re.search("Summary: There w.{2,3}? [1-9][0-9]* ERROR messages* shown", result.output)
60 self.assertTrue(find_warnings, msg="Did not find the mumber of warnings at the end of the build:\n" + result.output)
61 self.assertTrue(find_errors, msg="Did not find the mumber of errors at the end of the build:\n" + result.output)
62
63 @testcase(108)
64 def test_invalid_patch(self):
65 self.write_recipeinc('man', 'SRC_URI += "file://man-1.5h1-make.patch"')
66 result = bitbake('man -c patch', ignore_status=True)
67 self.delete_recipeinc('man')
68 bitbake('-cclean man')
69 self.assertTrue("ERROR: Function failed: patch_do_patch" in result.output)
70
71 @testcase(163)
72 def test_force_task(self):
73 bitbake('m4-native')
74 result = bitbake('-C compile m4-native')
75 look_for_tasks = ['do_compile', 'do_install', 'do_populate_sysroot']
76 for task in look_for_tasks:
77 find_task = re.search("m4-native.*%s" % task, result.output)
78 self.assertTrue(find_task)
79
80 @testcase(167)
81 def test_bitbake_g(self):
82 result = bitbake('-g core-image-full-cmdline')
83 self.assertTrue('NOTE: PN build list saved to \'pn-buildlist\'' in result.output)
84 self.assertTrue('openssh' in ftools.read_file(os.path.join(self.builddir, 'pn-buildlist')))
85 for f in ['pn-buildlist', 'pn-depends.dot', 'package-depends.dot', 'task-depends.dot']:
86 os.remove(f)
87
88 @testcase(899)
89 def test_image_manifest(self):
90 bitbake('core-image-minimal')
91 deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal")
92 imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal")
93 manifest = os.path.join(deploydir, imagename + ".manifest")
94 self.assertTrue(os.path.islink(manifest), msg="No manifest file created for image")
95
96 @testcase(168)
97 def test_invalid_recipe_src_uri(self):
98 data = 'SRC_URI = "file://invalid"'
99 self.write_recipeinc('man', data)
100 bitbake('-ccleanall man')
101 result = bitbake('-c fetch man', ignore_status=True)
102 bitbake('-ccleanall man')
103 self.delete_recipeinc('man')
104 self.assertEqual(result.status, 1, msg='Command succeded when it should have failed')
105 self.assertTrue('Fetcher failure: Unable to find file file://invalid anywhere. The paths that were searched were:' in result.output)
106 self.assertTrue('ERROR: Function failed: Fetcher failure for URL: \'file://invalid\'. Unable to fetch URL from any source.' in result.output)
107
108 @testcase(171)
109 def test_rename_downloaded_file(self):
110 data = 'SRC_URI_append = ";downloadfilename=test-aspell.tar.gz"'
111 self.write_recipeinc('aspell', data)
112 bitbake('-ccleanall aspell')
113 result = bitbake('-c fetch aspell', ignore_status=True)
114 self.delete_recipeinc('aspell')
115 self.assertEqual(result.status, 0)
116 self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz')))
117 self.assertTrue(os.path.isfile(os.path.join(get_bb_var("DL_DIR"), 'test-aspell.tar.gz.done')))
118 bitbake('-ccleanall aspell')
119
120 @testcase(1028)
121 def test_environment(self):
122 self.append_config("TEST_ENV=\"localconf\"")
123 result = runCmd('bitbake -e | grep TEST_ENV=')
124 self.assertTrue('localconf' in result.output)
125 self.remove_config("TEST_ENV=\"localconf\"")
126
127 @testcase(1029)
128 def test_dry_run(self):
129 result = runCmd('bitbake -n m4-native')
130 self.assertEqual(0, result.status)
131
132 @testcase(1030)
133 def test_just_parse(self):
134 result = runCmd('bitbake -p')
135 self.assertEqual(0, result.status)
136
137 @testcase(1031)
138 def test_version(self):
139 result = runCmd('bitbake -s | grep wget')
140 find = re.search("wget *:([0-9a-zA-Z\.\-]+)", result.output)
141 self.assertTrue(find)
142
143 @testcase(1032)
144 def test_prefile(self):
145 preconf = os.path.join(self.builddir, 'conf/prefile.conf')
146 self.track_for_cleanup(preconf)
147 ftools.write_file(preconf ,"TEST_PREFILE=\"prefile\"")
148 result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=')
149 self.assertTrue('prefile' in result.output)
150 self.append_config("TEST_PREFILE=\"localconf\"")
151 result = runCmd('bitbake -r conf/prefile.conf -e | grep TEST_PREFILE=')
152 self.assertTrue('localconf' in result.output)
153 self.remove_config("TEST_PREFILE=\"localconf\"")
154
155 @testcase(1033)
156 def test_postfile(self):
157 postconf = os.path.join(self.builddir, 'conf/postfile.conf')
158 self.track_for_cleanup(postconf)
159 ftools.write_file(postconf , "TEST_POSTFILE=\"postfile\"")
160 self.append_config("TEST_POSTFILE=\"localconf\"")
161 result = runCmd('bitbake -R conf/postfile.conf -e | grep TEST_POSTFILE=')
162 self.assertTrue('postfile' in result.output)
163 self.remove_config("TEST_POSTFILE=\"localconf\"")
164
165 @testcase(1034)
166 def test_checkuri(self):
167 result = runCmd('bitbake -c checkuri m4')
168 self.assertEqual(0, result.status)
169
170 @testcase(1035)
171 def test_continue(self):
172 self.write_recipeinc('man',"\ndo_fail_task () {\nexit 1 \n}\n\naddtask do_fail_task before do_fetch\n" )
173 runCmd('bitbake -c cleanall man xcursor-transparent-theme')
174 result = runCmd('bitbake man xcursor-transparent-theme -k', ignore_status=True)
175 errorpos = result.output.find('ERROR: Function failed: do_fail_task')
176 manver = re.search("NOTE: recipe xcursor-transparent-theme-(.*?): task do_unpack: Started", result.output)
177 continuepos = result.output.find('NOTE: recipe xcursor-transparent-theme-%s: task do_unpack: Started' % manver.group(1))
178 self.assertLess(errorpos,continuepos)
diff --git a/meta/lib/oeqa/selftest/buildhistory.py b/meta/lib/oeqa/selftest/buildhistory.py
new file mode 100644
index 0000000000..d8cae4664b
--- /dev/null
+++ b/meta/lib/oeqa/selftest/buildhistory.py
@@ -0,0 +1,45 @@
1import unittest
2import os
3import re
4import shutil
5import datetime
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer
10
11
12class BuildhistoryBase(oeSelfTest):
13
14 def config_buildhistory(self, tmp_bh_location=False):
15 if (not 'buildhistory' in get_bb_var('USER_CLASSES')) and (not 'buildhistory' in get_bb_var('INHERIT')):
16 add_buildhistory_config = 'INHERIT += "buildhistory"\nBUILDHISTORY_COMMIT = "1"'
17 self.append_config(add_buildhistory_config)
18
19 if tmp_bh_location:
20 # Using a temporary buildhistory location for testing
21 tmp_bh_dir = os.path.join(self.builddir, "tmp_buildhistory_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
22 buildhistory_dir_config = "BUILDHISTORY_DIR = \"%s\"" % tmp_bh_dir
23 self.append_config(buildhistory_dir_config)
24 self.track_for_cleanup(tmp_bh_dir)
25
26 def run_buildhistory_operation(self, target, global_config='', target_config='', change_bh_location=False, expect_error=False, error_regex=''):
27 if change_bh_location:
28 tmp_bh_location = True
29 else:
30 tmp_bh_location = False
31 self.config_buildhistory(tmp_bh_location)
32
33 self.append_config(global_config)
34 self.append_recipeinc(target, target_config)
35 bitbake("-cclean %s" % target)
36 result = bitbake(target, ignore_status=True)
37 self.remove_config(global_config)
38 self.remove_recipeinc(target, target_config)
39
40 if expect_error:
41 self.assertEqual(result.status, 1, msg="Error expected for global config '%s' and target config '%s'" % (global_config, target_config))
42 search_for_error = re.search(error_regex, result.output)
43 self.assertTrue(search_for_error, msg="Could not find desired error in output: %s" % error_regex)
44 else:
45 self.assertEqual(result.status, 0, msg="Command 'bitbake %s' has failed unexpectedly: %s" % (target, result.output))
diff --git a/meta/lib/oeqa/selftest/buildoptions.py b/meta/lib/oeqa/selftest/buildoptions.py
new file mode 100644
index 0000000000..a250cae0e1
--- /dev/null
+++ b/meta/lib/oeqa/selftest/buildoptions.py
@@ -0,0 +1,120 @@
1import unittest
2import os
3import logging
4import re
5
6from oeqa.selftest.base import oeSelfTest
7from oeqa.selftest.buildhistory import BuildhistoryBase
8from oeqa.utils.commands import runCmd, bitbake, get_bb_var
9import oeqa.utils.ftools as ftools
10from oeqa.utils.decorators import testcase
11
12class ImageOptionsTests(oeSelfTest):
13
14 @testcase(761)
15 def test_incremental_image_generation(self):
16 bitbake("-c cleanall core-image-minimal")
17 self.write_config('INC_RPM_IMAGE_GEN = "1"')
18 self.append_config('IMAGE_FEATURES += "ssh-server-openssh"')
19 bitbake("core-image-minimal")
20 res = runCmd("grep 'Installing openssh-sshd' %s" % (os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")), ignore_status=True)
21 self.remove_config('IMAGE_FEATURES += "ssh-server-openssh"')
22 self.assertEqual(0, res.status, msg="No match for openssh-sshd in log.do_rootfs")
23 bitbake("core-image-minimal")
24 res = runCmd("grep 'Removing openssh-sshd' %s" %(os.path.join(get_bb_var("WORKDIR", "core-image-minimal"), "temp/log.do_rootfs")),ignore_status=True)
25 self.assertEqual(0, res.status, msg="openssh-sshd was not removed from image")
26
27 @testcase(925)
28 def test_rm_old_image(self):
29 bitbake("core-image-minimal")
30 deploydir = get_bb_var("DEPLOY_DIR_IMAGE", target="core-image-minimal")
31 imagename = get_bb_var("IMAGE_LINK_NAME", target="core-image-minimal")
32 deploydir_files = os.listdir(deploydir)
33 track_original_files = []
34 for image_file in deploydir_files:
35 if imagename in image_file and os.path.islink(os.path.join(deploydir, image_file)):
36 track_original_files.append(os.path.realpath(os.path.join(deploydir, image_file)))
37 self.append_config("RM_OLD_IMAGE = \"1\"")
38 bitbake("-C rootfs core-image-minimal")
39 deploydir_files = os.listdir(deploydir)
40 remaining_not_expected = [path for path in track_original_files if os.path.basename(path) in deploydir_files]
41 self.assertFalse(remaining_not_expected, msg="\nThe following image files ware not removed: %s" % ', '.join(map(str, remaining_not_expected)))
42
43 @testcase(286)
44 def test_ccache_tool(self):
45 bitbake("ccache-native")
46 self.assertTrue(os.path.isfile(os.path.join(get_bb_var('STAGING_BINDIR_NATIVE', 'ccache-native'), "ccache")))
47 self.write_config('INHERIT += "ccache"')
48 bitbake("m4 -c cleansstate")
49 bitbake("m4 -c compile")
50 res = runCmd("grep ccache %s" % (os.path.join(get_bb_var("WORKDIR","m4"),"temp/log.do_compile")), ignore_status=True)
51 self.assertEqual(0, res.status, msg="No match for ccache in m4 log.do_compile")
52 bitbake("ccache-native -ccleansstate")
53
54
55class DiskMonTest(oeSelfTest):
56
57 @testcase(277)
58 def test_stoptask_behavior(self):
59 self.write_config('BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},100000G,100K"')
60 res = bitbake("m4", ignore_status = True)
61 self.assertTrue('ERROR: No new tasks can be executed since the disk space monitor action is "STOPTASKS"!' in res.output)
62 self.assertEqual(res.status, 1)
63 self.write_config('BB_DISKMON_DIRS = "ABORT,${TMPDIR},100000G,100K"')
64 res = bitbake("m4", ignore_status = True)
65 self.assertTrue('ERROR: Immediately abort since the disk space monitor action is "ABORT"!' in res.output)
66 self.assertEqual(res.status, 1)
67 self.write_config('BB_DISKMON_DIRS = "WARN,${TMPDIR},100000G,100K"')
68 res = bitbake("m4")
69 self.assertTrue('WARNING: The free space' in res.output)
70
71class SanityOptionsTest(oeSelfTest):
72
73 @testcase(927)
74 def test_options_warnqa_errorqa_switch(self):
75 bitbake("xcursor-transparent-theme -ccleansstate")
76
77 if "packages-list" not in get_bb_var("ERROR_QA"):
78 self.write_config("ERROR_QA_append = \" packages-list\"")
79
80 self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"')
81 res = bitbake("xcursor-transparent-theme", ignore_status=True)
82 self.delete_recipeinc('xcursor-transparent-theme')
83 self.assertTrue("ERROR: QA Issue: xcursor-transparent-theme-dbg is listed in PACKAGES multiple times, this leads to packaging errors." in res.output, msg=res.output)
84 self.assertEqual(res.status, 1)
85 self.write_recipeinc('xcursor-transparent-theme', 'PACKAGES += \"${PN}-dbg\"')
86 self.append_config('ERROR_QA_remove = "packages-list"')
87 self.append_config('WARN_QA_append = " packages-list"')
88 bitbake("xcursor-transparent-theme -ccleansstate")
89 res = bitbake("xcursor-transparent-theme")
90 self.delete_recipeinc('xcursor-transparent-theme')
91 self.assertTrue("WARNING: QA Issue: xcursor-transparent-theme-dbg is listed in PACKAGES multiple times, this leads to packaging errors." in res.output, msg=res.output)
92
93 @testcase(278)
94 def test_sanity_userspace_dependency(self):
95 self.append_config('WARN_QA_append = " unsafe-references-in-binaries unsafe-references-in-scripts"')
96 bitbake("-ccleansstate gzip nfs-utils")
97 res = bitbake("gzip nfs-utils")
98 self.assertTrue("WARNING: QA Issue: gzip" in res.output)
99 self.assertTrue("WARNING: QA Issue: nfs-utils" in res.output)
100
101class BuildhistoryTests(BuildhistoryBase):
102
103 @testcase(293)
104 def test_buildhistory_basic(self):
105 self.run_buildhistory_operation('xcursor-transparent-theme')
106 self.assertTrue(os.path.isdir(get_bb_var('BUILDHISTORY_DIR')))
107
108 @testcase(294)
109 def test_buildhistory_buildtime_pr_backwards(self):
110 self.add_command_to_tearDown('cleanup-workdir')
111 target = 'xcursor-transparent-theme'
112 error = "ERROR: QA Issue: Package version for package %s went backwards which would break package feeds from (.*-r1 to .*-r0)" % target
113 self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True)
114 self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True, error_regex=error)
115
116
117
118
119
120
diff --git a/meta/lib/oeqa/selftest/oescripts.py b/meta/lib/oeqa/selftest/oescripts.py
new file mode 100644
index 0000000000..31cd50809c
--- /dev/null
+++ b/meta/lib/oeqa/selftest/oescripts.py
@@ -0,0 +1,54 @@
1import datetime
2import unittest
3import os
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.selftest.buildhistory import BuildhistoryBase
10from oeqa.utils.commands import Command, runCmd, bitbake, get_bb_var, get_test_layer
11from oeqa.utils.decorators import testcase
12
13class TestScripts(oeSelfTest):
14
15 @testcase(300)
16 def test_cleanup_workdir(self):
17 path = os.path.dirname(get_bb_var('WORKDIR', 'gzip'))
18 old_version_recipe = os.path.join(get_bb_var('COREBASE'), 'meta/recipes-extended/gzip/gzip_1.3.12.bb')
19 old_version = '1.3.12'
20 bitbake("-ccleansstate gzip")
21 bitbake("-ccleansstate -b %s" % old_version_recipe)
22 if os.path.exists(get_bb_var('WORKDIR', "-b %s" % old_version_recipe)):
23 shutil.rmtree(get_bb_var('WORKDIR', "-b %s" % old_version_recipe))
24 if os.path.exists(get_bb_var('WORKDIR', 'gzip')):
25 shutil.rmtree(get_bb_var('WORKDIR', 'gzip'))
26
27 if os.path.exists(path):
28 initial_contents = os.listdir(path)
29 else:
30 initial_contents = []
31
32 bitbake('gzip')
33 intermediary_contents = os.listdir(path)
34 bitbake("-b %s" % old_version_recipe)
35 runCmd('cleanup-workdir')
36 remaining_contents = os.listdir(path)
37
38 expected_contents = [x for x in intermediary_contents if x not in initial_contents]
39 remaining_not_expected = [x for x in remaining_contents if x not in expected_contents]
40 self.assertFalse(remaining_not_expected, msg="Not all necessary content has been deleted from %s: %s" % (path, ', '.join(map(str, remaining_not_expected))))
41 expected_not_remaining = [x for x in expected_contents if x not in remaining_contents]
42 self.assertFalse(expected_not_remaining, msg="The script removed extra contents from %s: %s" % (path, ', '.join(map(str, expected_not_remaining))))
43
44class BuildhistoryDiffTests(BuildhistoryBase):
45
46 @testcase(295)
47 def test_buildhistory_diff(self):
48 self.add_command_to_tearDown('cleanup-workdir')
49 target = 'xcursor-transparent-theme'
50 self.run_buildhistory_operation(target, target_config="PR = \"r1\"", change_bh_location=True)
51 self.run_buildhistory_operation(target, target_config="PR = \"r0\"", change_bh_location=False, expect_error=True)
52 result = runCmd("buildhistory-diff -p %s" % get_bb_var('BUILDHISTORY_DIR'))
53 expected_output = 'PR changed from "r1" to "r0"'
54 self.assertTrue(expected_output in result.output, msg="Did not find expected output: %s" % result.output)
diff --git a/meta/lib/oeqa/selftest/prservice.py b/meta/lib/oeqa/selftest/prservice.py
new file mode 100644
index 0000000000..fb6d68d3bf
--- /dev/null
+++ b/meta/lib/oeqa/selftest/prservice.py
@@ -0,0 +1,121 @@
1import unittest
2import os
3import logging
4import re
5import shutil
6import datetime
7
8import oeqa.utils.ftools as ftools
9from oeqa.selftest.base import oeSelfTest
10from oeqa.utils.commands import runCmd, bitbake, get_bb_var
11from oeqa.utils.decorators import testcase
12
13class BitbakePrTests(oeSelfTest):
14
15 def get_pr_version(self, package_name):
16 pkgdata_dir = get_bb_var('PKGDATA_DIR')
17 package_data_file = os.path.join(pkgdata_dir, 'runtime', package_name)
18 package_data = ftools.read_file(package_data_file)
19 find_pr = re.search("PKGR: r[0-9]+\.([0-9]+)", package_data)
20 self.assertTrue(find_pr)
21 return int(find_pr.group(1))
22
23 def get_task_stamp(self, package_name, recipe_task):
24 stampdata = get_bb_var('STAMP', target=package_name).split('/')
25 prefix = stampdata[-1]
26 package_stamps_path = "/".join(stampdata[:-1])
27 stamps = []
28 for stamp in os.listdir(package_stamps_path):
29 find_stamp = re.match("%s\.%s\.([a-z0-9]{32})" % (prefix, recipe_task), stamp)
30 if find_stamp:
31 stamps.append(find_stamp.group(1))
32 self.assertFalse(len(stamps) == 0, msg="Cound not find stamp for task %s for recipe %s" % (recipe_task, package_name))
33 self.assertFalse(len(stamps) > 1, msg="Found multiple %s stamps for the %s recipe in the %s directory." % (recipe_task, package_name, package_stamps_path))
34 return str(stamps[0])
35
36 def increment_package_pr(self, package_name):
37 inc_data = "do_package_append() {\nbb.build.exec_func('do_test_prserv', d)\n}\ndo_test_prserv() {\necho \"The current date is: %s\"\n}" % datetime.datetime.now()
38 self.write_recipeinc(package_name, inc_data)
39 bitbake("-ccleansstate %s" % package_name)
40 res = bitbake(package_name, ignore_status=True)
41 self.delete_recipeinc(package_name)
42 self.assertEqual(res.status, 0, msg=res.output)
43 self.assertTrue("NOTE: Started PRServer with DBfile" in res.output, msg=res.output)
44
45 def config_pr_tests(self, package_name, package_type='rpm', pr_socket='localhost:0'):
46 config_package_data = 'PACKAGE_CLASSES = "package_%s"' % package_type
47 self.write_config(config_package_data)
48 config_server_data = 'PRSERV_HOST = "%s"' % pr_socket
49 self.append_config(config_server_data)
50
51 def run_test_pr_service(self, package_name, package_type='rpm', track_task='do_package', pr_socket='localhost:0'):
52 self.config_pr_tests(package_name, package_type, pr_socket)
53
54 self.increment_package_pr(package_name)
55 pr_1 = self.get_pr_version(package_name)
56 stamp_1 = self.get_task_stamp(package_name, track_task)
57
58 self.increment_package_pr(package_name)
59 pr_2 = self.get_pr_version(package_name)
60 stamp_2 = self.get_task_stamp(package_name, track_task)
61
62 bitbake("-ccleansstate %s" % package_name)
63 self.assertTrue(pr_2 - pr_1 == 1)
64 self.assertTrue(stamp_1 != stamp_2)
65
66 def run_test_pr_export_import(self, package_name, replace_current_db=True):
67 self.config_pr_tests(package_name)
68
69 self.increment_package_pr(package_name)
70 pr_1 = self.get_pr_version(package_name)
71
72 exported_db_path = os.path.join(self.builddir, 'export.inc')
73 export_result = runCmd("bitbake-prserv-tool export %s" % exported_db_path, ignore_status=True)
74 self.assertEqual(export_result.status, 0, msg="PR Service database export failed: %s" % export_result.output)
75
76 if replace_current_db:
77 current_db_path = os.path.join(get_bb_var('PERSISTENT_DIR'), 'prserv.sqlite3')
78 self.assertTrue(os.path.exists(current_db_path), msg="Path to current PR Service database is invalid: %s" % current_db_path)
79 os.remove(current_db_path)
80
81 import_result = runCmd("bitbake-prserv-tool import %s" % exported_db_path, ignore_status=True)
82 os.remove(exported_db_path)
83 self.assertEqual(import_result.status, 0, msg="PR Service database import failed: %s" % import_result.output)
84
85 self.increment_package_pr(package_name)
86 pr_2 = self.get_pr_version(package_name)
87
88 bitbake("-ccleansstate %s" % package_name)
89 self.assertTrue(pr_2 - pr_1 == 1)
90
91 @testcase(930)
92 def test_import_export_replace_db(self):
93 self.run_test_pr_export_import('m4')
94
95 @testcase(931)
96 def test_import_export_override_db(self):
97 self.run_test_pr_export_import('m4', replace_current_db=False)
98
99 @testcase(932)
100 def test_pr_service_rpm_arch_dep(self):
101 self.run_test_pr_service('m4', 'rpm', 'do_package')
102
103 @testcase(934)
104 def test_pr_service_deb_arch_dep(self):
105 self.run_test_pr_service('m4', 'deb', 'do_package')
106
107 @testcase(933)
108 def test_pr_service_ipk_arch_dep(self):
109 self.run_test_pr_service('m4', 'ipk', 'do_package')
110
111 @testcase(935)
112 def test_pr_service_rpm_arch_indep(self):
113 self.run_test_pr_service('xcursor-transparent-theme', 'rpm', 'do_package')
114
115 @testcase(937)
116 def test_pr_service_deb_arch_indep(self):
117 self.run_test_pr_service('xcursor-transparent-theme', 'deb', 'do_package')
118
119 @testcase(936)
120 def test_pr_service_ipk_arch_indep(self):
121 self.run_test_pr_service('xcursor-transparent-theme', 'ipk', 'do_package')
diff --git a/meta/lib/oeqa/selftest/sstate.py b/meta/lib/oeqa/selftest/sstate.py
new file mode 100644
index 0000000000..5989724432
--- /dev/null
+++ b/meta/lib/oeqa/selftest/sstate.py
@@ -0,0 +1,53 @@
1import datetime
2import unittest
3import os
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer
10
11
12class SStateBase(oeSelfTest):
13
14 def setUpLocal(self):
15 self.temp_sstate_location = None
16 self.sstate_path = get_bb_var('SSTATE_DIR')
17 self.distro = get_bb_var('NATIVELSBSTRING')
18 self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro)
19
20 # Creates a special sstate configuration with the option to add sstate mirrors
21 def config_sstate(self, temp_sstate_location=False, add_local_mirrors=[]):
22 self.temp_sstate_location = temp_sstate_location
23
24 if self.temp_sstate_location:
25 temp_sstate_path = os.path.join(self.builddir, "temp_sstate_%s" % datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
26 config_temp_sstate = "SSTATE_DIR = \"%s\"" % temp_sstate_path
27 self.append_config(config_temp_sstate)
28 self.track_for_cleanup(temp_sstate_path)
29 self.sstate_path = get_bb_var('SSTATE_DIR')
30 self.distro = get_bb_var('NATIVELSBSTRING')
31 self.distro_specific_sstate = os.path.join(self.sstate_path, self.distro)
32
33 if add_local_mirrors:
34 config_set_sstate_if_not_set = 'SSTATE_MIRRORS ?= ""'
35 self.append_config(config_set_sstate_if_not_set)
36 for local_mirror in add_local_mirrors:
37 self.assertFalse(os.path.join(local_mirror) == os.path.join(self.sstate_path), msg='Cannot add the current sstate path as a sstate mirror')
38 config_sstate_mirror = "SSTATE_MIRRORS += \"file://.* file:///%s/PATH\"" % local_mirror
39 self.append_config(config_sstate_mirror)
40
41 # Returns a list containing sstate files
42 def search_sstate(self, filename_regex, distro_specific=True, distro_nonspecific=True):
43 result = []
44 for root, dirs, files in os.walk(self.sstate_path):
45 if distro_specific and re.search("%s/[a-z0-9]{2}$" % self.distro, root):
46 for f in files:
47 if re.search(filename_regex, f):
48 result.append(f)
49 if distro_nonspecific and re.search("%s/[a-z0-9]{2}$" % self.sstate_path, root):
50 for f in files:
51 if re.search(filename_regex, f):
52 result.append(f)
53 return result
diff --git a/meta/lib/oeqa/selftest/sstatetests.py b/meta/lib/oeqa/selftest/sstatetests.py
new file mode 100644
index 0000000000..d578ddd489
--- /dev/null
+++ b/meta/lib/oeqa/selftest/sstatetests.py
@@ -0,0 +1,204 @@
1import datetime
2import unittest
3import os
4import re
5import shutil
6
7import oeqa.utils.ftools as ftools
8from oeqa.selftest.base import oeSelfTest
9from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_test_layer
10from oeqa.selftest.sstate import SStateBase
11from oeqa.utils.decorators import testcase
12
13class SStateTests(SStateBase):
14
15 # Test sstate files creation and their location
16 def run_test_sstate_creation(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True, should_pass=True):
17 self.config_sstate(temp_sstate_location)
18
19 if self.temp_sstate_location:
20 bitbake(['-cclean'] + targets)
21 else:
22 bitbake(['-ccleansstate'] + targets)
23
24 bitbake(targets)
25 file_tracker = self.search_sstate('|'.join(map(str, targets)), distro_specific, distro_nonspecific)
26 if should_pass:
27 self.assertTrue(file_tracker , msg="Could not find sstate files for: %s" % ', '.join(map(str, targets)))
28 else:
29 self.assertTrue(not file_tracker , msg="Found sstate files in the wrong place for: %s" % ', '.join(map(str, targets)))
30
31 @testcase(975)
32 def test_sstate_creation_distro_specific_pass(self):
33 targetarch = get_bb_var('TUNE_ARCH')
34 self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
35
36 @testcase(975)
37 def test_sstate_creation_distro_specific_fail(self):
38 targetarch = get_bb_var('TUNE_ARCH')
39 self.run_test_sstate_creation(['binutils-cross-'+ targetarch, 'binutils-native'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True, should_pass=False)
40
41 @testcase(976)
42 def test_sstate_creation_distro_nonspecific_pass(self):
43 self.run_test_sstate_creation(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
44
45 @testcase(976)
46 def test_sstate_creation_distro_nonspecific_fail(self):
47 self.run_test_sstate_creation(['glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True, should_pass=False)
48
49
50 # Test the sstate files deletion part of the do_cleansstate task
51 def run_test_cleansstate_task(self, targets, distro_specific=True, distro_nonspecific=True, temp_sstate_location=True):
52 self.config_sstate(temp_sstate_location)
53
54 bitbake(['-ccleansstate'] + targets)
55
56 bitbake(targets)
57 tgz_created = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific)
58 self.assertTrue(tgz_created, msg="Could not find sstate .tgz files for: %s" % ', '.join(map(str, targets)))
59
60 siginfo_created = self.search_sstate('|'.join(map(str, [s + '.*?\.siginfo$' for s in targets])), distro_specific, distro_nonspecific)
61 self.assertTrue(siginfo_created, msg="Could not find sstate .siginfo files for: %s" % ', '.join(map(str, targets)))
62
63 bitbake(['-ccleansstate'] + targets)
64 tgz_removed = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific, distro_nonspecific)
65 self.assertTrue(not tgz_removed, msg="do_cleansstate didn't remove .tgz sstate files for: %s" % ', '.join(map(str, targets)))
66
67 @testcase(977)
68 def test_cleansstate_task_distro_specific_nonspecific(self):
69 targetarch = get_bb_var('TUNE_ARCH')
70 self.run_test_cleansstate_task(['binutils-cross-' + targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=True, temp_sstate_location=True)
71
72 @testcase(977)
73 def test_cleansstate_task_distro_nonspecific(self):
74 self.run_test_cleansstate_task(['glibc-initial'], distro_specific=False, distro_nonspecific=True, temp_sstate_location=True)
75
76 @testcase(977)
77 def test_cleansstate_task_distro_specific(self):
78 targetarch = get_bb_var('TUNE_ARCH')
79 self.run_test_cleansstate_task(['binutils-cross-'+ targetarch, 'binutils-native', 'glibc-initial'], distro_specific=True, distro_nonspecific=False, temp_sstate_location=True)
80
81
82 # Test rebuilding of distro-specific sstate files
83 def run_test_rebuild_distro_specific_sstate(self, targets, temp_sstate_location=True):
84 self.config_sstate(temp_sstate_location)
85
86 bitbake(['-ccleansstate'] + targets)
87
88 bitbake(targets)
89 self.assertTrue(self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=False, distro_nonspecific=True) == [], msg="Found distro non-specific sstate for: %s" % ', '.join(map(str, targets)))
90 file_tracker_1 = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False)
91 self.assertTrue(len(file_tracker_1) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets)))
92
93 self.track_for_cleanup(self.distro_specific_sstate + "_old")
94 shutil.copytree(self.distro_specific_sstate, self.distro_specific_sstate + "_old")
95 shutil.rmtree(self.distro_specific_sstate)
96
97 bitbake(['-cclean'] + targets)
98 bitbake(targets)
99 file_tracker_2 = self.search_sstate('|'.join(map(str, [s + '.*?\.tgz$' for s in targets])), distro_specific=True, distro_nonspecific=False)
100 self.assertTrue(len(file_tracker_2) >= len(targets), msg = "Not all sstate files ware created for: %s" % ', '.join(map(str, targets)))
101
102 not_recreated = [x for x in file_tracker_1 if x not in file_tracker_2]
103 self.assertTrue(not_recreated == [], msg="The following sstate files ware not recreated: %s" % ', '.join(map(str, not_recreated)))
104
105 created_once = [x for x in file_tracker_2 if x not in file_tracker_1]
106 self.assertTrue(created_once == [], msg="The following sstate files ware created only in the second run: %s" % ', '.join(map(str, created_once)))
107
108 @testcase(175)
109 def test_rebuild_distro_specific_sstate_cross_native_targets(self):
110 targetarch = get_bb_var('TUNE_ARCH')
111 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch, 'binutils-native'], temp_sstate_location=True)
112
113 @testcase(175)
114 def test_rebuild_distro_specific_sstate_cross_target(self):
115 targetarch = get_bb_var('TUNE_ARCH')
116 self.run_test_rebuild_distro_specific_sstate(['binutils-cross-' + targetarch], temp_sstate_location=True)
117
118 @testcase(175)
119 def test_rebuild_distro_specific_sstate_native_target(self):
120 self.run_test_rebuild_distro_specific_sstate(['binutils-native'], temp_sstate_location=True)
121
122
123 # Test the sstate-cache-management script. Each element in the global_config list is used with the corresponding element in the target_config list
124 # global_config elements are expected to not generate any sstate files that would be removed by sstate-cache-management.sh (such as changing the value of MACHINE)
125 def run_test_sstate_cache_management_script(self, target, global_config=[''], target_config=[''], ignore_patterns=[]):
126 self.assertTrue(global_config)
127 self.assertTrue(target_config)
128 self.assertTrue(len(global_config) == len(target_config), msg='Lists global_config and target_config should have the same number of elements')
129 self.config_sstate(temp_sstate_location=True, add_local_mirrors=[self.sstate_path])
130
131 # If buildhistory is enabled, we need to disable version-going-backwards QA checks for this test. It may report errors otherwise.
132 if ('buildhistory' in get_bb_var('USER_CLASSES')) or ('buildhistory' in get_bb_var('INHERIT')):
133 remove_errors_config = 'ERROR_QA_remove = "version-going-backwards"'
134 self.append_config(remove_errors_config)
135
136 # For not this only checks if random sstate tasks are handled correctly as a group.
137 # In the future we should add control over what tasks we check for.
138
139 sstate_archs_list = []
140 expected_remaining_sstate = []
141 for idx in range(len(target_config)):
142 self.append_config(global_config[idx])
143 self.append_recipeinc(target, target_config[idx])
144 sstate_arch = get_bb_var('SSTATE_PKGARCH', target)
145 if not sstate_arch in sstate_archs_list:
146 sstate_archs_list.append(sstate_arch)
147 if target_config[idx] == target_config[-1]:
148 target_sstate_before_build = self.search_sstate(target + '.*?\.tgz$')
149 bitbake("-cclean %s" % target)
150 result = bitbake(target, ignore_status=True)
151 if target_config[idx] == target_config[-1]:
152 target_sstate_after_build = self.search_sstate(target + '.*?\.tgz$')
153 expected_remaining_sstate += [x for x in target_sstate_after_build if x not in target_sstate_before_build if not any(pattern in x for pattern in ignore_patterns)]
154 self.remove_config(global_config[idx])
155 self.remove_recipeinc(target, target_config[idx])
156 self.assertEqual(result.status, 0)
157
158 runCmd("sstate-cache-management.sh -y --cache-dir=%s --remove-duplicated --extra-archs=%s" % (self.sstate_path, ','.join(map(str, sstate_archs_list))))
159 actual_remaining_sstate = [x for x in self.search_sstate(target + '.*?\.tgz$') if not any(pattern in x for pattern in ignore_patterns)]
160
161 actual_not_expected = [x for x in actual_remaining_sstate if x not in expected_remaining_sstate]
162 self.assertFalse(actual_not_expected, msg="Files should have been removed but ware not: %s" % ', '.join(map(str, actual_not_expected)))
163 expected_not_actual = [x for x in expected_remaining_sstate if x not in actual_remaining_sstate]
164 self.assertFalse(expected_not_actual, msg="Extra files ware removed: %s" ', '.join(map(str, expected_not_actual)))
165
166 @testcase(973)
167 def test_sstate_cache_management_script_using_pr_1(self):
168 global_config = []
169 target_config = []
170 global_config.append('')
171 target_config.append('PR = "0"')
172 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
173
174 @testcase(978)
175 def test_sstate_cache_management_script_using_pr_2(self):
176 global_config = []
177 target_config = []
178 global_config.append('')
179 target_config.append('PR = "0"')
180 global_config.append('')
181 target_config.append('PR = "1"')
182 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
183
184 @testcase(979)
185 def test_sstate_cache_management_script_using_pr_3(self):
186 global_config = []
187 target_config = []
188 global_config.append('MACHINE = "qemux86-64"')
189 target_config.append('PR = "0"')
190 global_config.append(global_config[0])
191 target_config.append('PR = "1"')
192 global_config.append('MACHINE = "qemux86"')
193 target_config.append('PR = "1"')
194 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])
195
196 @testcase(974)
197 def test_sstate_cache_management_script_using_machine(self):
198 global_config = []
199 target_config = []
200 global_config.append('MACHINE = "qemux86-64"')
201 target_config.append('')
202 global_config.append('MACHINE = "qemux86"')
203 target_config.append('')
204 self.run_test_sstate_cache_management_script('m4', global_config, target_config, ignore_patterns=['populate_lic'])