Skip to content

Commit 271e8a2

Browse files
committed
Use round() for duration conversion
Using round is more appropriate and intuitive for the user. Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent 48f9fa5 commit 271e8a2

File tree

3 files changed

+76
-17
lines changed

3 files changed

+76
-17
lines changed

src/frequenz/client/dispatch/_cli_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def convert(
5151
class FuzzyTimeDelta(click.ParamType):
5252
"""Try to parse a string as a timedelta.
5353
54-
Uses parsedatetime and tries to parse it relative datetime first that
54+
Uses parsedatetime and tries to parse it as relative datetime first that
5555
is then converted to a timedelta.
5656
5757
If that fails, try to interpret the string as a number of seconds.

src/frequenz/client/dispatch/_internal_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def to_protobuf(self) -> PBDispatchCreateRequest:
101101
pb_request.microgrid_id = self.microgrid_id
102102
pb_request.type = self.type
103103
pb_request.start_time.CopyFrom(to_timestamp(self.start_time))
104-
pb_request.duration = int(self.duration.total_seconds())
104+
pb_request.duration = round(self.duration.total_seconds())
105105
pb_request.selector.CopyFrom(component_selector_to_protobuf(self.selector))
106106
pb_request.is_active = self.active
107107
pb_request.is_dry_run = self.dry_run

tests/test_dispatch_cli.py

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def fake_client() -> FakeClient:
3030

3131

3232
@pytest.fixture(autouse=True)
33-
def mock_get_client(fake_client: FakeClient) -> Generator:
33+
def mock_get_client(fake_client: FakeClient) -> Generator[None, None, None]:
3434
"""Fixture to mock get_client with FakeClient."""
3535
with patch(
3636
"frequenz.client.dispatch.__main__.get_client", return_value=fake_client
@@ -40,7 +40,7 @@ def mock_get_client(fake_client: FakeClient) -> Generator:
4040

4141
@pytest.mark.asyncio
4242
@pytest.mark.parametrize(
43-
"dispatches, microgrid_id, expected_output",
43+
"dispatches, microgrid_id, expected_output, expected_return_code",
4444
[
4545
(
4646
[
@@ -61,8 +61,9 @@ def mock_get_client(fake_client: FakeClient) -> Generator:
6161
],
6262
1,
6363
"1 dispatches total.",
64+
0,
6465
),
65-
([], 1, "0 dispatches total."),
66+
([], 1, "0 dispatches total.", 0),
6667
(
6768
[
6869
Dispatch(
@@ -82,6 +83,7 @@ def mock_get_client(fake_client: FakeClient) -> Generator:
8283
],
8384
1,
8485
"0 dispatches total.",
86+
0,
8587
),
8688
(
8789
[
@@ -116,27 +118,36 @@ def mock_get_client(fake_client: FakeClient) -> Generator:
116118
],
117119
1,
118120
"1 dispatches total.",
121+
0,
122+
),
123+
(
124+
[],
125+
"x",
126+
"Error: Invalid value for 'MICROGRID_ID': 'x' is not a valid integer.",
127+
2,
119128
),
120129
],
121130
)
122-
async def test_list_command(
131+
async def test_list_command( # pylint: disable=too-many-arguments
123132
runner: CliRunner,
124133
fake_client: FakeClient,
125134
dispatches: list[Dispatch],
126135
microgrid_id: int,
127136
expected_output: str,
137+
expected_return_code: int,
128138
) -> None:
129139
"""Test the list command."""
130140
fake_client.dispatches = dispatches
131141
result = await runner.invoke(cli, ["list", str(microgrid_id)])
132-
assert result.exit_code == 0
142+
assert result.exit_code == expected_return_code
133143
assert expected_output in result.output
134144

135145

136146
@pytest.mark.asyncio
137147
@pytest.mark.parametrize(
138148
"args, expected_microgrid_id, expected_type, "
139-
"expected_start_time_delta, expected_duration, expected_selector",
149+
"expected_start_time_delta, expected_duration, "
150+
"expected_selector, expected_return_code",
140151
[
141152
(
142153
["create", "1", "test", "in 1 hour", "1h", "BATTERY"],
@@ -145,6 +156,7 @@ async def test_list_command(
145156
timedelta(hours=1),
146157
timedelta(seconds=3600),
147158
ComponentCategory.BATTERY,
159+
0,
148160
),
149161
(
150162
["create", "1", "test", "in 2 hours", "1 hour", "1,2,3"],
@@ -153,6 +165,16 @@ async def test_list_command(
153165
timedelta(hours=2),
154166
timedelta(seconds=3600),
155167
[1, 2, 3],
168+
0,
169+
),
170+
(
171+
["create", "x"],
172+
0,
173+
"",
174+
timedelta(),
175+
timedelta(),
176+
[],
177+
2,
156178
),
157179
],
158180
)
@@ -165,15 +187,21 @@ async def test_create_command( # pylint: disable=too-many-arguments
165187
expected_start_time_delta: timedelta,
166188
expected_duration: timedelta,
167189
expected_selector: list[int] | ComponentCategory,
190+
expected_return_code: int,
168191
) -> None:
169192
"""Test the create command."""
170193
start_time = (datetime.now(get_localzone()) + expected_start_time_delta).astimezone(
171194
timezone.utc
172195
)
173196
result = await runner.invoke(cli, args)
174197

175-
assert result.exit_code == 0
198+
assert result.exit_code == expected_return_code
176199
assert "id" in result.output
200+
201+
if expected_return_code != 0:
202+
assert len(fake_client.dispatches) == 0
203+
return
204+
177205
assert len(fake_client.dispatches) == 1
178206
created_dispatch = fake_client.dispatches[0]
179207
assert created_dispatch.microgrid_id == expected_microgrid_id
@@ -189,7 +217,7 @@ async def test_create_command( # pylint: disable=too-many-arguments
189217

190218
@pytest.mark.asyncio
191219
@pytest.mark.parametrize(
192-
"dispatches, field, value, update_field, update_value",
220+
"dispatches, field, value, update_field, update_value, expected_return_code, expected_output",
193221
[
194222
(
195223
[
@@ -212,6 +240,8 @@ async def test_create_command( # pylint: disable=too-many-arguments
212240
"7200",
213241
"duration",
214242
timedelta(seconds=7200),
243+
0,
244+
"Dispatch updated.",
215245
),
216246
(
217247
[
@@ -234,6 +264,8 @@ async def test_create_command( # pylint: disable=too-many-arguments
234264
"False",
235265
"active",
236266
False,
267+
0,
268+
"Dispatch updated.",
237269
),
238270
(
239271
[
@@ -256,6 +288,17 @@ async def test_create_command( # pylint: disable=too-many-arguments
256288
"400, 401",
257289
"selector",
258290
[400, 401],
291+
0,
292+
"Dispatch updated.",
293+
),
294+
(
295+
[],
296+
"--duration",
297+
"frankly my dear, I don't give a damn",
298+
"",
299+
None,
300+
2,
301+
"Error: Invalid value for '--duration': Could not parse time expression",
259302
),
260303
],
261304
)
@@ -267,13 +310,16 @@ async def test_update_command( # pylint: disable=too-many-arguments
267310
value: str,
268311
update_field: str,
269312
update_value: Any,
313+
expected_return_code: int,
314+
expected_output: str,
270315
) -> None:
271316
"""Test the update command."""
272317
fake_client.dispatches = dispatches
273318
result = await runner.invoke(cli, ["update", "1", field, value])
274-
assert result.exit_code == 0
275-
assert "Dispatch updated." in result.output
276-
assert getattr(fake_client.dispatches[0], update_field) == update_value
319+
assert result.exit_code == expected_return_code
320+
assert expected_output in result.output
321+
if expected_return_code == 0:
322+
assert getattr(fake_client.dispatches[0], update_field) == update_value
277323

278324

279325
@pytest.mark.asyncio
@@ -301,6 +347,11 @@ async def test_update_command( # pylint: disable=too-many-arguments
301347
"Dispatch(id=1,",
302348
),
303349
([], 999, "Error"),
350+
(
351+
[],
352+
"x",
353+
"Error: Invalid value for '[DISPATCH_IDS]...': 'x' is not a valid integer.",
354+
),
304355
],
305356
)
306357
async def test_get_command(
@@ -319,7 +370,7 @@ async def test_get_command(
319370

320371
@pytest.mark.asyncio
321372
@pytest.mark.parametrize(
322-
"dispatches, dispatch_id, expected_output",
373+
"dispatches, dispatch_id, expected_output, expected_return_code",
323374
[
324375
(
325376
[
@@ -340,21 +391,29 @@ async def test_get_command(
340391
],
341392
1,
342393
"Dispatches deleted: [1]",
394+
0,
395+
),
396+
([], 999, "Error", 1),
397+
(
398+
[],
399+
"x",
400+
"Error: Invalid value for '[DISPATCH_IDS]...': Invalid integer",
401+
2,
343402
),
344-
([], 999, "Error"),
345403
],
346404
)
347-
async def test_delete_command(
405+
async def test_delete_command( # pylint: disable=too-many-arguments
348406
runner: CliRunner,
349407
fake_client: FakeClient,
350408
dispatches: list[Dispatch],
351409
dispatch_id: int,
352410
expected_output: str,
411+
expected_return_code: int,
353412
) -> None:
354413
"""Test the delete command."""
355414
fake_client.dispatches = dispatches
356415
result = await runner.invoke(cli, ["delete", str(dispatch_id)])
357-
assert result.exit_code == 0 if dispatches else 1
416+
assert result.exit_code == expected_return_code
358417
assert expected_output in result.output
359418
if dispatches:
360419
assert len(fake_client.dispatches) == 0

0 commit comments

Comments
 (0)