def test_stream_changed_with_detach(self): "Change a stream-id mid-stream, but with a DETACHED message" self.circuits[123] = FakeCircuit(123) self.circuits[456] = FakeCircuit(456) listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', {}), ('detach', { 'kwargs': dict(reason='END', remote_reason='MISC') }), ('attach', {})]) stream = Stream(self) stream.listen(listener) stream.update( "999 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("999 SENTCONNECT 123 1.2.3.4:80".split()) self.assertEqual(len(self.circuits[123].streams), 1) self.assertEqual(self.circuits[123].streams[0], stream) stream.update( "999 DETACHED 123 1.2.3.4:80 REASON=END REMOTE_REASON=MISC".split( )) self.assertEqual(len(self.circuits[123].streams), 0) stream.update("999 SENTCONNECT 456 1.2.3.4:80 SOURCE=EXIT".split()) self.assertEqual(len(self.circuits[456].streams), 1) self.assertEqual(self.circuits[456].streams[0], stream)
def test_args_in_ctor(self): stream = Stream(self) stream.update( "1 NEW 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH" .split()) self.assertEqual(stream.id, 1) self.assertEqual(stream.state, 'NEW')
def test_close_stream_with_stream(self): stream = Stream(self.state) stream.id = 1 self.state.streams[1] = stream self.state.close_stream(stream.id) self.assertEqual(self.transport.value(), 'CLOSESTREAM 1 1\r\n')
def test_str(self): stream = Stream(self) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.circuit = FakeCircuit(1) str(stream)
def test_attach_stream_failure(self): @implementer(ICircuitContainer) class FakeContainer(object): pass container = FakeContainer() stream = Stream(container) stream.source_addr = ipaddress.IPv4Address(u'0.0.0.0') stream.source_port = 12345 circuit = Mock() circuit.when_built = Mock(return_value=Failure(Exception('testing1234'))) target_endpoint = Mock() src_addr = Mock() src_addr.host = u'0.0.0.0' src_addr.port = 12345 target_endpoint._get_address = Mock(return_value=defer.succeed(src_addr)) reactor = Mock() state = Mock() TorCircuitEndpoint( reactor, state, circuit, target_endpoint, ) attacher = yield _get_circuit_attacher(reactor, state) d = attacher.add_endpoint(target_endpoint, circuit) self.assertEquals(len(attacher._circuit_targets), 1) # this will fail, but should be ignored yield attacher.attach_stream(stream, []) with self.assertRaises(Exception) as ctx: yield d self.assertTrue("testing1234" in str(ctx.exception))
def test_listener_new(self): listener = Listener([('new', {'target_port': 9001})]) stream = Stream(self) stream.listen(listener) stream.update( "1 NEW 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH" .split())
def test_magic_circuit_detach(self): stream = Stream(self) stream.circuit = FakeCircuit(1) stream.circuit.streams = [stream] stream.update( "1 SENTCONNECT 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH" .split()) self.assertTrue(stream.circuit is None)
def test_circuit_already_valid_in_new(self): stream = Stream(self) stream.circuit = FakeCircuit(1) stream.update( "1 NEW 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH" .split()) errs = self.flushLoggedErrors() self.assertEqual(len(errs), 1) self.assertTrue('Weird' in errs[0].getErrorMessage())
def test_close_stream_invalid_reason(self): stream = Stream(self.state) stream.id = 1 self.state.streams[1] = stream self.assertRaises( ValueError, self.state.close_stream, stream, 'FOO_INVALID_REASON' )
def test_listen_unlisten(self): self.circuits[186] = FakeCircuit(186) listener = Listener([]) stream = Stream(self) stream.listen(listener) stream.listen(listener) self.assertEqual(len(stream.listeners), 1) stream.unlisten(listener) self.assertEqual(len(stream.listeners), 0)
def test_update_illegal_state(self): self.circuits[186] = FakeCircuit(186) stream = Stream(self) try: stream.update( "316 FOO 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) self.fail() except Exception as e: self.assertTrue('Unknown state' in str(e))
def test_ipv6(self): listener = Listener([('new', { 'target_host': '::1', 'target_port': 80 })]) stream = Stream(self) stream.listen(listener) stream.update( "1234 NEW 0 ::1:80 SOURCE_ADDR=127.0.0.1:57349 PURPOSE=USER".split( ))
def test_ipv6_source(self): listener = Listener([('new', { 'source_addr': maybe_ip_addr('::1'), 'source_port': 12345 })]) stream = Stream(self) stream.listen(listener) stream.update( "1234 NEW 0 127.0.0.1:80 SOURCE_ADDR=::1:12345 PURPOSE=USER".split( ))
def test_update_wrong_stream(self): self.circuits[186] = FakeCircuit(186) stream = Stream(self) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) try: stream.update("999 SENTCONNECT 186 1.2.3.4:80 SOURCE=EXIT".split()) self.fail() except Exception as e: self.assertTrue('wrong stream' in str(e))
def test_close_stream(self): stream = Stream(self.state) stream.id = 1 try: self.state.close_stream(stream) self.assertTrue(False) except KeyError: pass self.state.streams[1] = stream self.state.close_stream(stream) self.assertEqual(self.transport.value(), 'CLOSESTREAM 1 1\r\n')
def test_lowercase_flags(self): # testing an internal method, maybe a no-no? stream = Stream(self) kw = dict(FOO='bar', BAR='baz') flags = stream._create_flags(kw) self.assertTrue('FOO' in flags) self.assertTrue('foo' in flags) self.assertTrue(flags['foo'] is flags['FOO']) self.assertTrue('BAR' in flags) self.assertTrue('bar' in flags) self.assertTrue(flags['bar'] is flags['BAR'])
def test_attach_failure_unfound(self): @implementer(ICircuitContainer) class FakeContainer(object): pass reactor = Mock() container = FakeContainer() stream = Stream(container) state = Mock() attacher = yield _get_circuit_attacher(reactor, state) attacher.attach_stream_failure(stream, None)
def test_closed_remaining_streams(self): tor = FakeTorController() circuit = Circuit(tor) circuit.listen(tor) circuit.update('1 LAUNCHED PURPOSE=GENERAL'.split()) stream = Stream(tor) stream.update("1 NEW 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH".split()) circuit.streams.append(stream) self.assertEqual(len(circuit.streams), 1) circuit.update('1 CLOSED $E11D2B2269CC25E67CA6C9FB5843497539A74FD0=eris,$50DD343021E509EB3A5A7FD0D8A4F8364AFBDCB5=venus,$253DFF1838A2B7782BE7735F74E50090D46CA1BC=chomsky PURPOSE=GENERAL REASON=FINISHED'.split()) circuit.update('1 FAILED $E11D2B2269CC25E67CA6C9FB5843497539A74FD0=eris,$50DD343021E509EB3A5A7FD0D8A4F8364AFBDCB5=venus,$253DFF1838A2B7782BE7735F74E50090D46CA1BC=chomsky PURPOSE=GENERAL REASON=TIMEOUT'.split()) errs = self.flushLoggedErrors() self.assertEqual(len(errs), 2)
def test_states_and_uris(self): self.circuits[1] = FakeCircuit(1) stream = Stream(self) for address in [ '1.2.3.4:80', '1.2.3.4.315D5684D5343580D409F16119F78D776A58AEFB.exit:80', 'timaq4ygg2iegci7.onion:80' ]: line = "316 %s 1 %s REASON=FOO" for state in [ 'NEW', 'SUCCEEDED', 'REMAP', 'SENTCONNECT', 'DETACHED', 'NEWRESOLVE', 'SENTRESOLVE', 'FAILED', 'CLOSED' ]: stream.update((line % (state, address)).split(' ')) self.assertEqual(stream.state, state)
def test_listener_attach_no_remap(self): "Attachment is via SENTCONNECT on .onion addresses (for example)" self.circuits[186] = FakeCircuit(186) listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', {})]) stream = Stream(self) stream.listen(listener) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("316 SENTCONNECT 186 1.2.3.4:80 SOURCE=EXIT".split()) self.assertEqual(self.circuits[186].streams[0], stream)
def test_close_stream(self): self.circuits[186] = FakeCircuit(186) stream = Stream(self) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split()) self.assertEqual(len(self.circuits[186].streams), 1) d = stream.close() self.assertTrue(not d.called) self.assertEqual(len(self.circuits[186].streams), 1) stream.update( "316 CLOSED 186 1.2.3.4:80 REASON=END REMOTE_REASON=DONE".split()) self.assertTrue(d.called) self.assertEqual(len(self.circuits[186].streams), 0)
def test_listener_attach(self): self.circuits[186] = FakeCircuit(186) listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', { 'target_addr': maybe_ip_addr('1.2.3.4') })]) stream = Stream(self) stream.listen(listener) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split()) self.assertEqual(self.circuits[186].streams[0], stream)
def test_attach(self): @implementer(ICircuitContainer) class FakeContainer(object): pass container = FakeContainer() stream = Stream(container) circuit = Mock() target_endpoint = Mock() reactor = Mock() state = Mock() TorCircuitEndpoint( reactor, state, circuit, target_endpoint, ) attacher = yield _get_circuit_attacher(reactor, state) attacher.add_endpoint(target_endpoint, circuit) yield attacher.attach_stream(stream, [])
def test_listener_exception(self): """A listener throws an exception during notify""" exc = Exception("the bad stuff happened") class Bad(StreamListenerMixin): def stream_new(*args, **kw): raise exc listener = Bad() stream = Stream(self) stream.listen(listener) stream.update( "1 NEW 0 94.23.164.42.$43ED8310EB968746970896E8835C2F1991E50B69.exit:9001 SOURCE_ADDR=(Tor_internal):0 PURPOSE=DIR_FETCH" .split()) errors = self.flushLoggedErrors() self.assertEqual(1, len(errors)) self.assertEqual(errors[0].value, exc)
def test_listener_close(self): self.circuits[186] = FakeCircuit(186) listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', { 'target_addr': maybe_ip_addr('1.2.3.4') }), ('closed', { 'kwargs': dict(REASON='END', REMOTE_REASON='DONE') })]) stream = Stream(self) stream.listen(listener) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split()) stream.update( "316 CLOSED 186 1.2.3.4:80 REASON=END REMOTE_REASON=DONE".split()) self.assertEqual(len(self.circuits[186].streams), 0)
def test_listener_fail(self): listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', { 'target_addr': maybe_ip_addr('1.2.3.4') }), ('failed', { 'kwargs': dict(REASON='TIMEOUT', REMOTE_REASON='DESTROYED') })]) stream = Stream(self) stream.listen(listener) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) self.circuits[186] = FakeCircuit(186) stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split()) stream.update( "316 FAILED 0 1.2.3.4:80 REASON=TIMEOUT REMOTE_REASON=DESTROYED". split())
def test_attacher_errors(self): class MyAttacher(object): implements(IStreamAttacher) def __init__(self, answer): self.streams = [] self.answer = answer def attach_stream(self, stream, circuits): return self.answer self.state.circuits[1] = FakeCircuit(1) attacher = MyAttacher(FakeCircuit(2)) self.state.set_attacher(attacher, FakeReactor(self)) stream = Stream(self.state) stream.id = 3 msg = '' try: self.state._maybe_attach(stream) except Exception, e: msg = str(e)
def test_attacher_errors(self): @implementer(IStreamAttacher) class MyAttacher(object): def __init__(self, answer): self.streams = [] self.answer = answer def attach_stream(self, stream, circuits): return self.answer self.state.circuits[1] = FakeCircuit(1) attacher = MyAttacher(FakeCircuit(2)) self.state.set_attacher(attacher, FakeReactor(self)) stream = Stream(self.state) stream.id = 3 msg = '' try: yield self.state._maybe_attach(stream) except Exception as e: msg = str(e) self.assertTrue('circuit unknown' in msg) attacher.answer = self.state.circuits[1] msg = '' try: yield self.state._maybe_attach(stream) except Exception as e: msg = str(e) self.assertTrue('only attach to BUILT' in msg) attacher.answer = 'not a Circuit instance' msg = '' try: yield self.state._maybe_attach(stream) except Exception as e: msg = str(e) self.assertTrue('Circuit instance' in msg)
def test_stream_changed(self): "Change a stream-id mid-stream." self.circuits[186] = FakeCircuit(186) listener = Listener([('new', { 'target_host': 'www.yahoo.com', 'target_port': 80 }), ('attach', {}), ('succeeded', {})]) stream = Stream(self) stream.listen(listener) stream.update( "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER" .split()) stream.update("316 SENTCONNECT 186 1.2.3.4:80 SOURCE=EXIT".split()) self.assertEqual(self.circuits[186].streams[0], stream) # magically change circuit ID without a DETACHED, should fail stream.update("316 SUCCEEDED 999 1.2.3.4:80 SOURCE=EXIT".split()) errs = self.flushLoggedErrors() self.assertEqual(len(errs), 1) # kind of fragile to look at strings, but... self.assertTrue('186 to 999' in str(errs[0]))
def test_ipv6_remap(self): stream = Stream(self) stream.update( "1234 REMAP 0 ::1:80 SOURCE_ADDR=127.0.0.1:57349 PURPOSE=USER". split()) self.assertEqual(stream.target_addr, maybe_ip_addr('::1'))