|
1 | 1 | # License: MIT |
2 | 2 | # Copyright © 2025 Frequenz Energy-as-a-Service GmbH |
3 | 3 |
|
4 | | -"""Tests for the Lifetime class.""" |
| 4 | +"""Tests for the Lifetime class and its protobuf conversion.""" |
5 | 5 |
|
6 | 6 | from dataclasses import dataclass |
7 | 7 | from datetime import datetime, timezone |
8 | 8 | from enum import Enum, auto |
| 9 | +from typing import Any |
9 | 10 |
|
10 | 11 | import pytest |
| 12 | +from frequenz.api.common.v1.microgrid import lifetime_pb2 |
| 13 | +from google.protobuf import timestamp_pb2 |
11 | 14 |
|
12 | 15 | from frequenz.client.microgrid import Lifetime |
| 16 | +from frequenz.client.microgrid._lifetime_proto import lifetime_from_proto |
13 | 17 |
|
14 | 18 |
|
15 | 19 | class _Time(Enum): |
@@ -65,6 +69,20 @@ class _ActivityTestCase: |
65 | 69 | """The expected operational state.""" |
66 | 70 |
|
67 | 71 |
|
| 72 | +@dataclass(frozen=True, kw_only=True) |
| 73 | +class _ProtoConversionTestCase: |
| 74 | + """Test case for protobuf conversion.""" |
| 75 | + |
| 76 | + name: str |
| 77 | + """The description of the test case.""" |
| 78 | + |
| 79 | + include_start: bool |
| 80 | + """Whether to include start timestamp.""" |
| 81 | + |
| 82 | + include_end: bool |
| 83 | + """Whether to include end timestamp.""" |
| 84 | + |
| 85 | + |
68 | 86 | @dataclass(frozen=True, kw_only=True) |
69 | 87 | class _FixedLifetimeTestCase: |
70 | 88 | """Test case for fixed lifetime activity testing.""" |
@@ -303,3 +321,51 @@ def test_active_at_with_fixed_lifetime( |
303 | 321 | }[case.test_time] |
304 | 322 |
|
305 | 323 | assert lifetime.is_operational_at(test_time) == case.expected_operational |
| 324 | + |
| 325 | + |
| 326 | +@pytest.mark.parametrize( |
| 327 | + "case", |
| 328 | + [ |
| 329 | + _ProtoConversionTestCase( |
| 330 | + name="both timestamps", include_start=True, include_end=True |
| 331 | + ), |
| 332 | + _ProtoConversionTestCase( |
| 333 | + name="only start timestamp", include_start=True, include_end=False |
| 334 | + ), |
| 335 | + _ProtoConversionTestCase( |
| 336 | + name="only end timestamp", include_start=False, include_end=True |
| 337 | + ), |
| 338 | + _ProtoConversionTestCase( |
| 339 | + name="no timestamps", include_start=False, include_end=False |
| 340 | + ), |
| 341 | + ], |
| 342 | + ids=lambda case: case.name, |
| 343 | +) |
| 344 | +def test_from_proto( |
| 345 | + now: datetime, future: datetime, case: _ProtoConversionTestCase |
| 346 | +) -> None: |
| 347 | + """Test conversion from protobuf message to Lifetime.""" |
| 348 | + now_ts = timestamp_pb2.Timestamp() |
| 349 | + now_ts.FromDatetime(now) |
| 350 | + |
| 351 | + future_ts = timestamp_pb2.Timestamp() |
| 352 | + future_ts.FromDatetime(future) |
| 353 | + |
| 354 | + proto_kwargs: dict[str, Any] = {} |
| 355 | + if case.include_start: |
| 356 | + proto_kwargs["start_timestamp"] = now_ts |
| 357 | + if case.include_end: |
| 358 | + proto_kwargs["end_timestamp"] = future_ts |
| 359 | + |
| 360 | + proto = lifetime_pb2.Lifetime(**proto_kwargs) |
| 361 | + lifetime = lifetime_from_proto(proto) |
| 362 | + |
| 363 | + if case.include_start: |
| 364 | + assert lifetime.start == now |
| 365 | + else: |
| 366 | + assert lifetime.start is None |
| 367 | + |
| 368 | + if case.include_end: |
| 369 | + assert lifetime.end == future |
| 370 | + else: |
| 371 | + assert lifetime.end is None |
0 commit comments