class TestExponentiallyDecayingReservoir(TestCase): def setUp(self): self.res = ExponentiallyDecayingReservoir(15) def test_sample_weight(self): for dt, w in [(0, 1), (1800, 532048240601.79865), (3600, 2.830753303274694e+23)]: self.assertEqual(w, self.res._sample_weight(dt)) @patch('caliper.reservoir.datetime') def test_set_next_rescale(self, datetime_mock): now = datetime.now() datetime_mock.now.return_value = now self.res._set_next_rescale() self.assertEqual(now + timedelta(hours=1), self.res._next_rescale) def test_add_15_elements(self): for i in range(15): self.res.update(i) self.assertEqual(len(self.res), 15) def test_add_30_elements(self): for i in range(30): self.res.update(i) self.assertEqual(len(self.res), 30) self.assertEqual(len(self.res._res), 15) def test_add_to_full_reservoir(self): self.res._res = dict((i, (i, i)) for i in range(15)) self.res._landmark = datetime.now() - timedelta(minutes=30) self.res._count = 15 self.assertTrue(0 in self.res._res) # Python 2.6 only supports nested CMs through contextlib.nested, # which is deprecated in 3.x. Easiest solution is to make this # indent-hell. A better solution would be to split the tests up # into multiple cases that each test one assertion. with patch.object(self.res, '_rescale_if_needed') as _rin: with patch.object(self.res, '_rescale') as _rescale: with patch.object(self.res, '_sample_weight') as _sample_weight: with patch('caliper.reservoir.random') as random: random.return_value = 0.5 _sample_weight.return_value = 20 self.res.update(42) _rin.assert_called_once_with() _rescale.assert_not_called() random.assert_called_once_with() for k, (v, w) in self.res._res.items(): if v == 42: self.assertEqual(w, 20) self.assertEqual(k, 40) break else: self.assertTrue(False) self.assertEqual(len(self.res._res), 15) self.assertFalse(0 in self.res._res) def test_rescale(self): now = datetime.now() landmark = now - timedelta(seconds=3600) self.res._landmark = landmark self.res._res = dict((i, (i, 2 * i)) for i in range(15)) self.res._count = 15 # Python 2.6 only supports nested CMs through contextlib.nested, # which is deprecated in 3.x. Easiest solution is to make this # indent-hell. A better solution would be to split the tests up # into multiple cases that each test one assertion. with patch.object(self.res, '_set_next_rescale') as _set_next_resacle: with patch('caliper.reservoir.exp') as exp: with patch('caliper.reservoir.datetime') as datetime_mock: datetime_mock.now.return_value = now exp.return_value = 0.5 self.res._rescale() datetime_mock.now.assert_called_once_with() exp.assert_called_once_with(-0.015 * 3600) _set_next_resacle.assert_called_once_with() expected = dict((0.5 * i, (i, i)) for i in range(15)) self.assertEqual(self.res._res, expected)