def test_authenticate_general_password(self): """ Tests the authenticate function's password argument. """ # this is a much better test if we're just using password auth, since # authenticate will work reguardless if there's something else to # authenticate with runner = test.runner.get_runner() tor_options = runner.get_options() is_password_only = test.runner.Torrc.PASSWORD in tor_options and test.runner.Torrc.COOKIE not in tor_options # tests without a password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.MissingPassword, stem.connection.authenticate, control_socket) else: stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the incorrect password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.IncorrectPassword, stem.connection.authenticate, control_socket, 'blarg') else: stem.connection.authenticate(control_socket, 'blarg', runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the right password with runner.get_tor_socket(False) as control_socket: stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
def test_authenticate_general_password(self): """ Tests the authenticate function's password argument. """ if test.runner.require_control(self): return # this is a much better test if we're just using password auth, since # authenticate will work reguardless if there's something else to # authenticate with runner = test.runner.get_runner() tor_options = runner.get_options() is_password_only = test.runner.Torrc.PASSWORD in tor_options and not test.runner.Torrc.COOKIE in tor_options # tests without a password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.MissingPassword, stem.connection.authenticate, control_socket) else: stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the incorrect password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.IncorrectPassword, stem.connection.authenticate, control_socket, "blarg") else: stem.connection.authenticate(control_socket, "blarg", runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the right password with runner.get_tor_socket(False) as control_socket: stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
def test_connection_time(self): """ Checks that our connection_time method tracks when our state's changed. """ test_start = time.time() runner = test.runner.get_runner() with runner.get_tor_socket() as control_socket: connection_time = control_socket.connection_time() # connection time should be between our tests start and now self.assertTrue(test_start <= connection_time <= time.time()) # connection time should be absolute (shouldn't change as time goes on) time.sleep(0.1) self.assertEqual(connection_time, control_socket.connection_time()) # should change to the disconnection time if we detactch control_socket.close() disconnection_time = control_socket.connection_time() self.assertTrue(connection_time < disconnection_time <= time.time()) # then change again if we reconnect time.sleep(0.1) control_socket.connect() reconnection_time = control_socket.connection_time() self.assertTrue(disconnection_time < reconnection_time <= time.time())
def test_get_connections(self): """ Checks for our control port in the stem.util.proc.get_connections output if we have one. """ runner = test.runner.get_runner() if not proc.is_available(): test.runner.skip(self, "(proc unavailable)") return elif not test.runner.Torrc.PORT in runner.get_options(): test.runner.skip(self, "(no control port)") return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, "(DisableDebuggerAttachment is set)") return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.get_connections(tor_pid): if ("127.0.0.1", test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def check_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid=runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return resolver_command = RESOLVER_COMMAND[resolver].format( pid=runner.get_pid()) resolver_output = stem.util.system.call(resolver_command) self.fail( 'Unable to find our controller connection with %s (%s). Connections found were...\n\n%s\n\nCommand output was...\n\n%s' % (resolver, resolver_command, '\n'.join(map( str, connections)), resolver_output))
def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if not proc.is_available(): test.runner.skip(self, '(proc unavailable)') return elif test.runner.Torrc.PORT not in runner.get_options(): test.runner.skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, '(DisableDebuggerAttachment is set)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access('/proc/net/udp', os.R_OK): test.runner.skip(self, '(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_authenticate_general_cookie(self): """ Tests the authenticate function with only cookie authentication methods. This manipulates our PROTOCOLINFO response to test each method individually. """ if test.runner.require_control(self): return runner = test.runner.get_runner() tor_options = runner.get_options() is_cookie_only = test.runner.Torrc.COOKIE in tor_options and not test.runner.Torrc.PASSWORD in tor_options # test both cookie authentication mechanisms with runner.get_tor_socket(False) as control_socket: if is_cookie_only: for method in (stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE): protocolinfo_response = stem.connection.get_protocolinfo(control_socket) if method in protocolinfo_response.auth_methods: # narrow to *only* use cookie auth or safecooke, so we exercise # both independently protocolinfo_response.auth_methods = (method, ) stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot(), protocolinfo_response = protocolinfo_response)
def test_connection_time(self): """ Checks that our connection_time method tracks when our state's changed. """ test_start = time.time() runner = test.runner.get_runner() with runner.get_tor_socket() as control_socket: connection_time = control_socket.connection_time() # connection time should be between our tests start and now self.assertTrue(test_start <= connection_time <= time.time()) # connection time should be absolute (shouldn't change as time goes on) time.sleep(0.001) self.assertEqual(connection_time, control_socket.connection_time()) # should change to the disconnection time if we detactch control_socket.close() disconnection_time = control_socket.connection_time() self.assertTrue( connection_time < disconnection_time <= time.time()) # then change again if we reconnect time.sleep(0.001) control_socket.connect() reconnection_time = control_socket.connection_time() self.assertTrue( disconnection_time < reconnection_time <= time.time())
def test_authenticate_general_cookie(self): """ Tests the authenticate function with only cookie authentication methods. This manipulates our PROTOCOLINFO response to test each method individually. """ if test.runner.require_control(self): return runner = test.runner.get_runner() tor_options = runner.get_options() is_cookie_only = test.runner.Torrc.COOKIE in tor_options and not test.runner.Torrc.PASSWORD in tor_options # test both cookie authentication mechanisms with runner.get_tor_socket(False) as control_socket: if is_cookie_only: for method in (stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE): protocolinfo_response = stem.connection.get_protocolinfo( control_socket) if method in protocolinfo_response.auth_methods: # narrow to *only* use cookie auth or safecooke, so we exercise # both independently protocolinfo_response.auth_methods = (method, ) stem.connection.authenticate( control_socket, chroot_path=runner.get_chroot(), protocolinfo_response=protocolinfo_response)
def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skiTestp('(no control port)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access( '/proc/net/udp', os.R_OK): self.skipTest('(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_authenticate_general_socket(self): """ Tests that the authenticate function can authenticate to our socket. """ runner = test.runner.get_runner() with runner.get_tor_socket(False) as control_socket: stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
def test_getinfo_config_text(self): """ Parses the 'GETINFO config-text' response. """ if test.runner.require_control(self): return elif test.runner.require_version( self, stem.version.Requirement.GETINFO_CONFIG_TEXT): return runner = test.runner.get_runner() # We can't be certain of the order, and there may be extra config-text # entries as per... # https://trac.torproject.org/projects/tor/ticket/2362 # # so we'll just check that the response is a superset of our config torrc_contents = [] for line in runner.get_torrc_contents().splitlines(): line = line.strip() if line and not line.startswith("#"): torrc_contents.append(line) with runner.get_tor_socket() as control_socket: control_socket.send("GETINFO config-text") config_text_response = control_socket.recv() # the response should contain two entries, the first being a data response self.assertEqual(2, len(list(config_text_response))) self.assertEqual("OK", list(config_text_response)[1]) self.assertEqual(("250", " ", "OK"), config_text_response.content()[1]) self.assertTrue(config_text_response.raw_content().startswith( "250+config-text=\r\n")) self.assertTrue(config_text_response.raw_content().endswith( "\r\n.\r\n250 OK\r\n")) self.assertTrue( str(config_text_response).startswith("config-text=\n")) self.assertTrue(str(config_text_response).endswith("\nOK")) for torrc_entry in torrc_contents: self.assertTrue("\n%s\n" % torrc_entry in str(config_text_response)) self.assertTrue(torrc_entry in list(config_text_response)[0]) self.assertTrue( "%s\r\n" % torrc_entry in config_text_response.raw_content()) self.assertTrue( "%s" % torrc_entry in config_text_response.content()[0][2])
def test_getinfo_config_file(self): """ Parses the 'GETINFO config-file' response. """ runner = test.runner.get_runner() torrc_dst = runner.get_torrc_path() with runner.get_tor_socket() as control_socket: control_socket.send('GETINFO config-file') config_file_response = control_socket.recv() self.assertEqual('config-file=%s\nOK' % torrc_dst, str(config_file_response)) self.assertEqual(['config-file=%s' % torrc_dst, 'OK'], list(config_file_response)) self.assertEqual('250-config-file=%s\r\n250 OK\r\n' % torrc_dst, config_file_response.raw_content()) self.assertEqual([('250', '-', 'config-file=%s' % torrc_dst), ('250', ' ', 'OK')], config_file_response.content())
def test_getinfo_config_file(self): """ Parses the 'GETINFO config-file' response. """ runner = test.runner.get_runner() torrc_dst = runner.get_torrc_path() with runner.get_tor_socket() as control_socket: control_socket.send("GETINFO config-file") config_file_response = control_socket.recv() self.assertEquals("config-file=%s\nOK" % torrc_dst, str(config_file_response)) self.assertEquals(["config-file=%s" % torrc_dst, "OK"], list(config_file_response)) self.assertEquals("250-config-file=%s\r\n250 OK\r\n" % torrc_dst, config_file_response.raw_content()) self.assertEquals([("250", "-", "config-file=%s" % torrc_dst), ("250", " ", "OK")], config_file_response.content())
def test_send_buffered(self): """ Sends multiple requests before receiving back any of the replies. """ runner = test.runner.get_runner() tor_version = runner.get_tor_version() with runner.get_tor_socket() as control_socket: for _ in range(100): control_socket.send('GETINFO version') for _ in range(100): response = control_socket.recv() self.assertTrue(str(response).startswith('version=%s' % tor_version)) self.assertTrue(str(response).endswith('\nOK'))
def test_getinfo_config_text(self): """ Parses the 'GETINFO config-text' response. """ runner = test.runner.get_runner() # We can't be certain of the order, and there may be extra config-text # entries as per... # https://trac.torproject.org/projects/tor/ticket/2362 # # so we'll just check that the response is a superset of our config torrc_contents = [] for line in runner.get_torrc_contents().splitlines(): line = line.strip() if line and not line.startswith('#'): torrc_contents.append(line) with runner.get_tor_socket() as control_socket: control_socket.send('GETINFO config-text') config_text_response = control_socket.recv() # the response should contain two entries, the first being a data response self.assertEqual(2, len(list(config_text_response))) self.assertEqual('OK', list(config_text_response)[1]) self.assertEqual(('250', ' ', 'OK'), config_text_response.content()[1]) self.assertTrue(config_text_response.raw_content().startswith( '250+config-text=\r\n')) self.assertTrue(config_text_response.raw_content().endswith( '\r\n.\r\n250 OK\r\n')) self.assertTrue( str(config_text_response).startswith('config-text=\n')) self.assertTrue(str(config_text_response).endswith('\nOK')) for torrc_entry in torrc_contents: self.assertTrue('\n%s\n' % torrc_entry in str(config_text_response)) self.assertTrue(torrc_entry in list(config_text_response)[0]) self.assertTrue( '%s\r\n' % torrc_entry in config_text_response.raw_content()) self.assertTrue( '%s' % torrc_entry in config_text_response.content()[0][2])
def test_send_buffered(self): """ Sends multiple requests before receiving back any of the replies. """ runner = test.runner.get_runner() tor_version = runner.get_tor_version() with runner.get_tor_socket() as control_socket: for _ in range(100): control_socket.send('GETINFO version') for _ in range(100): response = control_socket.recv() self.assertTrue( str(response).startswith('version=%s' % tor_version)) self.assertTrue(str(response).endswith('\nOK'))
def test_getinfo_config_file(self): """ Parses the 'GETINFO config-file' response. """ if test.runner.require_control(self): return runner = test.runner.get_runner() torrc_dst = runner.get_torrc_path() with runner.get_tor_socket() as control_socket: control_socket.send('GETINFO config-file') config_file_response = control_socket.recv() self.assertEqual('config-file=%s\nOK' % torrc_dst, str(config_file_response)) self.assertEqual(['config-file=%s' % torrc_dst, 'OK'], list(config_file_response)) self.assertEqual('250-config-file=%s\r\n250 OK\r\n' % torrc_dst, config_file_response.raw_content()) self.assertEqual([('250', '-', 'config-file=%s' % torrc_dst), ('250', ' ', 'OK')], config_file_response.content())
def check_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid = runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def test_getinfo_config_text(self): """ Parses the 'GETINFO config-text' response. """ if test.runner.require_control(self): return elif test.runner.require_version(self, stem.version.Requirement.GETINFO_CONFIG_TEXT): return runner = test.runner.get_runner() # We can't be certain of the order, and there may be extra config-text # entries as per... # https://trac.torproject.org/projects/tor/ticket/2362 # # so we'll just check that the response is a superset of our config torrc_contents = [] for line in runner.get_torrc_contents().splitlines(): line = line.strip() if line and not line.startswith("#"): torrc_contents.append(line) with runner.get_tor_socket() as control_socket: control_socket.send("GETINFO config-text") config_text_response = control_socket.recv() # the response should contain two entries, the first being a data response self.assertEqual(2, len(list(config_text_response))) self.assertEqual("OK", list(config_text_response)[1]) self.assertEqual(("250", " ", "OK"), config_text_response.content()[1]) self.assertTrue(config_text_response.raw_content().startswith("250+config-text=\r\n")) self.assertTrue(config_text_response.raw_content().endswith("\r\n.\r\n250 OK\r\n")) self.assertTrue(str(config_text_response).startswith("config-text=\n")) self.assertTrue(str(config_text_response).endswith("\nOK")) for torrc_entry in torrc_contents: self.assertTrue("\n%s\n" % torrc_entry in str(config_text_response)) self.assertTrue(torrc_entry in list(config_text_response)[0]) self.assertTrue("%s\r\n" % torrc_entry in config_text_response.raw_content()) self.assertTrue("%s" % torrc_entry in config_text_response.content()[0][2])
def check_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid=runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def test_get_connections(self): runner = test.runner.get_runner() if not test.runner.Torrc.PORT in runner.get_options(): test.runner.skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, '(DisableDebuggerAttachment is set)') return for resolver in get_system_resolvers(): with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() connections = get_connections(resolver, process_pid = tor_pid) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def test_getinfo_config_text(self): """ Parses the 'GETINFO config-text' response. """ runner = test.runner.get_runner() # We can't be certain of the order, and there may be extra config-text # entries as per... # https://trac.torproject.org/projects/tor/ticket/2362 # # so we'll just check that the response is a superset of our config torrc_contents = [] for line in runner.get_torrc_contents().splitlines(): line = line.strip() if line and not line.startswith('#'): torrc_contents.append(line) with runner.get_tor_socket() as control_socket: control_socket.send('GETINFO config-text') config_text_response = control_socket.recv() # the response should contain two entries, the first being a data response self.assertEqual(2, len(list(config_text_response))) self.assertEqual('OK', list(config_text_response)[1]) self.assertEqual(('250', ' ', 'OK'), config_text_response.content()[1]) self.assertTrue(config_text_response.raw_content().startswith('250+config-text=\r\n')) self.assertTrue(config_text_response.raw_content().endswith('\r\n.\r\n250 OK\r\n')) self.assertTrue(str(config_text_response).startswith('config-text=\n')) self.assertTrue(str(config_text_response).endswith('\nOK')) for torrc_entry in torrc_contents: self.assertTrue('\n%s\n' % torrc_entry in str(config_text_response)) self.assertTrue(torrc_entry in list(config_text_response)[0]) self.assertTrue('%s\r\n' % torrc_entry in config_text_response.raw_content()) self.assertTrue('%s' % torrc_entry in config_text_response.content()[0][2])
def test_getinfo_config_file(self): """ Parses the 'GETINFO config-file' response. """ if test.runner.require_control(self): return runner = test.runner.get_runner() torrc_dst = runner.get_torrc_path() with runner.get_tor_socket() as control_socket: control_socket.send("GETINFO config-file") config_file_response = control_socket.recv() self.assertEquals("config-file=%s\nOK" % torrc_dst, str(config_file_response)) self.assertEquals(["config-file=%s" % torrc_dst, "OK"], list(config_file_response)) self.assertEquals("250-config-file=%s\r\n250 OK\r\n" % torrc_dst, config_file_response.raw_content()) self.assertEquals([("250", "-", "config-file=%s" % torrc_dst), ("250", " ", "OK")], config_file_response.content())