#5384 Improve local testing, avoid unnecessary container builds, test code in current local folder without push to remote
Merged 11 months ago by ngompa. Opened a year ago by wombelix.
wombelix/pagure local_tests_container  into  master

file modified
+18 -15
@@ -125,28 +125,29 @@ 

  Running the unit-tests in container

  ***********************************

  

- To run the unit-tests, there is container available with all the dependencies needed.

+ To run the unit-tests, there are containers available with all the dependencies needed.

  

- First you will need to have podman installed on your workstation. ::

+ First you will need to have podman and git installed on your workstation. ::

  

-     $ sudo dnf install podman

+     $ sudo dnf install podman git

  

- 

- Use the following command to run the tests ::

+ Use the following command to run all tests on all container images, if the images not exist on your system, they will be build ::

  

      $ ./dev/run-tests-container.py

  

- This command will build a fedora based container and execute the test suite.

- 

  If you wish to execute the test suite on a centos based container run the following command ::

  

      $ ./dev/run-tests-container.py --centos

  

- When the test container image has been built you can skip the building step to save time

- and run directly the test suite. ::

+ Container images are separated from the pagure source that will be tested.

+ Therefore they will only automatically build if they not exist.

+ 

+ A manual rebuild should be done from time to time to include new package versions.

+ Also if you work on any changes in the pagure spec file, the tox config or any requirements.txt file,

+ perform a rebuild to ensure your changed will taken into account. ::

  

-     $ ./dev/run-tests-container.py --skip-build

-     $ ./dev/run-tests-container.py --centos --skip-build

+     $ ./dev/run-tests-container.py --rebuild # all base and code container

+     $ ./dev/run-tests-container.py --rebuild-code # code container only

  

  You can also run a single test case ::

  
@@ -156,16 +157,18 @@ 

  

      $ ./dev/run-tests-container.py tests/test_pagure_flask_ui_priorities.py:PagureFlaskPrioritiestests.test_ticket_with_no_priority

  

- You can also get `run-tests-container` help ::

+ You can also get ``run-tests-container`` help ::

  

      $ ./dev/run-tests-container.py --help

  

- Run the tests on your own development branch in your fork ::

+ By default, tests run against the git repo and the active branch in the current folder.

+ To override this behavior and run the tests on your remote development branch in your fork ::

  

      $ ./dev/run-tests-container.py --repo https://pagure.io/forks/<username>/pagure.git --branch <name of branch to test>

  

-   .. note:: This run could take pretty long to finish and there isn't any useful summary.

-             So it's better to redirect the output to some file. You can use `tee` for this.

+   .. note:: All build, test and shell activities executed via ``run-tests-container`` will automatically be logged.

+             Every container has it's own ``dev/results_<test-container-name>`` folder, every run creates separate

+             files with the current unix timestamp as prefix. You should cleanup this folder from time to time.

  

   

  Running the unit-tests in tox

@@ -0,0 +1,41 @@ 

+ FROM quay.io/centos/centos:stream8

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG specfile=https://pagure.io/pagure/raw/master/f/files/pagure.spec

+ 

+ ENV SPECFILE=$specfile

+ 

+ RUN dnf -y install \

+       epel-release epel-next-release 'dnf-command(config-manager)' \

+     && dnf -y config-manager --enable epel-testing epel-next-testing powertools \

+     && dnf -y install \

+       python3-setuptools \

+       python3-beautifulsoup4 \

+       python3-coverage \

+       python3-mock \

+       python3-docutils \

+       python3-flake8 \

+       python3-pytest-xdist \

+       python3-flask-oidc \

+       python3-cchardet \

+       python3-fedora-messaging \

+       python3-pip \

+       redis \

+       which \

+       git \

+     && dnf clean all

+ 

+ RUN pip3 install pagure-messages

+ 

+ # Install all the requirements from the spec file and replace the macro

+ # %{python_pkgversion} by '3' which thus installs all the py3 version of

+ # the dependencies.

+ RUN curl ${SPECFILE} -o /pagure.spec \

+     && dnf install -y `grep "Requires:" /pagure.spec | \

+       awk '{split($0, a, " "); print a[2]}' | grep -v "%{name}" | \

+       sed -e "s|%{python_pkgversion}|3|"` \

+     && dnf clean all 

\ No newline at end of file

@@ -0,0 +1,38 @@ 

+ FROM quay.io/fedora/fedora:36-x86_64

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG repo=https://pagure.io/pagure.git

+ ARG branch=master

+ 

+ ENV REPO=$repo

+ ENV BRANCH=$branch

+ 

+ RUN dnf -y install \

+         python3-setuptools \

+         redhat-rpm-config \

+         python3-devel \

+         libgit2-devel \

+         python3-tox \

+         libffi-devel \

+         zeromq-devel \

+         gcc \

+         redis \

+         which \

+         git \

+         glibc-langpack-en \

+     && dnf clean all

+ 

+ # Pre-build tox environments and keep em in the base container

+ # to avoid re-build on every run, even if tox config not changed

+ RUN mkdir /tox \

+     && echo Repo: ${REPO}, Branch: ${BRANCH} \

+     && git clone -b ${BRANCH} ${REPO} /pagure \

+     && ln -s /tox /pagure/.tox \

+     && cd /pagure \

+     && tox --notest \

+     && cd / \

+     && rm -rf /pagure 

\ No newline at end of file

@@ -0,0 +1,39 @@ 

+ FROM quay.io/fedora/fedora:36-x86_64

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG specfile=https://pagure.io/pagure/raw/master/f/files/pagure.spec

+ 

+ ENV SPECFILE=$specfile

+ 

+ RUN dnf -y --enablerepo=updates-testing install \

+       python3-setuptools \

+       python3-beautifulsoup4 \

+       python3-coverage \

+       python3-mock \

+       python3-docutils \

+       python3-black \

+       python3-flake8 \

+       python3-pytest-xdist \

+       python3-flask-oidc \

+       python3-cchardet \

+       python3-fedora-messaging \

+       python3-pip \

+       redis \

+       which \

+       git \

+     && dnf clean all

+ 

+ RUN pip install pagure-messages

+ 

+ # Install all the requirements from the spec file and replace the macro

+ # %{python_pkgversion} by '3' which thus installs all the py3 version of

+ # the dependencies.

+ RUN curl ${SPECFILE} -o /pagure.spec \

+     && dnf install -y --enablerepo=updates-testing `grep "Requires:" /pagure.spec | \

+       awk '{split($0, a, " "); print a[2]}' | grep -v "%{name}" | \

+       sed -e "s|%{python_pkgversion}|3|"` \

+     && dnf clean all 

\ No newline at end of file

@@ -0,0 +1,16 @@ 

+ FROM base-centos-stream8-rpms-py3:latest

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG repo=https://pagure.io/pagure.git

+ ARG branch=master

+ 

+ ENV REPO=$repo

+ ENV BRANCH=$branch

+ 

+ COPY entrypoint_rpms.sh /entrypoint.sh

+ RUN chmod +x /entrypoint.sh

+ ENTRYPOINT /entrypoint.sh 

\ No newline at end of file

@@ -0,0 +1,17 @@ 

+ FROM base-fedora-pip-py3:latest

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG repo=https://pagure.io/pagure.git

+ ARG branch=master

+ 

+ ENV REPO=$repo

+ ENV BRANCH=$branch

+ 

+ COPY tox_py3.sh /tox_py3.sh

+ COPY entrypoint_pip.sh /entrypoint.sh

+ RUN chmod +x /entrypoint.sh

+ ENTRYPOINT /entrypoint.sh 

\ No newline at end of file

@@ -0,0 +1,16 @@ 

+ FROM base-fedora-rpms-py3:latest

+ 

+ LABEL org.opencontainers.image.authors="pagure community"

+ LABEL org.opencontainers.image.url="https://pagure.io/pagure"

+ LABEL org.opencontainers.image.source="https://pagure.io/pagure/blob/master/f/dev/containers"

+ LABEL org.opencontainers.image.documentation="https://docs.pagure.org/pagure/index.html"

+ 

+ ARG repo=https://pagure.io/pagure.git

+ ARG branch=master

+ 

+ ENV REPO=$repo

+ ENV BRANCH=$branch

+ 

+ COPY entrypoint_rpms.sh /entrypoint.sh

+ RUN chmod +x /entrypoint.sh

+ ENTRYPOINT /entrypoint.sh 

\ No newline at end of file

@@ -0,0 +1,10 @@ 

+ #!/bin/bash

+ cd / \

+ && GIT_TRACE=1 GIT_CURL_VERBOSE=1 git clone -b ${BRANCH} ${REPO} /pagure \

+ && cp /tox_py3.sh /pagure/dev/containers/tox_py3.sh \

+ && chmod +x /pagure/dev/containers/tox_py3.sh \

+ && ln -s /tox /pagure/.tox \

+ && cd /pagure \

+ && ln -s /results /pagure/results \

+ && sed -i -e 's|"alembic-3"|"alembic"|' /pagure/tests/test_alembic.py \

+ && dev/containers/tox_py3.sh

@@ -0,0 +1,8 @@ 

+ #!/bin/bash

+ cd / \

+ && GIT_TRACE=1 GIT_CURL_VERBOSE=1 git clone -b ${BRANCH} ${REPO} /pagure \

+ && chmod +x /pagure/dev/containers/runtests_py3.sh \

+ && cd /pagure \

+ && ln -s /results /pagure/results \

+ && python3 setup.py build \

+ && dev/containers/runtests_py3.sh 

\ No newline at end of file

file modified
+1 -1
@@ -23,4 +23,4 @@ 

  fi

  

  export LANG="en_US.UTF-8"

- tox -v -e 'py38' -- /pagure/tests/

+ tox -v -e "${PYVER:-py38}" -- ${TESTCASE:-tests/} 

\ No newline at end of file

file modified
+253 -81
@@ -3,13 +3,109 @@ 

  import argparse

  import os

  import subprocess as sp

+ import time

  

  

  ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

+ TIMESTAMP = int(time.time())

+ 

+ 

+ def _container_image_exist(container_name, container_type):

+     cmd = [

+         "podman",

+         "image",

+         "exists",

+         containers[container_name][container_type],

+     ]

+     return _call_command(cmd)

+ 

+ 

+ # fmt: off

+ def _build_container(container_name, container_type, result_path,

+                      container_volume=None, **kwargs):

+     # fmt: on

+     # kwargs can be used to pass '--build-arg'

+     build_args = []

+     for arg in kwargs.values():

+         build_args.append("--build-arg")

+         build_args.append(arg)

+ 

+     volume = []

+     if container_volume:

+         volume.append("-v")

+         volume.append(volume)

+ 

+     container_file = ""

+     if container_type == "base":

+         container_file = containers[container_name]["base"]

+         container_name = container_file

+     if container_type == "code":

+         container_file = containers[container_name]["code"]

+         container_name = container_file

+ 

+     cmd = [

+         "podman",

+         "build",

+         "--no-cache",

+         "--rm",

+         "-t",

+         container_name,

+         "-f",

+         ROOT + "/dev/containers/%s" % container_file,

+         ROOT + "/dev/containers",

+     ]

+ 

+     cmd += build_args

+     cmd += volume

+ 

+     logfile = "{}/{}_{}-build.log".format(

+         result_path, TIMESTAMP, container_type

+     )

+     return _call_command(cmd, logfile)

+ 

+ 

+ def _call_command(cmd, logfile=None):

+     print("Command: " + " ".join(cmd))

+ 

+     if logfile is None:

+         rc = sp.call(cmd)

+     else:

+         # 'tee' like behavior, Kudos: falsetru

+         # https://stackoverflow.com/a/31583238

+         tee = sp.Popen(["tee", logfile], stdin=sp.PIPE)

+         rc = sp.call(cmd, stdout=tee.stdin, stderr=sp.STDOUT)

+         tee.stdin.close()

+ 

+     if rc != 0:

+         return False

+     else:

+         return True

+ 

+ 

+ def _check_pre_reqs():

+     programs = [

+         {"name": "podman", "cmd": ["podman", "version"]},

+         {"name": "git", "cmd": ["git", "version"]},

+     ]

+ 

+     # 'os.devnull' used for backward compatibility with Python2.

+     # for Py3 only, 'sp.DEVNULL' can be used and this workaround removed.

+     FNULL = open(os.devnull, "w")

+ 

+     missing = []

+     for program in programs:

+         try:

+             sp.call(program["cmd"], stdout=FNULL, stderr=sp.STDOUT)

+         except OSError:

+             missing.append(program["name"])

+ 

+     if len(missing) > 0:

+         print("Error! Required programs not found: " + ", ".join(missing))

+         os._exit(1)

  

  

  def setup_parser():

-     """ Setup the cli arguments """

+     """Setup the cli arguments"""

      parser = argparse.ArgumentParser(prog="pagure-test")

      parser.add_argument(

          "test_case", nargs="?", default="", help="Run the given test case"
@@ -30,10 +126,16 @@ 

          help="Run the tests in a venv on a Fedora host",

      )

      parser.add_argument(

-         "--skip-build",

-         dest="skip_build",

-         action="store_false",

-         help="Skip building the container image",

+         "--rebuild",

+         dest="rebuild",

+         action="store_true",

+         help="Enforce rebuild of container images",

+     )

+     parser.add_argument(

+         "--rebuild-code",

+         dest="rebuild_code",

+         action="store_true",

+         help="Enforce rebuild of code container images only",

      )

      parser.add_argument(

          "--shell",
@@ -46,120 +148,190 @@ 

      parser.add_argument(

          "--repo",

          dest="repo",

-         default="https://pagure.io/pagure.git",

-         help="URL of the public repo to use as source, can be overridden using "

-         "the REPO environment variable",

+         default="/wrkdir",

+         help="URL or local path to git repository as source of the "

+              "public repo to use as source, defaults to git repo in "

+              "current directory, can also be overridden using the "

+              "REPO environment variable",

      )

      parser.add_argument(

          "--branch",

          dest="branch",

-         default="master",

-         help="Branch of the repo to use as source, can be overridden using "

-         "the BRANCH environment variable",

+         default="wrkdirbranch",

+         help="Branch name to use as source, defaults to the active "

+              "branch in current directory, can also be overridden by "

+              "using the BRANCH environment variable",

      )

  

      return parser

  

  

  if __name__ == "__main__":

+     _check_pre_reqs()

+ 

      parser = setup_parser()

      args = parser.parse_args()

  

-     if args.centos is True:

-         container_names = ["pagure-c8s-rpms-py3"]

-         container_files = ["centos8-rpms-py3"]

-     elif args.fedora is True:

-         container_names = ["pagure-fedora-rpms-py3"]

-         container_files = ["fedora-rpms-py3"]

-     elif args.pip is True:

-         container_names = ["pagure-fedora-pip-py3"]

-         container_files = ["fedora-pip-py3"]

+     containers = {

+         "centos": {

+             "name": "pagure-tests-centos-stream8-rpms-py3",

+             "base": "base-centos-stream8-rpms-py3",

+             "code": "code-centos-stream8-rpms-py3",

+         },

+         "fedora": {

+             "name": "pagure-tests-fedora-rpms-py3",

+             "base": "base-fedora-rpms-py3",

+             "code": "code-fedora-rpms-py3",

+         },

+         "pip": {

+             "name": "pagure-tests-fedora-pip-py3",

+             "base": "base-fedora-pip-py3",

+             "code": "code-fedora-pip-py3",

+         },

+     }

+ 

+     if args.centos:

+         container_names = ["centos"]

+     elif args.fedora:

+         container_names = ["fedora"]

+     elif args.pip:

+         container_names = ["pip"]

      else:

-         container_names = [

-             "pagure-fedora-rpms-py3",

-             "pagure-c8s-rpms-py3",

-             "pagure-fedora-pip-py3",

-         ]

-         container_files = [

-             "fedora-rpms-py3",

-             "centos8-rpms-py3",

-             "fedora-pip-py3",

-         ]

+         container_names = ["centos", "fedora", "pip"]

+ 

+     # get full path of git repo in current directory

+     # and set var to mount it into the container

+     if args.repo == "/wrkdir":

+         # 'git rev-parse --show-toplevel' via python, Kudos: Ryne Everett

+         # https://stackoverflow.com/questions/22081209#comment44778829_22081487

+         wrkdir_path = (

+             sp.Popen(["git", "rev-parse", "--show-toplevel"], stdout=sp.PIPE)

+             .communicate()[0]

+             .rstrip()

+             .decode("ascii")

+         )

+         mount_wrkdir = True

+     # 'args.repo' will be set as path to mount it into the container and then

+     # overridden with '/wrkdir' to leverage existing logic to use a local path

+     elif "http://" not in args.repo and "https://" not in args.repo:

+         wrkdir_path = args.repo

+         args.repo = "/wrkdir"

+         mount_wrkdir = True

+ 

+     if args.branch == "wrkdirbranch":

+         args.branch = (

+             sp.Popen(["git", "branch", "--show-current"], stdout=sp.PIPE)

+             .communicate()[0]

+             .rstrip()

+             .decode("ascii")

+         )

  

      failed = []

-     print("Running for {} containers:".format(len(container_names)))

+     print("Running for %d containers:" % len(container_names))

      print("  - " + "\n  - ".join(container_names))

-     for idx, container_name in enumerate(container_names):

-         if args.skip_build is not False:

-             print("------ Building Container Image -----")

-             cmd = [

-                 "podman",

-                 "build",

-                 "--build-arg",

-                 "branch={}".format(os.environ.get("BRANCH") or args.branch),

-                 "--build-arg",

-                 "repo={}".format(os.environ.get("REPO") or args.repo),

-                 "--rm",

-                 "-t",

+     for container_name in container_names:

+         result_path = "{}/results_{}".format(

+             os.getcwd(), containers[container_name]["name"]

+         )

+         if not os.path.exists(result_path):

+             os.mkdir(result_path)

+ 

+         print("\n------ Building Container Image -----")

+ 

+         if not _container_image_exist(container_name, "base") or args.rebuild:

+             print(

+                 "Container does not exist, building: %s"

+                 % containers[container_name]["base"]

+             )

+             if _build_container(

                  container_name,

-                 "-f",

-                 ROOT + "/dev/containers/%s" % container_files[idx],

-                 ROOT + "/dev/containers",

-             ]

-             print(" ".join(cmd))

-             output_code = sp.call(cmd)

-             if output_code:

-                 print("Failed building: %s", container_name)

+                 "base",

+                 result_path,

+                 branch="{}".format(os.environ.get("BRANCH") or args.branch),

+                 repo="{}".format(os.environ.get("REPO") or args.repo),

+             ):

+                 base_build = True

+             else:

+                 print(

+                     "Failed building: %s" % containers[container_name]["base"]

+                 )

                  break

+         else:

+             base_build = False

+             print(

+                 "Container already exist, skipped building: %s"

+                 % containers[container_name]["base"]

+             )

  

-         result_path = "{}/results_{}".format(os.getcwd(), container_files[idx])

-         if not os.path.exists(result_path):

-             os.mkdir(result_path)

+         if (

+             not _container_image_exist(container_name, "code")

+             or base_build

+             or args.rebuild

+             or args.rebuild_code

+         ):

+             print(

+                 "Container does not exist, building: %s"

+                 % containers[container_name]["code"]

+             )

+             if not _build_container(container_name, "code", result_path):

+                 print(

+                     "Failed building: %s" % containers[container_name]["code"]

+                 )

+                 break

+         else:

+             print(

+                 "Container already exist, skipped building: %s"

+                 % containers[container_name]["code"]

+             )

+ 

+         volumes = ["-v", "{}:/results:z".format(result_path)]

+         if mount_wrkdir:

+             volumes += ["-v", "{}:/wrkdir:z,ro".format(wrkdir_path)]

+ 

+         env_vars = [

+             "-e",

+             "BRANCH={}".format(os.environ.get("BRANCH") or args.branch),

+             "-e",

+             "REPO={}".format(os.environ.get("REPO") or args.repo),

+             "-e",

+             "TESTCASE={}".format(args.test_case or ""),

+         ]

  

          if args.shell:

              print("--------- Shelling in the container --------------")

-             command = [

+             cmd = [

                  "podman",

                  "run",

                  "-it",

                  "--rm",

                  "--name",

-                 container_name,

-                 "-v",

-                 "{}/results_{}:/pagure/results:z".format(

-                     os.getcwd(), container_files[idx]

-                 ),

-                 "-e",

-                 "BRANCH={}".format(os.environ.get("BRANCH") or args.branch),

-                 "-e",

-                 "REPO={}".format(os.environ.get("REPO") or args.repo),

+                 containers[container_name]["name"],

+             ]

+             cmd += volumes

+             cmd += env_vars

+             cmd += [

                  "--entrypoint=/bin/bash",

-                 container_name,

+                 containers[container_name]["code"],

              ]

-             sp.call(command)

+             logfile = "{}/{}_shell.log".format(result_path, TIMESTAMP)

+             _call_command(cmd, logfile)

          else:

              print("--------- Running Test --------------")

-             command = [

+             cmd = [

                  "podman",

                  "run",

                  "-it",

                  "--rm",

                  "--name",

-                 container_name,

-                 "-v",

-                 "{}/results_{}:/pagure/results:z".format(

-                     os.getcwd(), container_files[idx]

-                 ),

-                 "-e",

-                 "BRANCH={}".format(os.environ.get("BRANCH") or args.branch),

-                 "-e",

-                 "REPO={}".format(os.environ.get("REPO") or args.repo),

-                 "-e",

-                 "TESTCASE={}".format(args.test_case or ""),

-                 container_name,

+                 containers[container_name]["name"],

+             ]

+             cmd += volumes

+             cmd += env_vars

+             cmd += [

+                 containers[container_name]["code"],

              ]

-             output_code = sp.call(command)

-             if output_code:

+             logfile = "{}/{}_tests.log".format(result_path, TIMESTAMP)

+             if not _call_command(cmd, logfile):

                  failed.append(container_name)

  

      if not args.shell:

TLDR; This PR split the container images into base and code Dockerfile as well as a separate entrypoint script. Testing of the local git repo and active branch by mounting the folder into the container as new default. REPO and BRANCH env vars can be set which allow testing of remote repositories as before if wanted. Image build only if they not exist in the local podman cache or when manually triggered, every test run use the existing container otherwise. This allows local testing of current changes within a few minutes or even just seconds.


To reduce the resources and time to test changes, I created some scripts a few months ago which I used a lot when I was working on fixing the unit tests. It was hacky and mainly for my personal use, so I brushed it up a and moved all the logic into the run-tests-container.py script.

General design changes:
The Dockerfiles of the old container image contained everything and also included the pagure source that should be tested. I found this very inflexible, every small change required a rebuild of the whole container, which is very time consuming. Therefore I split them in three parts: A base and code Dockerfile and a separate entrypoint script.
The base image contains all packages, rpm also everything required by pagure.spec, pip all tox environments pre-populated with the packages based on all requirements.txt files. The code image uses the base image and adds the entrypoint script.
The actual pagure code isn't part of any of the images and will either be downloaded from a external repo or (default), mounted from the current directory, when the code container get started.

./run-tests-container.py --centos "tests/test_pagure_flask_api_issue_change_status.py" > start c8s code container, local git top-folder mounted as /wrkdir, entrypoint script performs git clone from /wrkdir and given branch, default is the currently active, to /pagure inside the container. The rest is mostly unchanged to the original code.

Available container images:

==> dev/containers/base-centos-stream8-rpms-py3 <==
FROM quay.io/centos/centos:stream8

==> dev/containers/base-fedora-pip-py3 <==
FROM quay.io/fedora/fedora:36-x86_64

==> dev/containers/base-fedora-rpms-py3 <==
FROM quay.io/fedora/fedora:36-x86_64

I added additional tests to run-tests-container.py, if git or podman are not installed, it will exit. If the base or code container image not exist, they will be build. If the new parameter --rebuild or --rebuild-code is used, a new image build is forced by ignoring the local cache. As long no rebuild is triggered manually, the existing images will be used for every test run.

pagure/dev/results_<test-image-name> will still be mounted into the container as /results, but the logging is done my run-tests-container.py, I don't see any pagure test code that still writes into /results.
Log files are automatically created for build, test and also shell activities and saved in the related pagure/dev/results_<test-image-name> folder, with the current unix timestamp as prefix. This allows to go back and check logs for a previous test run. Example:

pagure/dev/results_pagure-tests-fedora-pip-py3/1681673866_base-build.log
pagure/dev/results_pagure-tests-fedora-pip-py3/1681673866_code-build.log
pagure/dev/results_pagure-tests-fedora-pip-py3/1681673866_tests.log

Specifying a test case was possible from a CLI perspective in the past but then only passed to the tests inside the rpm container, not pip. This is now possible with all images by adding the path to the test file as last argument. Example to run one test case and just a single test on c8s:

dev/run-tests-container.py --centos tests/test_pagure_flask_api_issue_change_status.py

dev/run-tests-container.py --centos tests/test_pagure_flask_ui_priorities.py:PagureFlaskPrioritiestests.test_ticket_with_no_priority

Testing changes quickly locally, without pushing to remote, was something I needed very urgent but was also requested for example here: https://pagure.io/pagure/issue/5186
As outlined in the above issue, if a PR is already open, pushing changes to perform a local test also triggered the Jenkins CI in the related PR, which is a waste of resources.

@ngompa @pingou sorry for the wall of text, I tried to explain this quite large change as good as possible. Feel free to give it a try and please let me know what you think. I'm happy to further improve it but for sure, you can also just merge it if you like the proposed approach.

Important:
This PR doesn't touch anything related to the CI pipeline, it only affects local testing. If parts of this approach would also be valuable to reduce the CI runtime, I can work an that at a later point.

1 new commit added

  • chore(run-tests-container): flask8 findings addressed
a year ago

1 new commit added

  • docs(README): minor typo corrected
a year ago

containers

changed and pushed.

rebased onto 08a5bc9

a year ago

Pull-Request has been merged by ngompa

11 months ago

Thanks for the improvements, merged!