1# 2# BitBake Tests for runqueue task processing 3# 4# Copyright (C) 2019 Richard Purdie 5# 6# SPDX-License-Identifier: GPL-2.0-only 7# 8 9import unittest 10import os 11import tempfile 12import subprocess 13import sys 14import time 15 16# 17# TODO: 18# Add tests on task ordering (X happens before Y after Z) 19# 20 21class RunQueueTests(unittest.TestCase): 22 23 alltasks = ['package', 'fetch', 'unpack', 'patch', 'prepare_recipe_sysroot', 'configure', 24 'compile', 'install', 'packagedata', 'package_qa', 'package_write_rpm', 'package_write_ipk', 25 'populate_sysroot', 'build'] 26 a1_sstatevalid = "a1:do_package a1:do_package_qa a1:do_packagedata a1:do_package_write_ipk a1:do_package_write_rpm a1:do_populate_lic a1:do_populate_sysroot" 27 b1_sstatevalid = "b1:do_package b1:do_package_qa b1:do_packagedata b1:do_package_write_ipk b1:do_package_write_rpm b1:do_populate_lic b1:do_populate_sysroot" 28 29 def run_bitbakecmd(self, cmd, builddir, sstatevalid="", slowtasks="", extraenv=None, cleanup=False): 30 env = os.environ.copy() 31 env["BBPATH"] = os.path.realpath(os.path.join(os.path.dirname(__file__), "runqueue-tests")) 32 env["BB_ENV_EXTRAWHITE"] = "SSTATEVALID SLOWTASKS" 33 env["SSTATEVALID"] = sstatevalid 34 env["SLOWTASKS"] = slowtasks 35 if extraenv: 36 for k in extraenv: 37 env[k] = extraenv[k] 38 env["BB_ENV_EXTRAWHITE"] = env["BB_ENV_EXTRAWHITE"] + " " + k 39 try: 40 output = subprocess.check_output(cmd, env=env, stderr=subprocess.STDOUT,universal_newlines=True, cwd=builddir) 41 print(output) 42 except subprocess.CalledProcessError as e: 43 self.fail("Command %s failed with %s" % (cmd, e.output)) 44 tasks = [] 45 tasklog = builddir + "/task.log" 46 if os.path.exists(tasklog): 47 with open(tasklog, "r") as f: 48 tasks = [line.rstrip() for line in f] 49 if cleanup: 50 os.remove(tasklog) 51 return tasks 52 53 def test_no_setscenevalid(self): 54 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 55 cmd = ["bitbake", "a1"] 56 sstatevalid = "" 57 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 58 expected = ['a1:' + x for x in self.alltasks] 59 self.assertEqual(set(tasks), set(expected)) 60 61 def test_single_setscenevalid(self): 62 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 63 cmd = ["bitbake", "a1"] 64 sstatevalid = "a1:do_package" 65 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 66 expected = ['a1:package_setscene', 'a1:fetch', 'a1:unpack', 'a1:patch', 'a1:prepare_recipe_sysroot', 'a1:configure', 67 'a1:compile', 'a1:install', 'a1:packagedata', 'a1:package_qa', 'a1:package_write_rpm', 'a1:package_write_ipk', 68 'a1:populate_sysroot', 'a1:build'] 69 self.assertEqual(set(tasks), set(expected)) 70 71 def test_intermediate_setscenevalid(self): 72 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 73 cmd = ["bitbake", "a1"] 74 sstatevalid = "a1:do_package a1:do_populate_sysroot" 75 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 76 expected = ['a1:package_setscene', 'a1:packagedata', 'a1:package_qa', 'a1:package_write_rpm', 'a1:package_write_ipk', 77 'a1:populate_sysroot_setscene', 'a1:build'] 78 self.assertEqual(set(tasks), set(expected)) 79 80 def test_intermediate_notcovered(self): 81 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 82 cmd = ["bitbake", "a1"] 83 sstatevalid = "a1:do_package_qa a1:do_packagedata a1:do_package_write_ipk a1:do_package_write_rpm a1:do_populate_lic a1:do_populate_sysroot" 84 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 85 expected = ['a1:package_write_ipk_setscene', 'a1:package_write_rpm_setscene', 'a1:packagedata_setscene', 86 'a1:package_qa_setscene', 'a1:build', 'a1:populate_sysroot_setscene'] 87 self.assertEqual(set(tasks), set(expected)) 88 89 def test_all_setscenevalid(self): 90 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 91 cmd = ["bitbake", "a1"] 92 sstatevalid = self.a1_sstatevalid 93 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 94 expected = ['a1:package_write_ipk_setscene', 'a1:package_write_rpm_setscene', 'a1:packagedata_setscene', 95 'a1:package_qa_setscene', 'a1:build', 'a1:populate_sysroot_setscene'] 96 self.assertEqual(set(tasks), set(expected)) 97 98 def test_no_settasks(self): 99 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 100 cmd = ["bitbake", "a1", "-c", "patch"] 101 sstatevalid = self.a1_sstatevalid 102 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 103 expected = ['a1:fetch', 'a1:unpack', 'a1:patch'] 104 self.assertEqual(set(tasks), set(expected)) 105 106 def test_mix_covered_notcovered(self): 107 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 108 cmd = ["bitbake", "a1:do_patch", "a1:do_populate_sysroot"] 109 sstatevalid = self.a1_sstatevalid 110 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 111 expected = ['a1:fetch', 'a1:unpack', 'a1:patch', 'a1:populate_sysroot_setscene'] 112 self.assertEqual(set(tasks), set(expected)) 113 114 115 # Test targets with intermediate setscene tasks alongside a target with no intermediate setscene tasks 116 def test_mixed_direct_tasks_setscene_tasks(self): 117 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 118 cmd = ["bitbake", "c1:do_patch", "a1"] 119 sstatevalid = self.a1_sstatevalid 120 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 121 expected = ['c1:fetch', 'c1:unpack', 'c1:patch', 'a1:package_write_ipk_setscene', 'a1:package_write_rpm_setscene', 'a1:packagedata_setscene', 122 'a1:package_qa_setscene', 'a1:build', 'a1:populate_sysroot_setscene'] 123 self.assertEqual(set(tasks), set(expected)) 124 125 # This test slows down the execution of do_package_setscene until after other real tasks have 126 # started running which tests for a bug where tasks were being lost from the buildable list of real 127 # tasks if they weren't in tasks_covered or tasks_notcovered 128 def test_slow_setscene(self): 129 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 130 cmd = ["bitbake", "a1"] 131 sstatevalid = "a1:do_package" 132 slowtasks = "a1:package_setscene" 133 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, slowtasks) 134 expected = ['a1:package_setscene', 'a1:fetch', 'a1:unpack', 'a1:patch', 'a1:prepare_recipe_sysroot', 'a1:configure', 135 'a1:compile', 'a1:install', 'a1:packagedata', 'a1:package_qa', 'a1:package_write_rpm', 'a1:package_write_ipk', 136 'a1:populate_sysroot', 'a1:build'] 137 self.assertEqual(set(tasks), set(expected)) 138 139 def test_setscenewhitelist(self): 140 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 141 cmd = ["bitbake", "a1"] 142 extraenv = { 143 "BB_SETSCENE_ENFORCE" : "1", 144 "BB_SETSCENE_ENFORCE_WHITELIST" : "a1:do_package_write_rpm a1:do_build" 145 } 146 sstatevalid = "a1:do_package a1:do_package_qa a1:do_packagedata a1:do_package_write_ipk a1:do_populate_lic a1:do_populate_sysroot" 147 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv) 148 expected = ['a1:packagedata_setscene', 'a1:package_qa_setscene', 'a1:package_write_ipk_setscene', 149 'a1:populate_sysroot_setscene', 'a1:package_setscene'] 150 self.assertEqual(set(tasks), set(expected)) 151 152 # Tests for problems with dependencies between setscene tasks 153 def test_no_setscenevalid_harddeps(self): 154 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 155 cmd = ["bitbake", "d1"] 156 sstatevalid = "" 157 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 158 expected = ['a1:package', 'a1:fetch', 'a1:unpack', 'a1:patch', 'a1:prepare_recipe_sysroot', 'a1:configure', 159 'a1:compile', 'a1:install', 'a1:packagedata', 'a1:package_write_rpm', 'a1:package_write_ipk', 160 'a1:populate_sysroot', 'd1:package', 'd1:fetch', 'd1:unpack', 'd1:patch', 'd1:prepare_recipe_sysroot', 'd1:configure', 161 'd1:compile', 'd1:install', 'd1:packagedata', 'd1:package_qa', 'd1:package_write_rpm', 'd1:package_write_ipk', 162 'd1:populate_sysroot', 'd1:build'] 163 self.assertEqual(set(tasks), set(expected)) 164 165 def test_no_setscenevalid_withdeps(self): 166 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 167 cmd = ["bitbake", "b1"] 168 sstatevalid = "" 169 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 170 expected = ['a1:' + x for x in self.alltasks] + ['b1:' + x for x in self.alltasks] 171 expected.remove('a1:build') 172 expected.remove('a1:package_qa') 173 self.assertEqual(set(tasks), set(expected)) 174 175 def test_single_a1_setscenevalid_withdeps(self): 176 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 177 cmd = ["bitbake", "b1"] 178 sstatevalid = "a1:do_package" 179 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 180 expected = ['a1:package_setscene', 'a1:fetch', 'a1:unpack', 'a1:patch', 'a1:prepare_recipe_sysroot', 'a1:configure', 181 'a1:compile', 'a1:install', 'a1:packagedata', 'a1:package_write_rpm', 'a1:package_write_ipk', 182 'a1:populate_sysroot'] + ['b1:' + x for x in self.alltasks] 183 self.assertEqual(set(tasks), set(expected)) 184 185 def test_single_b1_setscenevalid_withdeps(self): 186 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 187 cmd = ["bitbake", "b1"] 188 sstatevalid = "b1:do_package" 189 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 190 expected = ['a1:package', 'a1:fetch', 'a1:unpack', 'a1:patch', 'a1:prepare_recipe_sysroot', 'a1:configure', 191 'a1:compile', 'a1:install', 'a1:packagedata', 'a1:package_write_rpm', 'a1:package_write_ipk', 192 'a1:populate_sysroot', 'b1:package_setscene'] + ['b1:' + x for x in self.alltasks] 193 expected.remove('b1:package') 194 self.assertEqual(set(tasks), set(expected)) 195 196 def test_intermediate_setscenevalid_withdeps(self): 197 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 198 cmd = ["bitbake", "b1"] 199 sstatevalid = "a1:do_package a1:do_populate_sysroot b1:do_package" 200 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 201 expected = ['a1:package_setscene', 'a1:packagedata', 'a1:package_write_rpm', 'a1:package_write_ipk', 202 'a1:populate_sysroot_setscene', 'b1:package_setscene'] + ['b1:' + x for x in self.alltasks] 203 expected.remove('b1:package') 204 self.assertEqual(set(tasks), set(expected)) 205 206 def test_all_setscenevalid_withdeps(self): 207 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 208 cmd = ["bitbake", "b1"] 209 sstatevalid = self.a1_sstatevalid + " " + self.b1_sstatevalid 210 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid) 211 expected = ['a1:package_write_ipk_setscene', 'a1:package_write_rpm_setscene', 'a1:packagedata_setscene', 212 'b1:build', 'a1:populate_sysroot_setscene', 'b1:package_write_ipk_setscene', 'b1:package_write_rpm_setscene', 213 'b1:packagedata_setscene', 'b1:package_qa_setscene', 'b1:populate_sysroot_setscene'] 214 self.assertEqual(set(tasks), set(expected)) 215 216 def test_multiconfig_setscene_optimise(self): 217 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 218 extraenv = { 219 "BBMULTICONFIG" : "mc-1 mc_2", 220 "BB_SIGNATURE_HANDLER" : "basic" 221 } 222 cmd = ["bitbake", "b1", "mc:mc-1:b1", "mc:mc_2:b1"] 223 setscenetasks = ['package_write_ipk_setscene', 'package_write_rpm_setscene', 'packagedata_setscene', 224 'populate_sysroot_setscene', 'package_qa_setscene'] 225 sstatevalid = "" 226 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv) 227 expected = ['a1:' + x for x in self.alltasks] + ['b1:' + x for x in self.alltasks] + \ 228 ['mc-1:b1:' + x for x in setscenetasks] + ['mc-1:a1:' + x for x in setscenetasks] + \ 229 ['mc_2:b1:' + x for x in setscenetasks] + ['mc_2:a1:' + x for x in setscenetasks] + \ 230 ['mc-1:b1:build', 'mc_2:b1:build'] 231 for x in ['mc-1:a1:package_qa_setscene', 'mc_2:a1:package_qa_setscene', 'a1:build', 'a1:package_qa']: 232 expected.remove(x) 233 self.assertEqual(set(tasks), set(expected)) 234 235 def test_multiconfig_bbmask(self): 236 # This test validates that multiconfigs can independently mask off 237 # recipes they do not want with BBMASK. It works by having recipes 238 # that will fail to parse for mc-1 and mc_2, then making each multiconfig 239 # build the one that does parse. This ensures that the recipes are in 240 # each multiconfigs BBFILES, but each is masking only the one that 241 # doesn't parse 242 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 243 extraenv = { 244 "BBMULTICONFIG" : "mc-1 mc_2", 245 "BB_SIGNATURE_HANDLER" : "basic", 246 "EXTRA_BBFILES": "${COREBASE}/recipes/fails-mc/*.bb", 247 } 248 cmd = ["bitbake", "mc:mc-1:fails-mc2", "mc:mc_2:fails-mc1"] 249 self.run_bitbakecmd(cmd, tempdir, "", extraenv=extraenv) 250 251 def test_multiconfig_mcdepends(self): 252 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 253 extraenv = { 254 "BBMULTICONFIG" : "mc-1 mc_2", 255 "BB_SIGNATURE_HANDLER" : "TestMulticonfigDepends", 256 "EXTRA_BBFILES": "${COREBASE}/recipes/fails-mc/*.bb", 257 } 258 tasks = self.run_bitbakecmd(["bitbake", "mc:mc-1:f1"], tempdir, "", extraenv=extraenv, cleanup=True) 259 expected = ["mc-1:f1:%s" % t for t in self.alltasks] + \ 260 ["mc_2:a1:%s" % t for t in self.alltasks] 261 self.assertEqual(set(tasks), set(expected)) 262 263 # A rebuild does nothing 264 tasks = self.run_bitbakecmd(["bitbake", "mc:mc-1:f1"], tempdir, "", extraenv=extraenv, cleanup=True) 265 self.assertEqual(set(tasks), set()) 266 267 # Test that a signature change in the dependent task causes 268 # mcdepends to rebuild 269 tasks = self.run_bitbakecmd(["bitbake", "mc:mc_2:a1", "-c", "compile", "-f"], tempdir, "", extraenv=extraenv, cleanup=True) 270 expected = ["mc_2:a1:compile"] 271 self.assertEqual(set(tasks), set(expected)) 272 273 rerun_tasks = self.alltasks[:] 274 for x in ("fetch", "unpack", "patch", "prepare_recipe_sysroot", "configure", "compile"): 275 rerun_tasks.remove(x) 276 tasks = self.run_bitbakecmd(["bitbake", "mc:mc-1:f1"], tempdir, "", extraenv=extraenv, cleanup=True) 277 expected = ["mc-1:f1:%s" % t for t in rerun_tasks] + \ 278 ["mc_2:a1:%s" % t for t in rerun_tasks] 279 self.assertEqual(set(tasks), set(expected)) 280 281 @unittest.skipIf(sys.version_info < (3, 5, 0), 'Python 3.5 or later required') 282 def test_hashserv_single(self): 283 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 284 extraenv = { 285 "BB_HASHSERVE" : "auto", 286 "BB_SIGNATURE_HANDLER" : "TestEquivHash" 287 } 288 cmd = ["bitbake", "a1", "b1"] 289 setscenetasks = ['package_write_ipk_setscene', 'package_write_rpm_setscene', 'packagedata_setscene', 290 'populate_sysroot_setscene', 'package_qa_setscene'] 291 sstatevalid = "" 292 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 293 expected = ['a1:' + x for x in self.alltasks] + ['b1:' + x for x in self.alltasks] 294 self.assertEqual(set(tasks), set(expected)) 295 cmd = ["bitbake", "a1", "-c", "install", "-f"] 296 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 297 expected = ['a1:install'] 298 self.assertEqual(set(tasks), set(expected)) 299 cmd = ["bitbake", "a1", "b1"] 300 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 301 expected = ['a1:populate_sysroot', 'a1:package', 'a1:package_write_rpm_setscene', 'a1:packagedata_setscene', 302 'a1:package_write_ipk_setscene', 'a1:package_qa_setscene', 'a1:build'] 303 self.assertEqual(set(tasks), set(expected)) 304 305 self.shutdown(tempdir) 306 307 @unittest.skipIf(sys.version_info < (3, 5, 0), 'Python 3.5 or later required') 308 def test_hashserv_double(self): 309 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 310 extraenv = { 311 "BB_HASHSERVE" : "auto", 312 "BB_SIGNATURE_HANDLER" : "TestEquivHash" 313 } 314 cmd = ["bitbake", "a1", "b1", "e1"] 315 setscenetasks = ['package_write_ipk_setscene', 'package_write_rpm_setscene', 'packagedata_setscene', 316 'populate_sysroot_setscene', 'package_qa_setscene'] 317 sstatevalid = "" 318 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 319 expected = ['a1:' + x for x in self.alltasks] + ['b1:' + x for x in self.alltasks] + ['e1:' + x for x in self.alltasks] 320 self.assertEqual(set(tasks), set(expected)) 321 cmd = ["bitbake", "a1", "b1", "-c", "install", "-fn"] 322 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 323 cmd = ["bitbake", "e1"] 324 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 325 expected = ['a1:package', 'a1:install', 'b1:package', 'b1:install', 'a1:populate_sysroot', 'b1:populate_sysroot', 326 'a1:package_write_ipk_setscene', 'b1:packagedata_setscene', 'b1:package_write_rpm_setscene', 327 'a1:package_write_rpm_setscene', 'b1:package_write_ipk_setscene', 'a1:packagedata_setscene'] 328 self.assertEqual(set(tasks), set(expected)) 329 330 self.shutdown(tempdir) 331 332 @unittest.skipIf(sys.version_info < (3, 5, 0), 'Python 3.5 or later required') 333 def test_hashserv_multiple_setscene(self): 334 # Runs e1:do_package_setscene twice 335 with tempfile.TemporaryDirectory(prefix="runqueuetest") as tempdir: 336 extraenv = { 337 "BB_HASHSERVE" : "auto", 338 "BB_SIGNATURE_HANDLER" : "TestEquivHash" 339 } 340 cmd = ["bitbake", "a1", "b1", "e1"] 341 setscenetasks = ['package_write_ipk_setscene', 'package_write_rpm_setscene', 'packagedata_setscene', 342 'populate_sysroot_setscene', 'package_qa_setscene'] 343 sstatevalid = "" 344 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 345 expected = ['a1:' + x for x in self.alltasks] + ['b1:' + x for x in self.alltasks] + ['e1:' + x for x in self.alltasks] 346 self.assertEqual(set(tasks), set(expected)) 347 cmd = ["bitbake", "a1", "b1", "-c", "install", "-fn"] 348 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True) 349 cmd = ["bitbake", "e1"] 350 sstatevalid = "e1:do_package" 351 tasks = self.run_bitbakecmd(cmd, tempdir, sstatevalid, extraenv=extraenv, cleanup=True, slowtasks="a1:populate_sysroot b1:populate_sysroot") 352 expected = ['a1:package', 'a1:install', 'b1:package', 'b1:install', 'a1:populate_sysroot', 'b1:populate_sysroot', 353 'a1:package_write_ipk_setscene', 'b1:packagedata_setscene', 'b1:package_write_rpm_setscene', 354 'a1:package_write_rpm_setscene', 'b1:package_write_ipk_setscene', 'a1:packagedata_setscene', 355 'e1:package_setscene'] 356 self.assertEqual(set(tasks), set(expected)) 357 for i in expected: 358 self.assertEqual(tasks.count(i), 1, "%s not in task list once" % i) 359 360 self.shutdown(tempdir) 361 362 def shutdown(self, tempdir): 363 # Wait for the hashserve socket to disappear else we'll see races with the tempdir cleanup 364 while os.path.exists(tempdir + "/hashserve.sock"): 365 time.sleep(0.5) 366 367 368