Skip to content

Commit ce10525

Browse files
committed
Add exception group and test timeout
1 parent e1d561b commit ce10525

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

hcloud/actions/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Action,
1111
ActionException,
1212
ActionFailedException,
13+
ActionGroupException,
1314
ActionTimeoutException,
1415
)
1516

@@ -18,6 +19,7 @@
1819
"ActionException",
1920
"ActionFailedException",
2021
"ActionTimeoutException",
22+
"ActionGroupException",
2123
"ActionsClient",
2224
"ActionsPageResult",
2325
"BoundAction",

hcloud/actions/client.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66
from .._utils import batched, waiter
77
from ..core import BoundModelBase, ClientEntityBase, Meta
8-
from .domain import Action, ActionFailedException, ActionTimeoutException
8+
from .domain import (
9+
Action,
10+
ActionFailedException,
11+
ActionGroupException,
12+
ActionTimeoutException,
13+
)
914

1015
if TYPE_CHECKING:
1116
from .._client import Client
@@ -193,25 +198,25 @@ def wait_for_function(
193198
:raises: ActionFailedException when an Action failed.
194199
:return: List of succeeded Actions.
195200
"""
196-
running_ids = [a.id for a in actions]
197-
201+
running: list[BoundAction] = list(actions)
198202
completed: list[BoundAction] = []
199203

200204
retries = 0
201205
wait = waiter(timeout)
202-
while len(running_ids):
206+
while len(running):
203207
# pylint: disable=protected-access
204208
if wait(self._client._poll_interval_func(retries)):
205-
# TODO: How to raise a timeout exception for many actions without using an exception group.
206-
raise ActionTimeoutException("")
209+
raise ActionGroupException(
210+
[ActionTimeoutException(action=action) for action in running]
211+
)
207212

208213
retries += 1
209214

210-
updates = self._get_list_by_ids(running_ids)
215+
running = self._get_list_by_ids([a.id for a in running])
211216

212-
for update in updates:
217+
for update in running:
213218
if update.status != Action.STATUS_RUNNING:
214-
running_ids.remove(update.id)
219+
running.remove(update)
215220
completed.append(update)
216221

217222
handle_update(update)

hcloud/actions/domain.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,11 @@ class ActionFailedException(ActionException):
9898

9999
class ActionTimeoutException(ActionException):
100100
"""The pending action timed out"""
101+
102+
103+
class ActionGroupException(HCloudException):
104+
"""An exception for a group of actions"""
105+
106+
def __init__(self, exceptions: list[ActionException]):
107+
super().__init__("Multiple pending actions failed")
108+
self.exceptions = exceptions

tests/unit/actions/test_client.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from hcloud.actions import (
88
Action,
99
ActionFailedException,
10+
ActionGroupException,
1011
ActionsClient,
1112
ActionTimeoutException,
1213
BoundAction,
@@ -258,3 +259,29 @@ def test_wait_for_error(self, actions_client: ActionsClient):
258259
mock.call(method="GET", url="/actions", params={"id": (1, 2)}),
259260
]
260261
)
262+
263+
def test_wait_for_timeout(self, actions_client: ActionsClient):
264+
actions = [
265+
Action(id=1, status="running", command="create_server"),
266+
Action(id=2, status="running", command="start_server"),
267+
]
268+
269+
# Speed up test by not really waiting
270+
actions_client._client._poll_interval_func = mock.MagicMock()
271+
actions_client._client._poll_interval_func.return_value = 0.1
272+
273+
actions_client._client.request.return_value = {
274+
"actions": [
275+
{"id": 1, "status": "running", "command": "create_server"},
276+
{"id": 2, "status": "running", "command": "start_server"},
277+
]
278+
}
279+
280+
with pytest.raises(ActionGroupException):
281+
actions_client.wait_for(actions, timeout=0.2)
282+
283+
actions_client._client.request.assert_has_calls(
284+
[
285+
mock.call(method="GET", url="/actions", params={"id": (1, 2)}),
286+
]
287+
)

0 commit comments

Comments
 (0)