Skip to content

Commit 2009c46

Browse files
committed
Improve finalization of EV charger pool tests
Use the `MockMicrogrid` as a context manager, a custom async context manager and an async exit stack so all used components get automatically finalized. This commit can be reviewed much more easily hiding differences in spaces (with `diff -w`, or appending `?w=1` to the GitHub URL). Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 4b7a153 commit 2009c46

File tree

1 file changed

+150
-141
lines changed

1 file changed

+150
-141
lines changed

tests/timeseries/test_ev_charger_pool.py

Lines changed: 150 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66

77
import asyncio
8+
from contextlib import AsyncExitStack, asynccontextmanager
9+
from typing import Any, AsyncIterator
810

911
from pytest_mock import MockerFixture
1012

@@ -21,180 +23,187 @@
2123
from tests.timeseries.mock_microgrid import MockMicrogrid
2224

2325

26+
@asynccontextmanager
27+
async def new_state_tracker(*args: Any, **kwargs: Any) -> AsyncIterator[StateTracker]:
28+
"""Create a state tracker."""
29+
tracker = StateTracker(*args, **kwargs)
30+
try:
31+
yield tracker
32+
finally:
33+
await tracker.stop()
34+
35+
2436
class TestEVChargerPool:
2537
"""Tests for the `EVChargerPool`."""
2638

2739
async def test_state_updates(self, mocker: MockerFixture) -> None:
2840
"""Test ev charger state updates are visible."""
2941
mockgrid = MockMicrogrid(
30-
grid_meter=False, api_client_streaming=True, sample_rate_s=0.01
42+
grid_meter=False,
43+
api_client_streaming=True,
44+
sample_rate_s=0.01,
45+
mocker=mocker,
3146
)
3247
mockgrid.add_ev_chargers(5)
33-
await mockgrid.start(mocker)
34-
35-
state_tracker = StateTracker(set(mockgrid.evc_ids))
36-
await asyncio.sleep(0.05)
3748

38-
async def check_states(
39-
expected: dict[int, EVChargerState],
40-
) -> None:
41-
await mockgrid.send_ev_charger_data(
42-
[0.0] * 5 # for testing status updates, the values don't matter.
43-
)
49+
async with mockgrid, new_state_tracker(set(mockgrid.evc_ids)) as state_tracker:
4450
await asyncio.sleep(0.05)
45-
for comp_id, exp_state in expected.items():
46-
assert state_tracker.get(comp_id) == exp_state
47-
48-
# check that all chargers are in idle state.
49-
expected_states = {evc_id: EVChargerState.IDLE for evc_id in mockgrid.evc_ids}
50-
assert len(expected_states) == 5
51-
await check_states(expected_states)
52-
53-
# check that EV_PLUGGED state gets set
54-
evc_2_id = mockgrid.evc_ids[2]
55-
mockgrid.evc_cable_states[evc_2_id] = EVChargerCableState.EV_PLUGGED
56-
mockgrid.evc_component_states[evc_2_id] = EVChargerComponentState.READY
57-
expected_states[evc_2_id] = EVChargerState.EV_PLUGGED
58-
await check_states(expected_states)
59-
60-
# check that EV_LOCKED state gets set
61-
evc_3_id = mockgrid.evc_ids[3]
62-
mockgrid.evc_cable_states[evc_3_id] = EVChargerCableState.EV_LOCKED
63-
mockgrid.evc_component_states[evc_3_id] = EVChargerComponentState.READY
64-
expected_states[evc_3_id] = EVChargerState.EV_LOCKED
65-
await check_states(expected_states)
66-
67-
# check that ERROR state gets set
68-
evc_1_id = mockgrid.evc_ids[1]
69-
mockgrid.evc_cable_states[evc_1_id] = EVChargerCableState.EV_LOCKED
70-
mockgrid.evc_component_states[evc_1_id] = EVChargerComponentState.ERROR
71-
expected_states[evc_1_id] = EVChargerState.ERROR
72-
await check_states(expected_states)
73-
74-
await state_tracker.stop()
75-
await mockgrid.cleanup()
51+
52+
async def check_states(
53+
expected: dict[int, EVChargerState],
54+
) -> None:
55+
await mockgrid.send_ev_charger_data(
56+
[0.0] * 5 # for testing status updates, the values don't matter.
57+
)
58+
await asyncio.sleep(0.05)
59+
for comp_id, exp_state in expected.items():
60+
assert state_tracker.get(comp_id) == exp_state
61+
62+
# check that all chargers are in idle state.
63+
expected_states = {
64+
evc_id: EVChargerState.IDLE for evc_id in mockgrid.evc_ids
65+
}
66+
assert len(expected_states) == 5
67+
await check_states(expected_states)
68+
69+
# check that EV_PLUGGED state gets set
70+
evc_2_id = mockgrid.evc_ids[2]
71+
mockgrid.evc_cable_states[evc_2_id] = EVChargerCableState.EV_PLUGGED
72+
mockgrid.evc_component_states[evc_2_id] = EVChargerComponentState.READY
73+
expected_states[evc_2_id] = EVChargerState.EV_PLUGGED
74+
await check_states(expected_states)
75+
76+
# check that EV_LOCKED state gets set
77+
evc_3_id = mockgrid.evc_ids[3]
78+
mockgrid.evc_cable_states[evc_3_id] = EVChargerCableState.EV_LOCKED
79+
mockgrid.evc_component_states[evc_3_id] = EVChargerComponentState.READY
80+
expected_states[evc_3_id] = EVChargerState.EV_LOCKED
81+
await check_states(expected_states)
82+
83+
# check that ERROR state gets set
84+
evc_1_id = mockgrid.evc_ids[1]
85+
mockgrid.evc_cable_states[evc_1_id] = EVChargerCableState.EV_LOCKED
86+
mockgrid.evc_component_states[evc_1_id] = EVChargerComponentState.ERROR
87+
expected_states[evc_1_id] = EVChargerState.ERROR
88+
await check_states(expected_states)
7689

