@@ -27,7 +27,7 @@ def event_loop_policy() -> async_solipsism.EventLoopPolicy:
2727
2828async def push_logical_meter_data (
2929 sender : Sender [Sample [Quantity ]],
30- test_seq : Sequence [float ],
30+ test_seq : Sequence [float | None ],
3131 start_ts : datetime = UNIX_EPOCH ,
3232) -> None :
3333 """Push data in the passed sender to mock `LogicalMeter` behaviour.
@@ -41,7 +41,9 @@ async def push_logical_meter_data(
4141 """
4242 for i , j in zip (test_seq , range (0 , len (test_seq ))):
4343 timestamp = start_ts + timedelta (seconds = j )
44- await sender .send (Sample (timestamp , Quantity (float (i ))))
44+ await sender .send (
45+ Sample (timestamp , Quantity (float (i )) if i is not None else None )
46+ )
4547
4648 await asyncio .sleep (0.0 )
4749
@@ -210,10 +212,27 @@ async def test_access_empty_window() -> None:
210212 _ = window [42 ]
211213
212214
213- async def test_window_size () -> None :
215+ async def test_window_size () -> None : # pylint: disable=too-many-statements
214216 """Test the size of the window."""
215217 window , sender = init_moving_window (timedelta (seconds = 10 ))
216218 async with window :
219+
220+ def assert_valid_and_covered_counts (
221+ * ,
222+ since : datetime | None = None ,
223+ until : datetime | None = None ,
224+ expected : int | None = None ,
225+ expected_valid : int | None = None ,
226+ expected_covered : int | None = None ,
227+ ) -> None :
228+ if expected is not None :
229+ assert window .count_valid (since = since , until = until ) == expected
230+ assert window .count_covered (since = since , until = until ) == expected
231+ return
232+
233+ assert window .count_valid (since = since , until = until ) == expected_valid
234+ assert window .count_covered (since = since , until = until ) == expected_covered
235+
217236 assert window .capacity == 10 , "Wrong window capacity"
218237 assert window .count_valid () == 0 , "Window should be empty"
219238 assert window .count_covered () == 0 , "Window should be empty"
@@ -239,28 +258,26 @@ async def test_window_size() -> None:
239258 assert window .count_valid () == 10 , "Window should be full"
240259 assert window .count_covered () == 10 , "Window should be full"
241260
242- assert window .count_valid (since = UNIX_EPOCH + timedelta (seconds = 1 )) == 9
243- assert window .count_valid (until = UNIX_EPOCH + timedelta (seconds = 2 )) == 3
244- assert (
245- window .count_valid (
246- since = UNIX_EPOCH + timedelta (seconds = 1 ),
247- until = UNIX_EPOCH + timedelta (seconds = 1 ),
248- )
249- == 1
261+ assert_valid_and_covered_counts (
262+ since = UNIX_EPOCH + timedelta (seconds = 1 ), expected = 9
250263 )
251- assert (
252- window .count_valid (
253- since = UNIX_EPOCH + timedelta (seconds = 3 ),
254- until = UNIX_EPOCH + timedelta (seconds = 8 ),
255- )
256- == 6
264+ assert_valid_and_covered_counts (
265+ until = UNIX_EPOCH + timedelta (seconds = 2 ), expected = 3
257266 )
258- assert (
259- window .count_valid (
260- since = UNIX_EPOCH + timedelta (seconds = 8 ),
261- until = UNIX_EPOCH + timedelta (seconds = 3 ),
262- )
263- == 0
267+ assert_valid_and_covered_counts (
268+ since = UNIX_EPOCH + timedelta (seconds = 1 ),
269+ until = UNIX_EPOCH + timedelta (seconds = 1 ),
270+ expected = 1 ,
271+ )
272+ assert_valid_and_covered_counts (
273+ since = UNIX_EPOCH + timedelta (seconds = 3 ),
274+ until = UNIX_EPOCH + timedelta (seconds = 8 ),
275+ expected = 6 ,
276+ )
277+ assert_valid_and_covered_counts (
278+ since = UNIX_EPOCH + timedelta (seconds = 8 ),
279+ until = UNIX_EPOCH + timedelta (seconds = 3 ),
280+ expected = 0 ,
264281 )
265282
266283 newest_ts = window .newest_timestamp
@@ -269,33 +286,80 @@ async def test_window_size() -> None:
269286
270287 await push_logical_meter_data (sender , range (5 , 12 ), start_ts = newest_ts )
271288 assert window .capacity == 10 , "Wrong window capacity"
272- assert window .count_valid () == 10 , "Window should be full"
273- assert window .count_covered () == 10 , "Window should be full"
289+ assert_valid_and_covered_counts (expected = 10 )
290+
291+ newest_ts = window .newest_timestamp
292+ assert newest_ts is not None and newest_ts == UNIX_EPOCH + timedelta (seconds = 15 )
293+ assert window .oldest_timestamp == UNIX_EPOCH + timedelta (seconds = 6 )
294+
295+ assert_valid_and_covered_counts (
296+ since = UNIX_EPOCH + timedelta (seconds = 1 ),
297+ until = UNIX_EPOCH + timedelta (seconds = 5 ),
298+ expected = 0 ,
299+ )
300+ assert_valid_and_covered_counts (
301+ since = UNIX_EPOCH + timedelta (seconds = 3 ),
302+ until = UNIX_EPOCH + timedelta (seconds = 8 ),
303+ expected = 3 ,
304+ )
305+ assert_valid_and_covered_counts (
306+ since = UNIX_EPOCH + timedelta (seconds = 6 ),
307+ until = UNIX_EPOCH + timedelta (seconds = 20 ),
308+ expected = 10 ,
309+ )
274310
275311 newest_ts = window .newest_timestamp
276312 assert newest_ts is not None and newest_ts == UNIX_EPOCH + timedelta (seconds = 15 )
277313 assert window .oldest_timestamp == UNIX_EPOCH + timedelta (seconds = 6 )
278314
279- assert (
280- window .count_valid (
281- since = UNIX_EPOCH + timedelta (seconds = 1 ),
282- until = UNIX_EPOCH + timedelta (seconds = 5 ),
283- )
284- == 0
315+ await push_logical_meter_data (
316+ sender , [3 , 4 , None , None , 10 , 12 , None ], start_ts = newest_ts
317+ )
318+
319+ # After the last insertion, the moving window would look like this:
320+ #
321+ # +------------------------+----+----+-----+----+----+-----+-----+-----+-----+-----+
322+ # | MovingWindow timestamp | | | | | | | | | | |
323+ # | (seconds after EPOCH) | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
324+ # |------------------------+----+----+-----+----+----+-----+-----+-----+-----+-----|
325+ # | value in buffer | 8. | 9. | 10. | 3. | 4. | nan | nan | 10. | 12. | nan |
326+ # +------------------------+----+----+-----+----+----+-----+-----+-----+-----+-----+
327+
328+ newest_ts = window .newest_timestamp
329+ assert newest_ts is not None and newest_ts == UNIX_EPOCH + timedelta (seconds = 21 )
330+ assert window .oldest_timestamp == UNIX_EPOCH + timedelta (seconds = 12 )
331+
332+ assert_valid_and_covered_counts (
333+ expected_valid = 7 ,
334+ expected_covered = 10 ,
335+ )
336+ assert_valid_and_covered_counts (
337+ since = UNIX_EPOCH + timedelta (seconds = 15 ),
338+ expected_valid = 4 ,
339+ expected_covered = 7 ,
340+ )
341+ assert_valid_and_covered_counts (
342+ until = UNIX_EPOCH + timedelta (seconds = 19 ),
343+ expected_valid = 6 ,
344+ expected_covered = 8 ,
345+ )
346+ assert_valid_and_covered_counts (
347+ since = UNIX_EPOCH + timedelta (seconds = 12 ),
348+ until = UNIX_EPOCH + timedelta (seconds = 15 ),
349+ expected_valid = 4 ,
350+ expected_covered = 4 ,
285351 )
286- assert (
287- window .count_valid (
288- since = UNIX_EPOCH + timedelta (seconds = 3 ),
289- until = UNIX_EPOCH + timedelta (seconds = 8 ),
290- )
291- == 3
352+ assert_valid_and_covered_counts (
353+ since = UNIX_EPOCH + timedelta (seconds = 17 ),
354+ until = UNIX_EPOCH + timedelta (seconds = 18 ),
355+ expected_valid = 0 ,
356+ expected_covered = 2 ,
292357 )
293- assert (
294- window .count_valid (
295- since = UNIX_EPOCH + timedelta (seconds = 6 ),
296- until = UNIX_EPOCH + timedelta (seconds = 20 ),
297- )
298- == 10
358+ assert_valid_and_covered_counts (
359+ since = UNIX_EPOCH + timedelta (seconds = 16 ),
360+ until = UNIX_EPOCH + timedelta (seconds = 20 ),
361+ expected_valid = 3 ,
362+ expected_covered = 5 ,
299363 )
300364
301365
0 commit comments