|  | @@ -0,0 +1,446 @@
 | 
	
		
			
				|  |  | +# Copyright 2015, Google Inc.
 | 
	
		
			
				|  |  | +# All rights reserved.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# Redistribution and use in source and binary forms, with or without
 | 
	
		
			
				|  |  | +# modification, are permitted provided that the following conditions are
 | 
	
		
			
				|  |  | +# met:
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +#     * Redistributions of source code must retain the above copyright
 | 
	
		
			
				|  |  | +# notice, this list of conditions and the following disclaimer.
 | 
	
		
			
				|  |  | +#     * Redistributions in binary form must reproduce the above
 | 
	
		
			
				|  |  | +# copyright notice, this list of conditions and the following disclaimer
 | 
	
		
			
				|  |  | +# in the documentation and/or other materials provided with the
 | 
	
		
			
				|  |  | +# distribution.
 | 
	
		
			
				|  |  | +#     * Neither the name of Google Inc. nor the names of its
 | 
	
		
			
				|  |  | +# contributors may be used to endorse or promote products derived from
 | 
	
		
			
				|  |  | +# this software without specific prior written permission.
 | 
	
		
			
				|  |  | +#
 | 
	
		
			
				|  |  | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
	
		
			
				|  |  | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
	
		
			
				|  |  | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
	
		
			
				|  |  | +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
	
		
			
				|  |  | +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
	
		
			
				|  |  | +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
	
		
			
				|  |  | +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
	
		
			
				|  |  | +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
	
		
			
				|  |  | +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
	
		
			
				|  |  | +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
	
		
			
				|  |  | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +"""Code for making a service.TestService more amenable to use in tests."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import collections
 | 
	
		
			
				|  |  | +import threading
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# testing_control, interfaces, and testing_service are referenced from
 | 
	
		
			
				|  |  | +# specification in this module.
 | 
	
		
			
				|  |  | +from _framework.face import exceptions
 | 
	
		
			
				|  |  | +from _framework.face import interfaces as face_interfaces
 | 
	
		
			
				|  |  | +from _framework.face.testing import control as testing_control  # pylint: disable=unused-import
 | 
	
		
			
				|  |  | +from _framework.face.testing import interfaces  # pylint: disable=unused-import
 | 
	
		
			
				|  |  | +from _framework.face.testing import service as testing_service  # pylint: disable=unused-import
 | 
	
		
			
				|  |  | +from _framework.foundation import stream
 | 
	
		
			
				|  |  | +from _framework.foundation import stream_util
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +_IDENTITY = lambda x: x
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class TestServiceDigest(
 | 
	
		
			
				|  |  | +    collections.namedtuple(
 | 
	
		
			
				|  |  | +        'TestServiceDigest',
 | 
	
		
			
				|  |  | +        ['name',
 | 
	
		
			
				|  |  | +         'methods',
 | 
	
		
			
				|  |  | +         'inline_unary_unary_methods',
 | 
	
		
			
				|  |  | +         'inline_unary_stream_methods',
 | 
	
		
			
				|  |  | +         'inline_stream_unary_methods',
 | 
	
		
			
				|  |  | +         'inline_stream_stream_methods',
 | 
	
		
			
				|  |  | +         'event_unary_unary_methods',
 | 
	
		
			
				|  |  | +         'event_unary_stream_methods',
 | 
	
		
			
				|  |  | +         'event_stream_unary_methods',
 | 
	
		
			
				|  |  | +         'event_stream_stream_methods',
 | 
	
		
			
				|  |  | +         'multi_method',
 | 
	
		
			
				|  |  | +         'unary_unary_messages_sequences',
 | 
	
		
			
				|  |  | +         'unary_stream_messages_sequences',
 | 
	
		
			
				|  |  | +         'stream_unary_messages_sequences',
 | 
	
		
			
				|  |  | +         'stream_stream_messages_sequences'])):
 | 
	
		
			
				|  |  | +  """A transformation of a service.TestService.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Attributes:
 | 
	
		
			
				|  |  | +    name: The RPC service name to be used in the test.
 | 
	
		
			
				|  |  | +    methods: A sequence of interfaces.Method objects describing the RPC
 | 
	
		
			
				|  |  | +      methods that will be called during the test.
 | 
	
		
			
				|  |  | +    inline_unary_unary_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.InlineValueInValueOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      in-line calls to behaviors under test.
 | 
	
		
			
				|  |  | +    inline_unary_stream_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.InlineValueInStreamOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      in-line calls to behaviors under test.
 | 
	
		
			
				|  |  | +    inline_stream_unary_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.InlineStreamInValueOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      in-line calls to behaviors under test.
 | 
	
		
			
				|  |  | +    inline_stream_stream_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.InlineStreamInStreamOutMethod object to be used in tests
 | 
	
		
			
				|  |  | +      of in-line calls to behaviors under test.
 | 
	
		
			
				|  |  | +    event_unary_unary_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.EventValueInValueOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      event-driven calls to behaviors under test.
 | 
	
		
			
				|  |  | +    event_unary_stream_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.EventValueInStreamOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      event-driven calls to behaviors under test.
 | 
	
		
			
				|  |  | +    event_stream_unary_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.EventStreamInValueOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      event-driven calls to behaviors under test.
 | 
	
		
			
				|  |  | +    event_stream_stream_methods: A dict from method name to
 | 
	
		
			
				|  |  | +      face_interfaces.EventStreamInStreamOutMethod object to be used in tests of
 | 
	
		
			
				|  |  | +      event-driven calls to behaviors under test.
 | 
	
		
			
				|  |  | +    multi_method: A face_interfaces.MultiMethod to be used in tests of generic
 | 
	
		
			
				|  |  | +      calls to behaviors under test.
 | 
	
		
			
				|  |  | +    unary_unary_messages_sequences: A dict from method name to sequence of
 | 
	
		
			
				|  |  | +      service.UnaryUnaryTestMessages objects to be used to test the method
 | 
	
		
			
				|  |  | +      with the given name.
 | 
	
		
			
				|  |  | +    unary_stream_messages_sequences: A dict from method name to sequence of
 | 
	
		
			
				|  |  | +      service.UnaryStreamTestMessages objects to be used to test the method
 | 
	
		
			
				|  |  | +      with the given name.
 | 
	
		
			
				|  |  | +    stream_unary_messages_sequences: A dict from method name to sequence of
 | 
	
		
			
				|  |  | +      service.StreamUnaryTestMessages objects to be used to test the method
 | 
	
		
			
				|  |  | +      with the given name.
 | 
	
		
			
				|  |  | +    stream_stream_messages_sequences: A dict from method name to sequence of
 | 
	
		
			
				|  |  | +      service.StreamStreamTestMessages objects to be used to test the
 | 
	
		
			
				|  |  | +      method with the given name.
 | 
	
		
			
				|  |  | +    serialization: A serial.Serialization object describing serialization
 | 
	
		
			
				|  |  | +      behaviors for all the RPC methods.
 | 
	
		
			
				|  |  | +  """
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _BufferingConsumer(stream.Consumer):
 | 
	
		
			
				|  |  | +  """A trivial Consumer that dumps what it consumes in a user-mutable buffer."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self):
 | 
	
		
			
				|  |  | +    self.consumed = []
 | 
	
		
			
				|  |  | +    self.terminated = False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def consume(self, value):
 | 
	
		
			
				|  |  | +    self.consumed.append(value)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def terminate(self):
 | 
	
		
			
				|  |  | +    self.terminated = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def consume_and_terminate(self, value):
 | 
	
		
			
				|  |  | +    self.consumed.append(value)
 | 
	
		
			
				|  |  | +    self.terminated = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_unary_test_method, control):
 | 
	
		
			
				|  |  | +    self._test_method = unary_unary_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request, context):
 | 
	
		
			
				|  |  | +    response_list = []
 | 
	
		
			
				|  |  | +    self._test_method.service(
 | 
	
		
			
				|  |  | +        request, response_list.append, context, self._control)
 | 
	
		
			
				|  |  | +    return response_list.pop(0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _EventUnaryUnaryMethod(face_interfaces.EventValueInValueOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_unary_test_method, control, pool):
 | 
	
		
			
				|  |  | +    self._test_method = unary_unary_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +    self._pool = pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request, response_callback, context):
 | 
	
		
			
				|  |  | +    if self._pool is None:
 | 
	
		
			
				|  |  | +      self._test_method.service(
 | 
	
		
			
				|  |  | +          request, response_callback, context, self._control)
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +      self._pool.submit(
 | 
	
		
			
				|  |  | +          self._test_method.service, request, response_callback, context,
 | 
	
		
			
				|  |  | +          self._control)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_stream_test_method, control):
 | 
	
		
			
				|  |  | +    self._test_method = unary_stream_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request, context):
 | 
	
		
			
				|  |  | +    response_consumer = _BufferingConsumer()
 | 
	
		
			
				|  |  | +    self._test_method.service(
 | 
	
		
			
				|  |  | +        request, response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +    for response in response_consumer.consumed:
 | 
	
		
			
				|  |  | +      yield response
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _EventUnaryStreamMethod(face_interfaces.EventValueInStreamOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_stream_test_method, control, pool):
 | 
	
		
			
				|  |  | +    self._test_method = unary_stream_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +    self._pool = pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request, response_consumer, context):
 | 
	
		
			
				|  |  | +    if self._pool is None:
 | 
	
		
			
				|  |  | +      self._test_method.service(
 | 
	
		
			
				|  |  | +          request, response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +      self._pool.submit(
 | 
	
		
			
				|  |  | +          self._test_method.service, request, response_consumer, context,
 | 
	
		
			
				|  |  | +          self._control)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, stream_unary_test_method, control):
 | 
	
		
			
				|  |  | +    self._test_method = stream_unary_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request_iterator, context):
 | 
	
		
			
				|  |  | +    response_list = []
 | 
	
		
			
				|  |  | +    request_consumer = self._test_method.service(
 | 
	
		
			
				|  |  | +        response_list.append, context, self._control)
 | 
	
		
			
				|  |  | +    for request in request_iterator:
 | 
	
		
			
				|  |  | +      request_consumer.consume(request)
 | 
	
		
			
				|  |  | +    request_consumer.terminate()
 | 
	
		
			
				|  |  | +    return response_list.pop(0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _EventStreamUnaryMethod(face_interfaces.EventStreamInValueOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, stream_unary_test_method, control, pool):
 | 
	
		
			
				|  |  | +    self._test_method = stream_unary_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +    self._pool = pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, response_callback, context):
 | 
	
		
			
				|  |  | +    request_consumer = self._test_method.service(
 | 
	
		
			
				|  |  | +        response_callback, context, self._control)
 | 
	
		
			
				|  |  | +    if self._pool is None:
 | 
	
		
			
				|  |  | +      return request_consumer
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, stream_stream_test_method, control):
 | 
	
		
			
				|  |  | +    self._test_method = stream_stream_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, request_iterator, context):
 | 
	
		
			
				|  |  | +    response_consumer = _BufferingConsumer()
 | 
	
		
			
				|  |  | +    request_consumer = self._test_method.service(
 | 
	
		
			
				|  |  | +        response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for request in request_iterator:
 | 
	
		
			
				|  |  | +      request_consumer.consume(request)
 | 
	
		
			
				|  |  | +      while response_consumer.consumed:
 | 
	
		
			
				|  |  | +        yield response_consumer.consumed.pop(0)
 | 
	
		
			
				|  |  | +    response_consumer.terminate()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _EventStreamStreamMethod(face_interfaces.EventStreamInStreamOutMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, stream_stream_test_method, control, pool):
 | 
	
		
			
				|  |  | +    self._test_method = stream_stream_test_method
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +    self._pool = pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, response_consumer, context):
 | 
	
		
			
				|  |  | +    request_consumer = self._test_method.service(
 | 
	
		
			
				|  |  | +        response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +    if self._pool is None:
 | 
	
		
			
				|  |  | +      return request_consumer
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _UnaryConsumer(stream.Consumer):
 | 
	
		
			
				|  |  | +  """A Consumer that only allows consumption of exactly one value."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, action):
 | 
	
		
			
				|  |  | +    self._lock = threading.Lock()
 | 
	
		
			
				|  |  | +    self._action = action
 | 
	
		
			
				|  |  | +    self._consumed = False
 | 
	
		
			
				|  |  | +    self._terminated = False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def consume(self, value):
 | 
	
		
			
				|  |  | +    with self._lock:
 | 
	
		
			
				|  |  | +      if self._consumed:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer already consumed!')
 | 
	
		
			
				|  |  | +      elif self._terminated:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer already terminated!')
 | 
	
		
			
				|  |  | +      else:
 | 
	
		
			
				|  |  | +        self._consumed = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    self._action(value)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def terminate(self):
 | 
	
		
			
				|  |  | +    with self._lock:
 | 
	
		
			
				|  |  | +      if not self._consumed:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer hasn\'t yet consumed!')
 | 
	
		
			
				|  |  | +      elif self._terminated:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer already terminated!')
 | 
	
		
			
				|  |  | +      else:
 | 
	
		
			
				|  |  | +        self._terminated = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def consume_and_terminate(self, value):
 | 
	
		
			
				|  |  | +    with self._lock:
 | 
	
		
			
				|  |  | +      if self._consumed:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer already consumed!')
 | 
	
		
			
				|  |  | +      elif self._terminated:
 | 
	
		
			
				|  |  | +        raise ValueError('Unary consumer already terminated!')
 | 
	
		
			
				|  |  | +      else:
 | 
	
		
			
				|  |  | +        self._consumed = True
 | 
	
		
			
				|  |  | +        self._terminated = True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    self._action(value)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _UnaryUnaryAdaptation(object):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_unary_test_method):
 | 
	
		
			
				|  |  | +    self._method = unary_unary_test_method
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, response_consumer, context, control):
 | 
	
		
			
				|  |  | +    def action(request):
 | 
	
		
			
				|  |  | +      self._method.service(
 | 
	
		
			
				|  |  | +          request, response_consumer.consume_and_terminate, context, control)
 | 
	
		
			
				|  |  | +    return _UnaryConsumer(action)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _UnaryStreamAdaptation(object):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, unary_stream_test_method):
 | 
	
		
			
				|  |  | +    self._method = unary_stream_test_method
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, response_consumer, context, control):
 | 
	
		
			
				|  |  | +    def action(request):
 | 
	
		
			
				|  |  | +      self._method.service(request, response_consumer, context, control)
 | 
	
		
			
				|  |  | +    return _UnaryConsumer(action)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _StreamUnaryAdaptation(object):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, stream_unary_test_method):
 | 
	
		
			
				|  |  | +    self._method = stream_unary_test_method
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, response_consumer, context, control):
 | 
	
		
			
				|  |  | +    return self._method.service(
 | 
	
		
			
				|  |  | +        response_consumer.consume_and_terminate, context, control)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _MultiMethod(face_interfaces.MultiMethod):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def __init__(self, methods, control, pool):
 | 
	
		
			
				|  |  | +    self._methods = methods
 | 
	
		
			
				|  |  | +    self._control = control
 | 
	
		
			
				|  |  | +    self._pool = pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  def service(self, name, response_consumer, context):
 | 
	
		
			
				|  |  | +    method = self._methods.get(name, None)
 | 
	
		
			
				|  |  | +    if method is None:
 | 
	
		
			
				|  |  | +      raise exceptions.NoSuchMethodError(name)
 | 
	
		
			
				|  |  | +    elif self._pool is None:
 | 
	
		
			
				|  |  | +      return method(response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +      request_consumer = method(response_consumer, context, self._control)
 | 
	
		
			
				|  |  | +      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class _Assembly(
 | 
	
		
			
				|  |  | +    collections.namedtuple(
 | 
	
		
			
				|  |  | +        '_Assembly',
 | 
	
		
			
				|  |  | +        ['methods', 'inlines', 'events', 'adaptations', 'messages'])):
 | 
	
		
			
				|  |  | +  """An intermediate structure created when creating a TestServiceDigest."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +def _assemble(
 | 
	
		
			
				|  |  | +    scenarios, names, inline_method_constructor, event_method_constructor,
 | 
	
		
			
				|  |  | +    adapter, control, pool):
 | 
	
		
			
				|  |  | +  """Creates an _Assembly from the given scenarios."""
 | 
	
		
			
				|  |  | +  methods = []
 | 
	
		
			
				|  |  | +  inlines = {}
 | 
	
		
			
				|  |  | +  events = {}
 | 
	
		
			
				|  |  | +  adaptations = {}
 | 
	
		
			
				|  |  | +  messages = {}
 | 
	
		
			
				|  |  | +  for name, scenario in scenarios.iteritems():
 | 
	
		
			
				|  |  | +    if name in names:
 | 
	
		
			
				|  |  | +      raise ValueError('Repeated name "%s"!' % name)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    test_method = scenario[0]
 | 
	
		
			
				|  |  | +    inline_method = inline_method_constructor(test_method, control)
 | 
	
		
			
				|  |  | +    event_method = event_method_constructor(test_method, control, pool)
 | 
	
		
			
				|  |  | +    adaptation = adapter(test_method)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    methods.append(test_method)
 | 
	
		
			
				|  |  | +    inlines[name] = inline_method
 | 
	
		
			
				|  |  | +    events[name] = event_method
 | 
	
		
			
				|  |  | +    adaptations[name] = adaptation
 | 
	
		
			
				|  |  | +    messages[name] = scenario[1]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return _Assembly(methods, inlines, events, adaptations, messages)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +def digest(service, control, pool):
 | 
	
		
			
				|  |  | +  """Creates a TestServiceDigest from a TestService.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Args:
 | 
	
		
			
				|  |  | +    service: A testing_service.TestService.
 | 
	
		
			
				|  |  | +    control: A testing_control.Control.
 | 
	
		
			
				|  |  | +    pool: If RPC methods should be serviced in a separate thread, a thread pool.
 | 
	
		
			
				|  |  | +      None if RPC methods should be serviced in the thread belonging to the
 | 
	
		
			
				|  |  | +      run-time that calls for their service.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Returns:
 | 
	
		
			
				|  |  | +    A TestServiceDigest synthesized from the given service.TestService.
 | 
	
		
			
				|  |  | +  """
 | 
	
		
			
				|  |  | +  names = set()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  unary_unary = _assemble(
 | 
	
		
			
				|  |  | +      service.unary_unary_scenarios(), names, _InlineUnaryUnaryMethod,
 | 
	
		
			
				|  |  | +      _EventUnaryUnaryMethod, _UnaryUnaryAdaptation, control, pool)
 | 
	
		
			
				|  |  | +  names.update(set(unary_unary.inlines))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  unary_stream = _assemble(
 | 
	
		
			
				|  |  | +      service.unary_stream_scenarios(), names, _InlineUnaryStreamMethod,
 | 
	
		
			
				|  |  | +      _EventUnaryStreamMethod, _UnaryStreamAdaptation, control, pool)
 | 
	
		
			
				|  |  | +  names.update(set(unary_stream.inlines))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  stream_unary = _assemble(
 | 
	
		
			
				|  |  | +      service.stream_unary_scenarios(), names, _InlineStreamUnaryMethod,
 | 
	
		
			
				|  |  | +      _EventStreamUnaryMethod, _StreamUnaryAdaptation, control, pool)
 | 
	
		
			
				|  |  | +  names.update(set(stream_unary.inlines))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  stream_stream = _assemble(
 | 
	
		
			
				|  |  | +      service.stream_stream_scenarios(), names, _InlineStreamStreamMethod,
 | 
	
		
			
				|  |  | +      _EventStreamStreamMethod, _IDENTITY, control, pool)
 | 
	
		
			
				|  |  | +  names.update(set(stream_stream.inlines))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  methods = list(unary_unary.methods)
 | 
	
		
			
				|  |  | +  methods.extend(unary_stream.methods)
 | 
	
		
			
				|  |  | +  methods.extend(stream_unary.methods)
 | 
	
		
			
				|  |  | +  methods.extend(stream_stream.methods)
 | 
	
		
			
				|  |  | +  adaptations = dict(unary_unary.adaptations)
 | 
	
		
			
				|  |  | +  adaptations.update(unary_stream.adaptations)
 | 
	
		
			
				|  |  | +  adaptations.update(stream_unary.adaptations)
 | 
	
		
			
				|  |  | +  adaptations.update(stream_stream.adaptations)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return TestServiceDigest(
 | 
	
		
			
				|  |  | +      service.name(),
 | 
	
		
			
				|  |  | +      methods,
 | 
	
		
			
				|  |  | +      unary_unary.inlines,
 | 
	
		
			
				|  |  | +      unary_stream.inlines,
 | 
	
		
			
				|  |  | +      stream_unary.inlines,
 | 
	
		
			
				|  |  | +      stream_stream.inlines,
 | 
	
		
			
				|  |  | +      unary_unary.events,
 | 
	
		
			
				|  |  | +      unary_stream.events,
 | 
	
		
			
				|  |  | +      stream_unary.events,
 | 
	
		
			
				|  |  | +      stream_stream.events,
 | 
	
		
			
				|  |  | +      _MultiMethod(adaptations, control, pool),
 | 
	
		
			
				|  |  | +      unary_unary.messages,
 | 
	
		
			
				|  |  | +      unary_stream.messages,
 | 
	
		
			
				|  |  | +      stream_unary.messages,
 | 
	
		
			
				|  |  | +      stream_stream.messages)
 |