1212import async_solipsism
1313import pytest
1414from frequenz .channels import Broadcast , Receiver
15+ from frequenz .client .common .microgrid .components import ComponentId
1516from frequenz .quantities import Quantity
1617
1718from frequenz .sdk .timeseries import Sample
@@ -35,14 +36,17 @@ async def run_test( # pylint: disable=too-many-locals
3536 self ,
3637 formula_str : str ,
3738 expected : str ,
39+ component_ids : list [int ],
3840 io_pairs : list [tuple [list [float | None ], float | None ]],
3941 ) -> None :
4042 """Run a formula test."""
41- channels : OrderedDict [int , Broadcast [Sample [Quantity ]]] = OrderedDict ()
43+ channels : OrderedDict [ComponentId , Broadcast [Sample [Quantity ]]] = OrderedDict ()
44+ for comp_id in component_ids :
45+ channels [ComponentId (comp_id )] = Broadcast (
46+ name = f"chan-#{ comp_id } " , resend_latest = True
47+ )
4248
43- def stream_recv (comp_id : int ) -> Receiver [Sample [Quantity ]]:
44- if comp_id not in channels :
45- channels [comp_id ] = Broadcast (name = f"chan-#{ comp_id } " )
49+ def stream_recv (comp_id : ComponentId ) -> Receiver [Sample [Quantity ]]:
4650 return channels [comp_id ].new_receiver ()
4751
4852 telem_fetcher = MagicMock (spec = ResampledStreamFetcher )
@@ -60,14 +64,21 @@ def stream_recv(comp_id: int) -> Receiver[Sample[Quantity]]:
6064 await asyncio .sleep (0.1 ) # Allow time for setup
6165 now = datetime .now ()
6266 tests_passed = 0
67+
6368 for io_pair in io_pairs :
6469 io_input , io_output = io_pair
6570 _ = await asyncio .gather (
6671 * [
6772 chan .new_sender ().send (
6873 Sample (now , None if not value else Quantity (value ))
6974 )
70- for chan , value in zip (channels .values (), io_input )
75+ for chan , value in zip (
76+ [
77+ channels [ComponentId (comp_id )]
78+ for comp_id in component_ids
79+ ],
80+ io_input ,
81+ )
7182 ]
7283 )
7384 next_val = await results_rx .receive ()
@@ -86,6 +97,7 @@ async def test_simple(self) -> None:
8697 await self .run_test (
8798 "#2 - #4 + #5" ,
8899 "[f](#2 - #4 + #5)" ,
100+ [2 , 4 , 5 ],
89101 [
90102 ([10.0 , 12.0 , 15.0 ], 13.0 ),
91103 ([15.0 , 17.0 , 20.0 ], 18.0 ),
@@ -94,6 +106,7 @@ async def test_simple(self) -> None:
94106 await self .run_test (
95107 "#2 + #4 - #5" ,
96108 "[f](#2 + #4 - #5)" ,
109+ [2 , 4 , 5 ],
97110 [
98111 ([10.0 , 12.0 , 15.0 ], 7.0 ),
99112 ([15.0 , 17.0 , 20.0 ], 12.0 ),
@@ -102,6 +115,7 @@ async def test_simple(self) -> None:
102115 await self .run_test (
103116 "#2 * #4 + #5" ,
104117 "[f](#2 * #4 + #5)" ,
118+ [2 , 4 , 5 ],
105119 [
106120 ([10.0 , 12.0 , 15.0 ], 135.0 ),
107121 ([15.0 , 17.0 , 20.0 ], 275.0 ),
@@ -110,6 +124,7 @@ async def test_simple(self) -> None:
110124 await self .run_test (
111125 "#2 * #4 / #5" ,
112126 "[f](#2 * #4 / #5)" ,
127+ [2 , 4 , 5 ],
113128 [
114129 ([10.0 , 12.0 , 15.0 ], 8.0 ),
115130 ([15.0 , 17.0 , 20.0 ], 12.75 ),
@@ -118,6 +133,7 @@ async def test_simple(self) -> None:
118133 await self .run_test (
119134 "#2 / #4 - #5" ,
120135 "[f](#2 / #4 - #5)" ,
136+ [2 , 4 , 5 ],
121137 [
122138 ([6.0 , 12.0 , 15.0 ], - 14.5 ),
123139 ([15.0 , 20.0 , 20.0 ], - 19.25 ),
@@ -126,6 +142,7 @@ async def test_simple(self) -> None:
126142 await self .run_test (
127143 "#2 - #4 - #5" ,
128144 "[f](#2 - #4 - #5)" ,
145+ [2 , 4 , 5 ],
129146 [
130147 ([6.0 , 12.0 , 15.0 ], - 21.0 ),
131148 ([15.0 , 20.0 , 20.0 ], - 25.0 ),
@@ -134,6 +151,7 @@ async def test_simple(self) -> None:
134151 await self .run_test (
135152 "#2 + #4 + #5" ,
136153 "[f](#2 + #4 + #5)" ,
154+ [2 , 4 , 5 ],
137155 [
138156 ([6.0 , 12.0 , 15.0 ], 33.0 ),
139157 ([15.0 , 20.0 , 20.0 ], 55.0 ),
@@ -142,6 +160,7 @@ async def test_simple(self) -> None:
142160 await self .run_test (
143161 "#2 / #4 / #5" ,
144162 "[f](#2 / #4 / #5)" ,
163+ [2 , 4 , 5 ],
145164 [
146165 ([30.0 , 3.0 , 5.0 ], 2.0 ),
147166 ([15.0 , 3.0 , 2.0 ], 2.5 ),
@@ -153,6 +172,7 @@ async def test_compound(self) -> None:
153172 await self .run_test (
154173 "#2 + #4 - #5 * #6" ,
155174 "[f](#2 + #4 - #5 * #6)" ,
175+ [2 , 4 , 5 , 6 ],
156176 [
157177 ([10.0 , 12.0 , 15.0 , 2.0 ], - 8.0 ),
158178 ([15.0 , 17.0 , 20.0 , 1.5 ], 2.0 ),
@@ -161,6 +181,7 @@ async def test_compound(self) -> None:
161181 await self .run_test (
162182 "#2 + (#4 - #5) * #6" ,
163183 "[f](#2 + (#4 - #5) * #6)" ,
184+ [2 , 4 , 5 , 6 ],
164185 [
165186 ([10.0 , 12.0 , 15.0 , 2.0 ], 4.0 ),
166187 ([15.0 , 17.0 , 20.0 , 1.5 ], 10.5 ),
@@ -169,6 +190,7 @@ async def test_compound(self) -> None:
169190 await self .run_test (
170191 "#2 + (#4 - #5 * #6)" ,
171192 "[f](#2 + #4 - #5 * #6)" ,
193+ [2 , 4 , 5 , 6 ],
172194 [
173195 ([10.0 , 12.0 , 15.0 , 2.0 ], - 8.0 ),
174196 ([15.0 , 17.0 , 20.0 , 1.5 ], 2.0 ),
@@ -177,6 +199,7 @@ async def test_compound(self) -> None:
177199 await self .run_test (
178200 "#2 + (#4 - #5 - #6)" ,
179201 "[f](#2 + #4 - #5 - #6)" ,
202+ [2 , 4 , 5 , 6 ],
180203 [
181204 ([10.0 , 12.0 , 15.0 , 2.0 ], 5.0 ),
182205 ([15.0 , 17.0 , 20.0 , 1.5 ], 10.5 ),
@@ -185,6 +208,7 @@ async def test_compound(self) -> None:
185208 await self .run_test (
186209 "#2 + #4 - #5 - #6" ,
187210 "[f](#2 + #4 - #5 - #6)" ,
211+ [2 , 4 , 5 , 6 ],
188212 [
189213 ([10.0 , 12.0 , 15.0 , 2.0 ], 5.0 ),
190214 ([15.0 , 17.0 , 20.0 , 1.5 ], 10.5 ),
@@ -193,6 +217,7 @@ async def test_compound(self) -> None:
193217 await self .run_test (
194218 "#2 + #4 - (#5 - #6)" ,
195219 "[f](#2 + #4 - (#5 - #6))" ,
220+ [2 , 4 , 5 , 6 ],
196221 [
197222 ([10.0 , 12.0 , 15.0 , 2.0 ], 9.0 ),
198223 ([15.0 , 17.0 , 20.0 , 1.5 ], 13.5 ),
@@ -201,6 +226,7 @@ async def test_compound(self) -> None:
201226 await self .run_test (
202227 "(#2 + #4 - #5) * #6" ,
203228 "[f]((#2 + #4 - #5) * #6)" ,
229+ [2 , 4 , 5 , 6 ],
204230 [
205231 ([10.0 , 12.0 , 15.0 , 2.0 ], 14.0 ),
206232 ([15.0 , 17.0 , 20.0 , 1.5 ], 18.0 ),
@@ -209,6 +235,7 @@ async def test_compound(self) -> None:
209235 await self .run_test (
210236 "(#2 + #4 - #5) / #6" ,
211237 "[f]((#2 + #4 - #5) / #6)" ,
238+ [2 , 4 , 5 , 6 ],
212239 [
213240 ([10.0 , 12.0 , 15.0 , 2.0 ], 3.5 ),
214241 ([15.0 , 17.0 , 20.0 , 1.5 ], 8.0 ),
@@ -217,6 +244,7 @@ async def test_compound(self) -> None:
217244 await self .run_test (
218245 "#2 + #4 - (#5 / #6)" ,
219246 "[f](#2 + #4 - #5 / #6)" ,
247+ [2 , 4 , 5 , 6 ],
220248 [
221249 ([10.0 , 12.0 , 15.0 , 2.0 ], 14.5 ),
222250 ([15.0 , 17.0 , 20.0 , 5.0 ], 28.0 ),
@@ -226,6 +254,7 @@ async def test_compound(self) -> None:
226254 await self .run_test (
227255 "#2 - #4 + #5" ,
228256 "[f](#2 - #4 + #5)" ,
257+ [2 , 4 , 5 ],
229258 [
230259 ([10.0 , 12.0 , 15.0 ], 13.0 ),
231260 ([None , 12.0 , 15.0 ], None ),
@@ -238,6 +267,7 @@ async def test_compound(self) -> None:
238267 await self .run_test (
239268 "#2 + #4 - (#5 * #6)" ,
240269 "[f](#2 + #4 - #5 * #6)" ,
270+ [2 , 4 , 5 , 6 ],
241271 [
242272 ([10.0 , 12.0 , 15.0 , 2.0 ], - 8.0 ),
243273 ([10.0 , 12.0 , 15.0 , None ], None ),
@@ -252,13 +282,15 @@ async def test_max_min_coalesce(self) -> None:
252282 await self .run_test (
253283 "#2 + MAX(#4, #5)" ,
254284 "[f](#2 + MAX(#4, #5))" ,
285+ [2 , 4 , 5 ],
255286 [
256287 ([10.0 , 12.0 , 15.0 ], 25.0 ),
257288 ],
258289 )
259290 await self .run_test (
260291 "MIN(#2, #4) + COALESCE(#5, 0.0)" ,
261292 "[f](MIN(#2, #4) + COALESCE(#5, 0.0))" ,
293+ [2 , 4 , 5 ],
262294 [
263295 ([4.0 , 6.0 , 5.0 ], 9.0 ),
264296 ([- 2.0 , 1.0 , 5.0 ], 3.0 ),
@@ -269,6 +301,7 @@ async def test_max_min_coalesce(self) -> None:
269301 await self .run_test (
270302 "MIN(#23, 0.0) + COALESCE(MAX(#24 - #25, 0.0), 0.0)" ,
271303 "[f](MIN(#23, 0.0) + COALESCE(MAX(#24 - #25, 0.0), 0.0))" ,
304+ [23 , 24 , 25 ],
272305 [
273306 ([4.0 , 6.0 , 5.0 ], 1.0 ),
274307 ([- 2.0 , 1.0 , 5.0 ], - 2.0 ),
@@ -312,6 +345,9 @@ async def run_test( # pylint: disable=too-many-locals
312345 """Run a test with the specs provided."""
313346 channels : OrderedDict [int , Broadcast [Sample [Quantity ]]] = OrderedDict ()
314347
348+ for ctr in range (num_items ):
349+ channels [ctr ] = Broadcast (name = f"chan-#{ ctr } " , resend_latest = True )
350+
315351 def stream_recv (comp_id : int ) -> Receiver [Sample [Quantity ]]:
316352 comp_id = int (comp_id )
317353 if comp_id not in channels :
0 commit comments