7790
async def test_ev_power( # pylint: disable=too-many-locals
7891
self,
7992
mocker: MockerFixture,
8093
) -> None:
8194
"""Test the ev power formula."""
82-
mockgrid = MockMicrogrid(grid_meter=False)
95+
mockgrid = MockMicrogrid(grid_meter=False, mocker=mocker)
8396
mockgrid.add_ev_chargers(3)
84-
await mockgrid.start(mocker)
85-
86-
ev_pool = microgrid.ev_charger_pool()
87-
power_receiver = ev_pool.power.new_receiver()
8897

89-
await mockgrid.mock_resampler.send_evc_power([2.0, 4.0, 10.0])
90-
assert (await power_receiver.receive()).value == Power.from_watts(16.0)
98+
async with mockgrid:
99+
ev_pool = microgrid.ev_charger_pool()
100+
power_receiver = ev_pool.power.new_receiver()
91101

92-
await mockgrid.mock_resampler.send_evc_power([2.0, 4.0, -10.0])
93-
assert (await power_receiver.receive()).value == Power.from_watts(-4.0)
102+
await mockgrid.mock_resampler.send_evc_power([2.0, 4.0, 10.0])
103+
assert (await power_receiver.receive()).value == Power.from_watts(16.0)
94104

95-
await mockgrid.cleanup()
105+
await mockgrid.mock_resampler.send_evc_power([2.0, 4.0, -10.0])
106+
assert (await power_receiver.receive()).value == Power.from_watts(-4.0)
96107

97108
async def test_ev_component_data(self, mocker: MockerFixture) -> None:
98109
"""Test the component_data method of EVChargerPool."""
99110
mockgrid = MockMicrogrid(
100111
grid_meter=False,
101112
api_client_streaming=True,
102113
sample_rate_s=0.05,
114+
mocker=mocker,
103115
)
104116
mockgrid.add_ev_chargers(1)
105117

106-
await mockgrid.start(mocker)
118+
async with mockgrid, AsyncExitStack() as stack:
119+
evc_id = mockgrid.evc_ids[0]
120+
ev_pool = microgrid.ev_charger_pool()
121+
stack.push_async_callback(ev_pool.stop)
107122

108-
evc_id = mockgrid.evc_ids[0]
109-
ev_pool = microgrid.ev_charger_pool()
123+
recv = ev_pool.component_data(evc_id)
110124

111-
recv = ev_pool.component_data(evc_id)
112-
113-
await mockgrid.send_ev_charger_data(
114-
[0.0] # only the status gets used from this.
115-
)
116-
await asyncio.sleep(0.05)
117-
await mockgrid.mock_resampler.send_evc_current([[2, 3, 5]])
118-
status = await recv.receive()
119-
assert (
120-
status.current.value_p1,
121-
status.current.value_p2,
122-
status.current.value_p3,
123-
) == (
124-
Current.from_amperes(2),
125-
Current.from_amperes(3),
126-
Current.from_amperes(5),
127-
)
128-
assert status.state == EVChargerState.MISSING
129-
130-
await mockgrid.send_ev_charger_data(
131-
[0.0] # only the status gets used from this.
132-
)
133-
await asyncio.sleep(0.05)
134-
await mockgrid.mock_resampler.send_evc_current([[2, 3, None]])
135-
status = await recv.receive()
136-
assert (
137-
status.current.value_p1,
138-
status.current.value_p2,
139-
status.current.value_p3,
140-
) == (
141-
Current.from_amperes(2),
142-
Current.from_amperes(3),
143-
None,
144-
)
145-
assert status.state == EVChargerState.IDLE
125+
await mockgrid.send_ev_charger_data(
126+
[0.0] # only the status gets used from this.
127+
)
128+
await asyncio.sleep(0.05)
129+
await mockgrid.mock_resampler.send_evc_current([[2, 3, 5]])
130+
status = await recv.receive()
131+
assert (
132+
status.current.value_p1,
133+
status.current.value_p2,
134+
status.current.value_p3,
135+
) == (
136+
Current.from_amperes(2),
137+
Current.from_amperes(3),
138+
Current.from_amperes(5),
139+
)
140+
assert status.state == EVChargerState.MISSING
146141

