xref: /OK3568_Linux_fs/yocto/poky/meta/lib/oeqa/selftest/cases/runtime_test.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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