44import yaml
55
66import easykube
7- from easykube . rest . util import PropertyDict
7+ import httpx
88
99from capi_janitor .openstack import openstack
1010from capi_janitor .openstack import operator
@@ -103,12 +103,30 @@ async def test_secgroups_for_cluster(self):
103103
104104 async def test_filtered_volumes_for_cluster (self ):
105105 volumes = [
106- mock .Mock (metadata = {"cinder.csi.openstack.org/cluster" : "mycluster" }),
107- mock .Mock (metadata = {"cinder.csi.openstack.org/cluster" : "othercluster" }),
108- mock .Mock (metadata = {"cinder.csi.openstack.org/cluster" : "mycluster" }),
109- mock .Mock (metadata = {"cinder.csi.openstack.org/cluster" : "othercluster" }),
110- # Volumes with invalid metadata
111- mock .Mock (metadata = {"another_key" : "value" }),
106+ mock .Mock (
107+ metadata = {
108+ "cinder.csi.openstack.org/cluster" : "mycluster" ,
109+ OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "false" ,
110+ }
111+ ),
112+ mock .Mock (
113+ metadata = {
114+ "cinder.csi.openstack.org/cluster" : "mycluster" ,
115+ OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "true" ,
116+ }
117+ ),
118+ mock .Mock (
119+ metadata = {
120+ "cinder.csi.openstack.org/cluster" : "othercluster" ,
121+ OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "false" ,
122+ }
123+ ),
124+ mock .Mock (
125+ metadata = {
126+ "cinder.csi.openstack.org/cluster" : "mycluster" ,
127+ }
128+ ),
129+ mock .Mock (metadata = {"other_key" : "value" }),
112130 ]
113131 resource_mock = AsyncIterList (volumes )
114132
@@ -120,7 +138,7 @@ async def test_filtered_volumes_for_cluster(self):
120138
121139 self .assertEqual (len (result ), 2 )
122140 self .assertEqual (result [0 ], volumes [0 ])
123- self .assertEqual (result [1 ], volumes [2 ])
141+ self .assertEqual (result [1 ], volumes [3 ])
124142
125143 async def test_snapshots_for_cluster (self ):
126144 snapshots = [
@@ -151,6 +169,56 @@ async def test_non_empty_iterator_returns_false(self):
151169 result = await operator .empty (async_iter )
152170 self .assertFalse (result )
153171
172+ async def test_try_delete_success (self ):
173+ instances = [mock .Mock (id = 1 ), mock .Mock (id = 2 )]
174+ resource = mock .Mock ()
175+ resource .delete = mock .AsyncMock ()
176+ resource .singular_name = "test_resource"
177+ logger = mock .Mock ()
178+
179+ result = await operator .try_delete (logger , resource , AsyncIterList (instances ))
180+
181+ self .assertTrue (result )
182+ resource .delete .assert_any_await (1 )
183+ resource .delete .assert_any_await (2 )
184+ logger .warn .assert_not_called ()
185+
186+ async def test_try_delete_with_400_and_409_errors (self ):
187+ instances = [mock .Mock (id = 1 ), mock .Mock (id = 2 )]
188+ resource = mock .Mock ()
189+ resource .singular_name = "test_resource"
190+ logger = mock .Mock ()
191+
192+ resource .delete = mock .AsyncMock (
193+ side_effect = [
194+ httpx .HTTPStatusError (
195+ "error" , request = mock .Mock (), response = mock .Mock (status_code = 400 )
196+ ),
197+ httpx .HTTPStatusError (
198+ "error" , request = mock .Mock (), response = mock .Mock (status_code = 409 )
199+ ),
200+ ]
201+ )
202+ result = await operator .try_delete (logger , resource , AsyncIterList (instances ))
203+
204+ self .assertTrue (result )
205+ self .assertEqual (resource .delete .await_count , 2 )
206+ self .assertEqual (logger .warn .call_count , 2 )
207+
208+ async def test_delete_with_unexpected_error_raises (self ):
209+ instances = [mock .Mock (id = 1 )]
210+ resource = mock .Mock ()
211+ resource .singular_name = "test_resource"
212+ logger = mock .Mock ()
213+
214+ resource .delete = mock .AsyncMock (
215+ side_effect = httpx .HTTPStatusError (
216+ "error" , request = mock .Mock (), response = mock .Mock (status_code = 500 )
217+ )
218+ )
219+ with self .assertRaises (httpx .HTTPStatusError ):
220+ await operator .try_delete (logger , resource , AsyncIterList (instances ))
221+
154222 @mock .patch .object (operator , "patch_finalizers" )
155223 @mock .patch .object (operator , "_get_os_cluster_client" )
156224 async def test_on_openstackcluster_event_adds_finalizers (
@@ -401,48 +469,3 @@ async def test_purge_openstack_resources_raises(self, mock_from_clouds):
401469
402470 # # Example: Validate if appcred deletion was attempted
403471 # mock_identityapi.resource.assert_any_call("application_credentials")
404-
405- @mock .patch .object (openstack , "Resource" )
406- async def test_user_keep_volumes_filter (self , mock_volumes_resource ):
407- # Arrange
408- async def _list_volumes ():
409- test_volumes = [
410- {
411- "id" : "123" ,
412- "name" : "volume-1" ,
413- "metadata" : {
414- "cinder.csi.openstack.org/cluster" : "cluster-1" ,
415- OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "anything-but-true" ,
416- },
417- },
418- {
419- "id" : "456" ,
420- "name" : "volume-2" ,
421- "metadata" : {
422- "cinder.csi.openstack.org/cluster" : "cluster-1" ,
423- OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "true" ,
424- },
425- },
426- {
427- "id" : "789" ,
428- "name" : "volume-3" ,
429- "metadata" : {
430- "cinder.csi.openstack.org/cluster" : "cluster-2" ,
431- OPENSTACK_USER_VOLUMES_RECLAIM_PROPERTY : "true" ,
432- },
433- },
434- ]
435- for volume in map (PropertyDict , test_volumes ):
436- yield volume
437-
438- mock_volumes_resource .list .return_value = _list_volumes ()
439- # Act
440- filtered_volumes = [
441- v
442- async for v in operator .filtered_volumes_for_cluster (
443- mock_volumes_resource , "cluster-1"
444- )
445- ]
446- # Assert
447- self .assertEqual (len (filtered_volumes ), 1 )
448- self .assertEqual (filtered_volumes [0 ].get ("name" ), "volume-1" )
0 commit comments