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