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',