2424from airflow .providers .cncf .kubernetes .utils import delete_from
2525
2626
27- def create_api_constructor (monkeypatch , api_class_name ):
28- api_constructor = mock .create_autospec (getattr (delete_from .client , api_class_name ))
29- monkeypatch .setattr (delete_from .client , api_class_name , api_constructor )
30- return api_constructor
31-
32-
3327@pytest .mark .parametrize (
34- ("api_version" , "kind" , "api_class_name " , "method_name " ),
28+ ("api_version" , "kind" , "method_name " , "expected_kwargs " ),
3529 [
36- ("v1" , "ConfigMap" , "CoreV1Api" , "delete_namespaced_config_map" ),
37- ("apps/v1" , "Deployment" , "AppsV1Api" , "delete_namespaced_deployment" ),
3830 (
39- "apiextensions.k8s.io/ v1" ,
40- "CustomResourceDefinition " ,
41- "ApiextensionsV1Api " ,
42- "delete_custom_resource_definition" ,
31+ "v1" ,
32+ "ConfigMap " ,
33+ "delete_namespaced_config_map " ,
34+ { "name" : "resource" , "namespace" : "default" , "body" : delete_from . DEFAULT_DELETION_BODY } ,
4335 ),
4436 (
45- "flowcontrol.apiserver.k8s.io /v1" ,
46- "FlowSchema " ,
47- "FlowcontrolApiserverV1Api " ,
48- "delete_flow_schema" ,
37+ "apps /v1" ,
38+ "Deployment " ,
39+ "delete_namespaced_deployment " ,
40+ { "name" : "resource" , "namespace" : "default" , "body" : delete_from . DEFAULT_DELETION_BODY } ,
4941 ),
5042 ],
5143)
52- def test_delete_from_yaml_derives_api_class_and_kind (
53- monkeypatch , api_version , kind , api_class_name , method_name
44+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.client.AppsV1Api" , autospec = True )
45+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.client.CoreV1Api" , autospec = True )
46+ def test_delete_from_yaml_derives_namespaced_api_class_and_kind (
47+ mock_core_v1_api , mock_apps_v1_api , api_version , kind , method_name , expected_kwargs
5448):
55- api_constructor = create_api_constructor (monkeypatch , api_class_name )
56- api_client = mock .sentinel .api_client
49+ api_constructor = mock_core_v1_api if api_version == "v1" else mock_apps_v1_api
5750 api = api_constructor .return_value
5851 getattr (api , method_name ).return_value = mock .Mock (status = "Success" )
5952
6053 delete_from ._delete_from_yaml_single_item (
61- k8s_client = api_client ,
54+ k8s_client = mock . sentinel . api_client ,
6255 yml_document = {"apiVersion" : api_version , "kind" : kind , "metadata" : {"name" : "resource" }},
6356 )
6457
65- api_constructor .assert_called_once_with (api_client )
66- if method_name .startswith ("delete_namespaced" ):
67- getattr (api , method_name ).assert_called_once_with (
68- name = "resource" , namespace = "default" , body = delete_from .DEFAULT_DELETION_BODY
69- )
70- else :
71- getattr (api , method_name ).assert_called_once_with (
72- name = "resource" , body = delete_from .DEFAULT_DELETION_BODY
73- )
58+ api_constructor .assert_called_once_with (mock .sentinel .api_client )
59+ getattr (api , method_name ).assert_called_once_with (** expected_kwargs )
7460
7561
76- def test_delete_from_yaml_document_namespace_takes_precedence (monkeypatch ):
77- api_constructor = create_api_constructor (monkeypatch , "CoreV1Api" )
62+ @pytest .mark .parametrize (
63+ ("api_version" , "kind" , "method_name" ),
64+ [
65+ ("apiextensions.k8s.io/v1" , "CustomResourceDefinition" , "delete_custom_resource_definition" ),
66+ ("flowcontrol.apiserver.k8s.io/v1" , "FlowSchema" , "delete_flow_schema" ),
67+ ],
68+ )
69+ @mock .patch (
70+ "airflow.providers.cncf.kubernetes.utils.delete_from.client.FlowcontrolApiserverV1Api" , autospec = True
71+ )
72+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.client.ApiextensionsV1Api" , autospec = True )
73+ def test_delete_from_yaml_derives_cluster_scoped_api_class_and_kind (
74+ mock_apiextensions_v1_api , mock_flowcontrol_apiserver_v1_api , api_version , kind , method_name
75+ ):
76+ api_constructor = (
77+ mock_apiextensions_v1_api
78+ if api_version == "apiextensions.k8s.io/v1"
79+ else mock_flowcontrol_apiserver_v1_api
80+ )
7881 api = api_constructor .return_value
82+ getattr (api , method_name ).return_value = mock .Mock (status = "Success" )
83+
84+ delete_from ._delete_from_yaml_single_item (
85+ k8s_client = mock .sentinel .api_client ,
86+ yml_document = {"apiVersion" : api_version , "kind" : kind , "metadata" : {"name" : "resource" }},
87+ )
88+
89+ api_constructor .assert_called_once_with (mock .sentinel .api_client )
90+ getattr (api , method_name ).assert_called_once_with (name = "resource" , body = delete_from .DEFAULT_DELETION_BODY )
91+
92+
93+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.client.CoreV1Api" , autospec = True )
94+ def test_delete_from_yaml_document_namespace_takes_precedence (mock_core_v1_api ):
95+ api = mock_core_v1_api .return_value
7996 api .delete_namespaced_config_map .return_value = mock .Mock (status = "Success" )
8097
8198 delete_from ._delete_from_yaml_single_item (
@@ -93,9 +110,9 @@ def test_delete_from_yaml_document_namespace_takes_precedence(monkeypatch):
93110 )
94111
95112
96- def test_delete_from_dict_expands_lists_and_inherits_api_version ( monkeypatch ):
97- api_constructor = create_api_constructor ( monkeypatch , "CoreV1Api" )
98- api = api_constructor .return_value
113+ @ mock . patch ( "airflow.providers.cncf.kubernetes.utils.delete_from.client.CoreV1Api" , autospec = True )
114+ def test_delete_from_dict_expands_lists_and_inherits_api_version ( mock_core_v1_api ):
115+ api = mock_core_v1_api .return_value
99116 api .delete_namespaced_config_map .return_value = mock .Mock (status = "Success" )
100117 document = {
101118 "apiVersion" : "v1" ,
@@ -129,9 +146,9 @@ def test_delete_from_dict_expands_lists_and_inherits_api_version(monkeypatch):
129146 )
130147
131148
132- def test_delete_from_dict_collects_api_exceptions ( monkeypatch ):
133- api_constructor = create_api_constructor ( monkeypatch , "CoreV1Api" )
134- api = api_constructor .return_value
149+ @ mock . patch ( "airflow.providers.cncf.kubernetes.utils.delete_from.client.CoreV1Api" , autospec = True )
150+ def test_delete_from_dict_collects_api_exceptions ( mock_core_v1_api ):
151+ api = mock_core_v1_api .return_value
135152 first_exception = ApiException (reason = "first" )
136153 first_exception .body = "first body"
137154 second_exception = ApiException (reason = "second" )
@@ -154,3 +171,40 @@ def test_delete_from_dict_collects_api_exceptions(monkeypatch):
154171 assert (
155172 str (error .value ) == "Error from server (first):first body\n Error from server (second):second body\n "
156173 )
174+
175+
176+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.delete_from_dict" , autospec = True )
177+ def test_delete_from_yaml_skips_empty_documents_and_forwards_verbose (mock_delete_from_dict ):
178+ document = {"apiVersion" : "v1" , "kind" : "ConfigMap" , "metadata" : {"name" : "resource" }}
179+
180+ delete_from .delete_from_yaml (
181+ k8s_client = mock .sentinel .api_client ,
182+ yaml_objects = [None , document ],
183+ verbose = True ,
184+ namespace = "configured-namespace" ,
185+ body = mock .sentinel .body ,
186+ grace_period_seconds = 0 ,
187+ )
188+
189+ mock_delete_from_dict .assert_called_once_with (
190+ k8s_client = mock .sentinel .api_client ,
191+ data = document ,
192+ body = mock .sentinel .body ,
193+ namespace = "configured-namespace" ,
194+ verbose = True ,
195+ grace_period_seconds = 0 ,
196+ )
197+
198+
199+ @mock .patch ("airflow.providers.cncf.kubernetes.utils.delete_from.client.CoreV1Api" , autospec = True )
200+ def test_delete_from_yaml_prints_status_when_verbose (mock_core_v1_api , capsys ):
201+ api = mock_core_v1_api .return_value
202+ api .delete_namespaced_config_map .return_value = mock .Mock (status = "Success" )
203+
204+ delete_from ._delete_from_yaml_single_item (
205+ k8s_client = mock .sentinel .api_client ,
206+ yml_document = {"apiVersion" : "v1" , "kind" : "ConfigMap" , "metadata" : {"name" : "resource" }},
207+ verbose = True ,
208+ )
209+
210+ assert capsys .readouterr ().out == "config_map deleted. status='Success'\n "
0 commit comments