1# 2# SPDX-License-Identifier: MIT 3# 4 5from oeqa.selftest.case import OESelftestTestCase 6from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu 7from oeqa.core.decorator import OETestTag 8import os 9import tempfile 10import oe.lsb 11from oeqa.core.decorator.data import skipIfNotQemu 12 13class TestExport(OESelftestTestCase): 14 15 @OETestTag("runqemu") 16 def test_testexport_basic(self): 17 """ 18 Summary: Check basic testexport functionality with only ping test enabled. 19 Expected: 1. testexport directory must be created. 20 2. runexported.py must run without any error/exception. 21 3. ping test must succeed. 22 Product: oe-core 23 Author: Mariano Lopez <mariano.lopez@intel.com> 24 """ 25 26 features = 'INHERIT += "testexport"\n' 27 # These aren't the actual IP addresses but testexport class needs something defined 28 features += 'TEST_SERVER_IP = "192.168.7.1"\n' 29 features += 'TEST_TARGET_IP = "192.168.7.1"\n' 30 features += 'TEST_SUITES = "ping"\n' 31 self.write_config(features) 32 33 # Build tesexport for core-image-minimal 34 bitbake('core-image-minimal') 35 bitbake('-c testexport core-image-minimal') 36 37 testexport_dir = get_bb_var('TEST_EXPORT_DIR', 'core-image-minimal') 38 39 # Verify if TEST_EXPORT_DIR was created 40 isdir = os.path.isdir(testexport_dir) 41 self.assertEqual(True, isdir, 'Failed to create testexport dir: %s' % testexport_dir) 42 43 with runqemu('core-image-minimal') as qemu: 44 # Attempt to run runexported.py to perform ping test 45 test_path = os.path.join(testexport_dir, "oe-test") 46 data_file = os.path.join(testexport_dir, 'data', 'testdata.json') 47 manifest = os.path.join(testexport_dir, 'data', 'manifest') 48 cmd = ("%s runtime --test-data-file %s --packages-manifest %s " 49 "--target-ip %s --server-ip %s --quiet" 50 % (test_path, data_file, manifest, qemu.ip, qemu.server_ip)) 51 result = runCmd(cmd) 52 # Verify ping test was succesful 53 self.assertEqual(0, result.status, 'oe-test runtime returned a non 0 status') 54 55 def test_testexport_sdk(self): 56 """ 57 Summary: Check sdk functionality for testexport. 58 Expected: 1. testexport directory must be created. 59 2. SDK tarball must exists. 60 3. Uncompressing of tarball must succeed. 61 4. Check if the SDK directory is added to PATH. 62 5. Run tar from the SDK directory. 63 Product: oe-core 64 Author: Mariano Lopez <mariano.lopez@intel.com> 65 """ 66 67 features = 'INHERIT += "testexport"\n' 68 # These aren't the actual IP addresses but testexport class needs something defined 69 features += 'TEST_SERVER_IP = "192.168.7.1"\n' 70 features += 'TEST_TARGET_IP = "192.168.7.1"\n' 71 features += 'TEST_SUITES = "ping"\n' 72 features += 'TEST_EXPORT_SDK_ENABLED = "1"\n' 73 features += 'TEST_EXPORT_SDK_PACKAGES = "nativesdk-tar"\n' 74 self.write_config(features) 75 76 # Build tesexport for core-image-minimal 77 bitbake('core-image-minimal') 78 bitbake('-c testexport core-image-minimal') 79 80 needed_vars = ['TEST_EXPORT_DIR', 'TEST_EXPORT_SDK_DIR', 'TEST_EXPORT_SDK_NAME'] 81 bb_vars = get_bb_vars(needed_vars, 'core-image-minimal') 82 testexport_dir = bb_vars['TEST_EXPORT_DIR'] 83 sdk_dir = bb_vars['TEST_EXPORT_SDK_DIR'] 84 sdk_name = bb_vars['TEST_EXPORT_SDK_NAME'] 85 86 # Check for SDK 87 tarball_name = "%s.sh" % sdk_name 88 tarball_path = os.path.join(testexport_dir, sdk_dir, tarball_name) 89 msg = "Couldn't find SDK tarball: %s" % tarball_path 90 self.assertEqual(os.path.isfile(tarball_path), True, msg) 91 92 with tempfile.TemporaryDirectory() as tmpdirname: 93 # Extract SDK and run tar from SDK 94 result = runCmd("%s -y -d %s" % (tarball_path, tmpdirname)) 95 self.assertEqual(0, result.status, "Couldn't extract SDK") 96 97 env_script = result.output.split()[-1] 98 result = runCmd(". %s; which tar" % env_script, shell=True) 99 self.assertEqual(0, result.status, "Couldn't setup SDK environment") 100 is_sdk_tar = True if tmpdirname in result.output else False 101 self.assertTrue(is_sdk_tar, "Couldn't setup SDK environment") 102 103 tar_sdk = result.output 104 result = runCmd("%s --version" % tar_sdk) 105 self.assertEqual(0, result.status, "Couldn't run tar from SDK") 106 107 108@OETestTag("runqemu") 109class TestImage(OESelftestTestCase): 110 111 def test_testimage_install(self): 112 """ 113 Summary: Check install packages functionality for testimage/testexport. 114 Expected: 1. Import tests from a directory other than meta. 115 2. Check install/uninstall of socat. 116 Product: oe-core 117 Author: Mariano Lopez <mariano.lopez@intel.com> 118 """ 119 if get_bb_var('DISTRO') == 'poky-tiny': 120 self.skipTest('core-image-full-cmdline not buildable for poky-tiny') 121 122 features = 'INHERIT += "testimage"\n' 123 features += 'IMAGE_INSTALL:append = " libssl"\n' 124 features += 'TEST_SUITES = "ping ssh selftest"\n' 125 self.write_config(features) 126 127 bitbake('core-image-full-cmdline socat') 128 bitbake('-c testimage core-image-full-cmdline') 129 130 def test_testimage_dnf(self): 131 """ 132 Summary: Check package feeds functionality for dnf 133 Expected: 1. Check that remote package feeds can be accessed 134 Product: oe-core 135 Author: Alexander Kanavin <alex.kanavin@gmail.com> 136 """ 137 if get_bb_var('DISTRO') == 'poky-tiny': 138 self.skipTest('core-image-full-cmdline not buildable for poky-tiny') 139 140 features = 'INHERIT += "testimage"\n' 141 features += 'TEST_SUITES = "ping ssh dnf_runtime dnf.DnfBasicTest.test_dnf_help"\n' 142 # We don't yet know what the server ip and port will be - they will be patched 143 # in at the start of the on-image test 144 features += 'PACKAGE_FEED_URIS = "http://bogus_ip:bogus_port"\n' 145 features += 'EXTRA_IMAGE_FEATURES += "package-management"\n' 146 features += 'PACKAGE_CLASSES = "package_rpm"\n' 147 148 bitbake('gnupg-native -c addto_recipe_sysroot') 149 150 # Enable package feed signing 151 self.gpg_home = tempfile.mkdtemp(prefix="oeqa-feed-sign-") 152 self.track_for_cleanup(self.gpg_home) 153 signing_key_dir = os.path.join(self.testlayer_path, 'files', 'signing') 154 runCmd('gpgconf --list-dirs --homedir %s; gpg -v --batch --homedir %s --import %s' % (self.gpg_home, self.gpg_home, os.path.join(signing_key_dir, 'key.secret')), native_sysroot=get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native"), shell=True) 155 features += 'INHERIT += "sign_package_feed"\n' 156 features += 'PACKAGE_FEED_GPG_NAME = "testuser"\n' 157 features += 'PACKAGE_FEED_GPG_PASSPHRASE_FILE = "%s"\n' % os.path.join(signing_key_dir, 'key.passphrase') 158 features += 'GPG_PATH = "%s"\n' % self.gpg_home 159 features += 'PSEUDO_IGNORE_PATHS .= ",%s"\n' % self.gpg_home 160 self.write_config(features) 161 162 bitbake('core-image-full-cmdline socat') 163 bitbake('-c testimage core-image-full-cmdline') 164 165 def test_testimage_apt(self): 166 """ 167 Summary: Check package feeds functionality for apt 168 Expected: 1. Check that remote package feeds can be accessed 169 Product: oe-core 170 Author: Ferry Toth <fntoth@gmail.com> 171 """ 172 if get_bb_var('DISTRO') == 'poky-tiny': 173 self.skipTest('core-image-full-cmdline not buildable for poky-tiny') 174 175 features = 'INHERIT += "testimage"\n' 176 features += 'TEST_SUITES = "ping ssh apt.AptRepoTest.test_apt_install_from_repo"\n' 177 # We don't yet know what the server ip and port will be - they will be patched 178 # in at the start of the on-image test 179 features += 'PACKAGE_FEED_URIS = "http://bogus_ip:bogus_port"\n' 180 features += 'EXTRA_IMAGE_FEATURES += "package-management"\n' 181 features += 'PACKAGE_CLASSES = "package_deb"\n' 182 # We need gnupg on the target to install keys 183 features += 'IMAGE_INSTALL:append:pn-core-image-full-cmdline = " gnupg"\n' 184 185 bitbake('gnupg-native -c addto_recipe_sysroot') 186 187 # Enable package feed signing 188 self.gpg_home = tempfile.mkdtemp(prefix="oeqa-feed-sign-") 189 self.track_for_cleanup(self.gpg_home) 190 signing_key_dir = os.path.join(self.testlayer_path, 'files', 'signing') 191 runCmd('gpgconf --list-dirs --homedir %s; gpg -v --batch --homedir %s --import %s' % (self.gpg_home, self.gpg_home, os.path.join(signing_key_dir, 'key.secret')), native_sysroot=get_bb_var("RECIPE_SYSROOT_NATIVE", "gnupg-native"), shell=True) 192 features += 'INHERIT += "sign_package_feed"\n' 193 features += 'PACKAGE_FEED_GPG_NAME = "testuser"\n' 194 features += 'PACKAGE_FEED_GPG_PASSPHRASE_FILE = "%s"\n' % os.path.join(signing_key_dir, 'key.passphrase') 195 features += 'GPG_PATH = "%s"\n' % self.gpg_home 196 features += 'PSEUDO_IGNORE_PATHS .= ",%s"\n' % self.gpg_home 197 self.write_config(features) 198 199 # Build core-image-sato and testimage 200 bitbake('core-image-full-cmdline socat') 201 bitbake('-c testimage core-image-full-cmdline') 202 203 def test_testimage_virgl_gtk_sdl(self): 204 """ 205 Summary: Check host-assisted accelerate OpenGL functionality in qemu with gtk and SDL frontends 206 Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled 207 2. Check that kmscube demo runs without crashing. 208 Product: oe-core 209 Author: Alexander Kanavin <alex.kanavin@gmail.com> 210 """ 211 if "DISPLAY" not in os.environ: 212 self.skipTest("virgl gtk test must be run inside a X session") 213 distro = oe.lsb.distro_identifier() 214 if distro and distro == 'debian-8': 215 self.skipTest('virgl isn\'t working with Debian 8') 216 if distro and distro == 'debian-9': 217 self.skipTest('virgl isn\'t working with Debian 9') 218 if distro and distro == 'centos-7': 219 self.skipTest('virgl isn\'t working with Centos 7') 220 if distro and distro == 'opensuseleap-15.0': 221 self.skipTest('virgl isn\'t working with Opensuse 15.0') 222 223 qemu_packageconfig = get_bb_var('PACKAGECONFIG', 'qemu-system-native') 224 qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') 225 features = 'INHERIT += "testimage"\n' 226 if 'gtk+' not in qemu_packageconfig: 227 features += 'PACKAGECONFIG:append:pn-qemu-system-native = " gtk+"\n' 228 if 'sdl' not in qemu_packageconfig: 229 features += 'PACKAGECONFIG:append:pn-qemu-system-native = " sdl"\n' 230 if 'opengl' not in qemu_distrofeatures: 231 features += 'DISTRO_FEATURES:append = " opengl"\n' 232 features += 'TEST_SUITES = "ping ssh virgl"\n' 233 features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' 234 features += 'IMAGE_INSTALL:append = " kmscube"\n' 235 features_gtk = features + 'TEST_RUNQEMUPARAMS = "gtk gl"\n' 236 self.write_config(features_gtk) 237 bitbake('core-image-minimal') 238 bitbake('-c testimage core-image-minimal') 239 features_sdl = features + 'TEST_RUNQEMUPARAMS = "sdl gl"\n' 240 self.write_config(features_sdl) 241 bitbake('core-image-minimal') 242 bitbake('-c testimage core-image-minimal') 243 244 def test_testimage_virgl_headless(self): 245 """ 246 Summary: Check host-assisted accelerate OpenGL functionality in qemu with egl-headless frontend 247 Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled 248 2. Check that kmscube demo runs without crashing. 249 Product: oe-core 250 Author: Alexander Kanavin <alex.kanavin@gmail.com> 251 """ 252 import subprocess, os 253 254 distro = oe.lsb.distro_identifier() 255 if distro and (distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'ubuntu-16.04', 'ubuntu-18.04'] or 256 distro.startswith('almalinux') or distro.startswith('rocky')): 257 self.skipTest('virgl headless cannot be tested with %s' %(distro)) 258 259 render_hint = """If /dev/dri/renderD* is absent due to lack of suitable GPU, 'modprobe vgem' will create one suitable for mesa llvmpipe software renderer.""" 260 try: 261 content = os.listdir("/dev/dri") 262 if len([i for i in content if i.startswith('render')]) == 0: 263 self.fail("No render nodes found in /dev/dri: %s. %s" %(content, render_hint)) 264 except FileNotFoundError: 265 self.fail("/dev/dri directory does not exist; no render nodes available on this machine. %s" %(render_hint)) 266 try: 267 dripath = subprocess.check_output("PATH=/bin:/usr/bin:$PATH pkg-config --variable=dridriverdir dri", shell=True) 268 except subprocess.CalledProcessError as e: 269 self.fail("Could not determine the path to dri drivers on the host via pkg-config.\nPlease install Mesa development files (particularly, dri.pc) on the host machine.") 270 qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') 271 features = 'INHERIT += "testimage"\n' 272 if 'opengl' not in qemu_distrofeatures: 273 features += 'DISTRO_FEATURES:append = " opengl"\n' 274 features += 'TEST_SUITES = "ping ssh virgl"\n' 275 features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' 276 features += 'IMAGE_INSTALL:append = " kmscube"\n' 277 features += 'TEST_RUNQEMUPARAMS = "egl-headless"\n' 278 self.write_config(features) 279 bitbake('core-image-minimal') 280 bitbake('-c testimage core-image-minimal') 281 282@OETestTag("runqemu") 283class Postinst(OESelftestTestCase): 284 285 def init_manager_loop(self, init_manager): 286 import oe.path 287 288 vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal") 289 rootfs = vars["IMAGE_ROOTFS"] 290 self.assertIsNotNone(rootfs) 291 sysconfdir = vars["sysconfdir"] 292 self.assertIsNotNone(sysconfdir) 293 # Need to use oe.path here as sysconfdir starts with / 294 hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test") 295 targettestdir = os.path.join(sysconfdir, "postinst-test") 296 297 for classes in ("package_rpm", "package_deb", "package_ipk"): 298 with self.subTest(init_manager=init_manager, package_class=classes): 299 features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-delayed-b"\n' 300 features += 'IMAGE_FEATURES += "package-management empty-root-password"\n' 301 features += 'PACKAGE_CLASSES = "%s"\n' % classes 302 if init_manager == "systemd": 303 features += 'DISTRO_FEATURES:append = " systemd"\n' 304 features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' 305 features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' 306 features += 'VIRTUAL-RUNTIME_initscripts = ""\n' 307 self.write_config(features) 308 309 bitbake('core-image-minimal') 310 311 self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs")), 312 "rootfs state file was not created") 313 314 with runqemu('core-image-minimal') as qemu: 315 # Make the test echo a string and search for that as 316 # run_serial()'s status code is useless.' 317 for filename in ("rootfs", "delayed-a", "delayed-b"): 318 status, output = qemu.run_serial("test -f %s && echo found" % os.path.join(targettestdir, filename)) 319 self.assertIn("found", output, "%s was not present on boot" % filename) 320 321 322 323 @skipIfNotQemu() 324 def test_postinst_rootfs_and_boot_sysvinit(self): 325 """ 326 Summary: The purpose of this test case is to verify Post-installation 327 scripts are called when rootfs is created and also test 328 that script can be delayed to run at first boot. 329 Dependencies: NA 330 Steps: 1. Add proper configuration to local.conf file 331 2. Build a "core-image-minimal" image 332 3. Verify that file created by postinst_rootfs recipe is 333 present on rootfs dir. 334 4. Boot the image created on qemu and verify that the file 335 created by postinst_boot recipe is present on image. 336 Expected: The files are successfully created during rootfs and boot 337 time for 3 different package managers: rpm,ipk,deb and 338 for initialization managers: sysvinit. 339 340 """ 341 self.init_manager_loop("sysvinit") 342 343 344 @skipIfNotQemu() 345 def test_postinst_rootfs_and_boot_systemd(self): 346 """ 347 Summary: The purpose of this test case is to verify Post-installation 348 scripts are called when rootfs is created and also test 349 that script can be delayed to run at first boot. 350 Dependencies: NA 351 Steps: 1. Add proper configuration to local.conf file 352 2. Build a "core-image-minimal" image 353 3. Verify that file created by postinst_rootfs recipe is 354 present on rootfs dir. 355 4. Boot the image created on qemu and verify that the file 356 created by postinst_boot recipe is present on image. 357 Expected: The files are successfully created during rootfs and boot 358 time for 3 different package managers: rpm,ipk,deb and 359 for initialization managers: systemd. 360 361 """ 362 363 self.init_manager_loop("systemd") 364 365 366 def test_failing_postinst(self): 367 """ 368 Summary: The purpose of this test case is to verify that post-installation 369 scripts that contain errors are properly reported. 370 Expected: The scriptlet failure is properly reported. 371 The file that is created after the error in the scriptlet is not present. 372 Product: oe-core 373 Author: Alexander Kanavin <alex.kanavin@gmail.com> 374 """ 375 376 import oe.path 377 378 vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal") 379 rootfs = vars["IMAGE_ROOTFS"] 380 self.assertIsNotNone(rootfs) 381 sysconfdir = vars["sysconfdir"] 382 self.assertIsNotNone(sysconfdir) 383 # Need to use oe.path here as sysconfdir starts with / 384 hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test") 385 386 for classes in ("package_rpm", "package_deb", "package_ipk"): 387 with self.subTest(package_class=classes): 388 features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-rootfs-failing"\n' 389 features += 'PACKAGE_CLASSES = "%s"\n' % classes 390 self.write_config(features) 391 bb_result = bitbake('core-image-minimal', ignore_status=True) 392 self.assertGreaterEqual(bb_result.output.find("Postinstall scriptlets of ['postinst-rootfs-failing'] have failed."), 0, 393 "Warning about a failed scriptlet not found in bitbake output: %s" %(bb_result.output)) 394 395 self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs-before-failure")), 396 "rootfs-before-failure file was not created") 397 self.assertFalse(os.path.isfile(os.path.join(hosttestdir, "rootfs-after-failure")), 398 "rootfs-after-failure file was created") 399 400@OETestTag("runqemu") 401class SystemTap(OESelftestTestCase): 402 """ 403 Summary: The purpose of this test case is to verify native crosstap 404 works while talking to a target. 405 Expected: The script should successfully connect to the qemu machine 406 and run some systemtap examples on a qemu machine. 407 """ 408 409 @classmethod 410 def setUpClass(cls): 411 super(SystemTap, cls).setUpClass() 412 cls.image = "core-image-minimal" 413 414 def default_config(self): 415 return """ 416# These aren't the actual IP addresses but testexport class needs something defined 417TEST_SERVER_IP = "192.168.7.1" 418TEST_TARGET_IP = "192.168.7.2" 419 420EXTRA_IMAGE_FEATURES += "tools-profile dbg-pkgs" 421IMAGE_FEATURES:append = " ssh-server-dropbear" 422 423# enables kernel debug symbols 424KERNEL_EXTRA_FEATURES:append = " features/debug/debug-kernel.scc" 425KERNEL_EXTRA_FEATURES:append = " features/systemtap/systemtap.scc" 426 427# add systemtap run-time into target image if it is not there yet 428IMAGE_INSTALL:append = " systemtap-runtime" 429""" 430 431 def test_crosstap_helloworld(self): 432 self.write_config(self.default_config()) 433 bitbake('systemtap-native') 434 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 435 bitbake(self.image) 436 437 with runqemu(self.image) as qemu: 438 cmd = "crosstap -r root@192.168.7.2 -s %s/general/helloworld.stp " % systemtap_examples 439 result = runCmd(cmd) 440 self.assertEqual(0, result.status, 'crosstap helloworld returned a non 0 status:%s' % result.output) 441 442 def test_crosstap_pstree(self): 443 self.write_config(self.default_config()) 444 445 bitbake('systemtap-native') 446 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 447 bitbake(self.image) 448 449 with runqemu(self.image) as qemu: 450 cmd = "crosstap -r root@192.168.7.2 -s %s/process/pstree.stp" % systemtap_examples 451 result = runCmd(cmd) 452 self.assertEqual(0, result.status, 'crosstap pstree returned a non 0 status:%s' % result.output) 453 454 def test_crosstap_syscalls_by_proc(self): 455 self.write_config(self.default_config()) 456 457 bitbake('systemtap-native') 458 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 459 bitbake(self.image) 460 461 with runqemu(self.image) as qemu: 462 cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_proc.stp" % systemtap_examples 463 result = runCmd(cmd) 464 self.assertEqual(0, result.status, 'crosstap syscalls_by_proc returned a non 0 status:%s' % result.output) 465 466 def test_crosstap_syscalls_by_pid(self): 467 self.write_config(self.default_config()) 468 469 bitbake('systemtap-native') 470 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 471 bitbake(self.image) 472 473 with runqemu(self.image) as qemu: 474 cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_pid.stp" % systemtap_examples 475 result = runCmd(cmd) 476 self.assertEqual(0, result.status, 'crosstap syscalls_by_pid returned a non 0 status:%s' % result.output) 477