Skip to content

Commit f38f684

Browse files
Add methods for sending individual mock component data messages in tests (#483)
With this PR, there will be no remaining test dependencies on the flaky automatic raw-data streaming functionality of `MockMicrogrid`. The benchmarks for the data sourcing actor still depends on this, but that can be dealt with later. This PR also allows for the tests for the power distributing actor to use `MockMicrogrid`, because that would make it easy for the tests to be run on many different component graph configs, rather than the single config it uses now.
2 parents cf028ae + 202734b commit f38f684

File tree

6 files changed

+177
-85
lines changed

6 files changed

+177
-85
lines changed

tests/timeseries/_battery_pool/test_battery_pool.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,24 +440,24 @@ async def test_battery_pool_power(mocker: MockerFixture) -> None:
440440
"""Test `BatteryPool.{,production,consumption}_power` methods."""
441441
mockgrid = MockMicrogrid(grid_side_meter=True)
442442
mockgrid.add_batteries(2)
443-
await mockgrid.start_mock_datapipeline(mocker)
443+
await mockgrid.start(mocker)
444444

445445
battery_pool = microgrid.battery_pool()
446446
power_receiver = battery_pool.power.new_receiver()
447447
consumption_receiver = battery_pool.consumption_power.new_receiver()
448448
production_receiver = battery_pool.production_power.new_receiver()
449449

450-
await mockgrid.mock_data.send_bat_inverter_power([2.0, 3.0])
450+
await mockgrid.mock_resampler.send_bat_inverter_power([2.0, 3.0])
451451
assert (await power_receiver.receive()).value == Power.from_watts(5.0)
452452
assert (await consumption_receiver.receive()).value == Power.from_watts(5.0)
453453
assert (await production_receiver.receive()).value == Power.from_watts(0.0)
454454

455-
await mockgrid.mock_data.send_bat_inverter_power([-2.0, -5.0])
455+
await mockgrid.mock_resampler.send_bat_inverter_power([-2.0, -5.0])
456456
assert (await power_receiver.receive()).value == Power.from_watts(-7.0)
457457
assert (await consumption_receiver.receive()).value == Power.from_watts(0.0)
458458
assert (await production_receiver.receive()).value == Power.from_watts(7.0)
459459

460-
await mockgrid.mock_data.send_bat_inverter_power([2.0, -5.0])
460+
await mockgrid.mock_resampler.send_bat_inverter_power([2.0, -5.0])
461461
assert (await power_receiver.receive()).value == Power.from_watts(-3.0)
462462
assert (await consumption_receiver.receive()).value == Power.from_watts(0.0)
463463
assert (await production_receiver.receive()).value == Power.from_watts(3.0)

tests/timeseries/_formula_engine/test_formula_composition.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ async def test_formula_composition( # pylint: disable=too-many-locals
2727
mockgrid = MockMicrogrid(grid_side_meter=False)
2828
mockgrid.add_batteries(3)
2929
mockgrid.add_solar_inverters(2)
30-
await mockgrid.start_mock_datapipeline(mocker)
30+
await mockgrid.start(mocker)
3131

3232
logical_meter = microgrid.logical_meter()
3333
battery_pool = microgrid.battery_pool()
@@ -44,8 +44,8 @@ async def test_formula_composition( # pylint: disable=too-many-locals
4444
engine = (logical_meter.pv_power + battery_pool.power).build("inv_power")
4545
inv_calc_recv = engine.new_receiver()
4646

47-
await mockgrid.mock_data.send_bat_inverter_power([10.0, 12.0, 14.0])
48-
await mockgrid.mock_data.send_meter_power(
47+
await mockgrid.mock_resampler.send_bat_inverter_power([10.0, 12.0, 14.0])
48+
await mockgrid.mock_resampler.send_meter_power(
4949
[100.0, 10.0, 12.0, 14.0, -100.0, -200.0]
5050
)
5151

@@ -99,7 +99,7 @@ async def test_formula_composition_missing_pv(self, mocker: MockerFixture) -> No
9999
"""Test the composition of formulas with missing PV power data."""
100100
mockgrid = MockMicrogrid(grid_side_meter=False)
101101
mockgrid.add_batteries(3)
102-
await mockgrid.start_mock_datapipeline(mocker)
102+
await mockgrid.start(mocker)
103103
battery_pool = microgrid.battery_pool()
104104
logical_meter = microgrid.logical_meter()
105105

@@ -110,10 +110,10 @@ async def test_formula_composition_missing_pv(self, mocker: MockerFixture) -> No
110110

111111
count = 0
112112
for _ in range(10):
113-
await mockgrid.mock_data.send_bat_inverter_power(
113+
await mockgrid.mock_resampler.send_bat_inverter_power(
114114
[10.0 + count, 12.0 + count, 14.0 + count]
115115
)
116-
await mockgrid.mock_data.send_non_existing_component_value()
116+
await mockgrid.mock_resampler.send_non_existing_component_value()
117117

118118
bat_pow = await battery_power_recv.receive()
119119
pv_pow = await pv_power_recv.receive()
@@ -137,7 +137,7 @@ async def test_formula_composition_missing_bat(self, mocker: MockerFixture) -> N
137137
"""Test the composition of formulas with missing battery power data."""
138138
mockgrid = MockMicrogrid(grid_side_meter=False)
139139
mockgrid.add_solar_inverters(2)
140-
await mockgrid.start_mock_datapipeline(mocker)
140+
await mockgrid.start(mocker)
141141
battery_pool = microgrid.battery_pool()
142142
logical_meter = microgrid.logical_meter()
143143

@@ -148,10 +148,10 @@ async def test_formula_composition_missing_bat(self, mocker: MockerFixture) -> N
148148

149149
count = 0
150150
for _ in range(10):
151-
await mockgrid.mock_data.send_meter_power(
151+
await mockgrid.mock_resampler.send_meter_power(
152152
[10.0 + count, 12.0 + count, 14.0 + count]
153153
)
154-
await mockgrid.mock_data.send_non_existing_component_value()
154+
await mockgrid.mock_resampler.send_non_existing_component_value()
155155
bat_pow = await battery_power_recv.receive()
156156
pv_pow = await pv_power_recv.receive()
157157
inv_pow = await inv_calc_recv.receive()
@@ -177,7 +177,7 @@ async def test_3_phase_formulas(self, mocker: MockerFixture) -> None:
177177
)
178178
mockgrid.add_batteries(3)
179179
mockgrid.add_ev_chargers(1)
180-
await mockgrid.start_mock_datapipeline(mocker)
180+
await mockgrid.start(mocker)
181181
logical_meter = microgrid.logical_meter()
182182
ev_pool = microgrid.ev_charger_pool()
183183

@@ -190,15 +190,15 @@ async def test_3_phase_formulas(self, mocker: MockerFixture) -> None:
190190
count = 0
191191

192192
for _ in range(10):
193-
await mockgrid.mock_data.send_meter_current(
193+
await mockgrid.mock_resampler.send_meter_current(
194194
[
195195
[10.0, 12.0, 14.0],
196196
[10.0, 12.0, 14.0],
197197
[10.0, 12.0, 14.0],
198198
[10.0, 12.0, 14.0],
199199
]
200200
)
201-
await mockgrid.mock_data.send_evc_current(
201+
await mockgrid.mock_resampler.send_evc_current(
202202
[[10.0 + count, 12.0 + count, 14.0 + count]]
203203
)
204204

tests/timeseries/mock_microgrid.py

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
InverterDataWrapper,
3434
MeterDataWrapper,
3535
)
36-
from .mock_datapipeline import MockDataPipeline
36+
from .mock_resampler import MockResampler
3737

3838

3939
class MockMicrogrid: # pylint: disable=too-many-instance-attributes
@@ -49,7 +49,7 @@ class MockMicrogrid: # pylint: disable=too-many-instance-attributes
4949
battery_id_suffix = 9
5050

5151
_microgrid: MockMicrogridClient
52-
mock_data: MockDataPipeline
52+
mock_resampler: MockResampler
5353

5454
def __init__( # pylint: disable=too-many-arguments
5555
self,
@@ -105,10 +105,10 @@ def __init__( # pylint: disable=too-many-arguments
105105
self._streaming_tasks: list[asyncio.Task[None]] = []
106106
self._start_meter_streaming(4)
107107

108-
async def start_mock_datapipeline(self, mocker: MockerFixture) -> None:
109-
"""Start the MockDataPipeline."""
108+
async def start(self, mocker: MockerFixture) -> None:
109+
"""Init the mock microgrid client and start the mock resampler."""
110110
self.init_mock_client(lambda mock_client: mock_client.initialize(mocker))
111-
self.mock_data = MockDataPipeline(
111+
self.mock_resampler = MockResampler(
112112
mocker,
113113
ResamplerConfig(timedelta(seconds=self._sample_rate_s)),
114114
bat_inverter_ids=self.battery_inverter_ids,
@@ -148,24 +148,6 @@ def start_mock_client(
148148
]
149149
return self._microgrid
150150

151-
async def start(self, mocker: MockerFixture) -> None:
152-
"""Start the MockServer, and the data source and resampling actors."""
153-
self.start_mock_client(lambda mock_client: mock_client.initialize(mocker))
154-
await asyncio.sleep(self._sample_rate_s / 2)
155-
156-
# pylint: disable=protected-access
157-
_data_pipeline._DATA_PIPELINE = _data_pipeline._DataPipeline(
158-
ResamplerConfig(
159-
resampling_period=timedelta(seconds=self._sample_rate_s),
160-
# Align to the time the resampler is created to avoid flakiness
161-
# in the tests, it seems test using the mock microgrid assume
162-
# that the resampling window is aligned to the start of the
163-
# test.
164-
align_to=None,
165-
)
166-
)
167-
# pylint: enable=protected-access
168-
169151
async def _comp_data_send_task(
170152
self, comp_id: int, make_comp_data: Callable[[int, datetime], ComponentData]
171153
) -> None:
@@ -363,12 +345,104 @@ def add_ev_chargers(self, count: int) -> None:
363345
self._start_ev_charger_streaming(evc_id)
364346
self._connections.add(Connection(self._connect_to, evc_id))
365347

348+
async def send_meter_data(self, values: list[float]) -> None:
349+
"""Send raw meter data from the mock microgrid.
350+
351+
Args:
352+
values: list of active power values for each meter.
353+
"""
354+
assert len(values) == len(self.meter_ids)
355+
timestamp = datetime.now(tz=timezone.utc)
356+
for comp_id, value in zip(self.meter_ids, values):
357+
await self._microgrid.send(
358+
MeterDataWrapper(
359+
component_id=comp_id,
360+
timestamp=timestamp,
361+
active_power=value,
362+
current_per_phase=(
363+
value + 100.0,
364+
value + 101.0,
365+
value + 102.0,
366+
),
367+
)
368+
)
369+
370+
async def send_battery_data(self, socs: list[float]) -> None:
371+
"""Send raw battery data from the mock microgrid.
372+
373+
Args:
374+
values: list of soc values for each battery.
375+
"""
376+
assert len(socs) == len(self.battery_ids)
377+
timestamp = datetime.now(tz=timezone.utc)
378+
for comp_id, value in zip(self.battery_ids, socs):
379+
await self._microgrid.send(
380+
BatteryDataWrapper(component_id=comp_id, timestamp=timestamp, soc=value)
381+
)
382+
383+
async def send_battery_inverter_data(self, values: list[float]) -> None:
384+
"""Send raw battery inverter data from the mock microgrid.
385+
386+
Args:
387+
values: list of active power values for each battery inverter.
388+
"""
389+
assert len(values) == len(self.battery_inverter_ids)
390+
timestamp = datetime.now(tz=timezone.utc)
391+
for comp_id, value in zip(self.battery_inverter_ids, values):
392+
await self._microgrid.send(
393+
InverterDataWrapper(
394+
component_id=comp_id, timestamp=timestamp, active_power=value
395+
)
396+
)
397+
398+
async def send_pv_inverter_data(self, values: list[float]) -> None:
399+
"""Send raw pv inverter data from the mock microgrid.
400+
401+
Args:
402+
values: list of active power values for each pv inverter.
403+
"""
404+
assert len(values) == len(self.pv_inverter_ids)
405+
timestamp = datetime.now(tz=timezone.utc)
406+
for comp_id, value in zip(self.pv_inverter_ids, values):
407+
await self._microgrid.send(
408+
InverterDataWrapper(
409+
component_id=comp_id, timestamp=timestamp, active_power=value
410+
)
411+
)
412+
413+
async def send_ev_charger_data(self, values: list[float]) -> None:
414+
"""Send raw ev charger data from the mock microgrid.
415+
416+
Args:
417+
values: list of active power values for each ev charger.
418+
"""
419+
assert len(values) == len(self.evc_ids)
420+
timestamp = datetime.now(tz=timezone.utc)
421+
for comp_id, value in zip(self.evc_ids, values):
422+
await self._microgrid.send(
423+
EvChargerDataWrapper(
424+
component_id=comp_id,
425+
timestamp=timestamp,
426+
active_power=value,
427+
current_per_phase=(
428+
value + 100.0,
429+
value + 101.0,
430+
value + 102.0,
431+
),
432+
component_state=self.evc_component_states[comp_id],
433+
cable_state=self.evc_cable_states[comp_id],
434+
)
435+
)
436+
366437
async def cleanup(self) -> None:
367438
"""Clean up after a test."""
368439
# pylint: disable=protected-access
369440
if _data_pipeline._DATA_PIPELINE:
370441
await _data_pipeline._DATA_PIPELINE._stop()
371442

443+
for coro in self._streaming_coros:
444+
coro.close()
445+
372446
for task in self._streaming_tasks:
373447
await cancel_and_await(task)
374448
microgrid.connection_manager._CONNECTION_MANAGER = None
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
# pylint: disable=too-many-instance-attributes
2424

2525

26-
class MockDataPipeline:
27-
"""Mock data_pipeline."""
26+
class MockResampler:
27+
"""Mock resampler."""
2828

2929
def __init__( # pylint: disable=too-many-arguments
3030
self,

0 commit comments

Comments
 (0)