|  | @@ -52,7 +52,6 @@ def wait_for_events(completion_queues, deadline):
 | 
	
		
			
				|  |  |    def set_ith_result(i, completion_queue):
 | 
	
		
			
				|  |  |      result = completion_queue.next(deadline)
 | 
	
		
			
				|  |  |      with lock:
 | 
	
		
			
				|  |  | -      print i, completion_queue, result, time.time() - deadline
 | 
	
		
			
				|  |  |        results[i] = result
 | 
	
		
			
				|  |  |    for i, completion_queue in enumerate(completion_queues):
 | 
	
		
			
				|  |  |      thread = threading.Thread(target=set_ith_result,
 | 
	
	
		
			
				|  | @@ -80,10 +79,12 @@ class InsecureServerInsecureClient(unittest.TestCase):
 | 
	
		
			
				|  |  |      del self.client_channel
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      self.client_completion_queue.shutdown()
 | 
	
		
			
				|  |  | -    while self.client_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN:
 | 
	
		
			
				|  |  | +    while (self.client_completion_queue.next().type !=
 | 
	
		
			
				|  |  | +           _types.EventType.QUEUE_SHUTDOWN):
 | 
	
		
			
				|  |  |        pass
 | 
	
		
			
				|  |  |      self.server_completion_queue.shutdown()
 | 
	
		
			
				|  |  | -    while self.server_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN:
 | 
	
		
			
				|  |  | +    while (self.server_completion_queue.next().type !=
 | 
	
		
			
				|  |  | +           _types.EventType.QUEUE_SHUTDOWN):
 | 
	
		
			
				|  |  |        pass
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      del self.client_completion_queue
 | 
	
	
		
			
				|  | @@ -91,58 +92,68 @@ class InsecureServerInsecureClient(unittest.TestCase):
 | 
	
		
			
				|  |  |      del self.server
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    def testEcho(self):
 | 
	
		
			
				|  |  | -    DEADLINE = time.time()+5
 | 
	
		
			
				|  |  | -    DEADLINE_TOLERANCE = 0.25
 | 
	
		
			
				|  |  | -    CLIENT_METADATA_ASCII_KEY = 'key'
 | 
	
		
			
				|  |  | -    CLIENT_METADATA_ASCII_VALUE = 'val'
 | 
	
		
			
				|  |  | -    CLIENT_METADATA_BIN_KEY = 'key-bin'
 | 
	
		
			
				|  |  | -    CLIENT_METADATA_BIN_VALUE = b'\0'*1000
 | 
	
		
			
				|  |  | -    SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
 | 
	
		
			
				|  |  | -    SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
 | 
	
		
			
				|  |  | -    SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
 | 
	
		
			
				|  |  | -    SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
 | 
	
		
			
				|  |  | -    SERVER_STATUS_CODE = _types.StatusCode.OK
 | 
	
		
			
				|  |  | -    SERVER_STATUS_DETAILS = 'our work is never over'
 | 
	
		
			
				|  |  | -    REQUEST = 'in death a member of project mayhem has a name'
 | 
	
		
			
				|  |  | -    RESPONSE = 'his name is robert paulson'
 | 
	
		
			
				|  |  | -    METHOD = 'twinkies'
 | 
	
		
			
				|  |  | -    HOST = 'hostess'
 | 
	
		
			
				|  |  | +    deadline = time.time() + 5
 | 
	
		
			
				|  |  | +    event_time_tolerance = 2
 | 
	
		
			
				|  |  | +    deadline_tolerance = 0.25
 | 
	
		
			
				|  |  | +    client_metadata_ascii_key = 'key'
 | 
	
		
			
				|  |  | +    client_metadata_ascii_value = 'val'
 | 
	
		
			
				|  |  | +    client_metadata_bin_key = 'key-bin'
 | 
	
		
			
				|  |  | +    client_metadata_bin_value = b'\0'*1000
 | 
	
		
			
				|  |  | +    server_initial_metadata_key = 'init_me_me_me'
 | 
	
		
			
				|  |  | +    server_initial_metadata_value = 'whodawha?'
 | 
	
		
			
				|  |  | +    server_trailing_metadata_key = 'california_is_in_a_drought'
 | 
	
		
			
				|  |  | +    server_trailing_metadata_value = 'zomg it is'
 | 
	
		
			
				|  |  | +    server_status_code = _types.StatusCode.OK
 | 
	
		
			
				|  |  | +    server_status_details = 'our work is never over'
 | 
	
		
			
				|  |  | +    request = 'blarghaflargh'
 | 
	
		
			
				|  |  | +    response = 'his name is robert paulson'
 | 
	
		
			
				|  |  | +    method = 'twinkies'
 | 
	
		
			
				|  |  | +    host = 'hostess'
 | 
	
		
			
				|  |  |      server_request_tag = object()
 | 
	
		
			
				|  |  | -    request_call_result = self.server.request_call(self.server_completion_queue, server_request_tag)
 | 
	
		
			
				|  |  | +    request_call_result = self.server.request_call(self.server_completion_queue,
 | 
	
		
			
				|  |  | +                                                   server_request_tag)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    self.assertEquals(_types.CallError.OK, request_call_result)
 | 
	
		
			
				|  |  | +    self.assertEqual(_types.CallError.OK, request_call_result)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      client_call_tag = object()
 | 
	
		
			
				|  |  | -    client_call = self.client_channel.create_call(self.client_completion_queue, METHOD, HOST, DEADLINE)
 | 
	
		
			
				|  |  | -    client_initial_metadata = [(CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]
 | 
	
		
			
				|  |  | +    client_call = self.client_channel.create_call(
 | 
	
		
			
				|  |  | +        self.client_completion_queue, method, host, deadline)
 | 
	
		
			
				|  |  | +    client_initial_metadata = [
 | 
	
		
			
				|  |  | +        (client_metadata_ascii_key, client_metadata_ascii_value),
 | 
	
		
			
				|  |  | +        (client_metadata_bin_key, client_metadata_bin_value)
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  |      client_start_batch_result = client_call.start_batch([
 | 
	
		
			
				|  |  |          _types.OpArgs.send_initial_metadata(client_initial_metadata),
 | 
	
		
			
				|  |  | -        _types.OpArgs.send_message(REQUEST, 0),
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_message(request, 0),
 | 
	
		
			
				|  |  |          _types.OpArgs.send_close_from_client(),
 | 
	
		
			
				|  |  |          _types.OpArgs.recv_initial_metadata(),
 | 
	
		
			
				|  |  |          _types.OpArgs.recv_message(),
 | 
	
		
			
				|  |  |          _types.OpArgs.recv_status_on_client()
 | 
	
		
			
				|  |  |      ], client_call_tag)
 | 
	
		
			
				|  |  | -    self.assertEquals(_types.CallError.OK, client_start_batch_result)
 | 
	
		
			
				|  |  | +    self.assertEqual(_types.CallError.OK, client_start_batch_result)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    client_no_event, request_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 2)
 | 
	
		
			
				|  |  | -    self.assertEquals(client_no_event, None)
 | 
	
		
			
				|  |  | -    self.assertEquals(_types.EventType.OP_COMPLETE, request_event.type)
 | 
	
		
			
				|  |  | +    client_no_event, request_event, = wait_for_events(
 | 
	
		
			
				|  |  | +        [self.client_completion_queue, self.server_completion_queue],
 | 
	
		
			
				|  |  | +        time.time() + event_time_tolerance)
 | 
	
		
			
				|  |  | +    self.assertEqual(client_no_event, None)
 | 
	
		
			
				|  |  | +    self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
 | 
	
		
			
				|  |  |      self.assertIsInstance(request_event.call, _low.Call)
 | 
	
		
			
				|  |  |      self.assertIs(server_request_tag, request_event.tag)
 | 
	
		
			
				|  |  | -    self.assertEquals(1, len(request_event.results))
 | 
	
		
			
				|  |  | +    self.assertEqual(1, len(request_event.results))
 | 
	
		
			
				|  |  |      received_initial_metadata = dict(request_event.results[0].initial_metadata)
 | 
	
		
			
				|  |  |      # Check that our metadata were transmitted
 | 
	
		
			
				|  |  | -    self.assertEquals(
 | 
	
		
			
				|  |  | +    self.assertEqual(
 | 
	
		
			
				|  |  |          dict(client_initial_metadata),
 | 
	
		
			
				|  |  | -        dict((x, received_initial_metadata[x]) for x in zip(*client_initial_metadata)[0]))
 | 
	
		
			
				|  |  | +        dict((x, received_initial_metadata[x])
 | 
	
		
			
				|  |  | +             for x in zip(*client_initial_metadata)[0]))
 | 
	
		
			
				|  |  |      # Check that Python's user agent string is a part of the full user agent
 | 
	
		
			
				|  |  |      # string
 | 
	
		
			
				|  |  |      self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__),
 | 
	
		
			
				|  |  |                    received_initial_metadata['user-agent'])
 | 
	
		
			
				|  |  | -    self.assertEquals(METHOD, request_event.call_details.method)
 | 
	
		
			
				|  |  | -    self.assertEquals(HOST, request_event.call_details.host)
 | 
	
		
			
				|  |  | -    self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE)
 | 
	
		
			
				|  |  | +    self.assertEqual(method, request_event.call_details.method)
 | 
	
		
			
				|  |  | +    self.assertEqual(host, request_event.call_details.host)
 | 
	
		
			
				|  |  | +    self.assertLess(abs(deadline - request_event.call_details.deadline),
 | 
	
		
			
				|  |  | +                    deadline_tolerance)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      # Check that the channel is connected, and that both it and the call have
 | 
	
		
			
				|  |  |      # the proper target and peer; do this after the first flurry of messages to
 | 
	
	
		
			
				|  | @@ -155,33 +166,43 @@ class InsecureServerInsecureClient(unittest.TestCase):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      server_call_tag = object()
 | 
	
		
			
				|  |  |      server_call = request_event.call
 | 
	
		
			
				|  |  | -    server_initial_metadata = [(SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
 | 
	
		
			
				|  |  | -    server_trailing_metadata = [(SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]
 | 
	
		
			
				|  |  | +    server_initial_metadata = [
 | 
	
		
			
				|  |  | +        (server_initial_metadata_key, server_initial_metadata_value)
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  | +    server_trailing_metadata = [
 | 
	
		
			
				|  |  | +        (server_trailing_metadata_key, server_trailing_metadata_value)
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  |      server_start_batch_result = server_call.start_batch([
 | 
	
		
			
				|  |  |          _types.OpArgs.send_initial_metadata(server_initial_metadata),
 | 
	
		
			
				|  |  |          _types.OpArgs.recv_message(),
 | 
	
		
			
				|  |  | -        _types.OpArgs.send_message(RESPONSE, 0),
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_message(response, 0),
 | 
	
		
			
				|  |  |          _types.OpArgs.recv_close_on_server(),
 | 
	
		
			
				|  |  | -        _types.OpArgs.send_status_from_server(server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_status_from_server(
 | 
	
		
			
				|  |  | +            server_trailing_metadata, server_status_code, server_status_details)
 | 
	
		
			
				|  |  |      ], server_call_tag)
 | 
	
		
			
				|  |  | -    self.assertEquals(_types.CallError.OK, server_start_batch_result)
 | 
	
		
			
				|  |  | +    self.assertEqual(_types.CallError.OK, server_start_batch_result)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    client_event, server_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 1)
 | 
	
		
			
				|  |  | +    client_event, server_event, = wait_for_events(
 | 
	
		
			
				|  |  | +        [self.client_completion_queue, self.server_completion_queue],
 | 
	
		
			
				|  |  | +        time.time() + event_time_tolerance)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    self.assertEquals(6, len(client_event.results))
 | 
	
		
			
				|  |  | +    self.assertEqual(6, len(client_event.results))
 | 
	
		
			
				|  |  |      found_client_op_types = set()
 | 
	
		
			
				|  |  |      for client_result in client_event.results:
 | 
	
		
			
				|  |  | -      self.assertNotIn(client_result.type, found_client_op_types)  # we expect each op type to be unique
 | 
	
		
			
				|  |  | +      # we expect each op type to be unique
 | 
	
		
			
				|  |  | +      self.assertNotIn(client_result.type, found_client_op_types)
 | 
	
		
			
				|  |  |        found_client_op_types.add(client_result.type)
 | 
	
		
			
				|  |  |        if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
 | 
	
		
			
				|  |  | -        self.assertEquals(dict(server_initial_metadata), dict(client_result.initial_metadata))
 | 
	
		
			
				|  |  | +        self.assertEqual(dict(server_initial_metadata),
 | 
	
		
			
				|  |  | +                         dict(client_result.initial_metadata))
 | 
	
		
			
				|  |  |        elif client_result.type == _types.OpType.RECV_MESSAGE:
 | 
	
		
			
				|  |  | -        self.assertEquals(RESPONSE, client_result.message)
 | 
	
		
			
				|  |  | +        self.assertEqual(response, client_result.message)
 | 
	
		
			
				|  |  |        elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
 | 
	
		
			
				|  |  | -        self.assertEquals(dict(server_trailing_metadata), dict(client_result.trailing_metadata))
 | 
	
		
			
				|  |  | -        self.assertEquals(SERVER_STATUS_DETAILS, client_result.status.details)
 | 
	
		
			
				|  |  | -        self.assertEquals(SERVER_STATUS_CODE, client_result.status.code)
 | 
	
		
			
				|  |  | -    self.assertEquals(set([
 | 
	
		
			
				|  |  | +        self.assertEqual(dict(server_trailing_metadata),
 | 
	
		
			
				|  |  | +                         dict(client_result.trailing_metadata))
 | 
	
		
			
				|  |  | +        self.assertEqual(server_status_details, client_result.status.details)
 | 
	
		
			
				|  |  | +        self.assertEqual(server_status_code, client_result.status.code)
 | 
	
		
			
				|  |  | +    self.assertEqual(set([
 | 
	
		
			
				|  |  |            _types.OpType.SEND_INITIAL_METADATA,
 | 
	
		
			
				|  |  |            _types.OpType.SEND_MESSAGE,
 | 
	
		
			
				|  |  |            _types.OpType.SEND_CLOSE_FROM_CLIENT,
 | 
	
	
		
			
				|  | @@ -190,16 +211,16 @@ class InsecureServerInsecureClient(unittest.TestCase):
 | 
	
		
			
				|  |  |            _types.OpType.RECV_STATUS_ON_CLIENT
 | 
	
		
			
				|  |  |        ]), found_client_op_types)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    self.assertEquals(5, len(server_event.results))
 | 
	
		
			
				|  |  | +    self.assertEqual(5, len(server_event.results))
 | 
	
		
			
				|  |  |      found_server_op_types = set()
 | 
	
		
			
				|  |  |      for server_result in server_event.results:
 | 
	
		
			
				|  |  |        self.assertNotIn(client_result.type, found_server_op_types)
 | 
	
		
			
				|  |  |        found_server_op_types.add(server_result.type)
 | 
	
		
			
				|  |  |        if server_result.type == _types.OpType.RECV_MESSAGE:
 | 
	
		
			
				|  |  | -        self.assertEquals(REQUEST, server_result.message)
 | 
	
		
			
				|  |  | +        self.assertEqual(request, server_result.message)
 | 
	
		
			
				|  |  |        elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
 | 
	
		
			
				|  |  |          self.assertFalse(server_result.cancelled)
 | 
	
		
			
				|  |  | -    self.assertEquals(set([
 | 
	
		
			
				|  |  | +    self.assertEqual(set([
 | 
	
		
			
				|  |  |            _types.OpType.SEND_INITIAL_METADATA,
 | 
	
		
			
				|  |  |            _types.OpType.RECV_MESSAGE,
 | 
	
		
			
				|  |  |            _types.OpType.SEND_MESSAGE,
 | 
	
	
		
			
				|  | @@ -211,5 +232,81 @@ class InsecureServerInsecureClient(unittest.TestCase):
 | 
	
		
			
				|  |  |      del server_call
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +class HangingServerShutdown(unittest.TestCase):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def setUp(self):
 | 
	
		
			
				|  |  | +    self.server_completion_queue = _low.CompletionQueue()
 | 
	
		
			
				|  |  | +    self.server = _low.Server(self.server_completion_queue, [])
 | 
	
		
			
				|  |  | +    self.port = self.server.add_http2_port('[::]:0')
 | 
	
		
			
				|  |  | +    self.client_completion_queue = _low.CompletionQueue()
 | 
	
		
			
				|  |  | +    self.client_channel = _low.Channel('localhost:%d'%self.port, [])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    self.server.start()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def tearDown(self):
 | 
	
		
			
				|  |  | +    self.server.shutdown()
 | 
	
		
			
				|  |  | +    del self.client_channel
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    self.client_completion_queue.shutdown()
 | 
	
		
			
				|  |  | +    self.server_completion_queue.shutdown()
 | 
	
		
			
				|  |  | +    while True:
 | 
	
		
			
				|  |  | +      client_event, server_event = wait_for_events(
 | 
	
		
			
				|  |  | +          [self.client_completion_queue, self.server_completion_queue],
 | 
	
		
			
				|  |  | +          float("+inf"))
 | 
	
		
			
				|  |  | +      if (client_event.type == _types.EventType.QUEUE_SHUTDOWN and
 | 
	
		
			
				|  |  | +          server_event.type == _types.EventType.QUEUE_SHUTDOWN):
 | 
	
		
			
				|  |  | +        break
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    del self.client_completion_queue
 | 
	
		
			
				|  |  | +    del self.server_completion_queue
 | 
	
		
			
				|  |  | +    del self.server
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def testHangingServerCall(self):
 | 
	
		
			
				|  |  | +    deadline = time.time() + 5
 | 
	
		
			
				|  |  | +    deadline_tolerance = 0.25
 | 
	
		
			
				|  |  | +    event_time_tolerance = 2
 | 
	
		
			
				|  |  | +    cancel_all_calls_time_tolerance = 0.5
 | 
	
		
			
				|  |  | +    request = 'blarghaflargh'
 | 
	
		
			
				|  |  | +    method = 'twinkies'
 | 
	
		
			
				|  |  | +    host = 'hostess'
 | 
	
		
			
				|  |  | +    server_request_tag = object()
 | 
	
		
			
				|  |  | +    request_call_result = self.server.request_call(self.server_completion_queue,
 | 
	
		
			
				|  |  | +                                                   server_request_tag)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    client_call_tag = object()
 | 
	
		
			
				|  |  | +    client_call = self.client_channel.create_call(self.client_completion_queue,
 | 
	
		
			
				|  |  | +                                                  method, host, deadline)
 | 
	
		
			
				|  |  | +    client_start_batch_result = client_call.start_batch([
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_initial_metadata([]),
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_message(request, 0),
 | 
	
		
			
				|  |  | +        _types.OpArgs.send_close_from_client(),
 | 
	
		
			
				|  |  | +        _types.OpArgs.recv_initial_metadata(),
 | 
	
		
			
				|  |  | +        _types.OpArgs.recv_message(),
 | 
	
		
			
				|  |  | +        _types.OpArgs.recv_status_on_client()
 | 
	
		
			
				|  |  | +    ], client_call_tag)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    client_no_event, request_event, = wait_for_events(
 | 
	
		
			
				|  |  | +        [self.client_completion_queue, self.server_completion_queue],
 | 
	
		
			
				|  |  | +        time.time() + event_time_tolerance)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    # Now try to shutdown the server and expect that we see server shutdown
 | 
	
		
			
				|  |  | +    # almost immediately after calling cancel_all_calls.
 | 
	
		
			
				|  |  | +    with self.assertRaises(RuntimeError):
 | 
	
		
			
				|  |  | +      self.server.cancel_all_calls()
 | 
	
		
			
				|  |  | +    shutdown_tag = object()
 | 
	
		
			
				|  |  | +    self.server.shutdown(shutdown_tag)
 | 
	
		
			
				|  |  | +    pre_cancel_timestamp = time.time()
 | 
	
		
			
				|  |  | +    self.server.cancel_all_calls()
 | 
	
		
			
				|  |  | +    finish_shutdown_timestamp = None
 | 
	
		
			
				|  |  | +    client_call_event, server_shutdown_event = wait_for_events(
 | 
	
		
			
				|  |  | +        [self.client_completion_queue, self.server_completion_queue],
 | 
	
		
			
				|  |  | +        time.time() + event_time_tolerance)
 | 
	
		
			
				|  |  | +    self.assertIs(shutdown_tag, server_shutdown_event.tag)
 | 
	
		
			
				|  |  | +    self.assertGreater(pre_cancel_timestamp + cancel_all_calls_time_tolerance,
 | 
	
		
			
				|  |  | +                       time.time())
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    del client_call
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  if __name__ == '__main__':
 | 
	
		
			
				|  |  |    unittest.main(verbosity=2)
 |