diff options
Diffstat (limited to 'meta/lib/oeqa/sdk')
-rw-r--r-- | meta/lib/oeqa/sdk/buildtools-cases/README | 2 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/buildtools-cases/build.py | 30 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/buildtools-cases/gcc.py | 29 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/buildtools-cases/https.py | 20 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/buildtools-cases/sanity.py | 22 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/case.py | 46 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/assimp.py | 40 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/buildcpio.py | 53 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/buildepoxy.py | 41 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/buildgalculator.py | 62 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/buildlzip.py | 65 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/gcc.py | 11 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/perl.py | 32 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/cases/python.py | 49 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/context.py | 43 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/testsdk.py | 145 | ||||
-rw-r--r-- | meta/lib/oeqa/sdk/utils/sdkbuildproject.py | 16 |
17 files changed, 556 insertions, 150 deletions
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/README b/meta/lib/oeqa/sdk/buildtools-cases/README new file mode 100644 index 0000000000..d4f20faa9f --- /dev/null +++ b/meta/lib/oeqa/sdk/buildtools-cases/README @@ -0,0 +1,2 @@ +These test cases are used by buildtools-tarball, and are not used by the testsdk +class. diff --git a/meta/lib/oeqa/sdk/buildtools-cases/build.py b/meta/lib/oeqa/sdk/buildtools-cases/build.py new file mode 100644 index 0000000000..aee2e5a8c0 --- /dev/null +++ b/meta/lib/oeqa/sdk/buildtools-cases/build.py @@ -0,0 +1,30 @@ +# +# SPDX-License-Identifier: MIT +# + +import os, tempfile +import time +from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + +class BuildTests(OESDKTestCase): + """ + Verify that bitbake can build virtual/libc inside the buildtools. + """ + def test_libc(self): + with tempfile.TemporaryDirectory(prefix='bitbake-build-', dir=self.tc.sdk_dir) as testdir: + corebase = self.td['COREBASE'] + + self._run('. %s/oe-init-build-env %s' % (corebase, testdir)) + with open(os.path.join(testdir, 'conf', 'local.conf'), 'ta') as conf: + conf.write('\n') + conf.write('DL_DIR = "%s"\n' % self.td['DL_DIR']) + + try: + self._run('. %s/oe-init-build-env %s && bitbake virtual/libc' % (corebase, testdir)) + finally: + delay = 10 + while delay and (os.path.exists(testdir + "/bitbake.lock") or os.path.exists(testdir + "/cache/hashserv.db-wal")): + time.sleep(1) + delay = delay - 1 diff --git a/meta/lib/oeqa/sdk/buildtools-cases/gcc.py b/meta/lib/oeqa/sdk/buildtools-cases/gcc.py new file mode 100644 index 0000000000..36ba15b134 --- /dev/null +++ b/meta/lib/oeqa/sdk/buildtools-cases/gcc.py @@ -0,0 +1,29 @@ +# +# SPDX-License-Identifier: MIT +# + +import os.path +from oeqa.sdk.case import OESDKTestCase + +class GccTests(OESDKTestCase): + def test_verify_specs(self): + """ + Verify that the compiler has been relocated successfully and isn't + looking in the hard-coded prefix. + """ + # Canonicalise the SDK root + sdk_base = os.path.realpath(self.tc.sdk_dir) + # Canonicalise the location of GCC + gcc_path = os.path.realpath(self._run("command -v gcc").strip()) + # Skip the test if the GCC didn't come from the buildtools, as it only + # comes with buildtools-extended-tarball. + if os.path.commonprefix((sdk_base, gcc_path)) != sdk_base: + self.skipTest("Buildtools does not provide GCC") + + # This is the prefix that GCC is build with, and should be replaced at + # installation time. + sdkpath = self.td.get("SDKPATH") + self.assertTrue(sdkpath) + + for line in self._run('gcc -dumpspecs').splitlines(): + self.assertNotIn(sdkpath, line) diff --git a/meta/lib/oeqa/sdk/buildtools-cases/https.py b/meta/lib/oeqa/sdk/buildtools-cases/https.py new file mode 100644 index 0000000000..35e549eb40 --- /dev/null +++ b/meta/lib/oeqa/sdk/buildtools-cases/https.py @@ -0,0 +1,20 @@ +# +# SPDX-License-Identifier: MIT +# + +from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + +class HTTPTests(OESDKTestCase): + """ + Verify that HTTPS certificates are working correctly, as this depends on + environment variables being set correctly. + """ + + def test_wget(self): + self._run('env -i wget --debug --output-document /dev/null https://yoctoproject.org/connectivity.html') + + def test_python(self): + # urlopen() returns a file-like object on success and throws an exception otherwise + self._run('python3 -c \'import urllib.request; urllib.request.urlopen("https://yoctoproject.org/connectivity.html")\'') diff --git a/meta/lib/oeqa/sdk/buildtools-cases/sanity.py b/meta/lib/oeqa/sdk/buildtools-cases/sanity.py new file mode 100644 index 0000000000..64baaa8f84 --- /dev/null +++ b/meta/lib/oeqa/sdk/buildtools-cases/sanity.py @@ -0,0 +1,22 @@ +# +# SPDX-License-Identifier: MIT +# + +import shutil +import os.path +from oeqa.sdk.case import OESDKTestCase + +class SanityTests(OESDKTestCase): + def test_tools(self): + """ + Test that wget and tar come from the buildtools, not the host. This + verifies that the buildtools have installed correctly. We can't check + for gcc as that is only installed by buildtools-extended. + """ + for command in ("tar", "wget"): + # Canonicalise the SDK root + sdk_base = os.path.realpath(self.tc.sdk_dir) + # Canonicalise the location of this command + tool_path = os.path.realpath(self._run("command -v %s" % command).strip()) + # Assert that the tool was found inside the SDK root + self.assertEquals(os.path.commonprefix((sdk_base, tool_path)), sdk_base) diff --git a/meta/lib/oeqa/sdk/case.py b/meta/lib/oeqa/sdk/case.py index 963aa8d358..c45882689c 100644 --- a/meta/lib/oeqa/sdk/case.py +++ b/meta/lib/oeqa/sdk/case.py @@ -1,6 +1,10 @@ +# # Copyright (C) 2016 Intel Corporation -# Released under the MIT license (see COPYING.MIT) +# +# SPDX-License-Identifier: MIT +# +import os import subprocess from oeqa.core.case import OETestCase @@ -8,5 +12,43 @@ from oeqa.core.case import OETestCase class OESDKTestCase(OETestCase): def _run(self, cmd): return subprocess.check_output(". %s > /dev/null; %s;" % \ - (self.tc.sdk_env, cmd), shell=True, + (self.tc.sdk_env, cmd), shell=True, executable="/bin/bash", stderr=subprocess.STDOUT, universal_newlines=True) + + def fetch(self, workdir, dl_dir, url, archive=None): + if not archive: + from urllib.parse import urlparse + archive = os.path.basename(urlparse(url).path) + + if dl_dir: + tarball = os.path.join(dl_dir, archive) + if os.path.exists(tarball): + return tarball + + tarball = os.path.join(workdir, archive) + subprocess.check_output(["wget", "-O", tarball, url], stderr=subprocess.STDOUT) + return tarball + + def check_elf(self, path, target_os=None, target_arch=None): + """ + Verify that the ELF binary $path matches the specified target + OS/architecture, or if not specified the currently configured MACHINE's + OS/architecture. + """ + import oe.qa, oe.elf + + if not target_os or not target_arch: + output = self._run("echo $OECORE_TARGET_OS:$OECORE_TARGET_ARCH") + target_os, target_arch = output.strip().split(":") + + machine_data = oe.elf.machine_dict(None)[target_os][target_arch] + (machine, osabi, abiversion, endian, bits) = machine_data + + elf = oe.qa.ELFFile(path) + elf.open() + + self.assertEqual(machine, elf.machine(), + "Binary was %s but expected %s" % + (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine))) + self.assertEqual(bits, elf.abiSize()) + self.assertEqual(endian, elf.isLittleEndian()) diff --git a/meta/lib/oeqa/sdk/cases/assimp.py b/meta/lib/oeqa/sdk/cases/assimp.py new file mode 100644 index 0000000000..f166758e49 --- /dev/null +++ b/meta/lib/oeqa/sdk/cases/assimp.py @@ -0,0 +1,40 @@ +# +# SPDX-License-Identifier: MIT +# + +import os +import subprocess +import tempfile +import unittest +from oeqa.sdk.case import OESDKTestCase + +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + +class BuildAssimp(OESDKTestCase): + """ + Test case to build a project using cmake. + """ + + def setUp(self): + if not (self.tc.hasHostPackage("nativesdk-cmake") or + self.tc.hasHostPackage("cmake-native")): + raise unittest.SkipTest("Needs cmake") + + def test_assimp(self): + with tempfile.TemporaryDirectory(prefix="assimp", dir=self.tc.sdk_dir) as testdir: + tarball = self.fetch(testdir, self.td["DL_DIR"], "https://github.com/assimp/assimp/archive/v4.1.0.tar.gz") + + dirs = {} + dirs["source"] = os.path.join(testdir, "assimp-4.1.0") + dirs["build"] = os.path.join(testdir, "build") + dirs["install"] = os.path.join(testdir, "install") + + subprocess.check_output(["tar", "xf", tarball, "-C", testdir], stderr=subprocess.STDOUT) + self.assertTrue(os.path.isdir(dirs["source"])) + os.makedirs(dirs["build"]) + + self._run("cd {build} && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON {source}".format(**dirs)) + self._run("cmake --build {build} -- -j".format(**dirs)) + self._run("cmake --build {build} --target install -- DESTDIR={install}".format(**dirs)) + self.check_elf(os.path.join(dirs["install"], "usr", "local", "lib", "libassimp.so.4.1.0")) diff --git a/meta/lib/oeqa/sdk/cases/buildcpio.py b/meta/lib/oeqa/sdk/cases/buildcpio.py index 333dc7c226..e7fc211a47 100644 --- a/meta/lib/oeqa/sdk/cases/buildcpio.py +++ b/meta/lib/oeqa/sdk/cases/buildcpio.py @@ -1,33 +1,36 @@ +# +# SPDX-License-Identifier: MIT +# + +import os +import tempfile +import subprocess import unittest + from oeqa.sdk.case import OESDKTestCase -from oeqa.sdk.utils.sdkbuildproject import SDKBuildProject +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() class BuildCpioTest(OESDKTestCase): - td_vars = ['DATETIME'] - - @classmethod - def setUpClass(self): - dl_dir = self.td.get('DL_DIR', None) - - self.project = SDKBuildProject(self.tc.sdk_dir + "/cpio/", self.tc.sdk_env, - "https://ftp.gnu.org/gnu/cpio/cpio-2.12.tar.gz", - self.tc.sdk_dir, self.td['DATETIME'], dl_dir=dl_dir) - self.project.download_archive() - - machine = self.td.get("MACHINE") - if not self.tc.hasHostPackage("packagegroup-cross-canadian-%s" % machine): - raise unittest.SkipTest("SDK doesn't contain a cross-canadian toolchain") - + """ + Check that autotools will cross-compile correctly. + """ def test_cpio(self): - self.assertEqual(self.project.run_configure(), 0, - msg="Running configure failed") + with tempfile.TemporaryDirectory(prefix="cpio-", dir=self.tc.sdk_dir) as testdir: + tarball = self.fetch(testdir, self.td["DL_DIR"], "https://ftp.gnu.org/gnu/cpio/cpio-2.13.tar.gz") + + dirs = {} + dirs["source"] = os.path.join(testdir, "cpio-2.13") + dirs["build"] = os.path.join(testdir, "build") + dirs["install"] = os.path.join(testdir, "install") - self.assertEqual(self.project.run_make(), 0, - msg="Running make failed") + subprocess.check_output(["tar", "xf", tarball, "-C", testdir], stderr=subprocess.STDOUT) + self.assertTrue(os.path.isdir(dirs["source"])) + os.makedirs(dirs["build"]) - self.assertEqual(self.project.run_install(), 0, - msg="Running make install failed") + self._run("sed -i -e '/char.*program_name/d' {source}/src/global.c".format(**dirs)) + self._run("cd {build} && {source}/configure --disable-maintainer-mode $CONFIGURE_FLAGS".format(**dirs)) + self._run("cd {build} && make -j".format(**dirs)) + self._run("cd {build} && make install DESTDIR={install}".format(**dirs)) - @classmethod - def tearDownClass(self): - self.project.clean() + self.check_elf(os.path.join(dirs["install"], "usr", "local", "bin", "cpio")) diff --git a/meta/lib/oeqa/sdk/cases/buildepoxy.py b/meta/lib/oeqa/sdk/cases/buildepoxy.py new file mode 100644 index 0000000000..385f8ccca8 --- /dev/null +++ b/meta/lib/oeqa/sdk/cases/buildepoxy.py @@ -0,0 +1,41 @@ +# +# SPDX-License-Identifier: MIT +# + +import os +import subprocess +import tempfile +import unittest + +from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + +class EpoxyTest(OESDKTestCase): + """ + Test that Meson builds correctly. + """ + def setUp(self): + if not (self.tc.hasHostPackage("nativesdk-meson")): + raise unittest.SkipTest("GalculatorTest class: SDK doesn't contain Meson") + + def test_epoxy(self): + with tempfile.TemporaryDirectory(prefix="epoxy", dir=self.tc.sdk_dir) as testdir: + tarball = self.fetch(testdir, self.td["DL_DIR"], "https://github.com/anholt/libepoxy/releases/download/1.5.3/libepoxy-1.5.3.tar.xz") + + dirs = {} + dirs["source"] = os.path.join(testdir, "libepoxy-1.5.3") + dirs["build"] = os.path.join(testdir, "build") + dirs["install"] = os.path.join(testdir, "install") + + subprocess.check_output(["tar", "xf", tarball, "-C", testdir], stderr=subprocess.STDOUT) + self.assertTrue(os.path.isdir(dirs["source"])) + os.makedirs(dirs["build"]) + + log = self._run("meson -Degl=no -Dglx=no -Dx11=false {build} {source}".format(**dirs)) + # Check that Meson thinks we're doing a cross build and not a native + self.assertIn("Build type: cross build", log) + self._run("ninja -C {build} -v".format(**dirs)) + self._run("DESTDIR={install} ninja -C {build} -v install".format(**dirs)) + + self.check_elf(os.path.join(dirs["install"], "usr", "local", "lib", "libepoxy.so")) diff --git a/meta/lib/oeqa/sdk/cases/buildgalculator.py b/meta/lib/oeqa/sdk/cases/buildgalculator.py index 5a5bf992eb..eb3c8ddf39 100644 --- a/meta/lib/oeqa/sdk/cases/buildgalculator.py +++ b/meta/lib/oeqa/sdk/cases/buildgalculator.py @@ -1,37 +1,43 @@ +# +# SPDX-License-Identifier: MIT +# + +import os +import subprocess +import tempfile import unittest from oeqa.sdk.case import OESDKTestCase -from oeqa.sdk.utils.sdkbuildproject import SDKBuildProject +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() class GalculatorTest(OESDKTestCase): - td_vars = ['DATETIME'] - - @classmethod - def setUpClass(self): - if not (self.tc.hasTargetPackage("gtk\+3") or\ - self.tc.hasTargetPackage("libgtk-3.0")): + """ + Test that autotools and GTK+ 3 compiles correctly. + """ + def setUp(self): + if not (self.tc.hasTargetPackage("gtk+3", multilib=True) or \ + self.tc.hasTargetPackage("libgtk-3.0", multilib=True)): raise unittest.SkipTest("GalculatorTest class: SDK don't support gtk+3") - if not (self.tc.hasTargetPackage("gettext")): + if not (self.tc.hasHostPackage("nativesdk-gettext-dev")): raise unittest.SkipTest("GalculatorTest class: SDK doesn't contain gettext") def test_galculator(self): - dl_dir = self.td.get('DL_DIR', None) - project = None - try: - project = SDKBuildProject(self.tc.sdk_dir + "/galculator/", - self.tc.sdk_env, - "http://galculator.mnim.org/downloads/galculator-2.1.4.tar.bz2", - self.tc.sdk_dir, self.td['DATETIME'], dl_dir=dl_dir) - - project.download_archive() - - # regenerate configure to get support for --with-libtool-sysroot - legacy_preconf=("autoreconf -i -f -I ${OECORE_TARGET_SYSROOT}/usr/share/aclocal -I m4;") - - self.assertEqual(project.run_configure(extra_cmds=legacy_preconf), - 0, msg="Running configure failed") - - self.assertEqual(project.run_make(), 0, - msg="Running make failed") - finally: - project.clean() + with tempfile.TemporaryDirectory(prefix="galculator", dir=self.tc.sdk_dir) as testdir: + tarball = self.fetch(testdir, self.td["DL_DIR"], "http://galculator.mnim.org/downloads/galculator-2.1.4.tar.bz2") + + dirs = {} + dirs["source"] = os.path.join(testdir, "galculator-2.1.4") + dirs["build"] = os.path.join(testdir, "build") + dirs["install"] = os.path.join(testdir, "install") + + subprocess.check_output(["tar", "xf", tarball, "-C", testdir], stderr=subprocess.STDOUT) + self.assertTrue(os.path.isdir(dirs["source"])) + os.makedirs(dirs["build"]) + + self._run("cd {source} && sed -i -e '/s_preferences.*prefs;/d' src/main.c && autoreconf -i -f -I $OECORE_TARGET_SYSROOT/usr/share/aclocal -I m4".format(**dirs)) + self._run("cd {build} && {source}/configure $CONFIGURE_FLAGS".format(**dirs)) + self._run("cd {build} && make -j".format(**dirs)) + self._run("cd {build} && make install DESTDIR={install}".format(**dirs)) + + self.check_elf(os.path.join(dirs["install"], "usr", "local", "bin", "galculator")) diff --git a/meta/lib/oeqa/sdk/cases/buildlzip.py b/meta/lib/oeqa/sdk/cases/buildlzip.py index 3a89ce8627..49ae756bf3 100644 --- a/meta/lib/oeqa/sdk/cases/buildlzip.py +++ b/meta/lib/oeqa/sdk/cases/buildlzip.py @@ -1,36 +1,37 @@ -import unittest -from oeqa.sdk.case import OESDKTestCase -from oeqa.sdk.utils.sdkbuildproject import SDKBuildProject +# +# SPDX-License-Identifier: MIT +# +import os, tempfile, subprocess, unittest +from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() class BuildLzipTest(OESDKTestCase): - td_vars = ['DATETIME'] - - @classmethod - def setUpClass(self): - dl_dir = self.td.get('DL_DIR', None) - - self.project = SDKBuildProject(self.tc.sdk_dir + "/lzip/", self.tc.sdk_env, - "http://downloads.yoctoproject.org/mirror/sources/lzip-1.19.tar.gz", - self.tc.sdk_dir, self.td['DATETIME'], dl_dir=dl_dir) - self.project.download_archive() - - machine = self.td.get("MACHINE") - - if not (self.tc.hasTargetPackage("packagegroup-cross-canadian-%s" % machine) or - self.tc.hasTargetPackage("gcc")): - raise unittest.SkipTest("SDK doesn't contain a cross-canadian toolchain") - + """ + Test that "plain" compilation works, using just $CC $CFLAGS etc. + """ def test_lzip(self): - self.assertEqual(self.project.run_configure(), 0, - msg="Running configure failed") - - self.assertEqual(self.project.run_make(), 0, - msg="Running make failed") - - self.assertEqual(self.project.run_install(), 0, - msg="Running make install failed") - - @classmethod - def tearDownClass(self): - self.project.clean() + with tempfile.TemporaryDirectory(prefix="lzip", dir=self.tc.sdk_dir) as testdir: + tarball = self.fetch(testdir, self.td["DL_DIR"], "http://downloads.yoctoproject.org/mirror/sources/lzip-1.19.tar.gz") + + dirs = {} + dirs["source"] = os.path.join(testdir, "lzip-1.19") + dirs["build"] = os.path.join(testdir, "build") + dirs["install"] = os.path.join(testdir, "install") + + subprocess.check_output(["tar", "xf", tarball, "-C", testdir], stderr=subprocess.STDOUT) + self.assertTrue(os.path.isdir(dirs["source"])) + os.makedirs(dirs["build"]) + + cmd = """cd {build} && \ + {source}/configure --srcdir {source} \ + CXX="$CXX" \ + CPPFLAGS="$CPPFLAGS" \ + CXXFLAGS="$CXXFLAGS" \ + LDFLAGS="$LDFLAGS" \ + """ + self._run(cmd.format(**dirs)) + self._run("cd {build} && make -j".format(**dirs)) + self._run("cd {build} && make install DESTDIR={install}".format(**dirs)) + self.check_elf(os.path.join(dirs["install"], "usr", "local", "bin", "lzip")) diff --git a/meta/lib/oeqa/sdk/cases/gcc.py b/meta/lib/oeqa/sdk/cases/gcc.py index d11f4b63fb..eb08eadd28 100644 --- a/meta/lib/oeqa/sdk/cases/gcc.py +++ b/meta/lib/oeqa/sdk/cases/gcc.py @@ -1,3 +1,7 @@ +# +# SPDX-License-Identifier: MIT +# + import os import shutil import unittest @@ -5,6 +9,9 @@ import unittest from oeqa.core.utils.path import remove_safe from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + class GccCompileTest(OESDKTestCase): td_vars = ['MACHINE'] @@ -18,8 +25,8 @@ class GccCompileTest(OESDKTestCase): def setUp(self): machine = self.td.get("MACHINE") - if not (self.tc.hasTargetPackage("packagegroup-cross-canadian-%s" % machine) or - self.tc.hasTargetPackage("gcc")): + if not (self.tc.hasHostPackage("packagegroup-cross-canadian-%s" % machine) or + self.tc.hasHostPackage("^gcc-", regex=True)): raise unittest.SkipTest("GccCompileTest class: SDK doesn't contain a cross-canadian toolchain") def test_gcc_compile(self): diff --git a/meta/lib/oeqa/sdk/cases/perl.py b/meta/lib/oeqa/sdk/cases/perl.py index 8085678116..14d76d820f 100644 --- a/meta/lib/oeqa/sdk/cases/perl.py +++ b/meta/lib/oeqa/sdk/cases/perl.py @@ -1,28 +1,20 @@ -import os -import shutil -import unittest +# +# SPDX-License-Identifier: MIT +# -from oeqa.core.utils.path import remove_safe +import unittest from oeqa.sdk.case import OESDKTestCase +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() + class PerlTest(OESDKTestCase): - @classmethod - def setUpClass(self): + def setUp(self): if not (self.tc.hasHostPackage("nativesdk-perl") or self.tc.hasHostPackage("perl-native")): raise unittest.SkipTest("No perl package in the SDK") - for f in ['test.pl']: - shutil.copyfile(os.path.join(self.tc.files_dir, f), - os.path.join(self.tc.sdk_dir, f)) - self.testfile = os.path.join(self.tc.sdk_dir, "test.pl") - - def test_perl_exists(self): - self._run('which perl') - - def test_perl_works(self): - self._run('perl %s' % self.testfile) - - @classmethod - def tearDownClass(self): - remove_safe(self.testfile) + def test_perl(self): + cmd = "perl -e '$_=\"Uryyb, jbeyq\"; tr/a-zA-Z/n-za-mN-ZA-M/;print'" + output = self._run(cmd) + self.assertEqual(output, "Hello, world") diff --git a/meta/lib/oeqa/sdk/cases/python.py b/meta/lib/oeqa/sdk/cases/python.py index 72dfcc72bd..a334abce5f 100644 --- a/meta/lib/oeqa/sdk/cases/python.py +++ b/meta/lib/oeqa/sdk/cases/python.py @@ -1,32 +1,31 @@ -import os -import shutil -import unittest +# +# SPDX-License-Identifier: MIT +# -from oeqa.core.utils.path import remove_safe +import subprocess, unittest from oeqa.sdk.case import OESDKTestCase -class PythonTest(OESDKTestCase): - @classmethod - def setUpClass(self): - if not (self.tc.hasHostPackage("nativesdk-python") or - self.tc.hasHostPackage("python-native")): - raise unittest.SkipTest("No python package in the SDK") - - for f in ['test.py']: - shutil.copyfile(os.path.join(self.tc.files_dir, f), - os.path.join(self.tc.sdk_dir, f)) +from oeqa.utils.subprocesstweak import errors_have_output +errors_have_output() - def test_python_exists(self): - self._run('which python') +class Python2Test(OESDKTestCase): + def setUp(self): + if not (self.tc.hasHostPackage("nativesdk-python-core") or + self.tc.hasHostPackage("python-core-native")): + raise unittest.SkipTest("No python package in the SDK") - def test_python_stdout(self): - output = self._run('python %s/test.py' % self.tc.sdk_dir) - self.assertEqual(output.strip(), "the value of a is 0.01", msg="Incorrect output: %s" % output) + def test_python2(self): + cmd = "python -c \"import codecs; print(codecs.encode('Uryyb, jbeyq', 'rot13'))\"" + output = self._run(cmd) + self.assertEqual(output, "Hello, world\n") - def test_python_testfile(self): - self._run('ls /tmp/testfile.python') +class Python3Test(OESDKTestCase): + def setUp(self): + if not (self.tc.hasHostPackage("nativesdk-python3-core") or + self.tc.hasHostPackage("python3-core-native")): + raise unittest.SkipTest("No python3 package in the SDK") - @classmethod - def tearDownClass(self): - remove_safe("%s/test.py" % self.tc.sdk_dir) - remove_safe("/tmp/testfile.python") + def test_python3(self): + cmd = "python3 -c \"import codecs; print(codecs.encode('Uryyb, jbeyq', 'rot13'))\"" + output = self._run(cmd) + self.assertEqual(output, "Hello, world\n") diff --git a/meta/lib/oeqa/sdk/context.py b/meta/lib/oeqa/sdk/context.py index b3d7c75183..01c38c24e6 100644 --- a/meta/lib/oeqa/sdk/context.py +++ b/meta/lib/oeqa/sdk/context.py @@ -1,15 +1,17 @@ +# # Copyright (C) 2016 Intel Corporation -# Released under the MIT license (see COPYING.MIT) +# +# SPDX-License-Identifier: MIT +# import os import sys import glob import re -from oeqa.core.context import OETestContextExecutor -from oeqa.core.threaded import OETestContextThreaded +from oeqa.core.context import OETestContext, OETestContextExecutor -class OESDKTestContext(OETestContextThreaded): +class OESDKTestContext(OETestContext): sdk_files_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") def __init__(self, td=None, logger=None, sdk_dir=None, sdk_env=None, @@ -21,17 +23,30 @@ class OESDKTestContext(OETestContextThreaded): self.target_pkg_manifest = target_pkg_manifest self.host_pkg_manifest = host_pkg_manifest - def _hasPackage(self, manifest, pkg): - for host_pkg in manifest.keys(): - if re.search(pkg, host_pkg): + def _hasPackage(self, manifest, pkg, regex=False): + if regex: + # do regex match + pat = re.compile(pkg) + for p in manifest.keys(): + if pat.search(p): + return True + else: + # do exact match + if pkg in manifest.keys(): return True return False - def hasHostPackage(self, pkg): - return self._hasPackage(self.host_pkg_manifest, pkg) + def hasHostPackage(self, pkg, regex=False): + return self._hasPackage(self.host_pkg_manifest, pkg, regex=regex) - def hasTargetPackage(self, pkg): - return self._hasPackage(self.target_pkg_manifest, pkg) + def hasTargetPackage(self, pkg, multilib=False, regex=False): + if multilib: + # match multilib according to sdk_env + mls = self.td.get('MULTILIB_VARIANTS', '').split() + for ml in mls: + if ('ml'+ml) in self.sdk_env: + pkg = ml + '-' + pkg + return self._hasPackage(self.target_pkg_manifest, pkg, regex=regex) class OESDKTestContextExecutor(OETestContextExecutor): _context_class = OESDKTestContext @@ -66,6 +81,9 @@ class OESDKTestContextExecutor(OETestContextExecutor): sdk_rgroup.add_argument('--sdk-dir', required=False, action='store', help='sdk installed directory') + self.parser.add_argument('-j', '--num-processes', dest='processes', action='store', + type=int, help="number of processes to execute in parallel with") + @staticmethod def _load_manifest(manifest): pkg_manifest = {} @@ -86,6 +104,7 @@ class OESDKTestContextExecutor(OETestContextExecutor): OESDKTestContextExecutor._load_manifest(args.target_manifest) self.tc_kwargs['init']['host_pkg_manifest'] = \ OESDKTestContextExecutor._load_manifest(args.host_manifest) + self.tc_kwargs['run']['processes'] = args.processes @staticmethod def _get_sdk_environs(sdk_dir): @@ -117,7 +136,7 @@ class OESDKTestContextExecutor(OETestContextExecutor): sdk_envs = OESDKTestContextExecutor._get_sdk_environs(args.sdk_dir) if not sdk_envs: raise argparse_oe.ArgumentUsageError("No available SDK "\ - "enviroments found at %s" % args.sdk_dir, self.name) + "environments found at %s" % args.sdk_dir, self.name) if args.list_sdk_env: self._display_sdk_envs(logger.info, args, sdk_envs) diff --git a/meta/lib/oeqa/sdk/testsdk.py b/meta/lib/oeqa/sdk/testsdk.py new file mode 100644 index 0000000000..35e40187bc --- /dev/null +++ b/meta/lib/oeqa/sdk/testsdk.py @@ -0,0 +1,145 @@ +# +# Copyright 2018 by Garmin Ltd. or its subsidiaries +# +# SPDX-License-Identifier: MIT +# + +from oeqa.sdk.context import OESDKTestContext, OESDKTestContextExecutor + +class TestSDKBase(object): + @staticmethod + def get_sdk_configuration(d, test_type): + import platform + import oe.lsb + from oeqa.utils.metadata import get_layers + configuration = {'TEST_TYPE': test_type, + 'MACHINE': d.getVar("MACHINE"), + 'SDKMACHINE': d.getVar("SDKMACHINE"), + 'IMAGE_BASENAME': d.getVar("IMAGE_BASENAME"), + 'IMAGE_PKGTYPE': d.getVar("IMAGE_PKGTYPE"), + 'STARTTIME': d.getVar("DATETIME"), + 'HOST_DISTRO': oe.lsb.distro_identifier().replace(' ', '-'), + 'LAYERS': get_layers(d.getVar("BBLAYERS"))} + return configuration + + @staticmethod + def get_sdk_json_result_dir(d): + json_result_dir = os.path.join(d.getVar("LOG_DIR"), 'oeqa') + custom_json_result_dir = d.getVar("OEQA_JSON_RESULT_DIR") + if custom_json_result_dir: + json_result_dir = custom_json_result_dir + return json_result_dir + + @staticmethod + def get_sdk_result_id(configuration): + return '%s_%s_%s_%s_%s' % (configuration['TEST_TYPE'], configuration['IMAGE_BASENAME'], configuration['SDKMACHINE'], configuration['MACHINE'], configuration['STARTTIME']) + +class TestSDK(TestSDKBase): + context_executor_class = OESDKTestContextExecutor + context_class = OESDKTestContext + test_type = 'sdk' + + def get_tcname(self, d): + """ + Get the name of the SDK file + """ + return d.expand("${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh") + + def extract_sdk(self, tcname, sdk_dir, d): + """ + Extract the SDK to the specified location + """ + import subprocess + + try: + subprocess.check_output("cd %s; %s <<EOF\n./\nY\nEOF" % (sdk_dir, tcname), shell=True) + except subprocess.CalledProcessError as e: + bb.fatal("Couldn't install the SDK:\n%s" % e.output.decode("utf-8")) + + def setup_context(self, d): + """ + Return a dictionary of additional arguments that should be passed to + the context_class on construction + """ + return dict() + + def run(self, d): + + import os + import subprocess + import json + import logging + + from bb.utils import export_proxies + from oeqa.utils import make_logger_bitbake_compatible + + pn = d.getVar("PN") + logger = make_logger_bitbake_compatible(logging.getLogger("BitBake")) + + # sdk use network for download projects for build + export_proxies(d) + + tcname = self.get_tcname(d) + + if not os.path.exists(tcname): + bb.fatal("The toolchain %s is not built. Build it before running the tests: 'bitbake <image> -c populate_sdk' ." % tcname) + + tdname = d.expand("${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.testdata.json") + test_data = json.load(open(tdname, "r")) + + target_pkg_manifest = self.context_executor_class._load_manifest( + d.expand("${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.target.manifest")) + host_pkg_manifest = self.context_executor_class._load_manifest( + d.expand("${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.host.manifest")) + + processes = d.getVar("TESTIMAGE_NUMBER_THREADS") or d.getVar("BB_NUMBER_THREADS") + if processes: + try: + import testtools, subunit + except ImportError: + bb.warn("Failed to import testtools or subunit, the testcases will run serially") + processes = None + + sdk_dir = d.expand("${WORKDIR}/testimage-sdk/") + bb.utils.remove(sdk_dir, True) + bb.utils.mkdirhier(sdk_dir) + + context_args = self.setup_context(d) + + self.extract_sdk(tcname, sdk_dir, d) + + fail = False + sdk_envs = self.context_executor_class._get_sdk_environs(sdk_dir) + for s in sdk_envs: + sdk_env = sdk_envs[s] + bb.plain("SDK testing environment: %s" % s) + tc = self.context_class(td=test_data, logger=logger, sdk_dir=sdk_dir, + sdk_env=sdk_env, target_pkg_manifest=target_pkg_manifest, + host_pkg_manifest=host_pkg_manifest, **context_args) + + try: + tc.loadTests(self.context_executor_class.default_cases) + except Exception as e: + import traceback + bb.fatal("Loading tests failed:\n%s" % traceback.format_exc()) + + if processes: + result = tc.runTests(processes=int(processes)) + else: + result = tc.runTests() + + component = "%s %s" % (pn, self.context_executor_class.name) + context_msg = "%s:%s" % (os.path.basename(tcname), os.path.basename(sdk_env)) + configuration = self.get_sdk_configuration(d, self.test_type) + result.logDetails(self.get_sdk_json_result_dir(d), + configuration, + self.get_sdk_result_id(configuration)) + result.logSummary(component, context_msg) + + if not result.wasSuccessful(): + fail = True + + if fail: + bb.fatal("%s - FAILED - check the task log and the commands log" % pn) + + diff --git a/meta/lib/oeqa/sdk/utils/sdkbuildproject.py b/meta/lib/oeqa/sdk/utils/sdkbuildproject.py index 4e251142d7..32f5e3310d 100644 --- a/meta/lib/oeqa/sdk/utils/sdkbuildproject.py +++ b/meta/lib/oeqa/sdk/utils/sdkbuildproject.py @@ -1,5 +1,8 @@ +# # Copyright (C) 2016 Intel Corporation -# Released under the MIT license (see COPYING.MIT) +# +# SPDX-License-Identifier: MIT +# import os import subprocess @@ -20,10 +23,9 @@ class SDKBuildProject(BuildProject): BuildProject.__init__(self, uri, foldername, tmpdir=testpath, dl_dir=dl_dir) def download_archive(self): - self._download_archive() - cmd = 'tar xf %s%s -C %s' % (self.targetdir, self.archive, self.targetdir) + cmd = 'tar xf %s -C %s' % (os.path.join(self.targetdir, self.archive), self.targetdir) subprocess.check_output(cmd, shell=True) #Change targetdir to project folder @@ -42,4 +44,10 @@ class SDKBuildProject(BuildProject): def _run(self, cmd): self.log("Running . %s; " % self.sdkenv + cmd) - return subprocess.call(". %s; " % self.sdkenv + cmd, shell=True) + try: + output = subprocess.check_output(". %s; " % self.sdkenv + cmd, shell=True, + executable='/bin/bash', stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as exc: + print(exc.output.decode('utf-8')) + return exc.returncode + return 0 |