public inbox for isar-users@googlegroups.com
 help / color / mirror / Atom feed
* [RFC PATCH v2] testsuite: refactor
@ 2021-12-10  8:15 Adriaan Schmidt
  2021-12-10 15:05 ` Anton Mikanovich
  0 siblings, 1 reply; 3+ messages in thread
From: Adriaan Schmidt @ 2021-12-10  8:15 UTC (permalink / raw)
  To: amikan, isar-users; +Cc: Adriaan Schmidt

- make test initialization more explicit.
  tests now call init() to initialize build_dir and environment,
  and configure() to generate the config file and bitbake_args
- only configure() touches the config file. if config needs to change
  during one test case, it is created from scratch (no appending
  by the test case itself).
- build_dir is not passed via avocado parameter. each test
  can set it in the call to init(). this makes dependencies
  between tests explicit and permits parallelization.
- in the main invocation script, rename --build to --base.
  what we're setting here is not the bitbake build_dir but
  the base dir for avocado test output.

Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
---
 scripts/ci_build.sh                |  22 +++---
 testsuite/build_test/build_test.py |  35 +++++-----
 testsuite/build_test/cibase.py     | 103 +++++++++--------------------
 testsuite/build_test/cibuilder.py  |  98 +++++++++++++++++++--------
 4 files changed, 128 insertions(+), 130 deletions(-)

diff --git a/scripts/ci_build.sh b/scripts/ci_build.sh
index e9ba034..339ebca 100755
--- a/scripts/ci_build.sh
+++ b/scripts/ci_build.sh
@@ -27,8 +27,8 @@ fi
 # Get Avocado build tests path
 BUILD_TEST_DIR="$(pwd)/testsuite/build_test"
 
-# Start build in Isar tree by default
-BUILD_DIR=./build
+# Start tests in current path by default
+BASE_DIR=./build
 
 # Check dependencies
 DEPENDENCIES="umoci skopeo"
@@ -45,8 +45,8 @@ show_help() {
     echo "    $0 [params]"
     echo
     echo "Parameters:"
-    echo "    -b, --build BUILD_DIR    set path to build directory. If not set,"
-    echo "                             the build will be started in current path."
+    echo "    -b, --base BASE_DIR      set path to base directory. If not set,"
+    echo "                             the tests will be started in current path."
     echo "    -c, --cross              enable cross-compilation."
     echo "    -d, --debug              enable debug bitbake output."
     echo "    -f, --fast               cross build reduced set of configurations."
@@ -73,8 +73,8 @@ do
         show_help
         exit 0
         ;;
-    -b|--build)
-        BUILD_DIR="$2"
+    -b|--base)
+        BASE_DIR="$2"
         shift
         ;;
     -c|--cross)
@@ -117,10 +117,10 @@ fi
 mkdir -p .config/avocado
 cat <<EOF > .config/avocado/avocado.conf
 [datadir.paths]
-base_dir = $(realpath $BUILD_DIR)/
-test_dir = $(realpath $BUILD_DIR)/tests
-data_dir = $(realpath $BUILD_DIR)/data
-logs_dir = $(realpath $BUILD_DIR)/job-results
+base_dir = $(realpath $BASE_DIR)/
+test_dir = $(realpath $BASE_DIR)/tests
+data_dir = $(realpath $BASE_DIR)/data
+logs_dir = $(realpath $BASE_DIR)/job-results
 EOF
 export VIRTUAL_ENV="./"
 
@@ -129,4 +129,4 @@ set -x
 
 avocado $VERBOSE run "$BUILD_TEST_DIR/build_test.py" \
     -t $TAGS --test-runner=runner --disable-sysinfo \
-    -p build_dir="$BUILD_DIR" -p quiet=$QUIET -p cross=$CROSS_BUILD
+    -p quiet=$QUIET -p cross=$CROSS_BUILD
diff --git a/testsuite/build_test/build_test.py b/testsuite/build_test/build_test.py
index de9e3fc..7359295 100644
--- a/testsuite/build_test/build_test.py
+++ b/testsuite/build_test/build_test.py
@@ -3,7 +3,7 @@
 import os
 
 from avocado import skipUnless
-from avocado.utils import path
+from avocado.utils import path, process
 from cibase import CIBaseTest
 
 UMOCI_AVAILABLE = True
@@ -30,7 +30,7 @@ class ReproTest(CIBaseTest):
             'mc:qemuarm64-stretch:isar-image-base'
                   ]
 
-        self.perform_repro_test(targets, 1)
+        self.perform_repro_test(targets, signed=True)
 
     def test_repro_unsigned(self):
         targets = [
@@ -38,7 +38,7 @@ class ReproTest(CIBaseTest):
             'mc:qemuarm-stretch:isar-image-base'
                   ]
 
-        self.perform_repro_test(targets, 0)
+        self.perform_repro_test(targets)
 
 class CcacheTest(CIBaseTest):
 
@@ -69,7 +69,7 @@ class CrossTest(CIBaseTest):
             'mc:rpi-stretch:isar-image-base'
                   ]
 
-        self.perform_build_test(targets, 1, None)
+        self.perform_build_test(targets, cross=True)
 
     def test_cross_ubuntu(self):
         targets = [
@@ -77,7 +77,7 @@ class CrossTest(CIBaseTest):
                   ]
 
         try:
-            self.perform_build_test(targets, 1, None)
+            self.perform_build_test(targets, cross=True)
         except:
             self.cancel('KFAIL')
 
@@ -87,7 +87,7 @@ class CrossTest(CIBaseTest):
                   ]
 
         try:
-            self.perform_build_test(targets, 1, None)
+            self.perform_build_test(targets, cross=True)
         except:
             self.cancel('KFAIL')
 
@@ -101,7 +101,7 @@ class SdkTest(CIBaseTest):
     def test_sdk(self):
         targets = ['mc:qemuarm-stretch:isar-image-base']
 
-        self.perform_build_test(targets, 1, 'do_populate_sdk')
+        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk')
 
 class NoCrossTest(CIBaseTest):
 
@@ -131,10 +131,9 @@ class NoCrossTest(CIBaseTest):
                   ]
 
         # Cleanup after cross build
-        self.deletetmp(self.params.get('build_dir',
-                       default=os.path.dirname(__file__) + '/../../build'))
-
-        self.perform_build_test(targets, 0, None)
+        self.init()
+        self.delete_from_build_dir('tmp')
+        self.perform_build_test(targets, cross=False)
 
     def test_nocross_bullseye(self):
         targets = [
@@ -146,7 +145,7 @@ class NoCrossTest(CIBaseTest):
                   ]
 
         try:
-            self.perform_build_test(targets, 0, None)
+            self.perform_build_test(targets, cross=False)
         except:
             self.cancel('KFAIL')
 
@@ -158,19 +157,16 @@ class RebuildTest(CIBaseTest):
     :avocado: tags=rebuild,fast,full
     """
     def test_rebuild(self):
-        is_cross_build = int(self.params.get('cross', default=0))
-
+        self.init()
         layerdir_core = self.getlayerdir('core')
 
         dpkgbase_file = layerdir_core + '/classes/dpkg-base.bbclass'
-
         self.backupfile(dpkgbase_file)
         with open(dpkgbase_file, 'a') as file:
             file.write('do_fetch_append() {\n\n}')
 
         try:
-            self.perform_build_test('mc:qemuamd64-stretch:isar-image-base',
-                                    is_cross_build, None)
+            self.perform_build_test('mc:qemuamd64-stretch:isar-image-base')
         finally:
             self.restorefile(dpkgbase_file)
 
@@ -189,6 +185,7 @@ class WicTest(CIBaseTest):
         self.perform_wic_test('mc:qemuamd64-stretch:isar-image-base',
                               wks_path, wic_path)
 
+
 class ContainerImageTest(CIBaseTest):
 
     """
@@ -204,7 +201,7 @@ class ContainerImageTest(CIBaseTest):
             'mc:container-amd64-bullseye:isar-image-base'
                   ]
 
-        self.perform_container_test(targets, None)
+        self.perform_build_test(targets, container=True)
 
 class ContainerSdkTest(CIBaseTest):
 
@@ -217,4 +214,4 @@ class ContainerSdkTest(CIBaseTest):
     def test_container_sdk(self):
         targets = ['mc:container-amd64-stretch:isar-image-base']
 
-        self.perform_container_test(targets, 'do_populate_sdk')
+        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk', container=True)
diff --git a/testsuite/build_test/cibase.py b/testsuite/build_test/cibase.py
index 0b053aa..9c06c94 100644
--- a/testsuite/build_test/cibase.py
+++ b/testsuite/build_test/cibase.py
@@ -8,50 +8,24 @@ import time
 from cibuilder import CIBuilder
 from avocado.utils import process
 
-isar_root = os.path.dirname(__file__) + '/../..'
 
 class CIBaseTest(CIBuilder):
-
-    def prep(self, testname, targets, cross, debsrc_cache):
-        build_dir = self.params.get('build_dir', default=isar_root + '/build')
-        build_dir = os.path.realpath(build_dir)
-        quiet = int(self.params.get('quiet', default=0))
-        bitbake_args = '-v'
-
-        if quiet:
-            bitbake_args = ''
-
-        self.log.info('===================================================')
-        self.log.info('Running ' + testname + ' test for:')
-        self.log.info(targets)
-        self.log.info('Isar build folder is: ' + build_dir)
-        self.log.info('===================================================')
-
-        self.init(build_dir)
-        self.confprepare(build_dir, 1, cross, debsrc_cache)
-
-        return build_dir, bitbake_args;
-
-    def perform_build_test(self, targets, cross, bitbake_cmd):
-        build_dir, bb_args = self.prep('Isar build', targets, cross, 1)
+    def perform_build_test(self, targets, **kwargs):
+        self.init(**kwargs)
+        self.configure(**kwargs)
 
         self.log.info('Starting build...')
 
-        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
-
-    def perform_repro_test(self, targets, signed):
-        cross = int(self.params.get('cross', default=0))
-        build_dir, bb_args = self.prep('repro Isar build', targets, cross, 0)
+        self.bitbake(targets, **kwargs)
 
+    def perform_repro_test(self, targets, signed=False, **kwargs):
         gpg_pub_key = os.path.dirname(__file__) + '/../base-apt/test_pub.key'
         gpg_priv_key = os.path.dirname(__file__) + '/../base-apt/test_priv.key'
 
-        if signed:
-            with open(build_dir + '/conf/ci_build.conf', 'a') as file:
-                # Enable use of signed cached base repository
-                file.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
+        self.init(**kwargs)
+        self.configure(gpg_pub_key=gpg_pub_key if signed else None, **kwargs)
 
-        os.chdir(build_dir)
+        os.chdir(self.build_dir)
 
         os.environ['GNUPGHOME'] = tempfile.mkdtemp()
         result = process.run('gpg --import %s %s' % (gpg_pub_key, gpg_priv_key))
@@ -59,33 +33,31 @@ class CIBaseTest(CIBuilder):
         if result.exit_status:
             self.fail('GPG import failed')
 
-        self.bitbake(build_dir, targets, None, bb_args)
+        self.bitbake(targets, **kwargs)
 
-        self.deletetmp(build_dir)
-        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
-            file.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
-            file.write('BB_NO_NETWORK = "1"\n')
+        self.delete_from_build_dir('tmp')
+        self.configure(gpg_pub_key=gpg_pub_key if signed else None, offline=True, **kwargs)
 
-        self.bitbake(build_dir, targets, None, bb_args)
+        self.bitbake(targets, **kwargs)
 
         # Disable use of cached base repository
-        self.confcleanup(build_dir)
+        self.unconfigure()
 
         if not signed:
             # Try to build with changed configuration with no cleanup
-            self.bitbake(build_dir, targets, None, bb_args)
+            self.bitbake(targets, **kwargs)
 
         # Cleanup
-        self.deletetmp(build_dir)
+        self.delete_from_build_dir('tmp')
 
-    def perform_wic_test(self, targets, wks_path, wic_path):
-        cross = int(self.params.get('cross', default=0))
-        build_dir, bb_args = self.prep('WIC exclude build', targets, cross, 1)
+    def perform_wic_test(self, targets, wks_path, wic_path, **kwargs):
+        self.init(**kwargs)
+        self.configure(**kwargs)
 
         layerdir_isar = self.getlayerdir('isar')
 
         wks_file = layerdir_isar + wks_path
-        wic_img = build_dir + wic_path
+        wic_img = self.build_dir + wic_path
 
         if not os.path.isfile(wic_img):
             self.fail('No build started before: ' + wic_img + ' not exist')
@@ -99,44 +71,30 @@ class CIBaseTest(CIBuilder):
             for line in lines:
                 file.write(re.sub(r'part \/ ', 'part \/ --exclude-path usr ',
                                   line))
-
         try:
-            self.bitbake(build_dir, targets, None, bb_args)
+            self.bitbake(targets, **kwargs)
         finally:
             self.restorefile(wks_file)
-
         self.restorefile(wic_img)
 
-    def perform_container_test(self, targets, bitbake_cmd):
-        cross = int(self.params.get('cross', default=0))
-        build_dir, bb_args = self.prep('Isar Container', targets, cross, 1)
-
-        self.containerprep(build_dir)
-
-        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
-
+    def perform_ccache_test(self, targets, **kwargs):
+        self.init(**kwargs)
+        self.configure(ccache=True, **kwargs)
 
-    def perform_ccache_test(self, targets):
-        build_dir, bb_args = self.prep('Isar ccache build', targets, 0, 0)
-
-        self.deletetmp(build_dir)
-        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
-
-        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
-            file.write('USE_CCACHE = "1"\n')
-            file.write('CCACHE_TOP_DIR = "${TOPDIR}/ccache"')
+        self.delete_from_build_dir('tmp')
+        self.delete_from_build_dir('ccache')
 
         self.log.info('Starting build and filling ccache dir...')
         start = time.time()
-        self.bitbake(build_dir, targets, None, bb_args)
+        self.bitbake(targets, **kwargs)
         first_time = time.time() - start
         self.log.info('Non-cached build: ' + str(round(first_time)) + 's')
 
-        self.deletetmp(build_dir)
+        self.delete_from_build_dir('tmp')
 
         self.log.info('Starting build and using ccache dir...')
         start = time.time()
-        self.bitbake(build_dir, targets, None, bb_args)
+        self.bitbake(targets, **kwargs)
         second_time = time.time() - start
         self.log.info('Cached build: ' + str(round(second_time)) + 's')
 
@@ -145,5 +103,6 @@ class CIBaseTest(CIBuilder):
             self.fail('No speedup after rebuild with ccache')
 
         # Cleanup
-        self.deletetmp(build_dir)
-        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
+        self.delete_from_build_dir('tmp')
+        self.delete_from_build_dir('ccache')
+
diff --git a/testsuite/build_test/cibuilder.py b/testsuite/build_test/cibuilder.py
index 94786c7..6a9f6a0 100644
--- a/testsuite/build_test/cibuilder.py
+++ b/testsuite/build_test/cibuilder.py
@@ -2,7 +2,6 @@
 
 import logging
 import os
-import re
 import select
 import shutil
 import subprocess
@@ -11,9 +10,8 @@ from avocado import Test
 from avocado.utils import path
 from avocado.utils import process
 
-isar_root = os.path.dirname(__file__) + '/../..'
+isar_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
 backup_prefix = '.ci-backup'
-
 app_log = logging.getLogger("avocado.app")
 
 class CIBuilder(Test):
@@ -28,17 +26,55 @@ class CIBuilder(Test):
         self._file_handler.setFormatter(formatter)
         app_log.addHandler(self._file_handler)
 
-    def init(self, build_dir):
+
+    def init(self, build_dir='build', **kwargs):
+        # initialize build_dir and setup environment
+        # needs to run once (per test case)
+        self.build_dir = os.path.join(isar_root, build_dir)
         os.chdir(isar_root)
-        path.usable_rw_dir(build_dir)
+        path.usable_rw_dir(self.build_dir)
         output = process.getoutput('/bin/bash -c "source isar-init-build-env \
-                                    %s 2>&1 >/dev/null; env"' % build_dir)
+                                    %s 2>&1 >/dev/null; env"' % self.build_dir)
         env = dict(((x.split('=', 1) + [''])[:2] \
                     for x in output.splitlines() if x != ''))
         os.environ.update(env)
 
-    def confprepare(self, build_dir, compat_arch, cross, debsrc_cache):
-        with open(build_dir + '/conf/ci_build.conf', 'w') as f:
+
+    def configure(self, compat_arch=True, cross=None, debsrc_cache=True,
+                  container=False, ccache=False, sstate=False, offline=False,
+                  gpg_pub_key=None, **kwargs):
+        # write configuration file and set bitbake_args
+        # can run multiple times per test case
+
+        # get parameters from avocado cmdline
+        quiet = bool(int(self.params.get('quiet', default=0)))
+        if cross is None:
+            cross = bool(int(self.params.get('cross', default=0)))
+
+        # get parameters from environment
+        distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
+
+        self.log.info(f'===================================================\n'
+                      f'Configuring build_dir {self.build_dir}\n'
+                      f'  compat_arch = {compat_arch}\n'
+                      f'  cross = {cross}\n'
+                      f'  debsrc_cache = {debsrc_cache}\n'
+                      f'  offline = {offline}\n'
+                      f'  container = {container}\n'
+                      f'  ccache = {ccache}\n'
+                      f'  sstate = {sstate}\n'
+                      f'  gpg_pub_key = {gpg_pub_key}\n'
+                      f'===================================================')
+
+        # determine bitbake_args
+        self.bitbake_args = []
+        if not quiet:
+            self.bitbake_args.append('-v')
+        if not sstate:
+            self.bitbake_args.append('--no-setscene')
+
+        # write ci_build.conf
+        with open(self.build_dir + '/conf/ci_build.conf', 'w') as f:
             if compat_arch:
                 f.write('ISAR_ENABLE_COMPAT_ARCH_amd64 = "1"\n')
                 f.write('ISAR_ENABLE_COMPAT_ARCH_arm64 = "1"\n')
@@ -48,36 +84,42 @@ class CIBuilder(Test):
                 f.write('ISAR_CROSS_COMPILE = "1"\n')
             if debsrc_cache:
                 f.write('BASE_REPO_FEATURES = "cache-deb-src"\n')
-            distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
+            if offline:
+                f.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
+                f.write('BB_NO_NETWORK = "1"\n')
+            if container:
+                f.write('SDK_FORMATS = "docker-archive"\n')
+                f.write('IMAGE_INSTALL_remove = "example-module-${KERNEL_NAME} enable-fsck"\n')
+            if gpg_pub_key:
+                f.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
             if distro_apt_premir:
                 f.write('DISTRO_APT_PREMIRRORS = "%s"\n' % distro_apt_premir)
 
-        with open(build_dir + '/conf/local.conf', 'r+') as f:
+        # include ci_build.conf in local.conf
+        with open(self.build_dir + '/conf/local.conf', 'r+') as f:
             for line in f:
                 if 'include ci_build.conf' in line:
                     break
             else:
                 f.write('\ninclude ci_build.conf')
 
-    def containerprep(self, build_dir):
-        with open(build_dir + '/conf/ci_build.conf', 'a') as f:
-            f.write('SDK_FORMATS = "docker-archive"\n')
-            f.write('IMAGE_INSTALL_remove = "example-module-${KERNEL_NAME} enable-fsck"\n')
-
-    def confcleanup(self, build_dir):
-        open(build_dir + '/conf/ci_build.conf', 'w').close()
+    def unconfigure(self):
+        open(self.build_dir + '/conf/ci_build.conf', 'w').close()
 
-    def deletetmp(self, build_dir):
-        process.run('rm -rf ' + build_dir + '/tmp', sudo=True)
+    def delete_from_build_dir(self, path):
+        process.run('rm -rf ' + self.build_dir + '/' + path, sudo=True)
 
-    def bitbake(self, build_dir, target, cmd, args):
-        os.chdir(build_dir)
+    def bitbake(self, target, bitbake_cmd=None, **kwargs):
+        self.log.info('===================================================')
+        self.log.info('Building ' + str(target))
+        self.log.info('===================================================')
+        os.chdir(self.build_dir)
         cmdline = ['bitbake']
-        if args:
-            cmdline.append(args)
-        if cmd:
+        if self.bitbake_args:
+            cmdline.extend(self.bitbake_args)
+        if bitbake_cmd:
             cmdline.append('-c')
-            cmdline.append(cmd)
+            cmdline.append(bitbake_cmd)
         if isinstance(target, list):
             cmdline.extend(target)
         else:
@@ -124,9 +166,9 @@ class CIBuilder(Test):
         try:
             path.find_command('bitbake')
         except path.CmdNotFoundError:
-            build_dir = self.params.get('build_dir',
-                                        default=isar_root + '/build')
-            self.init(build_dir)
+            self.log.error("Broken test implementation: must call init() before "
+                           "using getlayerdir()!")
+            raise
         output = process.getoutput('bitbake -e | grep "^LAYERDIR_.*="')
         env = dict(((x.split('=', 1) + [''])[:2] \
                     for x in output.splitlines() if x != ''))
-- 
2.30.2


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH v2] testsuite: refactor
  2021-12-10  8:15 [RFC PATCH v2] testsuite: refactor Adriaan Schmidt
@ 2021-12-10 15:05 ` Anton Mikanovich
  2021-12-10 16:12   ` Schmidt, Adriaan
  0 siblings, 1 reply; 3+ messages in thread
From: Anton Mikanovich @ 2021-12-10 15:05 UTC (permalink / raw)
  To: Adriaan Schmidt, isar-users

Thanks for v2, it looks much better now.
But there are still some comments bellow.

10.12.2021 11:15, Adriaan Schmidt wrote:
> - make test initialization more explicit.
>    tests now call init() to initialize build_dir and environment,
>    and configure() to generate the config file and bitbake_args
> - only configure() touches the config file. if config needs to change
>    during one test case, it is created from scratch (no appending
>    by the test case itself).
> - build_dir is not passed via avocado parameter. each test
>    can set it in the call to init(). this makes dependencies
>    between tests explicit and permits parallelization.
> - in the main invocation script, rename --build to --base.
>    what we're setting here is not the bitbake build_dir but
>    the base dir for avocado test output.
>
> Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
> ---
>   scripts/ci_build.sh                |  22 +++---
>   testsuite/build_test/build_test.py |  35 +++++-----
>   testsuite/build_test/cibase.py     | 103 +++++++++--------------------
>   testsuite/build_test/cibuilder.py  |  98 +++++++++++++++++++--------
>   4 files changed, 128 insertions(+), 130 deletions(-)
>
> diff --git a/scripts/ci_build.sh b/scripts/ci_build.sh
> index e9ba034..339ebca 100755
> --- a/scripts/ci_build.sh
> +++ b/scripts/ci_build.sh
> @@ -27,8 +27,8 @@ fi
>   # Get Avocado build tests path
>   BUILD_TEST_DIR="$(pwd)/testsuite/build_test"
>   
> -# Start build in Isar tree by default
> -BUILD_DIR=./build
> +# Start tests in current path by default
> +BASE_DIR=./build
>   
>   # Check dependencies
>   DEPENDENCIES="umoci skopeo"
> @@ -45,8 +45,8 @@ show_help() {
>       echo "    $0 [params]"
>       echo
>       echo "Parameters:"
> -    echo "    -b, --build BUILD_DIR    set path to build directory. If not set,"
> -    echo "                             the build will be started in current path."
> +    echo "    -b, --base BASE_DIR      set path to base directory. If not set,"
> +    echo "                             the tests will be started in current path."
>       echo "    -c, --cross              enable cross-compilation."
>       echo "    -d, --debug              enable debug bitbake output."
>       echo "    -f, --fast               cross build reduced set of configurations."
> @@ -73,8 +73,8 @@ do
>           show_help
>           exit 0
>           ;;
> -    -b|--build)
> -        BUILD_DIR="$2"
> +    -b|--base)
> +        BASE_DIR="$2"
>           shift
>           ;;
>       -c|--cross)
> @@ -117,10 +117,10 @@ fi
>   mkdir -p .config/avocado
>   cat <<EOF > .config/avocado/avocado.conf
>   [datadir.paths]
> -base_dir = $(realpath $BUILD_DIR)/
> -test_dir = $(realpath $BUILD_DIR)/tests
> -data_dir = $(realpath $BUILD_DIR)/data
> -logs_dir = $(realpath $BUILD_DIR)/job-results
> +base_dir = $(realpath $BASE_DIR)/
> +test_dir = $(realpath $BASE_DIR)/tests
> +data_dir = $(realpath $BASE_DIR)/data
> +logs_dir = $(realpath $BASE_DIR)/job-results
>   EOF
>   export VIRTUAL_ENV="./"
>   
> @@ -129,4 +129,4 @@ set -x
>   
>   avocado $VERBOSE run "$BUILD_TEST_DIR/build_test.py" \
>       -t $TAGS --test-runner=runner --disable-sysinfo \
> -    -p build_dir="$BUILD_DIR" -p quiet=$QUIET -p cross=$CROSS_BUILD
> +    -p quiet=$QUIET -p cross=$CROSS_BUILD
> diff --git a/testsuite/build_test/build_test.py b/testsuite/build_test/build_test.py
> index de9e3fc..7359295 100644
> --- a/testsuite/build_test/build_test.py
> +++ b/testsuite/build_test/build_test.py
> @@ -3,7 +3,7 @@
>   import os
>   
>   from avocado import skipUnless
> -from avocado.utils import path
> +from avocado.utils import path, process

Does it really needed here?

>   from cibase import CIBaseTest
>   
>   UMOCI_AVAILABLE = True
> @@ -30,7 +30,7 @@ class ReproTest(CIBaseTest):
>               'mc:qemuarm64-stretch:isar-image-base'
>                     ]
>   
> -        self.perform_repro_test(targets, 1)
> +        self.perform_repro_test(targets, signed=True)
>   
>       def test_repro_unsigned(self):
>           targets = [
> @@ -38,7 +38,7 @@ class ReproTest(CIBaseTest):
>               'mc:qemuarm-stretch:isar-image-base'
>                     ]
>   
> -        self.perform_repro_test(targets, 0)
> +        self.perform_repro_test(targets)
>   
>   class CcacheTest(CIBaseTest):
>   
> @@ -69,7 +69,7 @@ class CrossTest(CIBaseTest):
>               'mc:rpi-stretch:isar-image-base'
>                     ]
>   
> -        self.perform_build_test(targets, 1, None)
> +        self.perform_build_test(targets, cross=True)
>   
>       def test_cross_ubuntu(self):
>           targets = [
> @@ -77,7 +77,7 @@ class CrossTest(CIBaseTest):
>                     ]
>   
>           try:
> -            self.perform_build_test(targets, 1, None)
> +            self.perform_build_test(targets, cross=True)
>           except:
>               self.cancel('KFAIL')
>   
> @@ -87,7 +87,7 @@ class CrossTest(CIBaseTest):
>                     ]
>   
>           try:
> -            self.perform_build_test(targets, 1, None)
> +            self.perform_build_test(targets, cross=True)
>           except:
>               self.cancel('KFAIL')
>   
> @@ -101,7 +101,7 @@ class SdkTest(CIBaseTest):
>       def test_sdk(self):
>           targets = ['mc:qemuarm-stretch:isar-image-base']
>   
> -        self.perform_build_test(targets, 1, 'do_populate_sdk')
> +        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk')
>   
>   class NoCrossTest(CIBaseTest):
>   
> @@ -131,10 +131,9 @@ class NoCrossTest(CIBaseTest):
>                     ]
>   
>           # Cleanup after cross build
> -        self.deletetmp(self.params.get('build_dir',
> -                       default=os.path.dirname(__file__) + '/../../build'))
> -
> -        self.perform_build_test(targets, 0, None)
> +        self.init()

Is that the second init? Why we need it here?

> +        self.delete_from_build_dir('tmp')
> +        self.perform_build_test(targets, cross=False)
>   
>       def test_nocross_bullseye(self):
>           targets = [
> @@ -146,7 +145,7 @@ class NoCrossTest(CIBaseTest):
>                     ]
>   
>           try:
> -            self.perform_build_test(targets, 0, None)
> +            self.perform_build_test(targets, cross=False)
>           except:
>               self.cancel('KFAIL')
>   
> @@ -158,19 +157,16 @@ class RebuildTest(CIBaseTest):
>       :avocado: tags=rebuild,fast,full
>       """
>       def test_rebuild(self):
> -        is_cross_build = int(self.params.get('cross', default=0))
> -
> +        self.init()

The same question here. Init is already done inside perform_build_test.

>           layerdir_core = self.getlayerdir('core')
>   
>           dpkgbase_file = layerdir_core + '/classes/dpkg-base.bbclass'
> -

Please remove changes that just remove empty lines. It can be confusing 
for the history.

>           self.backupfile(dpkgbase_file)
>           with open(dpkgbase_file, 'a') as file:
>               file.write('do_fetch_append() {\n\n}')
>   
>           try:
> -            self.perform_build_test('mc:qemuamd64-stretch:isar-image-base',
> -                                    is_cross_build, None)
> +            self.perform_build_test('mc:qemuamd64-stretch:isar-image-base')
>           finally:
>               self.restorefile(dpkgbase_file)
>   
> @@ -189,6 +185,7 @@ class WicTest(CIBaseTest):
>           self.perform_wic_test('mc:qemuamd64-stretch:isar-image-base',
>                                 wks_path, wic_path)
>   
> +

The same with adding newlines.

>   class ContainerImageTest(CIBaseTest):
>   
>       """
> @@ -204,7 +201,7 @@ class ContainerImageTest(CIBaseTest):
>               'mc:container-amd64-bullseye:isar-image-base'
>                     ]
>   
> -        self.perform_container_test(targets, None)
> +        self.perform_build_test(targets, container=True)
>   
>   class ContainerSdkTest(CIBaseTest):
>   
> @@ -217,4 +214,4 @@ class ContainerSdkTest(CIBaseTest):
>       def test_container_sdk(self):
>           targets = ['mc:container-amd64-stretch:isar-image-base']
>   
> -        self.perform_container_test(targets, 'do_populate_sdk')
> +        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk', container=True)
> diff --git a/testsuite/build_test/cibase.py b/testsuite/build_test/cibase.py
> index 0b053aa..9c06c94 100644
> --- a/testsuite/build_test/cibase.py
> +++ b/testsuite/build_test/cibase.py
> @@ -8,50 +8,24 @@ import time
>   from cibuilder import CIBuilder
>   from avocado.utils import process
>   
> -isar_root = os.path.dirname(__file__) + '/../..'
>   
>   class CIBaseTest(CIBuilder):
> -
> -    def prep(self, testname, targets, cross, debsrc_cache):
> -        build_dir = self.params.get('build_dir', default=isar_root + '/build')
> -        build_dir = os.path.realpath(build_dir)
> -        quiet = int(self.params.get('quiet', default=0))
> -        bitbake_args = '-v'
> -
> -        if quiet:
> -            bitbake_args = ''
> -
> -        self.log.info('===================================================')
> -        self.log.info('Running ' + testname + ' test for:')
> -        self.log.info(targets)
> -        self.log.info('Isar build folder is: ' + build_dir)
> -        self.log.info('===================================================')
> -
> -        self.init(build_dir)
> -        self.confprepare(build_dir, 1, cross, debsrc_cache)
> -
> -        return build_dir, bitbake_args;
> -
> -    def perform_build_test(self, targets, cross, bitbake_cmd):
> -        build_dir, bb_args = self.prep('Isar build', targets, cross, 1)
> +    def perform_build_test(self, targets, **kwargs):
> +        self.init(**kwargs)
> +        self.configure(**kwargs)
>   
>           self.log.info('Starting build...')
>   
> -        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
> -
> -    def perform_repro_test(self, targets, signed):
> -        cross = int(self.params.get('cross', default=0))
> -        build_dir, bb_args = self.prep('repro Isar build', targets, cross, 0)
> +        self.bitbake(targets, **kwargs)
>   
> +    def perform_repro_test(self, targets, signed=False, **kwargs):
>           gpg_pub_key = os.path.dirname(__file__) + '/../base-apt/test_pub.key'
>           gpg_priv_key = os.path.dirname(__file__) + '/../base-apt/test_priv.key'
>   
> -        if signed:
> -            with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> -                # Enable use of signed cached base repository
> -                file.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
> +        self.init(**kwargs)
> +        self.configure(gpg_pub_key=gpg_pub_key if signed else None, **kwargs)
>   
> -        os.chdir(build_dir)
> +        os.chdir(self.build_dir)
>   
>           os.environ['GNUPGHOME'] = tempfile.mkdtemp()
>           result = process.run('gpg --import %s %s' % (gpg_pub_key, gpg_priv_key))
> @@ -59,33 +33,31 @@ class CIBaseTest(CIBuilder):
>           if result.exit_status:
>               self.fail('GPG import failed')
>   
> -        self.bitbake(build_dir, targets, None, bb_args)
> +        self.bitbake(targets, **kwargs)
>   
> -        self.deletetmp(build_dir)
> -        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> -            file.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
> -            file.write('BB_NO_NETWORK = "1"\n')
> +        self.delete_from_build_dir('tmp')
> +        self.configure(gpg_pub_key=gpg_pub_key if signed else None, offline=True, **kwargs)
>   
> -        self.bitbake(build_dir, targets, None, bb_args)
> +        self.bitbake(targets, **kwargs)
>   
>           # Disable use of cached base repository
> -        self.confcleanup(build_dir)
> +        self.unconfigure()
>   
>           if not signed:
>               # Try to build with changed configuration with no cleanup
> -            self.bitbake(build_dir, targets, None, bb_args)
> +            self.bitbake(targets, **kwargs)
>   
>           # Cleanup
> -        self.deletetmp(build_dir)
> +        self.delete_from_build_dir('tmp')
>   
> -    def perform_wic_test(self, targets, wks_path, wic_path):
> -        cross = int(self.params.get('cross', default=0))
> -        build_dir, bb_args = self.prep('WIC exclude build', targets, cross, 1)
> +    def perform_wic_test(self, targets, wks_path, wic_path, **kwargs):
> +        self.init(**kwargs)
> +        self.configure(**kwargs)
>   
>           layerdir_isar = self.getlayerdir('isar')
>   
>           wks_file = layerdir_isar + wks_path
> -        wic_img = build_dir + wic_path
> +        wic_img = self.build_dir + wic_path
>   
>           if not os.path.isfile(wic_img):
>               self.fail('No build started before: ' + wic_img + ' not exist')
> @@ -99,44 +71,30 @@ class CIBaseTest(CIBuilder):
>               for line in lines:
>                   file.write(re.sub(r'part \/ ', 'part \/ --exclude-path usr ',
>                                     line))
> -
>           try:
> -            self.bitbake(build_dir, targets, None, bb_args)
> +            self.bitbake(targets, **kwargs)
>           finally:
>               self.restorefile(wks_file)
> -
>           self.restorefile(wic_img)
>   
> -    def perform_container_test(self, targets, bitbake_cmd):
> -        cross = int(self.params.get('cross', default=0))
> -        build_dir, bb_args = self.prep('Isar Container', targets, cross, 1)
> -
> -        self.containerprep(build_dir)
> -
> -        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
> -
> +    def perform_ccache_test(self, targets, **kwargs):
> +        self.init(**kwargs)
> +        self.configure(ccache=True, **kwargs)
>   
> -    def perform_ccache_test(self, targets):
> -        build_dir, bb_args = self.prep('Isar ccache build', targets, 0, 0)
> -
> -        self.deletetmp(build_dir)
> -        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
> -
> -        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> -            file.write('USE_CCACHE = "1"\n')
> -            file.write('CCACHE_TOP_DIR = "${TOPDIR}/ccache"')
> +        self.delete_from_build_dir('tmp')
> +        self.delete_from_build_dir('ccache')
>   
>           self.log.info('Starting build and filling ccache dir...')
>           start = time.time()
> -        self.bitbake(build_dir, targets, None, bb_args)
> +        self.bitbake(targets, **kwargs)
>           first_time = time.time() - start
>           self.log.info('Non-cached build: ' + str(round(first_time)) + 's')
>   
> -        self.deletetmp(build_dir)
> +        self.delete_from_build_dir('tmp')
>   
>           self.log.info('Starting build and using ccache dir...')
>           start = time.time()
> -        self.bitbake(build_dir, targets, None, bb_args)
> +        self.bitbake(targets, **kwargs)
>           second_time = time.time() - start
>           self.log.info('Cached build: ' + str(round(second_time)) + 's')
>   
> @@ -145,5 +103,6 @@ class CIBaseTest(CIBuilder):
>               self.fail('No speedup after rebuild with ccache')
>   
>           # Cleanup
> -        self.deletetmp(build_dir)
> -        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
> +        self.delete_from_build_dir('tmp')
> +        self.delete_from_build_dir('ccache')
> +
> diff --git a/testsuite/build_test/cibuilder.py b/testsuite/build_test/cibuilder.py
> index 94786c7..6a9f6a0 100644
> --- a/testsuite/build_test/cibuilder.py
> +++ b/testsuite/build_test/cibuilder.py
> @@ -2,7 +2,6 @@
>   
>   import logging
>   import os
> -import re
>   import select
>   import shutil
>   import subprocess
> @@ -11,9 +10,8 @@ from avocado import Test
>   from avocado.utils import path
>   from avocado.utils import process
>   
> -isar_root = os.path.dirname(__file__) + '/../..'
> +isar_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
>   backup_prefix = '.ci-backup'
> -
>   app_log = logging.getLogger("avocado.app")
>   
>   class CIBuilder(Test):
> @@ -28,17 +26,55 @@ class CIBuilder(Test):
>           self._file_handler.setFormatter(formatter)
>           app_log.addHandler(self._file_handler)
>   
> -    def init(self, build_dir):
> +
> +    def init(self, build_dir='build', **kwargs):
> +        # initialize build_dir and setup environment
> +        # needs to run once (per test case)
> +        self.build_dir = os.path.join(isar_root, build_dir)
>           os.chdir(isar_root)
> -        path.usable_rw_dir(build_dir)
> +        path.usable_rw_dir(self.build_dir)
>           output = process.getoutput('/bin/bash -c "source isar-init-build-env \
> -                                    %s 2>&1 >/dev/null; env"' % build_dir)
> +                                    %s 2>&1 >/dev/null; env"' % self.build_dir)
>           env = dict(((x.split('=', 1) + [''])[:2] \
>                       for x in output.splitlines() if x != ''))
>           os.environ.update(env)
>   
> -    def confprepare(self, build_dir, compat_arch, cross, debsrc_cache):
> -        with open(build_dir + '/conf/ci_build.conf', 'w') as f:
> +
> +    def configure(self, compat_arch=True, cross=None, debsrc_cache=True,
> +                  container=False, ccache=False, sstate=False, offline=False,
> +                  gpg_pub_key=None, **kwargs):
> +        # write configuration file and set bitbake_args
> +        # can run multiple times per test case
> +
> +        # get parameters from avocado cmdline
> +        quiet = bool(int(self.params.get('quiet', default=0)))
> +        if cross is None:
> +            cross = bool(int(self.params.get('cross', default=0)))
> +
> +        # get parameters from environment
> +        distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
> +
> +        self.log.info(f'===================================================\n'
> +                      f'Configuring build_dir {self.build_dir}\n'
> +                      f'  compat_arch = {compat_arch}\n'
> +                      f'  cross = {cross}\n'
> +                      f'  debsrc_cache = {debsrc_cache}\n'
> +                      f'  offline = {offline}\n'
> +                      f'  container = {container}\n'
> +                      f'  ccache = {ccache}\n'
> +                      f'  sstate = {sstate}\n'
> +                      f'  gpg_pub_key = {gpg_pub_key}\n'
> +                      f'===================================================')
> +
> +        # determine bitbake_args
> +        self.bitbake_args = []
> +        if not quiet:
> +            self.bitbake_args.append('-v')
> +        if not sstate:
> +            self.bitbake_args.append('--no-setscene')
> +
> +        # write ci_build.conf
> +        with open(self.build_dir + '/conf/ci_build.conf', 'w') as f:
>               if compat_arch:
>                   f.write('ISAR_ENABLE_COMPAT_ARCH_amd64 = "1"\n')
>                   f.write('ISAR_ENABLE_COMPAT_ARCH_arm64 = "1"\n')
> @@ -48,36 +84,42 @@ class CIBuilder(Test):
>                   f.write('ISAR_CROSS_COMPILE = "1"\n')
>               if debsrc_cache:
>                   f.write('BASE_REPO_FEATURES = "cache-deb-src"\n')
> -            distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
> +            if offline:
> +                f.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
> +                f.write('BB_NO_NETWORK = "1"\n')
> +            if container:
> +                f.write('SDK_FORMATS = "docker-archive"\n')
> +                f.write('IMAGE_INSTALL_remove = "example-module-${KERNEL_NAME} enable-fsck"\n')
> +            if gpg_pub_key:
> +                f.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
>               if distro_apt_premir:
>                   f.write('DISTRO_APT_PREMIRRORS = "%s"\n' % distro_apt_premir)
>   
> -        with open(build_dir + '/conf/local.conf', 'r+') as f:
> +        # include ci_build.conf in local.conf
> +        with open(self.build_dir + '/conf/local.conf', 'r+') as f:
>               for line in f:
>                   if 'include ci_build.conf' in line:
>                       break
>               else:
>                   f.write('\ninclude ci_build.conf')
>   
> -    def containerprep(self, build_dir):
> -        with open(build_dir + '/conf/ci_build.conf', 'a') as f:
> -            f.write('SDK_FORMATS = "docker-archive"\n')
> -            f.write('IMAGE_INSTALL_remove = "example-module-${KERNEL_NAME} enable-fsck"\n')
> -
> -    def confcleanup(self, build_dir):
> -        open(build_dir + '/conf/ci_build.conf', 'w').close()
> +    def unconfigure(self):
> +        open(self.build_dir + '/conf/ci_build.conf', 'w').close()
>   
> -    def deletetmp(self, build_dir):
> -        process.run('rm -rf ' + build_dir + '/tmp', sudo=True)
> +    def delete_from_build_dir(self, path):
> +        process.run('rm -rf ' + self.build_dir + '/' + path, sudo=True)
>   
> -    def bitbake(self, build_dir, target, cmd, args):
> -        os.chdir(build_dir)
> +    def bitbake(self, target, bitbake_cmd=None, **kwargs):
> +        self.log.info('===================================================')
> +        self.log.info('Building ' + str(target))
> +        self.log.info('===================================================')
> +        os.chdir(self.build_dir)
>           cmdline = ['bitbake']
> -        if args:
> -            cmdline.append(args)
> -        if cmd:
> +        if self.bitbake_args:
> +            cmdline.extend(self.bitbake_args)
> +        if bitbake_cmd:
>               cmdline.append('-c')
> -            cmdline.append(cmd)
> +            cmdline.append(bitbake_cmd)
>           if isinstance(target, list):
>               cmdline.extend(target)
>           else:
> @@ -124,9 +166,9 @@ class CIBuilder(Test):
>           try:
>               path.find_command('bitbake')
>           except path.CmdNotFoundError:
> -            build_dir = self.params.get('build_dir',
> -                                        default=isar_root + '/build')
> -            self.init(build_dir)
> +            self.log.error("Broken test implementation: must call init() before "
> +                           "using getlayerdir()!")
> +            raise
>           output = process.getoutput('bitbake -e | grep "^LAYERDIR_.*="')
>           env = dict(((x.split('=', 1) + [''])[:2] \
>                       for x in output.splitlines() if x != ''))

-- 
Anton Mikanovich
Promwad Ltd.
External service provider of ilbers GmbH
Maria-Merian-Str. 8
85521 Ottobrunn, Germany
+49 (89) 122 67 24-0
Commercial register Munich, HRB 214197
General Manager: Baurzhan Ismagulov


^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [RFC PATCH v2] testsuite: refactor
  2021-12-10 15:05 ` Anton Mikanovich
