commit f388d3b984001207bca9c423d5340a3e44ea857c Author: Damian Johnson atagar@torproject.org Date: Mon Jul 11 09:39:54 2016 -0700
Test torrc panel
This panel is tiny enough that I'm not gonna break its draw function up for now. Just testing the whole panel instead. --- nyx/panel/torrc.py | 29 ++++++++++------- test/panel/__init__.py | 1 + test/panel/connection.py | 50 +++++++++++++++++++--------- test/panel/torrc.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 27 deletions(-)
diff --git a/nyx/panel/torrc.py b/nyx/panel/torrc.py index 278fbeb..868e546 100644 --- a/nyx/panel/torrc.py +++ b/nyx/panel/torrc.py @@ -17,6 +17,17 @@ from stem import ControllerError from stem.control import State
+def _read_torrc(path): + contents = [] + + with open(path) as torrc_file: + for line in torrc_file.readlines(): + line = line.replace('\t', ' ').replace('\xc2', "'").rstrip() + contents.append(filter(lambda char: char in string.printable, line)) + + return contents + + class TorrcPanel(panel.Panel): """ Renders the current torrc or nyxrc with syntax highlighting in a scrollable @@ -47,20 +58,14 @@ class TorrcPanel(panel.Panel): if event_type == State.RESET: try: self._torrc_location = expand_path(controller.get_info('config-file')) - contents = [] - - with open(self._torrc_location) as torrc_file: - for line in torrc_file.readlines(): - line = line.replace('\t', ' ').replace('\xc2', "'").rstrip() - contents.append(filter(lambda char: char in string.printable, line)) - - self._torrc_content = contents + self._torrc_content = _read_torrc(self._torrc_location) except ControllerError as exc: self._torrc_load_error = msg('panel.torrc.unable_to_find_torrc', error = exc) self._torrc_location = None self._torrc_content = None except Exception as exc: - self._torrc_load_error = msg('panel.torrc.unable_to_load_torrc', error = exc.strerror) + exc_msg = exc.strerror if (hasattr(exc, 'strerror') and exc.strerror) else str(exc) + self._torrc_load_error = msg('panel.torrc.unable_to_load_torrc', error = exc_msg) self._torrc_content = None
def set_comments_visible(self, is_visible): @@ -121,7 +126,7 @@ class TorrcPanel(panel.Panel):
if self._last_content_height > subwindow.height - 1: scroll_offset = 3 - subwindow.scrollbar(1, scroll, height - 1) + subwindow.scrollbar(1, scroll, subwindow.height - 1)
y = 1 - scroll is_multiline = False # true if we're in the middle of a multiline torrc entry @@ -144,8 +149,8 @@ class TorrcPanel(panel.Panel): elif ' ' not in line.strip(): option, argument = line, '' # no argument else: - whitespace = ' ' * (len(line) - len(line.strip())) - option, argument = line.strip().split(' ', 1) + whitespace = ' ' * (len(line) - len(line.lstrip())) + option, argument = line.lstrip().split(' ', 1) option = whitespace + option + ' '
is_multiline = line.endswith('\') # next line's part of a multi-line entry diff --git a/test/panel/__init__.py b/test/panel/__init__.py index f1a9d7d..9142e64 100644 --- a/test/panel/__init__.py +++ b/test/panel/__init__.py @@ -7,4 +7,5 @@ __all__ = [ 'graph', 'log', 'connection', + 'torrc', ] diff --git a/test/panel/connection.py b/test/panel/connection.py index 632ced0..30db919 100644 --- a/test/panel/connection.py +++ b/test/panel/connection.py @@ -118,30 +118,40 @@ def line(entry = MockEntry(), line_type = LineType.CONNECTION, connection = CONN class TestConnectionPanel(unittest.TestCase): @require_curses def test_draw_title(self): - self.assertEqual('Connection Details:', test.render(nyx.panel.connection._draw_title, [], True).content) - self.assertEqual('Connections:', test.render(nyx.panel.connection._draw_title, [], False).content) + rendered = test.render(nyx.panel.connection._draw_title, [], True) + self.assertEqual('Connection Details:', rendered.content) + + rendered = test.render(nyx.panel.connection._draw_title, [], False) + self.assertEqual('Connections:', rendered.content)
entries = [MockEntry(entry_type = category) for category in (Category.INBOUND, Category.INBOUND, Category.OUTBOUND, Category.INBOUND, Category.CONTROL)] - self.assertEqual('Connections (3 inbound, 1 outbound, 1 control):', test.render(nyx.panel.connection._draw_title, entries, False).content) + + rendered = test.render(nyx.panel.connection._draw_title, entries, False) + self.assertEqual('Connections (3 inbound, 1 outbound, 1 control):', rendered.content)
@require_curses def test_draw_details_incomplete_circuit(self): selected = line(line_type = LineType.CIRCUIT_HEADER, circ = MockCircuit(status = 'EXTENDING')) - self.assertEqual(DETAILS_BUILDING_CIRCUIT, test.render(nyx.panel.connection._draw_details, selected).content) + + rendered = test.render(nyx.panel.connection._draw_details, selected) + self.assertEqual(DETAILS_BUILDING_CIRCUIT, rendered.content)
@require_curses @patch('nyx.tracker.get_consensus_tracker') def test_draw_details_no_consensus_data(self, consensus_tracker_mock): consensus_tracker_mock().get_relay_fingerprints.return_value = None - self.assertEqual(DETAILS_NO_CONSENSUS_DATA, test.render(nyx.panel.connection._draw_details, line()).content) + + rendered = test.render(nyx.panel.connection._draw_details, line()) + self.assertEqual(DETAILS_NO_CONSENSUS_DATA, rendered.content)
@require_curses @patch('nyx.tracker.get_consensus_tracker') def test_draw_details_when_private(self, consensus_tracker_mock): consensus_tracker_mock().get_relay_fingerprints.return_value = None - selected = line(entry = MockEntry(is_private = True)) - self.assertEqual(DETAILS_WHEN_PRIVATE, test.render(nyx.panel.connection._draw_details, selected).content) + + rendered = test.render(nyx.panel.connection._draw_details, selected) + self.assertEqual(DETAILS_WHEN_PRIVATE, rendered.content)
@require_curses @patch('nyx.panel.connection.tor_controller') @@ -168,7 +178,8 @@ class TestConnectionPanel(unittest.TestCase): 22: 'B6D83EC2D9E18B0A7A33428F8CFA9C536769E209' }
- self.assertEqual(DETAILS_FOR_RELAY, test.render(nyx.panel.connection._draw_details, line()).content) + rendered = test.render(nyx.panel.connection._draw_details, line()) + self.assertEqual(DETAILS_FOR_RELAY, rendered.content)
@require_curses @patch('nyx.tracker.get_consensus_tracker') @@ -179,7 +190,8 @@ class TestConnectionPanel(unittest.TestCase): 443: 'E0BD57A11F00041A9789577C53A1B784473669E4', }
- self.assertEqual(DETAILS_FOR_MULTIPLE_MATCHES, test.render(nyx.panel.connection._draw_details, line()).content) + rendered = test.render(nyx.panel.connection._draw_details, line()) + self.assertEqual(DETAILS_FOR_MULTIPLE_MATCHES, rendered.content)
@require_curses @patch('nyx.panel.connection.tor_controller') @@ -201,7 +213,8 @@ class TestConnectionPanel(unittest.TestCase): }
for test_line, expected in test_data.items(): - self.assertEqual(expected, test.render(nyx.panel.connection._draw_line, 0, 0, test_line, False, 80, TIMESTAMP + 15.4).content) + rendered = test.render(nyx.panel.connection._draw_line, 0, 0, test_line, False, 80, TIMESTAMP + 15.4) + self.assertEqual(expected, rendered.content)
@require_curses @patch('nyx.panel.connection.tor_controller') @@ -221,7 +234,8 @@ class TestConnectionPanel(unittest.TestCase): }
for test_line, expected in test_data.items(): - self.assertEqual(expected, test.render(nyx.panel.connection._draw_address_column, 0, 0, test_line, ()).content) + rendered = test.render(nyx.panel.connection._draw_address_column, 0, 0, test_line, ()) + self.assertEqual(expected, rendered.content)
@require_curses @patch('nyx.tracker.get_port_usage_tracker') @@ -242,15 +256,19 @@ class TestConnectionPanel(unittest.TestCase): }
for test_line, expected in test_data.items(): - self.assertEqual(expected, test.render(nyx.panel.connection._draw_line_details, 0, 0, test_line, 80, ()).content) + rendered = test.render(nyx.panel.connection._draw_line_details, 0, 0, test_line, 80, ()) + self.assertEqual(expected, rendered.content)
@require_curses def test_draw_right_column(self): - self.assertEqual(' 1.0m (INBOUND)', test.render(nyx.panel.connection._draw_right_column, 0, 0, line(), TIMESTAMP + 62, ()).content) + rendered = test.render(nyx.panel.connection._draw_right_column, 0, 0, line(), TIMESTAMP + 62, ()) + self.assertEqual(' 1.0m (INBOUND)', rendered.content)
legacy_connection = Connection(TIMESTAMP, True, '127.0.0.1', 3531, '75.119.206.243', 22, 'tcp', False) test_line = line(entry = MockEntry(entry_type = Category.CONTROL), connection = legacy_connection) - self.assertEqual('+ 1.1m (CONTROL)', test.render(nyx.panel.connection._draw_right_column, 0, 0, test_line, TIMESTAMP + 68, ()).content) + + rendered = test.render(nyx.panel.connection._draw_right_column, 0, 0, test_line, TIMESTAMP + 68, ()) + self.assertEqual('+ 1.1m (CONTROL)', rendered.content)
test_data = { '1F43EE37A0670301AD9CB555D94AFEC2C89FDE86': ' 1 / Guard', @@ -260,4 +278,6 @@ class TestConnectionPanel(unittest.TestCase):
for fp, expected in test_data.items(): test_line = line(line_type = LineType.CIRCUIT, fingerprint = fp) - self.assertEqual(expected, test.render(nyx.panel.connection._draw_right_column, 0, 0, test_line, TIMESTAMP + 62, ()).content) + + rendered = test.render(nyx.panel.connection._draw_right_column, 0, 0, test_line, TIMESTAMP + 62, ()) + self.assertEqual(expected, rendered.content) diff --git a/test/panel/torrc.py b/test/panel/torrc.py new file mode 100644 index 0000000..96d222c --- /dev/null +++ b/test/panel/torrc.py @@ -0,0 +1,84 @@ +""" +Unit tests for nyx.panel.torrc. +""" + +import unittest + +import nyx.panel.torrc +import test + +from test import require_curses +from mock import patch, Mock + +TORRC = """ +ORPort 9050 +ControlPort 9051 +Exitpolicy reject *:* # non-exit relay +CookieAuthentication 1 +""".strip() + +RENDERED_DEFAULT = """ +Tor Configuration File (/path/to/torrc): +1 ORPort 9050 +2 ControlPort 9051 +3 Exitpolicy reject *:* # non-exit relay +4 CookieAuthentication 1 +""".strip() + +RENDERED_WITHOUT_COMMENTS = """ +Tor Configuration File (/path/to/torrc): +1 ORPort 9050 +2 ControlPort 9051 +3 Exitpolicy reject *:* +4 CookieAuthentication 1 +""".strip() + +RENDERED_WITHOUT_LINE_NUMBERS = """ +Tor Configuration File (/path/to/torrc): +ORPort 9050 +ControlPort 9051 +Exitpolicy reject *:* # non-exit relay +CookieAuthentication 1 +""".strip() + +RENDERED_WITH_ERROR = """ +Tor Configuration File (/path/to/torrc): +Unable to read our torrc: [Errno 2] No such file or directory: '/path/to/torrc' +""".strip() + + +class TestGraphPanel(unittest.TestCase): + @require_curses + @patch('nyx.panel.torrc._read_torrc', Mock(return_value = TORRC.splitlines())) + @patch('nyx.panel.torrc.expand_path', Mock(return_value = '/path/to/torrc')) + @patch('nyx.panel.torrc.tor_controller', Mock()) + def test_draw_with_content(self): + panel = nyx.panel.torrc.TorrcPanel() + self.assertEqual(RENDERED_DEFAULT, test.render(panel.draw).content) + + @require_curses + @patch('nyx.panel.torrc._read_torrc', Mock(return_value = TORRC.splitlines())) + @patch('nyx.panel.torrc.expand_path', Mock(return_value = '/path/to/torrc')) + @patch('nyx.panel.torrc.tor_controller', Mock()) + def test_draw_without_comments(self): + panel = nyx.panel.torrc.TorrcPanel() + panel._show_comments = False + self.assertEqual(RENDERED_WITHOUT_COMMENTS, test.render(panel.draw).content) + + @require_curses + @patch('nyx.panel.torrc._read_torrc', Mock(return_value = TORRC.splitlines())) + @patch('nyx.panel.torrc.expand_path', Mock(return_value = '/path/to/torrc')) + @patch('nyx.panel.torrc.tor_controller', Mock()) + def test_draw_without_line_numbers(self): + panel = nyx.panel.torrc.TorrcPanel() + panel._show_line_numbers = False + self.assertEqual(RENDERED_WITHOUT_LINE_NUMBERS, test.render(panel.draw).content) + + @require_curses + @patch('nyx.panel.torrc._read_torrc', Mock(side_effect = IOError("[Errno 2] No such file or directory: '/path/to/torrc'"))) + @patch('nyx.panel.torrc.expand_path', Mock(return_value = '/path/to/torrc')) + @patch('nyx.panel.torrc.tor_controller', Mock()) + def test_draw_with_error(self): + panel = nyx.panel.torrc.TorrcPanel() + panel._show_line_numbers = False + self.assertEqual(RENDERED_WITH_ERROR, test.render(panel.draw).content)
tor-commits@lists.torproject.org