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