147-
await mockgrid.send_ev_charger_data(
148-
[0.0] # only the status gets used from this.
149-
)
150-
await asyncio.sleep(0.05)
151-
await mockgrid.mock_resampler.send_evc_current([[None, None, None]])
152-
status = await recv.receive()
153-
assert (
154-
status.current.value_p1,
155-
status.current.value_p2,
156-
status.current.value_p3,
157-
) == (
158-
None,
159-
None,
160-
None,
161-
)
162-
assert status.state == EVChargerState.MISSING
142+
await mockgrid.send_ev_charger_data(
143+
[0.0] # only the status gets used from this.
144+
)
145+
await asyncio.sleep(0.05)
146+
await mockgrid.mock_resampler.send_evc_current([[2, 3, None]])
147+
status = await recv.receive()
148+
assert (
149+
status.current.value_p1,
150+
status.current.value_p2,
151+
status.current.value_p3,
152+
) == (
153+
Current.from_amperes(2),
154+
Current.from_amperes(3),
155+
None,
156+
)
157+
assert status.state == EVChargerState.IDLE
163158

164-
mockgrid.evc_cable_states[evc_id] = EVChargerCableState.EV_PLUGGED
165-
await mockgrid.send_ev_charger_data(
166-
[0.0] # only the status gets used from this.
167-
)
168-
await asyncio.sleep(0.05)
169-
await mockgrid.mock_resampler.send_evc_current([[None, None, None]])
170-
status = await recv.receive()
171-
assert (
172-
status.current.value_p1,
173-
status.current.value_p2,
174-
status.current.value_p3,
175-
) == (
176-
None,
177-
None,
178-
None,
179-
)
180-
assert status.state == EVChargerState.MISSING
159+
await mockgrid.send_ev_charger_data(
160+
[0.0] # only the status gets used from this.
161+
)
162+
await asyncio.sleep(0.05)
163+
await mockgrid.mock_resampler.send_evc_current([[None, None, None]])
164+
status = await recv.receive()
165+
assert (
166+
status.current.value_p1,
167+
status.current.value_p2,
168+
status.current.value_p3,
169+
) == (
170+
None,
171+
None,
172+
None,
173+
)
174+
assert status.state == EVChargerState.MISSING
181175

182-
await mockgrid.send_ev_charger_data(
183-
[0.0] # only the status gets used from this.
184-
)
185-
await asyncio.sleep(0.05)
186-
await mockgrid.mock_resampler.send_evc_current([[4, None, None]])
187-
status = await recv.receive()
188-
assert (
189-
status.current.value_p1,
190-
status.current.value_p2,
191-
status.current.value_p3,
192-
) == (
193-
Current.from_amperes(4),
194-
None,
195-
None,
196-
)
197-
assert status.state == EVChargerState.EV_PLUGGED
176+
mockgrid.evc_cable_states[evc_id] = EVChargerCableState.EV_PLUGGED
177+
await mockgrid.send_ev_charger_data(
178+
[0.0] # only the status gets used from this.
179+
)
180+
await asyncio.sleep(0.05)
181+
await mockgrid.mock_resampler.send_evc_current([[None, None, None]])
182+
status = await recv.receive()
183+
assert (
184+
status.current.value_p1,
185+
status.current.value_p2,
186+
status.current.value_p3,
187+
) == (
188+
None,
189+
None,
190+
None,
191+
)
192+
assert status.state == EVChargerState.MISSING
198193

199-
await mockgrid.cleanup()
200-
await ev_pool.stop()
194+
await mockgrid.send_ev_charger_data(
195+
[0.0] # only the status gets used from this.
196+
)
197+
await asyncio.sleep(0.05)
198+
await mockgrid.mock_resampler.send_evc_current([[4, None, None]])
199+
status = await recv.receive()
200+
assert (
201+
status.current.value_p1,
202+
status.current.value_p2,
203+
status.current.value_p3,
204+
) == (
205+
Current.from_amperes(4),
206+
None,
207+
None,
208+
)
209+
assert status.state == EVChargerState.EV_PLUGGED

0 commit comments

Comments
 (0)