commit c7c91370f5008aa4757340799e880e175d3b8830 Author: juga0 juga@riseup.net Date: Sat Mar 21 14:49:50 2020 +0000
chg: relayprioritizer: Count priorities with timestamps
in RelayPrioritizer: - Rename recent_priority_list_count to recent_priority_list when there is no counting - Rename recent_priority_relay_count to recent_priority_relay when there is no counting - Use the timestamps class to manage/count priority lists/relays --- sbws/lib/relayprioritizer.py | 38 +++++++++++------ sbws/lib/v3bwfile.py | 4 +- tests/conftest.py | 30 +++++++++++++ tests/unit/conftest.py | 11 +++++ tests/unit/lib/test_relayprioritizer.py | 76 +++++++++++++++++++++++++++++++++ tests/unit/lib/test_v3bwfile.py | 20 +++++++++ 6 files changed, 163 insertions(+), 16 deletions(-)
diff --git a/sbws/lib/relayprioritizer.py b/sbws/lib/relayprioritizer.py index 4932ea8..3647a8b 100644 --- a/sbws/lib/relayprioritizer.py +++ b/sbws/lib/relayprioritizer.py @@ -6,7 +6,8 @@ import copy import time import logging
-from ..util import state +from ..globals import MAX_RECENT_PRIORITY_RELAY_COUNT +from ..util import state, timestamps
log = logging.getLogger(__name__)
@@ -24,30 +25,39 @@ class RelayPrioritizer: self.fraction_to_return = conf.getfloat( 'relayprioritizer', 'fraction_relays') self._state = state.State(conf.getpath('paths', 'state_fname')) - if self._state is not None: - # If it was not in previous state versions, initialize it to 0 - if self._state.get('recent_priority_list_count', None) is None: - self._state['recent_priority_list_count'] = 0 - if self._state.get('recent_priority_relay_count') is None: - self._state['recent_priority_relay_count'] = 0 - - def increment_priority_lists(self): + self._recent_priority_list = timestamps.DateTimeSeq( + [], 120, self._state, "recent_priority_list" + ) + self._recent_priority_relay = timestamps.DateTimeIntSeq( + [], MAX_RECENT_PRIORITY_RELAY_COUNT, self._state, + "recent_priority_relay" + ) + + def increment_recent_priority_list(self): """ Increment the number of times that :meth:`~sbws.lib.relayprioritizer.RelayPrioritizer.best_priority` has been run. """ # NOTE: blocking, writes to file! - self._state['recent_priority_list_count'] += 1 + self._recent_priority_list.update()
- def increment_priority_relays(self, relays_count): + @property + def recent_priority_list_count(self): + return len(self._recent_priority_list) + + def increment_recent_priority_relay(self, relays_count): """ Increment the number of relays that have been "prioritized" to be measured in a :meth:`~sbws.lib.relayprioritizer.RelayPrioritizer.best_priority`. """ # NOTE: blocking, writes to file! - self._state['recent_priority_relay_count'] += relays_count + self._recent_priority_relay.update(number=relays_count) + + @property + def recent_priority_relay_count(self): + return len(self._recent_priority_relay)
def best_priority(self, prioritize_result_error=False, return_fraction=True): @@ -141,11 +151,11 @@ class RelayPrioritizer: upper_limit = cutoff if return_fraction else len(relays) # NOTE: these two are blocking, write to disk # Increment the number of times ``best_priority`` has been run. - self.increment_priority_lists() + self.increment_recent_priority_list() # Increment the number of relays that have been "prioritized". # Because in a small testing network the upper limit could be smaller # than the number of relays in the network, use the length of the list. - self.increment_priority_relays(len(relays[0:upper_limit])) + self.increment_recent_priority_relay(len(relays[0:upper_limit])) for relay in relays[0:upper_limit]: log.debug('Returning next relay %s with priority %f', relay.nickname, relay.priority) diff --git a/sbws/lib/v3bwfile.py b/sbws/lib/v3bwfile.py index f81ef82..ee9fd17 100644 --- a/sbws/lib/v3bwfile.py +++ b/sbws/lib/v3bwfile.py @@ -481,7 +481,7 @@ class V3BWHeader(object): in the recent (by default 5) days from the state file. """ state = State(state_fpath) - return state.get('recent_priority_list_count', None) + return state.count('recent_priority_list')
@staticmethod def recent_priority_relay_count_from_file(state_fpath): @@ -490,7 +490,7 @@ class V3BWHeader(object): in the recent (by default 5) days from the state file. """ state = State(state_fpath) - return state.get('recent_priority_relay_count', None) + return state.count('recent_priority_relay')
@staticmethod def latest_bandwidth_from_results(results): diff --git a/tests/conftest.py b/tests/conftest.py index d968cac..b2b54d1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,10 @@ from unittest import mock
from stem import descriptor
+from sbws import settings +from sbws.lib import relaylist +from sbws.lib import relayprioritizer +from sbws.lib import resultdump from sbws.util.parser import create_parser
@@ -87,3 +91,29 @@ def controller_5days_later(router_statuses_5days_later): controller = mock.Mock() controller.get_network_statuses.return_value = router_statuses_5days_later return controller + + +# Because of the function scoped `args` in `tests.unit.conftest`, this has to +# be function scoped too. +@pytest.fixture(scope='function') +def relay_list(args, conf, controller): + """Returns a RelayList containing the Relays in the controller""" + return relaylist.RelayList(args, conf, controller) + + +@pytest.fixture(scope='function') +def result_dump(args, conf): + """Returns a ResultDump without Results""" + # To stop the thread that would be waiting for new results + settings.set_end_event() + return resultdump.ResultDump(args, conf) + + +@pytest.fixture(scope="function") +def relay_prioritizer(args, conf_results, relay_list, result_dump): + """ + Returns a RelayPrioritizer with a RelayList and a ResultDump. + """ + return relayprioritizer.RelayPrioritizer( + args, conf_results, relay_list, result_dump + ) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 295e777..bc812f0 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -187,6 +187,17 @@ def conf(sbwshome_empty, tmpdir): return conf
+@pytest.fixture(scope='function') +def conf_results(sbwshome_success_result_two_relays, conf): + """Minimal configuration having a datadir + + So that `ResultDump` does not raise AssertionError. + + """ + conf['paths']['sbws_home'] = sbwshome_success_result_two_relays + return conf + + @pytest.fixture() def result(): return RESULT diff --git a/tests/unit/lib/test_relayprioritizer.py b/tests/unit/lib/test_relayprioritizer.py new file mode 100644 index 0000000..e692343 --- /dev/null +++ b/tests/unit/lib/test_relayprioritizer.py @@ -0,0 +1,76 @@ +"""relayprioritizer.py unit tests.""" +from freezegun import freeze_time + + +def test_increment_recent_priority_list(relay_prioritizer): + """Test that incrementing the priority lists do not go on forever. + + And instead it only counts the number of priority lists in the last days. + """ + + state = relay_prioritizer._state + assert 0 == relay_prioritizer.recent_priority_list_count + assert not state.get("recent_priority_list", None) + + # Pretend that a priority list is made. + with freeze_time("2020-02-29 10:00:00"): + relay_prioritizer.increment_recent_priority_list() + assert 1 == relay_prioritizer.recent_priority_list_count + assert 1 == len(state["recent_priority_list"]) + + # And a second priority list is made 4 days later. + with freeze_time("2020-03-04 10:00:00"): + relay_prioritizer.increment_recent_priority_list() + assert 2 == relay_prioritizer.recent_priority_list_count + assert 2 == len(state["recent_priority_list"]) + + # And a third priority list is made 5 days later. + with freeze_time("2020-03-05 10:00:00"): + relay_prioritizer.increment_recent_priority_list() + assert 3 == relay_prioritizer.recent_priority_list_count + assert 3 == len(state["recent_priority_list"]) + + # And a fourth priority list is made 6 days later. The first one is + # now removed and not counted. + with freeze_time("2020-03-06 10:00:00"): + relay_prioritizer.increment_recent_priority_list() + assert 3 == relay_prioritizer.recent_priority_list_count + assert 3 == len(state["recent_priority_list"]) + + +def test_increment_priority_relay(relay_prioritizer): + """Test that incrementing the number of relays in the priority lists + do not go on forever. + + And instead it only counts number of relays in priority lists in the last + days. + """ + + state = relay_prioritizer._state + assert 0 == relay_prioritizer.recent_priority_relay_count + assert not state.get("recent_priority_relay", None) + + # Pretend that a priority list is made. + with freeze_time("2020-02-29 10:00:00"): + relay_prioritizer.increment_recent_priority_relay(2) + assert 2 == relay_prioritizer.recent_priority_relay_count + assert 2 == state.count("recent_priority_relay") + + # And a second priority list is made 4 days later. + with freeze_time("2020-03-04 10:00:00"): + relay_prioritizer.increment_recent_priority_relay(2) + assert 4 == relay_prioritizer.recent_priority_relay_count + assert 4 == state.count("recent_priority_relay") + + # And a third priority list is made 5 days later. + with freeze_time("2020-03-05 10:00:00"): + relay_prioritizer.increment_recent_priority_relay(2) + assert 6 == relay_prioritizer.recent_priority_relay_count + assert 6 == state.count("recent_priority_relay") + + # And a fourth priority list is made 6 days later. The first one is + # now removed and the relays are not counted. + with freeze_time("2020-03-06 10:00:00"): + relay_prioritizer.increment_recent_priority_relay(2) + assert 6 == relay_prioritizer.recent_priority_relay_count + assert 6 == state.count("recent_priority_relay") diff --git a/tests/unit/lib/test_v3bwfile.py b/tests/unit/lib/test_v3bwfile.py index 2ce34ff..7d26b8d 100644 --- a/tests/unit/lib/test_v3bwfile.py +++ b/tests/unit/lib/test_v3bwfile.py @@ -551,3 +551,23 @@ def test_recent_measurement_attempt_count(root_data_path, datadir): results = load_result_file(str(datadir.join("results.txt"))) header = V3BWHeader.from_results(results, '', '', state_fpath) assert "15" == header.recent_measurement_attempt_count + + +def test_recent_priority_list_count(root_data_path, datadir): + # This state has recent_priority_list + state_fpath = os.path.join(root_data_path, '.sbws/state.dat') + assert 1 == V3BWHeader.recent_priority_list_count_from_file(state_fpath) + # `results` does not matter here, using them to don't have an empty list. + results = load_result_file(str(datadir.join("results.txt"))) + header = V3BWHeader.from_results(results, '', '', state_fpath) + assert "1" == header.recent_priority_list_count + + +def test_recent_priority_relay_count(root_data_path, datadir): + # This state has recent_priority_relay_count + state_fpath = os.path.join(root_data_path, '.sbws/state.dat') + assert 15 == V3BWHeader.recent_priority_relay_count_from_file(state_fpath) + # `results` does not matter here, using them to don't have an empty list. + results = load_result_file(str(datadir.join("results.txt"))) + header = V3BWHeader.from_results(results, '', '', state_fpath) + assert "15" == header.recent_priority_relay_count
tor-commits@lists.torproject.org