commit 3cf69496466a46af56bf7b9bc789003ead7d1118 Author: Damian Johnson atagar@torproject.org Date: Fri Oct 28 09:45:42 2016 -0700
Unit tests fail when no address is available
When expanding the 'private' alias for exit policies the last entry is for our pubic address. When python is unable to determine one get_config_policy() excludes this last entry, in turn causing our unit tests to fail...
https://trac.torproject.org/projects/tor/ticket/20476
Being more careful to treat this part of the policy as being optional. --- stem/exit_policy.py | 26 ++++++++++++++------------ test/unit/exit_policy/policy.py | 14 +++++++++++++- 2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/stem/exit_policy.py b/stem/exit_policy.py index 1aa2537..2e2b459 100644 --- a/stem/exit_policy.py +++ b/stem/exit_policy.py @@ -165,10 +165,10 @@ def _flag_private_rules(rules): series of rules exactly matching it. """
- matches = [] + matches = [] # find all possible starting indexes
for i, rule in enumerate(rules): - if i + len(PRIVATE_ADDRESSES) + 1 > len(rules): + if i + len(PRIVATE_ADDRESSES) > len(rules): break
rule_str = '%s/%s' % (rule.address, rule.get_masked_bits()) @@ -180,33 +180,35 @@ def _flag_private_rules(rules): # To match the private policy the following must all be true... # # * series of addresses and bit masks match PRIVATE_ADDRESSES - # * all rules have the same port range and acceptance + # * all rules have the same port range # * all rules have the same acceptance (all accept or reject entries) + # + # The last rule is dynamically based on the relay's public address. It may + # not be present if get_config_policy() created this policy and we couldn't + # resolve our address.
- rule_set = rules[start_index:start_index + len(PRIVATE_ADDRESSES) + 1] + last_index = start_index + len(PRIVATE_ADDRESSES) + rule_set = rules[start_index:last_index] + last_rule = rules[last_index] if len(rules) > last_index else None is_match = True
min_port, max_port = rule_set[0].min_port, rule_set[0].max_port is_accept = rule_set[0].is_accept
- for i, rule in enumerate(rule_set[:-1]): + for i, rule in enumerate(rule_set): rule_str = '%s/%s' % (rule.address, rule.get_masked_bits())
if rule_str != PRIVATE_ADDRESSES[i] or rule.min_port != min_port or rule.max_port != max_port or rule.is_accept != is_accept: is_match = False break
- # The last rule is for the relay's public address, so it's dynamic. - - last_rule = rule_set[-1] - - if last_rule.is_address_wildcard() or last_rule.min_port != min_port or last_rule.max_port != max_port or last_rule.is_accept != is_accept: - is_match = False - if is_match: for rule in rule_set: rule._is_private = True
+ if last_rule and not last_rule.is_address_wildcard() and last_rule.min_port == min_port and last_rule.max_port == max_port and last_rule.is_accept == is_accept: + last_rule._is_private = True +
def _flag_default_rules(rules): """ diff --git a/test/unit/exit_policy/policy.py b/test/unit/exit_policy/policy.py index 5c20d0d..b1187ac 100644 --- a/test/unit/exit_policy/policy.py +++ b/test/unit/exit_policy/policy.py @@ -5,6 +5,12 @@ Unit tests for the stem.exit_policy.ExitPolicy class. import pickle import unittest
+try: + # added in python 3.3 + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch + from stem.exit_policy import ( DEFAULT_POLICY_RULES, get_config_policy, @@ -123,7 +129,7 @@ class TestExitPolicy(unittest.TestCase):
def test_all_private_policy(self): for port in ('*', '80', '1-1024'): - private_policy = get_config_policy('reject private:%s' % port) + private_policy = get_config_policy('reject private:%s' % port, '12.34.56.78')
for rule in private_policy: self.assertTrue(rule.is_private()) @@ -135,6 +141,12 @@ class TestExitPolicy(unittest.TestCase): private_policy = get_config_policy('accept private:*') self.assertEqual(ExitPolicy(), private_policy.strip_private())
+ @patch('socket.gethostname', Mock(side_effect = IOError('no address'))) + def test_all_private_policy_without_network(self): + for rule in get_config_policy('reject private:80, accept *:80'): + # all rules except the ending accept are part of the private policy + self.assertEqual(str(rule) != 'accept *:80', rule.is_private()) + def test_all_default_policy(self): policy = ExitPolicy(*DEFAULT_POLICY_RULES)