This is an automated email from the ASF dual-hosted git repository.
shahar1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 005fd649bdf Add dedicated tests for cncf.kubernetes secret and
k8s_model modules (#73751)
005fd649bdf is described below
commit 005fd649bdf44d1cae66a48da341fef039b3ec67
Author: Karthik Mohankumar <[email protected]>
AuthorDate: Sat Sep 26 10:59:40 2026 -0500
Add dedicated tests for cncf.kubernetes secret and k8s_model modules
(#73751)
* Add dedicated tests for cncf.kubernetes secret and k8s_model modules
The Secret tests lived under a models/ test package that has no matching
source package, so the project-structure check could not see them and both
modules stayed on the OVERLOOKED_TESTS allowlist. Placing the tests where the
check expects them lets the allowlist shrink, and covers constructor
validation, equality semantics and append_to_pod chaining, which were
previously untested.
* Remove secret and k8s_model from OVERLOOKED_TESTS
* Remove models test package now that Secret tests mirror source
layoutDelete providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models
directory
---
.../tests/unit/always/test_project_structure.py | 2 -
.../tests/unit/cncf/kubernetes/models/__init__.py | 17 --------
.../tests/unit/cncf/kubernetes/test_k8s_model.py | 47 ++++++++++++++++++++++
.../cncf/kubernetes/{models => }/test_secret.py | 45 +++++++++++++++++++++
4 files changed, 92 insertions(+), 19 deletions(-)
diff --git a/airflow-core/tests/unit/always/test_project_structure.py
b/airflow-core/tests/unit/always/test_project_structure.py
index 106df1e7336..ed83b0aae0a 100644
--- a/airflow-core/tests/unit/always/test_project_structure.py
+++ b/airflow-core/tests/unit/always/test_project_structure.py
@@ -76,10 +76,8 @@ class TestProjectStructure:
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/executors/test_kubernetes_executor_types.py",
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/executors/test_kubernetes_executor_utils.py",
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_exceptions.py",
-
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_k8s_model.py",
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_kube_config.py",
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_python_kubernetes_script.py",
-
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_secret.py",
"providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_delete_from.py",
"providers/common/compat/tests/unit/common/compat/standard/test_utils.py",
"providers/fab/tests/unit/fab/auth_manager/api_fastapi/datamodels/test_login.py",
diff --git
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/__init__.py
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/__init__.py
deleted file mode 100644
index 217e5db9607..00000000000
--- a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
diff --git
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_k8s_model.py
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_k8s_model.py
new file mode 100644
index 00000000000..7dace4ed558
--- /dev/null
+++ b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_k8s_model.py
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from unittest import mock
+
+import pytest
+from kubernetes.client import models as k8s
+
+from airflow.providers.cncf.kubernetes.k8s_model import K8SModel, append_to_pod
+
+
[email protected]
+def pod() -> k8s.V1Pod:
+ return k8s.V1Pod(metadata=k8s.V1ObjectMeta(name="base"))
+
+
+class TestAppendToPod:
+ @pytest.mark.parametrize("k8s_objects", [None, []], ids=["none", "empty"])
+ def test_no_objects_returns_pod_unchanged(self, pod, k8s_objects):
+ assert append_to_pod(pod, k8s_objects) is pod
+
+ def test_each_object_receives_previous_result(self, pod):
+ intermediate =
k8s.V1Pod(metadata=k8s.V1ObjectMeta(name="intermediate"))
+ final = k8s.V1Pod(metadata=k8s.V1ObjectMeta(name="final"))
+ first = mock.create_autospec(K8SModel, instance=True)
+ first.attach_to_pod.return_value = intermediate
+ second = mock.create_autospec(K8SModel, instance=True)
+ second.attach_to_pod.return_value = final
+
+ assert append_to_pod(pod, [first, second]) is final
+ first.attach_to_pod.assert_called_once_with(pod)
+ second.attach_to_pod.assert_called_once_with(intermediate)
diff --git
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/test_secret.py
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_secret.py
similarity index 74%
rename from
providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/test_secret.py
rename to providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_secret.py
index 1f299529687..9ccdae57921 100644
--- a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/models/test_secret.py
+++ b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_secret.py
@@ -19,14 +19,59 @@ from __future__ import annotations
import uuid
from unittest import mock
+import pytest
from kubernetes.client import ApiClient, models as k8s
+from airflow.exceptions import AirflowConfigException
from airflow.providers.cncf.kubernetes.k8s_model import append_to_pod
from airflow.providers.cncf.kubernetes.pod_generator import PodGenerator
from airflow.providers.cncf.kubernetes.secret import Secret
class TestSecret:
+ def test_invalid_deploy_type(self):
+ with pytest.raises(AirflowConfigException, match="deploy_type must be
env or volume"):
+ Secret("file", "/etc/foo", "secret")
+
+ def test_key_without_deploy_target(self):
+ with pytest.raises(
+ AirflowConfigException, match="If `key` is set, `deploy_target`
should not be None"
+ ):
+ Secret("env", None, "secret", "key")
+
+ @pytest.mark.parametrize(
+ ("deploy_type", "deploy_target", "expected_target"),
+ [
+ pytest.param("env", "my_var", "MY_VAR",
id="env-target-uppercased"),
+ pytest.param("volume", "/etc/lower", "/etc/lower",
id="volume-target-unchanged"),
+ ],
+ )
+ def test_deploy_target_normalization(self, deploy_type, deploy_target,
expected_target):
+ assert Secret(deploy_type, deploy_target, "secret").deploy_target ==
expected_target
+
+ def test_equality_and_hash(self):
+ secret = Secret("env", "name", "secret", "key")
+ same = Secret("env", "NAME", "secret", "key")
+ different = Secret("env", "name", "secret", "other_key")
+
+ assert secret == same
+ assert hash(secret) == hash(same)
+ assert secret != different
+ assert len({secret, same, different}) == 2
+
+ def test_repr(self):
+ assert repr(Secret("env", "name", "secret", "key")) == "Secret(env,
NAME, secret, key)"
+
+ def test_attach_to_pod_does_not_mutate_input(self):
+ pod =
k8s.V1Pod(spec=k8s.V1PodSpec(containers=[k8s.V1Container(name="base")]))
+
+ result = Secret("env", None, "secret_a").attach_to_pod(pod)
+
+ assert result.spec.containers[0].env_from == [
+
k8s.V1EnvFromSource(secret_ref=k8s.V1SecretEnvSource(name="secret_a"))
+ ]
+ assert pod.spec.containers[0].env_from is None
+
def test_to_env_secret(self):
secret = Secret("env", "name", "secret", "key")
assert secret.to_env_secret() == k8s.V1EnvVar(