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, skipIfNotMachine 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_slirp(self): 133 """ 134 Summary: Check basic testimage functionality with qemu and slirp networking. 135 """ 136 137 features = ''' 138IMAGE_CLASSES:append = " testimage" 139IMAGE_FEATURES:append = " ssh-server-dropbear" 140IMAGE_ROOTFS_EXTRA_SPACE:append = "${@bb.utils.contains("IMAGE_CLASSES", "testimage", " + 5120", "", d)}" 141TEST_RUNQEMUPARAMS += " slirp" 142''' 143 self.write_config(features) 144 145 bitbake('core-image-minimal') 146 bitbake('-c testimage core-image-minimal') 147 148 def test_testimage_dnf(self): 149 """ 150 Summary: Check package feeds functionality for dnf 151 Expected: 1. Check that remote package feeds can be accessed 152 Product: oe-core 153 Author: Alexander Kanavin <alex.kanavin@gmail.com> 154 """ 155 if get_bb_var('DISTRO') == 'poky-tiny': 156 self.skipTest('core-image-full-cmdline not buildable for poky-tiny') 157 158 features = 'IMAGE_CLASSES += "testimage"\n' 159 features += 'TEST_SUITES = "ping ssh dnf_runtime dnf.DnfBasicTest.test_dnf_help"\n' 160 # We don't yet know what the server ip and port will be - they will be patched 161 # in at the start of the on-image test 162 features += 'PACKAGE_FEED_URIS = "http://bogus_ip:bogus_port"\n' 163 features += 'EXTRA_IMAGE_FEATURES += "package-management"\n' 164 features += 'PACKAGE_CLASSES = "package_rpm"\n' 165 166 bitbake('gnupg-native -c addto_recipe_sysroot') 167 168 # Enable package feed signing 169 self.gpg_home = tempfile.mkdtemp(prefix="oeqa-feed-sign-") 170 self.track_for_cleanup(self.gpg_home) 171 signing_key_dir = os.path.join(self.testlayer_path, 'files', 'signing') 172 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) 173 features += 'INHERIT += "sign_package_feed"\n' 174 features += 'PACKAGE_FEED_GPG_NAME = "testuser"\n' 175 features += 'PACKAGE_FEED_GPG_PASSPHRASE_FILE = "%s"\n' % os.path.join(signing_key_dir, 'key.passphrase') 176 features += 'GPG_PATH = "%s"\n' % self.gpg_home 177 features += 'PSEUDO_IGNORE_PATHS .= ",%s"\n' % self.gpg_home 178 self.write_config(features) 179 180 bitbake('core-image-full-cmdline socat') 181 bitbake('-c testimage core-image-full-cmdline') 182 183 def test_testimage_apt(self): 184 """ 185 Summary: Check package feeds functionality for apt 186 Expected: 1. Check that remote package feeds can be accessed 187 Product: oe-core 188 Author: Ferry Toth <fntoth@gmail.com> 189 """ 190 if get_bb_var('DISTRO') == 'poky-tiny': 191 self.skipTest('core-image-full-cmdline not buildable for poky-tiny') 192 193 features = 'IMAGE_CLASSES += "testimage"\n' 194 features += 'TEST_SUITES = "ping ssh apt.AptRepoTest.test_apt_install_from_repo"\n' 195 # We don't yet know what the server ip and port will be - they will be patched 196 # in at the start of the on-image test 197 features += 'PACKAGE_FEED_URIS = "http://bogus_ip:bogus_port"\n' 198 features += 'EXTRA_IMAGE_FEATURES += "package-management"\n' 199 features += 'PACKAGE_CLASSES = "package_deb"\n' 200 # We need gnupg on the target to install keys 201 features += 'IMAGE_INSTALL:append:pn-core-image-full-cmdline = " gnupg"\n' 202 203 bitbake('gnupg-native -c addto_recipe_sysroot') 204 205 # Enable package feed signing 206 self.gpg_home = tempfile.mkdtemp(prefix="oeqa-feed-sign-") 207 self.track_for_cleanup(self.gpg_home) 208 signing_key_dir = os.path.join(self.testlayer_path, 'files', 'signing') 209 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) 210 features += 'INHERIT += "sign_package_feed"\n' 211 features += 'PACKAGE_FEED_GPG_NAME = "testuser"\n' 212 features += 'PACKAGE_FEED_GPG_PASSPHRASE_FILE = "%s"\n' % os.path.join(signing_key_dir, 'key.passphrase') 213 features += 'GPG_PATH = "%s"\n' % self.gpg_home 214 features += 'PSEUDO_IGNORE_PATHS .= ",%s"\n' % self.gpg_home 215 self.write_config(features) 216 217 # Build core-image-sato and testimage 218 bitbake('core-image-full-cmdline socat') 219 bitbake('-c testimage core-image-full-cmdline') 220 221 # https://bugzilla.yoctoproject.org/show_bug.cgi?id=14966 222 @skipIfNotMachine("qemux86-64", "test needs qemux86-64") 223 def test_testimage_virgl_gtk_sdl(self): 224 """ 225 Summary: Check host-assisted accelerate OpenGL functionality in qemu with gtk and SDL frontends 226 Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled 227 2. Check that kmscube demo runs without crashing. 228 Product: oe-core 229 Author: Alexander Kanavin <alex.kanavin@gmail.com> 230 """ 231 if "DISPLAY" not in os.environ: 232 self.skipTest("virgl gtk test must be run inside a X session") 233 distro = oe.lsb.distro_identifier() 234 if distro and distro == 'debian-8': 235 self.skipTest('virgl isn\'t working with Debian 8') 236 if distro and distro == 'debian-9': 237 self.skipTest('virgl isn\'t working with Debian 9') 238 if distro and distro == 'centos-7': 239 self.skipTest('virgl isn\'t working with Centos 7') 240 if distro and distro == 'opensuseleap-15.0': 241 self.skipTest('virgl isn\'t working with Opensuse 15.0') 242 243 qemu_packageconfig = get_bb_var('PACKAGECONFIG', 'qemu-system-native') 244 qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') 245 features = 'IMAGE_CLASSES += "testimage"\n' 246 if 'gtk+' not in qemu_packageconfig: 247 features += 'PACKAGECONFIG:append:pn-qemu-system-native = " gtk+"\n' 248 if 'sdl' not in qemu_packageconfig: 249 features += 'PACKAGECONFIG:append:pn-qemu-system-native = " sdl"\n' 250 if 'opengl' not in qemu_distrofeatures: 251 features += 'DISTRO_FEATURES:append = " opengl"\n' 252 features += 'TEST_SUITES = "ping ssh virgl"\n' 253 features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' 254 features += 'IMAGE_INSTALL:append = " kmscube"\n' 255 features_gtk = features + 'TEST_RUNQEMUPARAMS += " gtk gl"\n' 256 self.write_config(features_gtk) 257 bitbake('core-image-minimal') 258 bitbake('-c testimage core-image-minimal') 259 features_sdl = features + 'TEST_RUNQEMUPARAMS += " sdl gl"\n' 260 self.write_config(features_sdl) 261 bitbake('core-image-minimal') 262 bitbake('-c testimage core-image-minimal') 263 264 @skipIfNotMachine("qemux86-64", "test needs qemux86-64") 265 def test_testimage_virgl_headless(self): 266 """ 267 Summary: Check host-assisted accelerate OpenGL functionality in qemu with egl-headless frontend 268 Expected: 1. Check that virgl kernel driver is loaded and 3d acceleration is enabled 269 2. Check that kmscube demo runs without crashing. 270 Product: oe-core 271 Author: Alexander Kanavin <alex.kanavin@gmail.com> 272 """ 273 import subprocess, os 274 275 distro = oe.lsb.distro_identifier() 276 if distro and (distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'ubuntu-16.04', 'ubuntu-18.04'] or 277 distro.startswith('almalinux') or distro.startswith('rocky')): 278 self.skipTest('virgl headless cannot be tested with %s' %(distro)) 279 280 qemu_distrofeatures = get_bb_var('DISTRO_FEATURES', 'qemu-system-native') 281 features = 'IMAGE_CLASSES += "testimage"\n' 282 if 'opengl' not in qemu_distrofeatures: 283 features += 'DISTRO_FEATURES:append = " opengl"\n' 284 features += 'TEST_SUITES = "ping ssh virgl"\n' 285 features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n' 286 features += 'IMAGE_INSTALL:append = " kmscube"\n' 287 features += 'TEST_RUNQEMUPARAMS += " egl-headless"\n' 288 self.write_config(features) 289 bitbake('core-image-minimal') 290 bitbake('-c testimage core-image-minimal') 291 292@OETestTag("runqemu") 293class Postinst(OESelftestTestCase): 294 295 def init_manager_loop(self, init_manager): 296 import oe.path 297 298 vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal") 299 rootfs = vars["IMAGE_ROOTFS"] 300 self.assertIsNotNone(rootfs) 301 sysconfdir = vars["sysconfdir"] 302 self.assertIsNotNone(sysconfdir) 303 # Need to use oe.path here as sysconfdir starts with / 304 hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test") 305 targettestdir = os.path.join(sysconfdir, "postinst-test") 306 307 for classes in ("package_rpm", "package_deb", "package_ipk"): 308 with self.subTest(init_manager=init_manager, package_class=classes): 309 features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-delayed-b"\n' 310 features += 'IMAGE_FEATURES += "package-management empty-root-password"\n' 311 features += 'PACKAGE_CLASSES = "%s"\n' % classes 312 if init_manager == "systemd": 313 features += 'DISTRO_FEATURES:append = " systemd usrmerge"\n' 314 features += 'VIRTUAL-RUNTIME_init_manager = "systemd"\n' 315 features += 'DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"\n' 316 features += 'VIRTUAL-RUNTIME_initscripts = ""\n' 317 self.write_config(features) 318 319 bitbake('core-image-minimal') 320 321 self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs")), 322 "rootfs state file was not created") 323 324 with runqemu('core-image-minimal') as qemu: 325 # Make the test echo a string and search for that as 326 # run_serial()'s status code is useless.' 327 for filename in ("rootfs", "delayed-a", "delayed-b"): 328 status, output = qemu.run_serial("test -f %s && echo found" % os.path.join(targettestdir, filename)) 329 self.assertIn("found", output, "%s was not present on boot" % filename) 330 331 332 333 @skipIfNotQemu() 334 def test_postinst_rootfs_and_boot_sysvinit(self): 335 """ 336 Summary: The purpose of this test case is to verify Post-installation 337 scripts are called when rootfs is created and also test 338 that script can be delayed to run at first boot. 339 Dependencies: NA 340 Steps: 1. Add proper configuration to local.conf file 341 2. Build a "core-image-minimal" image 342 3. Verify that file created by postinst_rootfs recipe is 343 present on rootfs dir. 344 4. Boot the image created on qemu and verify that the file 345 created by postinst_boot recipe is present on image. 346 Expected: The files are successfully created during rootfs and boot 347 time for 3 different package managers: rpm,ipk,deb and 348 for initialization managers: sysvinit. 349 350 """ 351 self.init_manager_loop("sysvinit") 352 353 354 @skipIfNotQemu() 355 def test_postinst_rootfs_and_boot_systemd(self): 356 """ 357 Summary: The purpose of this test case is to verify Post-installation 358 scripts are called when rootfs is created and also test 359 that script can be delayed to run at first boot. 360 Dependencies: NA 361 Steps: 1. Add proper configuration to local.conf file 362 2. Build a "core-image-minimal" image 363 3. Verify that file created by postinst_rootfs recipe is 364 present on rootfs dir. 365 4. Boot the image created on qemu and verify that the file 366 created by postinst_boot recipe is present on image. 367 Expected: The files are successfully created during rootfs and boot 368 time for 3 different package managers: rpm,ipk,deb and 369 for initialization managers: systemd. 370 371 """ 372 373 self.init_manager_loop("systemd") 374 375 376 def test_failing_postinst(self): 377 """ 378 Summary: The purpose of this test case is to verify that post-installation 379 scripts that contain errors are properly reported. 380 Expected: The scriptlet failure is properly reported. 381 The file that is created after the error in the scriptlet is not present. 382 Product: oe-core 383 Author: Alexander Kanavin <alex.kanavin@gmail.com> 384 """ 385 386 import oe.path 387 388 vars = get_bb_vars(("IMAGE_ROOTFS", "sysconfdir"), "core-image-minimal") 389 rootfs = vars["IMAGE_ROOTFS"] 390 self.assertIsNotNone(rootfs) 391 sysconfdir = vars["sysconfdir"] 392 self.assertIsNotNone(sysconfdir) 393 # Need to use oe.path here as sysconfdir starts with / 394 hosttestdir = oe.path.join(rootfs, sysconfdir, "postinst-test") 395 396 for classes in ("package_rpm", "package_deb", "package_ipk"): 397 with self.subTest(package_class=classes): 398 features = 'CORE_IMAGE_EXTRA_INSTALL = "postinst-rootfs-failing"\n' 399 features += 'PACKAGE_CLASSES = "%s"\n' % classes 400 self.write_config(features) 401 bb_result = bitbake('core-image-minimal', ignore_status=True) 402 self.assertGreaterEqual(bb_result.output.find("Postinstall scriptlets of ['postinst-rootfs-failing'] have failed."), 0, 403 "Warning about a failed scriptlet not found in bitbake output: %s" %(bb_result.output)) 404 405 self.assertTrue(os.path.isfile(os.path.join(hosttestdir, "rootfs-before-failure")), 406 "rootfs-before-failure file was not created") 407 self.assertFalse(os.path.isfile(os.path.join(hosttestdir, "rootfs-after-failure")), 408 "rootfs-after-failure file was created") 409 410@OETestTag("runqemu") 411class SystemTap(OESelftestTestCase): 412 """ 413 Summary: The purpose of this test case is to verify native crosstap 414 works while talking to a target. 415 Expected: The script should successfully connect to the qemu machine 416 and run some systemtap examples on a qemu machine. 417 """ 418 419 @classmethod 420 def setUpClass(cls): 421 super(SystemTap, cls).setUpClass() 422 cls.image = "core-image-minimal" 423 424 def default_config(self): 425 return """ 426# These aren't the actual IP addresses but testexport class needs something defined 427TEST_SERVER_IP = "192.168.7.1" 428TEST_TARGET_IP = "192.168.7.2" 429 430EXTRA_IMAGE_FEATURES += "tools-profile dbg-pkgs" 431IMAGE_FEATURES:append = " ssh-server-dropbear" 432 433# enables kernel debug symbols 434KERNEL_EXTRA_FEATURES:append = " features/debug/debug-kernel.scc" 435KERNEL_EXTRA_FEATURES:append = " features/systemtap/systemtap.scc" 436 437# add systemtap run-time into target image if it is not there yet 438IMAGE_INSTALL:append = " systemtap-runtime" 439""" 440 441 def test_crosstap_helloworld(self): 442 self.write_config(self.default_config()) 443 bitbake('systemtap-native') 444 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 445 bitbake(self.image) 446 447 with runqemu(self.image) as qemu: 448 cmd = "crosstap -r root@192.168.7.2 -s %s/general/helloworld.stp " % systemtap_examples 449 result = runCmd(cmd) 450 self.assertEqual(0, result.status, 'crosstap helloworld returned a non 0 status:%s' % result.output) 451 452 def test_crosstap_pstree(self): 453 self.write_config(self.default_config()) 454 455 bitbake('systemtap-native') 456 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 457 bitbake(self.image) 458 459 with runqemu(self.image) as qemu: 460 cmd = "crosstap -r root@192.168.7.2 -s %s/process/pstree.stp" % systemtap_examples 461 result = runCmd(cmd) 462 self.assertEqual(0, result.status, 'crosstap pstree returned a non 0 status:%s' % result.output) 463 464 def test_crosstap_syscalls_by_proc(self): 465 self.write_config(self.default_config()) 466 467 bitbake('systemtap-native') 468 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 469 bitbake(self.image) 470 471 with runqemu(self.image) as qemu: 472 cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_proc.stp" % systemtap_examples 473 result = runCmd(cmd) 474 self.assertEqual(0, result.status, 'crosstap syscalls_by_proc returned a non 0 status:%s' % result.output) 475 476 def test_crosstap_syscalls_by_pid(self): 477 self.write_config(self.default_config()) 478 479 bitbake('systemtap-native') 480 systemtap_examples = os.path.join(get_bb_var("WORKDIR","systemtap-native"), "usr/share/systemtap/examples") 481 bitbake(self.image) 482 483 with runqemu(self.image) as qemu: 484 cmd = "crosstap -r root@192.168.7.2 -s %s/process/ syscalls_by_pid.stp" % systemtap_examples 485 result = runCmd(cmd) 486 self.assertEqual(0, result.status, 'crosstap syscalls_by_pid returned a non 0 status:%s' % result.output) 487