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