This is an automated email from the ASF dual-hosted git repository.

kamilbregula pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/master by this push:
     new bdb76be  Run helm chart tests in parallel (#15706)
bdb76be is described below

commit bdb76be7470621891b8382454477eca076831e65
Author: Jed Cunningham <[email protected]>
AuthorDate: Thu May 6 15:06:41 2021 -0600

    Run helm chart tests in parallel (#15706)
    
    * Allow helm chart tests to run in parallel
    
    The helm chart tests are pretty slow when run sequentially. Modifying
    them so they can be run in parallel saves a lot of time, from 10 minutes
    to 3 minutes on my machine with 8 cores.
    
    The only test that needed modification was `test_pod_template_file.py`,
    as it temporarily moves a file into the templates directory
    which was causing other tests to fail as they weren't expecting any
    objects from that temporary file. This is resolved by giving the
    pod_template_file test an isolated chart directory it can modify.
    
    `helm dep update` also doesn't work when it is called in parallel, so
    the fixture responsible for running it now ensures we only run it one at
    a time.
    
    * Enable parallelism for helm unit tests in CI
    
    Co-authored-by: Kamil Breguła <[email protected]>
    
    Co-authored-by: Kamil Breguła <[email protected]>
---
 chart/tests/conftest.py                | 23 +++++++++++++++---
 chart/tests/helm_template_generator.py |  5 ++--
 chart/tests/test_pod_template_file.py  | 44 ++++++++++++++++++++++++----------
 scripts/in_container/entrypoint_ci.sh  |  9 +++++--
 setup.py                               |  1 +
 5 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/chart/tests/conftest.py b/chart/tests/conftest.py
index 789f311..7ac27d9 100644
--- a/chart/tests/conftest.py
+++ b/chart/tests/conftest.py
@@ -19,12 +19,29 @@ import subprocess
 import sys
 
 import pytest
+from filelock import FileLock
 
 
 @pytest.fixture(autouse=True, scope="session")
-def upgrade_helm():
+def upgrade_helm(tmp_path_factory, worker_id):
     """
     Upgrade Helm repo
     """
-    subprocess.check_output(["helm", "repo", "add", "stable", 
"https://charts.helm.sh/stable/";])
-    subprocess.check_output(["helm", "dep", "update", sys.path[0]])
+
+    def _upgrade_helm():
+        subprocess.check_output(["helm", "repo", "add", "stable", 
"https://charts.helm.sh/stable/";])
+        subprocess.check_output(["helm", "dep", "update", sys.path[0]])
+
+    if worker_id == "main":
+        # not executing in with multiple workers, just update
+        _upgrade_helm()
+        return
+
+    root_tmp_dir = tmp_path_factory.getbasetemp().parent
+    lock_fn = root_tmp_dir / "upgrade_helm.lock"
+    flag_fn = root_tmp_dir / "upgrade_helm.done"
+
+    with FileLock(str(lock_fn)):
+        if not flag_fn.is_file():
+            _upgrade_helm()
+            flag_fn.touch()
diff --git a/chart/tests/helm_template_generator.py 
b/chart/tests/helm_template_generator.py
index 56a0691..6523d32 100644
--- a/chart/tests/helm_template_generator.py
+++ b/chart/tests/helm_template_generator.py
@@ -83,16 +83,17 @@ def validate_k8s_object(instance):
     validate.validate(instance)
 
 
-def render_chart(name="RELEASE-NAME", values=None, show_only=None):
+def render_chart(name="RELEASE-NAME", values=None, show_only=None, 
chart_dir=None):
     """
     Function that renders a helm chart into dictionaries. For helm chart 
testing only
     """
     values = values or {}
+    chart_dir = chart_dir or sys.path[0]
     with NamedTemporaryFile() as tmp_file:
         content = yaml.dump(values)
         tmp_file.write(content.encode())
         tmp_file.flush()
-        command = ["helm", "template", name, sys.path[0], '--values', 
tmp_file.name]
+        command = ["helm", "template", name, chart_dir, '--values', 
tmp_file.name]
         if show_only:
             for i in show_only:
                 command.extend(["--show-only", i])
diff --git a/chart/tests/test_pod_template_file.py 
b/chart/tests/test_pod_template_file.py
index 2a315e4..d949ec1 100644
--- a/chart/tests/test_pod_template_file.py
+++ b/chart/tests/test_pod_template_file.py
@@ -16,33 +16,36 @@
 # under the License.
 
 import re
+import sys
 import unittest
-from os import remove
-from os.path import dirname, realpath
-from shutil import copyfile
+from shutil import copyfile, copytree
+from tempfile import TemporaryDirectory
 
 import jmespath
+import pytest
 from parameterized import parameterized
 
 from tests.helm_template_generator import render_chart
 
-ROOT_FOLDER = realpath(dirname(realpath(__file__)) + "/..")
-
 
 class PodTemplateFileTest(unittest.TestCase):
-    def setUp(self):
-        copyfile(
-            ROOT_FOLDER + "/files/pod-template-file.kubernetes-helm-yaml",
-            ROOT_FOLDER + "/templates/pod-template-file.yaml",
-        )
-
-    def tearDown(self):
-        remove(ROOT_FOLDER + "/templates/pod-template-file.yaml")
+    @classmethod
+    @pytest.fixture(autouse=True, scope="class")
+    def isolate_chart(cls):
+        with TemporaryDirectory() as tmp_dir:
+            cls.temp_chart_dir = tmp_dir + "/chart"
+            copytree(sys.path[0], cls.temp_chart_dir)
+            copyfile(
+                cls.temp_chart_dir + 
"/files/pod-template-file.kubernetes-helm-yaml",
+                cls.temp_chart_dir + "/templates/pod-template-file.yaml",
+            )
+            yield
 
     def test_should_work(self):
         docs = render_chart(
             values={},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert re.search("Pod", docs[0]["kind"])
@@ -79,6 +82,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 },
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert re.search("Pod", docs[0]["kind"])
@@ -111,6 +115,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert jmespath.search("spec.initContainers", docs[0]) is None
@@ -131,6 +136,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"dags": dag_values},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"mountPath": "/opt/airflow/dags", "name": "dags", "readOnly": 
True} in jmespath.search(
@@ -146,6 +152,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"mountPath": "/opt/airflow/dags", "name": "dags", "readOnly": 
True} in jmespath.search(
@@ -166,6 +173,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"name": "GIT_SSH_KEY_FILE", "value": "/etc/git-secret/ssh"} in 
jmespath.search(
@@ -196,6 +204,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
         assert {"name": "GIT_KNOWN_HOSTS", "value": "true"} in jmespath.search(
             "spec.initContainers[0].env", docs[0]
@@ -222,6 +231,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {
@@ -237,6 +247,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"dags": {"persistence": {"enabled": True, "existingClaim": 
"test-claim"}}},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"name": "dags", "persistentVolumeClaim": {"claimName": 
"test-claim"}} in jmespath.search(
@@ -247,6 +258,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"dags": {"gitSync": {"enabled": True}}},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"name": "dags", "emptyDir": {}} in 
jmespath.search("spec.volumes", docs[0])
@@ -265,6 +277,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"logs": {"persistence": log_persistence_values}},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert {"name": "logs", **expected} in jmespath.search("spec.volumes", 
docs[0])
@@ -273,6 +286,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"images": {"pod_template": {"repository": "dummy_image", 
"tag": "latest"}}},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert re.search("Pod", docs[0]["kind"])
@@ -283,6 +297,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert re.search("Pod", docs[0]["kind"])
@@ -318,6 +333,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 "nodeSelector": {"diskType": "ssd"},
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert re.search("Pod", docs[0]["kind"])
@@ -342,6 +358,7 @@ class PodTemplateFileTest(unittest.TestCase):
         docs = render_chart(
             values={"gid": 5000},
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         self.assertEqual(5000, jmespath.search("spec.securityContext.fsGroup", 
docs[0]))
@@ -355,6 +372,7 @@ class PodTemplateFileTest(unittest.TestCase):
                 }
             },
             show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
         )
 
         assert "test-volume" == jmespath.search(
diff --git a/scripts/in_container/entrypoint_ci.sh 
b/scripts/in_container/entrypoint_ci.sh
index a7b5788..a6e31a2 100755
--- a/scripts/in_container/entrypoint_ci.sh
+++ b/scripts/in_container/entrypoint_ci.sh
@@ -242,9 +242,14 @@ EXTRA_PYTEST_ARGS=(
     "-rfEX"
 )
 
-if [[ "${TEST_TYPE}" != "Helm" ]]; then
+if [[ "${TEST_TYPE}" == "Helm" ]]; then
+    # Enable parallelism
     EXTRA_PYTEST_ARGS+=(
-    "--with-db-init"
+        "-n" "auto"
+    )
+else
+    EXTRA_PYTEST_ARGS+=(
+        "--with-db-init"
     )
 fi
 
diff --git a/setup.py b/setup.py
index 9331d1c..6083c14 100644
--- a/setup.py
+++ b/setup.py
@@ -484,6 +484,7 @@ devel = [
     'click~=7.1',
     'coverage',
     'docutils',
+    'filelock',
     'flake8>=3.6.0',
     'flake8-colors',
     'flaky',

Reply via email to