1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
"""relaylist.py unit tests."""
from datetime import datetime
try:
from datetime import UTC
except ImportError:
from datetime import timezone
UTC = timezone.utc
# When datetime is imported as a class (`from datetime import datetime`) it can
# not be mocked because it is a built-in type. It can only be mocked when
# imported as module.
# time_machine is able to mock any datetime object, it also allows comparisons.
import time_machine
from sbws.lib.relaylist import Relay, RelayList
from sbws.util.state import State
def test_init_relays(
args, conf, controller, controller_1h_later, controller_5days_later
):
"""
Test `init_relays` when creating the RelayList the first time and when a
new consensus is received.
Test that the number of consesus timestamps and relays is correct.
Additionally, make sure the calculated min bw for the second hop for
exit/non-exit relays is correct, too.
"""
state = State(conf["paths"]["state_fpath"])
# There is no need to mock datetime to update the consensus, since the
# actual date will be always later.
# But it's needed to have the correct list of timestamps both for RelayList
# and Relay.
with time_machine.travel("2020-02-29 10:00:00 +0000"):
relay_list = RelayList(args, conf, controller, state=state)
assert relay_list.recent_consensus_count == 1
assert relay_list._relays[0].relay_in_recent_consensus_count == 1
# The actual number of relays in the consensus
assert len(relay_list._relays) == 6433
fps = {r.fingerprint for r in relay_list._relays}
# The calculated min bw for the second hop
assert 2100000 == relay_list._exit_min_bw
assert 220000 == relay_list._non_exit_min_bw
# One hour later there is a new consensus
relay_list._controller = controller_1h_later
with time_machine.travel("2020-02-29 11:00:00 +0000"):
# Call relays update the list of relays.
relay_list.relays
assert relay_list.recent_consensus_count == 2
assert relay_list._relays[0].relay_in_recent_consensus_count == 2
# Check that the number of relays is now the previous one plus the relays
# that are in the new consensus that there were not in the previous one.
fps_1h_later = {r.fingerprint for r in relay_list._relays}
added_fps = fps_1h_later.difference(fps)
assert 6505 == 6433 + len(added_fps)
# The calculated min bw for the second hop
assert 2120000 == relay_list._exit_min_bw
assert 210000 == relay_list._non_exit_min_bw
# Five days later plus 1 second.
# The first consensus timestamp will get removed.
relay_list._controller = controller_5days_later
with time_machine.travel("2020-03-05 10:00:01 +0000"):
relay_list.relays
assert relay_list.recent_consensus_count == 2
assert relay_list._relays[0].relay_in_recent_consensus_count == 2
fps_5days_later = {r.fingerprint for r in relay_list._relays}
# The number of added relays will be the number of relays in this
# consensus that were not in the other 2 conensuses
added_fps = fps_5days_later.difference(fps_1h_later)
# The number of removed relays that are in this consensus, plus the added
# ones that were not in the first consensus (because it has been removed).
removed_fps = fps.difference(fps_5days_later)
# The number of relays will be the number of relays in the cosensus plus
# the added ones minus the removed ones.
assert 6596 == 6505 + len(added_fps) - len(removed_fps)
# The calculated min bw for the second hop
assert 2800000 == relay_list._exit_min_bw
assert 150000 == relay_list._non_exit_min_bw
def test_increment_recent_measurement_attempt(args, conf, controller):
"""Test that incrementing the measurement attempts does not go on forever
And instead it only counts the number of attempts in the last days.
It also tests that the state file is updated correctly.
"""
state = State(conf["paths"]["state_fpath"])
with time_machine.travel("2020-02-29 10:00:00 +0000"):
relay_list = RelayList(args, conf, controller=controller, state=state)
# The initial count is 0 and the state does not have that key.
assert 0 == relay_list.recent_measurement_attempt_count
assert not state.get("recent_measurement_attempt", None)
# Pretend that a measurement attempt is made.
with time_machine.travel("2020-02-29 10:00:00 +0000"):
relay_list.increment_recent_measurement_attempt()
assert 1 == relay_list.recent_measurement_attempt_count
assert ["2020-02-29T10:00:00+00:00"] == state["recent_measurement_attempt"]
# And a second measurement attempt is made 4 days later.
with time_machine.travel("2020-03-04 10:00:00 +0000"):
relay_list.increment_recent_measurement_attempt()
assert 2 == relay_list.recent_measurement_attempt_count
assert 2 == len(state["recent_measurement_attempt"])
# And a third measurement attempt is made 5 days later.
with time_machine.travel("2020-03-05 10:00:00 +0000"):
relay_list.increment_recent_measurement_attempt()
assert 3 == relay_list.recent_measurement_attempt_count
assert 3 == len(state["recent_measurement_attempt"])
# And a fourth measurement attempt is made 6 days later. The first one is
# now removed and not counted.
with time_machine.travel("2020-03-06 10:00:00 +0000"):
relay_list.increment_recent_measurement_attempt()
assert 3 == relay_list.recent_measurement_attempt_count
assert 3 == len(state["recent_measurement_attempt"])
def test_increment_relay_recent_measurement_attempt(
controller, router_status, server_descriptor
):
"""Test that incrementing the measurement attempts do not go on forever
And instead it only counts the number of attempts in the last days.
"""
# For this test it does not matter that the consensus timestamps
# are not correct.
now = datetime.now(UTC)
relay = Relay("A" * 40, controller, timestamp=now)
# The initial count is 0 and the state does not have that key.
assert 0 == relay.relay_recent_measurement_attempt_count
# Pretend that a measurement attempt is made.
with time_machine.travel("2020-02-29 10:00:00 +0000"):
relay.increment_relay_recent_measurement_attempt()
assert 1 == relay.relay_recent_measurement_attempt_count
# And a second measurement attempt is made 4 days later.
with time_machine.travel("2020-03-04 10:00:00 +0000"):
relay.increment_relay_recent_measurement_attempt()
assert 2 == relay.relay_recent_measurement_attempt_count
# And a third measurement attempt is made before 5 days later.
with time_machine.travel("2020-03-05 09:00:00 +0000"):
relay.increment_relay_recent_measurement_attempt()
assert 3 == relay.relay_recent_measurement_attempt_count
# And a fourth measurement attempt is made 6 days later. The first one is
# now removed and not counted.
with time_machine.travel("2020-03-06 10:00:00 +0000"):
relay.increment_relay_recent_measurement_attempt()
assert 3 == relay.relay_recent_measurement_attempt_count
# XXX: Write to a Result and load it back
def test_increment_relay_recent_priority_list(
controller, router_status, server_descriptor
):
"""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.
"""
# For this test it does not matter that the consensus timestamps
# are not correct.
now = datetime.now(UTC)
relay = Relay("A" * 40, controller, timestamp=now)
# The initial count is 0 and the state does not have that key.
assert 0 == relay.relay_recent_priority_list_count
# Pretend that a measurement attempt is made.
with time_machine.travel("2020-02-29 10:00:00 +0000"):
relay.increment_relay_recent_priority_list()
assert 1 == relay.relay_recent_priority_list_count
# And a second measurement attempt is made 4 days later.
with time_machine.travel("2020-03-04 10:00:00 +0000"):
relay.increment_relay_recent_priority_list()
assert 2 == relay.relay_recent_priority_list_count
# And a third measurement attempt is made 5 days later.
with time_machine.travel("2020-03-05 10:00:00 +0000"):
relay.increment_relay_recent_priority_list()
assert 3 == relay.relay_recent_priority_list_count
# And a fourth measurement attempt is made 6 days later. The first one is
# now removed and not counted.
with time_machine.travel("2020-03-06 10:00:00 +0000"):
relay.increment_relay_recent_priority_list()
assert 3 == relay.relay_recent_priority_list_count
|