@ 2021-12-10 16:12   ` Schmidt, Adriaan
  0 siblings, 0 replies; 3+ messages in thread
From: Schmidt, Adriaan @ 2021-12-10 16:12 UTC (permalink / raw)
  To: Anton Mikanovich, isar-users

Anton Mikanovich, 10. Dezember 2021 16:05:
> 
> Thanks for v2, it looks much better now.
> But there are still some comments bellow.
> 
> 10.12.2021 11:15, Adriaan Schmidt wrote:
> > - make test initialization more explicit.
> >    tests now call init() to initialize build_dir and environment,
> >    and configure() to generate the config file and bitbake_args
> > - only configure() touches the config file. if config needs to change
> >    during one test case, it is created from scratch (no appending
> >    by the test case itself).
> > - build_dir is not passed via avocado parameter. each test
> >    can set it in the call to init(). this makes dependencies
> >    between tests explicit and permits parallelization.
> > - in the main invocation script, rename --build to --base.
> >    what we're setting here is not the bitbake build_dir but
> >    the base dir for avocado test output.
> >
> > Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
> > ---
> >   scripts/ci_build.sh                |  22 +++---
> >   testsuite/build_test/build_test.py |  35 +++++-----
> >   testsuite/build_test/cibase.py     | 103 +++++++++--------------------
> >   testsuite/build_test/cibuilder.py  |  98 +++++++++++++++++++--------
> >   4 files changed, 128 insertions(+), 130 deletions(-)
> >
> > diff --git a/scripts/ci_build.sh b/scripts/ci_build.sh
> > index e9ba034..339ebca 100755
> > --- a/scripts/ci_build.sh
> > +++ b/scripts/ci_build.sh
> > @@ -27,8 +27,8 @@ fi
> >   # Get Avocado build tests path
> >   BUILD_TEST_DIR="$(pwd)/testsuite/build_test"
> >
> > -# Start build in Isar tree by default
> > -BUILD_DIR=./build
> > +# Start tests in current path by default
> > +BASE_DIR=./build
> >
> >   # Check dependencies
> >   DEPENDENCIES="umoci skopeo"
> > @@ -45,8 +45,8 @@ show_help() {
> >       echo "    $0 [params]"
> >       echo
> >       echo "Parameters:"
> > -    echo "    -b, --build BUILD_DIR    set path to build directory. If not
> set,"
> > -    echo "                             the build will be started in
> current path."
> > +    echo "    -b, --base BASE_DIR      set path to base directory. If not
> set,"
> > +    echo "                             the tests will be started in
> current path."
> >       echo "    -c, --cross              enable cross-compilation."
> >       echo "    -d, --debug              enable debug bitbake output."
> >       echo "    -f, --fast               cross build reduced set of
> configurations."
> > @@ -73,8 +73,8 @@ do
> >           show_help
> >           exit 0
> >           ;;
> > -    -b|--build)
> > -        BUILD_DIR="$2"
> > +    -b|--base)
> > +        BASE_DIR="$2"
> >           shift
> >           ;;
> >       -c|--cross)
> > @@ -117,10 +117,10 @@ fi
> >   mkdir -p .config/avocado
> >   cat <<EOF > .config/avocado/avocado.conf
> >   [datadir.paths]
> > -base_dir = $(realpath $BUILD_DIR)/
> > -test_dir = $(realpath $BUILD_DIR)/tests
> > -data_dir = $(realpath $BUILD_DIR)/data
> > -logs_dir = $(realpath $BUILD_DIR)/job-results
> > +base_dir = $(realpath $BASE_DIR)/
> > +test_dir = $(realpath $BASE_DIR)/tests
> > +data_dir = $(realpath $BASE_DIR)/data
> > +logs_dir = $(realpath $BASE_DIR)/job-results
> >   EOF
> >   export VIRTUAL_ENV="./"
> >
> > @@ -129,4 +129,4 @@ set -x
> >
> >   avocado $VERBOSE run "$BUILD_TEST_DIR/build_test.py" \
> >       -t $TAGS --test-runner=runner --disable-sysinfo \
> > -    -p build_dir="$BUILD_DIR" -p quiet=$QUIET -p cross=$CROSS_BUILD
> > +    -p quiet=$QUIET -p cross=$CROSS_BUILD
> > diff --git a/testsuite/build_test/build_test.py
> b/testsuite/build_test/build_test.py
> > index de9e3fc..7359295 100644
> > --- a/testsuite/build_test/build_test.py
> > +++ b/testsuite/build_test/build_test.py
> > @@ -3,7 +3,7 @@
> >   import os
> >
> >   from avocado import skipUnless
> > -from avocado.utils import path
> > +from avocado.utils import path, process
> 
> Does it really needed here?

No, that was just left over from moving things around...

> >   from cibase import CIBaseTest
> >
> >   UMOCI_AVAILABLE = True
> > @@ -30,7 +30,7 @@ class ReproTest(CIBaseTest):
> >               'mc:qemuarm64-stretch:isar-image-base'
> >                     ]
> >
> > -        self.perform_repro_test(targets, 1)
> > +        self.perform_repro_test(targets, signed=True)
> >
> >       def test_repro_unsigned(self):
> >           targets = [
> > @@ -38,7 +38,7 @@ class ReproTest(CIBaseTest):
> >               'mc:qemuarm-stretch:isar-image-base'
> >                     ]
> >
> > -        self.perform_repro_test(targets, 0)
> > +        self.perform_repro_test(targets)
> >
> >   class CcacheTest(CIBaseTest):
> >
> > @@ -69,7 +69,7 @@ class CrossTest(CIBaseTest):
> >               'mc:rpi-stretch:isar-image-base'
> >                     ]
> >
> > -        self.perform_build_test(targets, 1, None)
> > +        self.perform_build_test(targets, cross=True)
> >
> >       def test_cross_ubuntu(self):
> >           targets = [
> > @@ -77,7 +77,7 @@ class CrossTest(CIBaseTest):
> >                     ]
> >
> >           try:
> > -            self.perform_build_test(targets, 1, None)
> > +            self.perform_build_test(targets, cross=True)
> >           except:
> >               self.cancel('KFAIL')
> >
> > @@ -87,7 +87,7 @@ class CrossTest(CIBaseTest):
> >                     ]
> >
> >           try:
> > -            self.perform_build_test(targets, 1, None)
> > +            self.perform_build_test(targets, cross=True)
> >           except:
> >               self.cancel('KFAIL')
> >
> > @@ -101,7 +101,7 @@ class SdkTest(CIBaseTest):
> >       def test_sdk(self):
> >           targets = ['mc:qemuarm-stretch:isar-image-base']
> >
> > -        self.perform_build_test(targets, 1, 'do_populate_sdk')
> > +        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk')
> >
> >   class NoCrossTest(CIBaseTest):
> >
> > @@ -131,10 +131,9 @@ class NoCrossTest(CIBaseTest):
> >                     ]
> >
> >           # Cleanup after cross build
> > -        self.deletetmp(self.params.get('build_dir',
> > -                       default=os.path.dirname(__file__) +
> '/../../build'))
> > -
> > -        self.perform_build_test(targets, 0, None)
> > +        self.init()
> 
> Is that the second init? Why we need it here?

This one is a bit tricky... init() sets the build_dir, so it needs to be called
before delete_from_build_dir() or (below) before getlayerdir().
My goal is to remove all the passing-around of build_dir, but my current proposal
is also not good, because init() can be called multiple times, and if different
values are passed I think undesired things will happen.

I think the clean solution is to require that all tests call init() explicitly.
For now that will seem like duplication, but if we move to separate build dirs later
(also to enable parallel execution), I think it will make test much clearer
to understand.

In addition, I'd add checks to CiBuilder, to ensure init() is called exactly once.

Will send v3.

Adriaan

> > +        self.delete_from_build_dir('tmp')
> > +        self.perform_build_test(targets, cross=False)
> >
> >       def test_nocross_bullseye(self):
> >           targets = [
> > @@ -146,7 +145,7 @@ class NoCrossTest(CIBaseTest):
> >                     ]
> >
> >           try:
> > -            self.perform_build_test(targets, 0, None)
> > +            self.perform_build_test(targets, cross=False)
> >           except:
> >               self.cancel('KFAIL')
> >
> > @@ -158,19 +157,16 @@ class RebuildTest(CIBaseTest):
> >       :avocado: tags=rebuild,fast,full
> >       """
> >       def test_rebuild(self):
> > -        is_cross_build = int(self.params.get('cross', default=0))
> > -
> > +        self.init()
> 
> The same question here. Init is already done inside perform_build_test.
> 
> >           layerdir_core = self.getlayerdir('core')
> >
> >           dpkgbase_file = layerdir_core + '/classes/dpkg-base.bbclass'
> > -
> 
> Please remove changes that just remove empty lines. It can be confusing
> for the history.
> 
> >           self.backupfile(dpkgbase_file)
> >           with open(dpkgbase_file, 'a') as file:
> >               file.write('do_fetch_append() {\n\n}')
> >
> >           try:
> > -            self.perform_build_test('mc:qemuamd64-stretch:isar-image-
> base',
> > -                                    is_cross_build, None)
> > +            self.perform_build_test('mc:qemuamd64-stretch:isar-image-
> base')
> >           finally:
> >               self.restorefile(dpkgbase_file)
> >
> > @@ -189,6 +185,7 @@ class WicTest(CIBaseTest):
> >           self.perform_wic_test('mc:qemuamd64-stretch:isar-image-base',
> >                                 wks_path, wic_path)
> >
> > +
> 
> The same with adding newlines.
> 
> >   class ContainerImageTest(CIBaseTest):
> >
> >       """
> > @@ -204,7 +201,7 @@ class ContainerImageTest(CIBaseTest):
> >               'mc:container-amd64-bullseye:isar-image-base'
> >                     ]
> >
> > -        self.perform_container_test(targets, None)
> > +        self.perform_build_test(targets, container=True)
> >
> >   class ContainerSdkTest(CIBaseTest):
> >
> > @@ -217,4 +214,4 @@ class ContainerSdkTest(CIBaseTest):
> >       def test_container_sdk(self):
> >           targets = ['mc:container-amd64-stretch:isar-image-base']
> >
> > -        self.perform_container_test(targets, 'do_populate_sdk')
> > +        self.perform_build_test(targets, bitbake_cmd='do_populate_sdk',
> container=True)
> > diff --git a/testsuite/build_test/cibase.py
> b/testsuite/build_test/cibase.py
> > index 0b053aa..9c06c94 100644
> > --- a/testsuite/build_test/cibase.py
> > +++ b/testsuite/build_test/cibase.py
> > @@ -8,50 +8,24 @@ import time
> >   from cibuilder import CIBuilder
> >   from avocado.utils import process
> >
> > -isar_root = os.path.dirname(__file__) + '/../..'
> >
> >   class CIBaseTest(CIBuilder):
> > -
> > -    def prep(self, testname, targets, cross, debsrc_cache):
> > -        build_dir = self.params.get('build_dir', default=isar_root +
> '/build')
> > -        build_dir = os.path.realpath(build_dir)
> > -        quiet = int(self.params.get('quiet', default=0))
> > -        bitbake_args = '-v'
> > -
> > -        if quiet:
> > -            bitbake_args = ''
> > -
> > -
> self.log.info('===================================================')
> > -        self.log.info('Running ' + testname + ' test for:')
> > -        self.log.info(targets)
> > -        self.log.info('Isar build folder is: ' + build_dir)
> > -
> self.log.info('===================================================')
> > -
> > -        self.init(build_dir)
> > -        self.confprepare(build_dir, 1, cross, debsrc_cache)
> > -
> > -        return build_dir, bitbake_args;
> > -
> > -    def perform_build_test(self, targets, cross, bitbake_cmd):
> > -        build_dir, bb_args = self.prep('Isar build', targets, cross, 1)
> > +    def perform_build_test(self, targets, **kwargs):
> > +        self.init(**kwargs)
> > +        self.configure(**kwargs)
> >
> >           self.log.info('Starting build...')
> >
> > -        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
> > -
> > -    def perform_repro_test(self, targets, signed):
> > -        cross = int(self.params.get('cross', default=0))
> > -        build_dir, bb_args = self.prep('repro Isar build', targets, cross,
> 0)
> > +        self.bitbake(targets, **kwargs)
> >
> > +    def perform_repro_test(self, targets, signed=False, **kwargs):
> >           gpg_pub_key = os.path.dirname(__file__) + '/../base-
> apt/test_pub.key'
> >           gpg_priv_key = os.path.dirname(__file__) + '/../base-
> apt/test_priv.key'
> >
> > -        if signed:
> > -            with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> > -                # Enable use of signed cached base repository
> > -                file.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
> > +        self.init(**kwargs)
> > +        self.configure(gpg_pub_key=gpg_pub_key if signed else None,
> **kwargs)
> >
> > -        os.chdir(build_dir)
> > +        os.chdir(self.build_dir)
> >
> >           os.environ['GNUPGHOME'] = tempfile.mkdtemp()
> >           result = process.run('gpg --import %s %s' % (gpg_pub_key,
> gpg_priv_key))
> > @@ -59,33 +33,31 @@ class CIBaseTest(CIBuilder):
> >           if result.exit_status:
> >               self.fail('GPG import failed')
> >
> > -        self.bitbake(build_dir, targets, None, bb_args)
> > +        self.bitbake(targets, **kwargs)
> >
> > -        self.deletetmp(build_dir)
> > -        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> > -            file.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
> > -            file.write('BB_NO_NETWORK = "1"\n')
> > +        self.delete_from_build_dir('tmp')
> > +        self.configure(gpg_pub_key=gpg_pub_key if signed else None,
> offline=True, **kwargs)
> >
> > -        self.bitbake(build_dir, targets, None, bb_args)
> > +        self.bitbake(targets, **kwargs)
> >
> >           # Disable use of cached base repository
> > -        self.confcleanup(build_dir)
> > +        self.unconfigure()
> >
> >           if not signed:
> >               # Try to build with changed configuration with no cleanup
> > -            self.bitbake(build_dir, targets, None, bb_args)
> > +            self.bitbake(targets, **kwargs)
> >
> >           # Cleanup
> > -        self.deletetmp(build_dir)
> > +        self.delete_from_build_dir('tmp')
> >
> > -    def perform_wic_test(self, targets, wks_path, wic_path):
> > -        cross = int(self.params.get('cross', default=0))
> > -        build_dir, bb_args = self.prep('WIC exclude build', targets,
> cross, 1)
> > +    def perform_wic_test(self, targets, wks_path, wic_path, **kwargs):
> > +        self.init(**kwargs)
> > +        self.configure(**kwargs)
> >
> >           layerdir_isar = self.getlayerdir('isar')
> >
> >           wks_file = layerdir_isar + wks_path
> > -        wic_img = build_dir + wic_path
> > +        wic_img = self.build_dir + wic_path
> >
> >           if not os.path.isfile(wic_img):
> >               self.fail('No build started before: ' + wic_img + ' not
> exist')
> > @@ -99,44 +71,30 @@ class CIBaseTest(CIBuilder):
> >               for line in lines:
> >                   file.write(re.sub(r'part \/ ', 'part \/ --exclude-path
> usr ',
> >                                     line))
> > -
> >           try:
> > -            self.bitbake(build_dir, targets, None, bb_args)
> > +            self.bitbake(targets, **kwargs)
> >           finally:
> >               self.restorefile(wks_file)
> > -
> >           self.restorefile(wic_img)
> >
> > -    def perform_container_test(self, targets, bitbake_cmd):
> > -        cross = int(self.params.get('cross', default=0))
> > -        build_dir, bb_args = self.prep('Isar Container', targets, cross,
> 1)
> > -
> > -        self.containerprep(build_dir)
> > -
> > -        self.bitbake(build_dir, targets, bitbake_cmd, bb_args)
> > -
> > +    def perform_ccache_test(self, targets, **kwargs):
> > +        self.init(**kwargs)
> > +        self.configure(ccache=True, **kwargs)
> >
> > -    def perform_ccache_test(self, targets):
> > -        build_dir, bb_args = self.prep('Isar ccache build', targets, 0, 0)
> > -
> > -        self.deletetmp(build_dir)
> > -        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
> > -
> > -        with open(build_dir + '/conf/ci_build.conf', 'a') as file:
> > -            file.write('USE_CCACHE = "1"\n')
> > -            file.write('CCACHE_TOP_DIR = "${TOPDIR}/ccache"')
> > +        self.delete_from_build_dir('tmp')
> > +        self.delete_from_build_dir('ccache')
> >
> >           self.log.info('Starting build and filling ccache dir...')
> >           start = time.time()
> > -        self.bitbake(build_dir, targets, None, bb_args)
> > +        self.bitbake(targets, **kwargs)
> >           first_time = time.time() - start
> >           self.log.info('Non-cached build: ' + str(round(first_time)) +
> 's')
> >
> > -        self.deletetmp(build_dir)
> > +        self.delete_from_build_dir('tmp')
> >
> >           self.log.info('Starting build and using ccache dir...')
> >           start = time.time()
> > -        self.bitbake(build_dir, targets, None, bb_args)
> > +        self.bitbake(targets, **kwargs)
> >           second_time = time.time() - start
> >           self.log.info('Cached build: ' + str(round(second_time)) + 's')
> >
> > @@ -145,5 +103,6 @@ class CIBaseTest(CIBuilder):
> >               self.fail('No speedup after rebuild with ccache')
> >
> >           # Cleanup
> > -        self.deletetmp(build_dir)
> > -        process.run('rm -rf ' + build_dir + '/ccache', sudo=True)
> > +        self.delete_from_build_dir('tmp')
> > +        self.delete_from_build_dir('ccache')
> > +
> > diff --git a/testsuite/build_test/cibuilder.py
> b/testsuite/build_test/cibuilder.py
> > index 94786c7..6a9f6a0 100644
> > --- a/testsuite/build_test/cibuilder.py
> > +++ b/testsuite/build_test/cibuilder.py
> > @@ -2,7 +2,6 @@
> >
> >   import logging
> >   import os
> > -import re
> >   import select
> >   import shutil
> >   import subprocess
> > @@ -11,9 +10,8 @@ from avocado import Test
> >   from avocado.utils import path
> >   from avocado.utils import process
> >
> > -isar_root = os.path.dirname(__file__) + '/../..'
> > +isar_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..',
> '..'))
> >   backup_prefix = '.ci-backup'
> > -
> >   app_log = logging.getLogger("avocado.app")
> >
> >   class CIBuilder(Test):
> > @@ -28,17 +26,55 @@ class CIBuilder(Test):
> >           self._file_handler.setFormatter(formatter)
> >           app_log.addHandler(self._file_handler)
> >
> > -    def init(self, build_dir):
> > +
> > +    def init(self, build_dir='build', **kwargs):
> > +        # initialize build_dir and setup environment
> > +        # needs to run once (per test case)
> > +        self.build_dir = os.path.join(isar_root, build_dir)
> >           os.chdir(isar_root)
> > -        path.usable_rw_dir(build_dir)
> > +        path.usable_rw_dir(self.build_dir)
> >           output = process.getoutput('/bin/bash -c "source isar-init-build-
> env \
> > -                                    %s 2>&1 >/dev/null; env"' % build_dir)
> > +                                    %s 2>&1 >/dev/null; env"' %
> self.build_dir)
> >           env = dict(((x.split('=', 1) + [''])[:2] \
> >                       for x in output.splitlines() if x != ''))
> >           os.environ.update(env)
> >
> > -    def confprepare(self, build_dir, compat_arch, cross, debsrc_cache):
> > -        with open(build_dir + '/conf/ci_build.conf', 'w') as f:
> > +
> > +    def configure(self, compat_arch=True, cross=None, debsrc_cache=True,
> > +                  container=False, ccache=False, sstate=False,
> offline=False,
> > +                  gpg_pub_key=None, **kwargs):
> > +        # write configuration file and set bitbake_args
> > +        # can run multiple times per test case
> > +
> > +        # get parameters from avocado cmdline
> > +        quiet = bool(int(self.params.get('quiet', default=0)))
> > +        if cross is None:
> > +            cross = bool(int(self.params.get('cross', default=0)))
> > +
> > +        # get parameters from environment
> > +        distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
> > +
> > +
> self.log.info(f'===================================================\n'
> > +                      f'Configuring build_dir {self.build_dir}\n'
> > +                      f'  compat_arch = {compat_arch}\n'
> > +                      f'  cross = {cross}\n'
> > +                      f'  debsrc_cache = {debsrc_cache}\n'
> > +                      f'  offline = {offline}\n'
> > +                      f'  container = {container}\n'
> > +                      f'  ccache = {ccache}\n'
> > +                      f'  sstate = {sstate}\n'
> > +                      f'  gpg_pub_key = {gpg_pub_key}\n'
> > +
> f'===================================================')
> > +
> > +        # determine bitbake_args
> > +        self.bitbake_args = []
> > +        if not quiet:
> > +            self.bitbake_args.append('-v')
> > +        if not sstate:
> > +            self.bitbake_args.append('--no-setscene')
> > +
> > +        # write ci_build.conf
> > +        with open(self.build_dir + '/conf/ci_build.conf', 'w') as f:
> >               if compat_arch:
> >                   f.write('ISAR_ENABLE_COMPAT_ARCH_amd64 = "1"\n')
> >                   f.write('ISAR_ENABLE_COMPAT_ARCH_arm64 = "1"\n')
> > @@ -48,36 +84,42 @@ class CIBuilder(Test):
> >                   f.write('ISAR_CROSS_COMPILE = "1"\n')
> >               if debsrc_cache:
> >                   f.write('BASE_REPO_FEATURES = "cache-deb-src"\n')
> > -            distro_apt_premir = os.getenv('DISTRO_APT_PREMIRRORS')
> > +            if offline:
> > +                f.write('ISAR_USE_CACHED_BASE_REPO = "1"\n')
> > +                f.write('BB_NO_NETWORK = "1"\n')
> > +            if container:
> > +                f.write('SDK_FORMATS = "docker-archive"\n')
> > +                f.write('IMAGE_INSTALL_remove = "example-module-
> ${KERNEL_NAME} enable-fsck"\n')
> > +            if gpg_pub_key:
> > +                f.write('BASE_REPO_KEY="file://' + gpg_pub_key + '"\n')
> >               if distro_apt_premir:
> >                   f.write('DISTRO_APT_PREMIRRORS = "%s"\n' %
> distro_apt_premir)
> >
> > -        with open(build_dir + '/conf/local.conf', 'r+') as f:
> > +        # include ci_build.conf in local.conf
> > +        with open(self.build_dir + '/conf/local.conf', 'r+') as f:
> >               for line in f:
> >                   if 'include ci_build.conf' in line:
> >                       break
> >               else:
> >                   f.write('\ninclude ci_build.conf')
> >
> > -    def containerprep(self, build_dir):
> > -        with open(build_dir + '/conf/ci_build.conf', 'a') as f:
> > -            f.write('SDK_FORMATS = "docker-archive"\n')
> > -            f.write('IMAGE_INSTALL_remove = "example-module-${KERNEL_NAME}
> enable-fsck"\n')
> > -
> > -    def confcleanup(self, build_dir):
> > -        open(build_dir + '/conf/ci_build.conf', 'w').close()
> > +    def unconfigure(self):
> > +        open(self.build_dir + '/conf/ci_build.conf', 'w').close()
> >
> > -    def deletetmp(self, build_dir):
> > -        process.run('rm -rf ' + build_dir + '/tmp', sudo=True)
> > +    def delete_from_build_dir(self, path):
> > +        process.run('rm -rf ' + self.build_dir + '/' + path, sudo=True)
> >
> > -    def bitbake(self, build_dir, target, cmd, args):
> > -        os.chdir(build_dir)
> > +    def bitbake(self, target, bitbake_cmd=None, **kwargs):
> > +
> self.log.info('===================================================')
> > +        self.log.info('Building ' + str(target))
> > +
> self.log.info('===================================================')
> > +        os.chdir(self.build_dir)
> >           cmdline = ['bitbake']
> > -        if args:
> > -            cmdline.append(args)
> > -        if cmd:
> > +        if self.bitbake_args:
> > +            cmdline.extend(self.bitbake_args)
> > +        if bitbake_cmd:
> >               cmdline.append('-c')
> > -            cmdline.append(cmd)
> > +            cmdline.append(bitbake_cmd)
> >           if isinstance(target, list):
> >               cmdline.extend(target)
> >           else:
> > @@ -124,9 +166,9 @@ class CIBuilder(Test):
> >           try:
> >               path.find_command('bitbake')
> >           except path.CmdNotFoundError:
> > -            build_dir = self.params.get('build_dir',
> > -                                        default=isar_root + '/build')
> > -            self.init(build_dir)
> > +            self.log.error("Broken test implementation: must call init()
> before "
> > +                           "using getlayerdir()!")
> > +            raise
> >           output = process.getoutput('bitbake -e | grep "^LAYERDIR_.*="')
> >           env = dict(((x.split('=', 1) + [''])[:2] \
> >                       for x in output.splitlines() if x != ''))
> 
> --
> Anton Mikanovich
> Promwad Ltd.
> External service provider of ilbers GmbH
> Maria-Merian-Str. 8
> 85521 Ottobrunn, Germany
> +49 (89) 122 67 24-0
> Commercial register Munich, HRB 214197
> General Manager: Baurzhan Ismagulov


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-12-10 16:12 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-10  8:15 [RFC PATCH v2] testsuite: refactor Adriaan Schmidt
2021-12-10 15:05 ` Anton Mikanovich
2021-12-10 16:12   ` Schmidt, Adriaan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox