def test_type_def(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testTypedef(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) x = 0xffffffffffffff # 7 bytes of 0xff resp = yield tchannel.thrift( service.testTypedef(thing=x) ) assert resp.headers == {} assert resp.body == x
def test_void_with_headers(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testVoid(request): assert request.headers == {'req': 'header'} return Response(headers={'resp': 'header'}) server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) resp = yield tchannel.thrift( service.testVoid(), headers={'req': 'header'}, ) assert resp.headers == { 'resp': 'header' } assert resp.body is None
def test_void(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testVoid(request): pass server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) resp = yield tchannel.thrift(service.testVoid()) assert resp.headers == {} assert resp.body is None
def test_enum(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testEnum(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) x = ThriftTest.Numberz.FIVE resp = yield tchannel.thrift( service.testEnum(thing=x) ) assert resp.headers == {} assert resp.body == x
def test_map(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testMap(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) x = { 0: 1, 1: 2, 2: 3, 3: 4, -1: -2, } resp = yield tchannel.thrift( service.testMap(thing=x) ) assert resp.headers == {} assert resp.body == x
def test_string_map(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testStringMap(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) x = { 'hello': 'there', 'my': 'name', 'is': 'shirly', } resp = yield tchannel.thrift( service.testStringMap(thing=x) ) assert resp.headers == {} assert resp.body == x
def test_struct(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testStruct(request): assert request.body.thing.string_thing == 'req string' return ThriftTest.Xtruct( string_thing="resp string" ) server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='service', thrift_module=ThriftTest, hostport=server.hostport ) resp = yield tchannel.thrift( service.testStruct(ThriftTest.Xtruct("req string")) ) # verify response assert isinstance(resp, Response) assert resp.headers == {} assert resp.body == ThriftTest.Xtruct("resp string")
def test_binary(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testBinary(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) resp = yield tchannel.thrift( service.testBinary( # this is ThriftTest.Xtruct(string_thing='hi') '\x0c\x00\x00\x0b\x00\x01\x00\x00\x00\x0bhi\x00\x00' ) ) assert resp.headers == {} assert ( resp.body == '\x0c\x00\x00\x0b\x00\x01\x00\x00\x00\x0bhi\x00\x00' )
def test_double(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testDouble(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) resp = yield tchannel.thrift( service.testDouble(-5.235098235) ) assert resp.headers == {} assert resp.body == -5.235098235
def test_oneway(): # Given this test server: server = TChannel(name='server') # TODO - server should raise same exception as client with pytest.raises(AssertionError): @server.thrift.register(ThriftTest) def testOneway(request): pass server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) with pytest.raises(OneWayNotSupportedError): yield tchannel.thrift(service.testOneway(1))
def test_value_expected_but_none_returned_should_error( server, service, ThriftTest, use_thriftrw_server ): # Given this test server: @server.thrift.register(ThriftTest) def testString(request): pass # Make a call: tchannel = TChannel(name='client') if use_thriftrw_server: # With thirftrw the client only sees an unexpected error because # thriftrw always disallows None results for functions that return # values. exc = UnexpectedError else: exc = ValueExpectedError with pytest.raises(exc) as exc_info: yield tchannel.thrift( service.testString('no return!?') ) if not use_thriftrw_server: assert 'Expected a value to be returned' in str(exc_info) assert 'ThriftTest::testString' in str(exc_info)
def test_roundtrip(benchmark): loop = ioloop.IOLoop.current() server = TChannel('benchmark-server') server.listen() clients = [TChannel('benchmark-client') for _ in range(10)] @server.thrift.register(service.KeyValue) def getValue(request): return 'bar' def roundtrip(): @gen.coroutine def doit(): futures = [] # 10 clients send 10 requests concurrently for client in clients: for _ in range(10): futures.append( client.thrift( service.KeyValue.getValue("foo"), hostport=server.hostport, ) ) yield futures return loop.run_sync(doit) # Establish initial connection roundtrip() benchmark(roundtrip)
def test_client_connection_change_callback(): server = TChannel('server') server.listen() @server.raw.register def hello(request): return 'hi' client = TChannel('client') count = [0] def test_cb(peer): count[0] += 1 client._dep_tchannel.peers.get( server.hostport)._on_conn_change_cb = test_cb yield client.raw( hostport=server.hostport, body='work', endpoint='hello', service='server' ) # 1: connection built, 1: sending request, 1: finish sending request assert count[0] == 3
def test_call_response_should_contain_transport_headers( server, service, ThriftTest ): # Given this test server: @server.thrift.register(ThriftTest) def testString(request): return request.body.thing # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.thrift(service.testString('hi')) # verify response assert isinstance(resp, Response) assert resp.headers == {} assert resp.body == 'hi' # verify response transport headers assert isinstance(resp.transport, TransportHeaders) assert resp.transport.scheme == schemes.THRIFT assert resp.transport.failure_domain is None
def keyvalue_server(io_loop, keyvalue, keyvalue_data): server = TChannel(name='keyvalue') server.listen() @server.thrift.register(keyvalue.KeyValue) def getItem(request): assert request.service == 'keyvalue' key = request.body.key if key in keyvalue_data: assert request.headers == {'expect': 'success'} return keyvalue_data[key] else: assert request.headers == {'expect': 'failure'} raise keyvalue.ItemDoesNotExist(key) @server.json.register('putItem') def json_put_item(request): assert request.service == 'keyvalue' assert request.timeout == 0.5 key = request.body['key'] value = request.body['value'] keyvalue_data[key] = value return {'success': True} return server
def test_map_map(server, service, ThriftTest): # Given this test server: map_map = { -4: { -4: -4, -3: -3, -2: -2, -1: -1, }, 4: { 1: 1, 2: 2, 3: 3, 4: 4, }, } @server.thrift.register(ThriftTest) def testMapMap(request): return map_map # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.thrift( service.testMapMap(1) ) assert resp.headers == {} assert resp.body == map_map
def test_second_service_blah_blah( server, service, second_service, ThriftTest, SecondService ): # Given this test server: @server.thrift.register(ThriftTest) def testString(request): return request.body.thing @server.thrift.register(SecondService) def blahBlah(request): pass # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.thrift(service.testString('thing')) assert isinstance(resp, Response) assert resp.headers == {} assert resp.body == 'thing' resp = yield tchannel.thrift(second_service.blahBlah()) assert isinstance(resp, Response) assert resp.headers == {} assert resp.body is None
def test_timeout_during_handshake_is_retried(timeout_server): tchannel = TChannel(name='client', known_peers=[timeout_server]) # We want the client to look for other peers if an INIT times out rather # than raising a timeout error so we expect a NoAvailablePeerError here. with patch.object(connection, 'DEFAULT_INIT_TIMEOUT_SECS', 0.1): with pytest.raises(errors.NoAvailablePeerError): yield tchannel.raw(service='server', endpoint='endpoint')
def test_map(server, service, ThriftTest): # Given this test server: @server.thrift.register(ThriftTest) def testMap(request): return request.body.thing # Make a call: tchannel = TChannel(name='client') x = { 0: 1, 1: 2, 2: 3, 3: 4, -1: -2, } resp = yield tchannel.thrift( service.testMap(thing=x) ) assert resp.headers == {} assert resp.body == x
def test_i32(server, service, ThriftTest): # Given this test server: @server.thrift.register(ThriftTest) def testI32(request): return request.body.thing # Make a call: tchannel = TChannel(name='client') # case #1 resp = yield tchannel.thrift( service.testI32(-1) ) assert resp.headers == {} assert resp.body == -1 # case #2 resp = yield tchannel.thrift( service.testI32(1) ) assert resp.headers == {} assert resp.body == 1
def test_struct_with_headers( server, service, ThriftTest, server_ttypes, client_ttypes ): # Given this test server: @server.thrift.register(ThriftTest) def testStruct(request): assert isinstance(request, Request) assert request.headers == {'req': 'header'} assert request.body.thing.string_thing == 'req string' return Response( server_ttypes.Xtruct( string_thing="resp string" ), headers={'resp': 'header'}, ) # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.thrift( service.testStruct(client_ttypes.Xtruct("req string")), headers={'req': 'header'}, ) # verify response assert isinstance(resp, Response) assert resp.headers == {'resp': 'header'} assert resp.body == client_ttypes.Xtruct("resp string")
def test_endpoint_can_return_just_body(): # Given this test server: server = TChannel(name='server') @server.register(scheme=schemes.RAW) def endpoint(request): return 'resp body' server.listen() # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.call( scheme=schemes.RAW, service='server', arg1='endpoint', hostport=server.hostport, ) # verify response assert isinstance(resp, Response) assert resp.headers == '' # TODO should be is None to match server assert resp.body == 'resp body'
def test_headers_and_body_should_be_optional(): # Given this test server: server = TChannel(name='server') @server.register(scheme=schemes.RAW) def endpoint(request): # assert request.headers is None # TODO uncomment # assert request.body is None # TODO uncomment pass server.listen() # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.call( scheme=schemes.RAW, service='server', arg1='endpoint', hostport=server.hostport, ) # verify response assert isinstance(resp, Response) assert resp.headers == '' # TODO should be None to match server assert resp.body == '' # TODO should be None to match server
def proxy_server(keyvalue_server): server = TChannel(name='keyvalue-proxy') server.listen() # The client that the proxy uses to make requests should be a different # TChannel. That's because TChannel treats all peers (incoming and # outgoing) as the same. So, if the server receives a request and then # uses the same channel to make the request, there's a chance that it gets # forwarded back to the peer that originally made the request. # # This is desirable behavior because we do want to treat all Hyperbahn # nodes as equal. proxy_server_client = TChannel( name='proxy-client', known_peers=[keyvalue_server.hostport], ) @server.register(TChannel.FALLBACK) @gen.coroutine def handler(request): response = yield proxy_server_client.call( scheme=request.transport.scheme, service=request.service, arg1=request.endpoint, arg2=request.headers, arg3=request.body, timeout=request.timeout / 2, retry_on=request.transport.retry_flags, retry_limit=0, shard_key=request.transport.shard_key, routing_delegate=request.transport.routing_delegate, ) raise gen.Return(response) return server
def test_advertise_is_retryable(router_file): from tchannel.tornado.response import Response as TornadoResponse def new_advertise(*args, **kwargs): f = gen.Future() f.set_result( TornadoResponse( argstreams=[closed_stream(b'{}') for i in range(3)], )) return f tchannel = TChannel(name='client') with patch('tchannel.tornado.TChannel.advertise', autospec=True) as mock_advertise: f = gen.Future() f.set_exception(Exception('great sadness')) mock_advertise.return_value = f with pytest.raises(Exception) as e: yield tchannel.advertise(router_file=router_file) assert 'great sadness' in str(e) assert mock_advertise.call_count == 1 mock_advertise.side_effect = new_advertise yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) assert mock_advertise.call_count == 2
def test_exception(server, service, ThriftTest, server_ttypes, client_ttypes): # Given this test server: @server.thrift.register(ThriftTest) def testException(request): if request.body.arg == 'Xception': raise server_ttypes.Xception(errorCode=1001, message=request.body.arg) elif request.body.arg == 'TException': # TODO - what to raise here? We dont want dep on Thrift # so we don't have thrift.TException available to us... raise Exception() # Make a call: tchannel = TChannel(name='client') # case #1 with pytest.raises(client_ttypes.Xception) as e: yield tchannel.thrift(service.testException(arg='Xception')) assert e.value.errorCode == 1001 assert e.value.message == 'Xception' # case #2 with pytest.raises(UnexpectedError): yield tchannel.thrift(service.testException(arg='TException')) # case #3 resp = yield tchannel.thrift(service.testException(arg='something else')) assert isinstance(resp, Response) assert resp.headers == {} assert resp.body is None
def test_nest(server, service, ThriftTest, client_ttypes): # Given this test server: @server.thrift.register(ThriftTest) def testNest(request): return request.body.thing # Make a call: tchannel = TChannel(name='client') xstruct = client_ttypes.Xtruct( string_thing='hi', byte_thing=1, i32_thing=-1, i64_thing=-34359738368, ) xstruct2 = client_ttypes.Xtruct2( byte_thing=1, struct_thing=xstruct, i32_thing=1, ) resp = yield tchannel.thrift( service.testNest(thing=xstruct2) ) assert resp.headers == {} assert resp.body == xstruct2
def test_inbound_will_call_listen_on_tchannel(): tchannel = TChannel('yaboi') assert not tchannel.is_listening() inbound = TChannelInbound(tchannel) inbound.start(None) assert tchannel.is_listening()
def test_error_trace(): tchannel = TChannel('test') class ErrorEventHook(EventHook): def __init__(self): self.request_trace = None self.error_trace = None def before_receive_request(self, request): self.request_trace = request.tracing def after_send_error(self, error): self.error_trace = error.tracing hook = ErrorEventHook() tchannel.hooks.register(hook) tchannel.listen() with pytest.raises(BadRequestError): yield tchannel.call( scheme=schemes.RAW, service='test', arg1='endpoint', hostport=tchannel.hostport, timeout=0.02, ) assert hook.error_trace assert hook.request_trace assert hook.error_trace == hook.request_trace
def test_local_timeout_unconsumed_message(): """Verify that if the client has a local timeout and the server eventually sends the message, the client does not log an "Unconsumed message" warning. """ server = TChannel('server') @server.raw.register('hello') @gen.coroutine def hello(request): yield gen.sleep(0.07) raise gen.Return('eventual response') server.listen() client = TChannel('client') with pytest.raises(TimeoutError): yield client.raw( 'server', 'hello', 'world', timeout=0.05, hostport=server.hostport, # The server will take 70 milliseconds but we allow at most 50. ) # Wait for the server to send the late response and make sure it doesn't # log a warning. with mock.patch.object(connection.log, 'warn') as mock_warn: # :( yield gen.sleep(0.03) assert mock_warn.call_count == 0
def test_advertise_is_retryable(router_file): from tchannel.tornado.response import Response as TornadoResponse def new_advertise(*args, **kwargs): f = gen.Future() f.set_result(TornadoResponse( argstreams=[closed_stream(b'{}') for i in range(3)], )) return f tchannel = TChannel(name='client') with patch( 'tchannel.tornado.TChannel.advertise', autospec=True ) as mock_advertise: f = gen.Future() f.set_exception(Exception('great sadness')) mock_advertise.return_value = f with pytest.raises(Exception) as e: yield tchannel.advertise(router_file=router_file) assert 'great sadness' in str(e) assert mock_advertise.call_count == 1 mock_advertise.side_effect = new_advertise yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) yield tchannel.advertise(router_file=router_file) assert mock_advertise.call_count == 2
def test_roundtrip(benchmark): loop = ioloop.IOLoop.current() server = TChannel('benchmark-server') server.listen() clients = [TChannel('benchmark-client') for _ in range(10)] @server.thrift.register(service.KeyValue) def getValue(request): return 'bar' def roundtrip(): @gen.coroutine def doit(): futures = [] # 10 clients send 10 requests concurrently for client in clients: for _ in range(10): futures.append( client.thrift( service.KeyValue.getValue("foo"), hostport=server.hostport, )) yield futures return loop.run_sync(doit) # Establish initial connection roundtrip() benchmark(roundtrip)
def test_endpoint_can_return_just_body(): # Given this test server: server = TChannel(name='server') @server.json.register def endpoint(request): return {'resp': 'body'} server.listen() # Make a call: tchannel = TChannel(name='client') resp = yield tchannel.json( service='server', endpoint='endpoint', hostport=server.hostport, ) # verify response assert isinstance(resp, Response) assert resp.body == {'resp': 'body'}
def test_parse_host_port(): tchannel = TChannel('test') tchannel.listen() tracer = TChannelZipkinTracer(tchannel) host_span = tracer.parse_host_port() assert tchannel.hostport == "%s:%d" % (host_span.ipv4, host_span.port) assert tchannel.name == host_span.service_name
def test_hostport_gets_set(): tchannel = TChannel(name='holler') tchannel.listen() host, port = tchannel.hostport.split(':') assert tchannel.host == host assert tchannel.port == int(port)
def test_advertise_should_raise_on_invalid_router_file(): tchannel = TChannel(name='client') with pytest.raises(IOError): yield tchannel.advertise(router_file='?~~lala') with pytest.raises(ValueError): yield tchannel.advertise(routers='lala', router_file='?~~lala')
def test_endpoint_not_found(mock_server): tchannel = TChannel(name='test') with pytest.raises(BadRequestError): yield tchannel.raw( service='test-server', endpoint='fooo', hostport=mock_server.hostport, )
def test_headers_should_be_a_map_of_strings(headers, service): tchannel = TChannel('client') with pytest.raises(ValueError): yield tchannel.thrift( request=service.testString('howdy'), headers=headers, )
def test_headers_should_be_a_map_of_strings(headers): tchannel = TChannel('client') with pytest.raises(ValueError): yield tchannel.thrift( request=mock.MagicMock(), headers=headers, )
def test_get_rank_with_imcoming(): server = TChannel('server') server.listen() connection = yield TornadoConnection.outgoing(server.hostport) connection.direction = INCOMING peer = Peer(TChannel('test'), '10.10.101.21:230') calculator = PreferIncomingCalculator() peer.register_incoming_conn(connection) assert sys.maxint != calculator.get_rank(peer)
def test_get_rank_with_outgoing(): server = TChannel('server') server.listen() connection = yield TornadoConnection.outgoing(server.hostport) peer = Peer(TChannel('test'), '10.10.101.21:230') calculator = PreferIncomingCalculator() peer.register_outgoing_conn(connection) assert PreferIncomingCalculator.TIERS[1] == calculator.get_rank(peer)
def test_init_req_header(): with mock.patch.object( TornadoConnection, '_extract_handshake_headers', side_effect=verify_init_header, ) as mock_extract: mock_extract.return_value = None server = TChannel('test_server') server.listen() yield TornadoConnection.outgoing(server.hostport)
def test_tcurl_health(): server = TChannel(name='server') server.listen() response = yield main([ '-s', 'server', '--host', server.hostport, '--health', ]) assert response.body.ok
def test_close_callback_is_called(): server = TChannel('server') server.listen() close_cb = mock.Mock() conn = yield StreamConnection.outgoing(server.hostport, tchannel=mock.MagicMock()) conn.set_close_callback(close_cb) conn.close() close_cb.assert_called_once_with()
def __init__(self, port=None, timeout=None): port = port or 0 self.tchannel = TChannel( name='test', hostport="localhost:%s" % str(port), ) self.timeout = timeout or self.TIMEOUT self.thread = None self.ready = False self.io_loop = None
def run(): app_name = 'keyvalue-client' tchannel = TChannel(app_name) KeyValueClient.setValue("foo", "Hello, world!"), yield tchannel.thrift(KeyValueClient.setValue("foo", "Hello, world!"), ) response = yield tchannel.thrift(KeyValueClient.getValue("foo"), ) print response.body
def test_close_callback_is_called(): server = TChannel('server') server.listen() cb_future = tornado.gen.Future() conn = yield connection.StreamConnection.outgoing( server.hostport, tchannel=mock.MagicMock()) conn.set_close_callback(lambda: cb_future.set_result(True)) conn.close() assert (yield cb_future)
def test_i32(): # Given this test server: server = TChannel(name='server') @server.thrift.register(ThriftTest) def testI32(request): return request.body.thing server.listen() # Make a call: tchannel = TChannel(name='client') service = thrift_request_builder( service='server', thrift_module=ThriftTest, hostport=server.hostport, ) # case #1 resp = yield tchannel.thrift(service.testI32(-1)) assert resp.headers == {} assert resp.body == -1 # case #2 resp = yield tchannel.thrift(service.testI32(1)) assert resp.headers == {} assert resp.body == 1
def test_timeout_should_raise_timeout_error(): # Given this test server: server = TChannel(name='server') @server.register(scheme=schemes.RAW) @gen.coroutine def endpoint(request): yield gen.sleep(0.05) raise gen.Return('hello') server.listen() # Make a call: tchannel = TChannel(name='client') # timeout is less than server, should timeout with pytest.raises(TimeoutError): yield tchannel.call( scheme=schemes.RAW, service='server', arg1='endpoint', hostport=server.hostport, timeout=0.02, ) # timeout is more than server, should not timeout yield tchannel.raw( service='server', endpoint='endpoint', hostport=server.hostport, timeout=0.1, )