@@ -607,7 +607,7 @@ async def test_resampling_with_one_window(
607607 #
608608 # t(s) 0 1 2 2.5 3 4
609609 # |----------|----------R----|-----|----------R-----> (no more samples)
610- # value 5.0 12.0 2 .0 4.0 5.0
610+ # value 5.0 12.0 0 .0 4.0 5.0
611611 #
612612 # R = resampling is done
613613
@@ -637,7 +637,7 @@ async def test_resampling_with_one_window(
637637 resampling_fun_mock .reset_mock ()
638638
639639 # Second resampling run
640- sample2_5s = Sample (timestamp + timedelta (seconds = 2.5 ), value = Quantity ( 2.0 ))
640+ sample2_5s = Sample (timestamp + timedelta (seconds = 2.5 ), value = Quantity . zero ( ))
641641 sample3s = Sample (timestamp + timedelta (seconds = 3 ), value = Quantity (4.0 ))
642642 sample4s = Sample (timestamp + timedelta (seconds = 4 ), value = Quantity (5.0 ))
643643 await source_sender .send (sample2_5s )
@@ -1195,6 +1195,117 @@ async def test_timer_is_aligned(
11951195 resampling_fun_mock .reset_mock ()
11961196
11971197
1198+ async def test_resampling_all_zeros (
1199+ fake_time : time_machine .Coordinates , source_chan : Broadcast [Sample [Quantity ]]
1200+ ) -> None :
1201+ """Test resampling with one resampling window full of zeros."""
1202+ timestamp = datetime .now (timezone .utc )
1203+
1204+ resampling_period_s = 2
1205+ expected_resampled_value = 0.0
1206+
1207+ resampling_fun_mock = MagicMock (
1208+ spec = ResamplingFunction , return_value = expected_resampled_value
1209+ )
1210+ config = ResamplerConfig (
1211+ resampling_period = timedelta (seconds = resampling_period_s ),
1212+ max_data_age_in_periods = 1.0 ,
1213+ resampling_function = resampling_fun_mock ,
1214+ initial_buffer_len = 4 ,
1215+ )
1216+ resampler = Resampler (config )
1217+
1218+ source_receiver = source_chan .new_receiver ()
1219+ source_sender = source_chan .new_sender ()
1220+
1221+ sink_mock = AsyncMock (spec = Sink , return_value = True )
1222+
1223+ resampler .add_timeseries ("test" , source_receiver , sink_mock )
1224+ source_props = resampler .get_source_properties (source_receiver )
1225+
1226+ # Test timeline
1227+ #
1228+ # t(s) 0 1 2 2.5 3 4
1229+ # |----------|----------R----|-----|----------R-----> (no more samples)
1230+ # value 0.0 0.0 0.0 0.0 0.0
1231+ #
1232+ # R = resampling is done
1233+
1234+ # Send a few samples and run a resample tick, advancing the fake time by one period
1235+ sample0s = Sample (timestamp , value = Quantity .zero ())
1236+ sample1s = Sample (timestamp + timedelta (seconds = 1 ), value = Quantity .zero ())
1237+ await source_sender .send (sample0s )
1238+ await source_sender .send (sample1s )
1239+ await _advance_time (fake_time , resampling_period_s )
1240+ await resampler .resample (one_shot = True )
1241+
1242+ assert datetime .now (timezone .utc ).timestamp () == 2
1243+ sink_mock .assert_called_once_with (
1244+ Sample (
1245+ timestamp + timedelta (seconds = resampling_period_s ),
1246+ Quantity (expected_resampled_value ),
1247+ )
1248+ )
1249+ resampling_fun_mock .assert_called_once_with (
1250+ a_sequence (sample1s ), config , source_props
1251+ )
1252+ assert source_props == SourceProperties (
1253+ sampling_start = timestamp , received_samples = 2 , sampling_period = None
1254+ )
1255+ assert _get_buffer_len (resampler , source_receiver ) == config .initial_buffer_len
1256+ sink_mock .reset_mock ()
1257+ resampling_fun_mock .reset_mock ()
1258+
1259+ # Second resampling run
1260+ sample2_5s = Sample (timestamp + timedelta (seconds = 2.5 ), value = Quantity .zero ())
1261+ sample3s = Sample (timestamp + timedelta (seconds = 3 ), value = Quantity .zero ())
1262+ sample4s = Sample (timestamp + timedelta (seconds = 4 ), value = Quantity .zero ())
1263+ await source_sender .send (sample2_5s )
1264+ await source_sender .send (sample3s )
1265+ await source_sender .send (sample4s )
1266+ await _advance_time (fake_time , resampling_period_s )
1267+ await resampler .resample (one_shot = True )
1268+
1269+ assert datetime .now (timezone .utc ).timestamp () == 4
1270+ sink_mock .assert_called_once_with (
1271+ Sample (
1272+ timestamp + timedelta (seconds = resampling_period_s * 2 ),
1273+ Quantity (expected_resampled_value ),
1274+ )
1275+ )
1276+ resampling_fun_mock .assert_called_once_with (
1277+ a_sequence (sample2_5s , sample3s , sample4s ), config , source_props
1278+ )
1279+ # By now we have a full buffer (5 samples and a buffer of length 4), which
1280+ # we received in 4 seconds, so we have an input period of 0.8s.
1281+ assert source_props == SourceProperties (
1282+ sampling_start = timestamp ,
1283+ received_samples = 5 ,
1284+ sampling_period = timedelta (seconds = 0.8 ),
1285+ )
1286+ # The buffer should be able to hold 2 seconds of data, and data is coming
1287+ # every 0.8 seconds, so we should be able to store 3 samples.
1288+ assert _get_buffer_len (resampler , source_receiver ) == 3
1289+ sink_mock .reset_mock ()
1290+ resampling_fun_mock .reset_mock ()
1291+
1292+ await _assert_no_more_samples (
1293+ resampler ,
1294+ timestamp ,
1295+ sink_mock ,
1296+ resampling_fun_mock ,
1297+ fake_time ,
1298+ resampling_period_s ,
1299+ current_iteration = 3 ,
1300+ )
1301+ assert source_props == SourceProperties (
1302+ sampling_start = timestamp ,
1303+ received_samples = 5 ,
1304+ sampling_period = timedelta (seconds = 0.8 ),
1305+ )
1306+ assert _get_buffer_len (resampler , source_receiver ) == 3
1307+
1308+
11981309def _get_buffer_len (resampler : Resampler , source_receiver : Source ) -> int :
11991310 # pylint: disable=protected-access
12001311 blen = resampler ._resamplers [source_receiver ]._helper ._buffer .maxlen
0 commit comments