The rest of the Python Beta API
diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py
new file mode 100644
index 0000000..4e46ffd
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_server.py
@@ -0,0 +1,112 @@
+# 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.
+
+"""Beta API server implementation."""
+
+import threading
+
+from grpc._links import service
+from grpc.framework.core import implementations as _core_implementations
+from grpc.framework.crust import implementations as _crust_implementations
+from grpc.framework.foundation import logging_pool
+from grpc.framework.interfaces.links import utilities
+
+_DEFAULT_POOL_SIZE = 8
+_DEFAULT_TIMEOUT = 300
+_MAXIMUM_TIMEOUT = 24 * 60 * 60
+
+
+def _disassemble(grpc_link, end_link, pool, event, grace):
+  grpc_link.begin_stop()
+  end_link.stop(grace).wait()
+  grpc_link.end_stop()
+  grpc_link.join_link(utilities.NULL_LINK)
+  end_link.join_link(utilities.NULL_LINK)
+  if pool is not None:
+    pool.shutdown(wait=True)
+  event.set()
+
+
+class Server(object):
+
+  def __init__(self, grpc_link, end_link, pool):
+    self._grpc_link = grpc_link
+    self._end_link = end_link
+    self._pool = pool
+
+  def add_insecure_port(self, address):
+    return self._grpc_link.add_port(address, None)
+
+  def add_secure_port(self, address, intermediary_low_server_credentials):
+    return self._grpc_link.add_port(
+        address, intermediary_low_server_credentials)
+
+  def start(self):
+    self._grpc_link.join_link(self._end_link)
+    self._end_link.join_link(self._grpc_link)
+    self._grpc_link.start()
+    self._end_link.start()
+
+  def stop(self, grace):
+    stop_event = threading.Event()
+    if 0 < grace:
+      disassembly_thread = threading.Thread(
+          target=_disassemble,
+          args=(
+              self._grpc_link, self._end_link, self._pool, stop_event, grace,))
+      disassembly_thread.start()
+      return stop_event
+    else:
+      _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0)
+      return stop_event
+
+
+def server(
+    implementations, multi_implementation, request_deserializers,
+    response_serializers, thread_pool, thread_pool_size, default_timeout,
+    maximum_timeout):
+  if thread_pool is None:
+    service_thread_pool = logging_pool.pool(
+        _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
+    assembly_thread_pool = service_thread_pool
+  else:
+    service_thread_pool = thread_pool
+    assembly_thread_pool = None
+
+  servicer = _crust_implementations.servicer(
+      implementations, multi_implementation, service_thread_pool)
+
+  grpc_link = service.service_link(request_deserializers, response_serializers)
+
+  end_link = _core_implementations.service_end_link(
+      servicer,
+      _DEFAULT_TIMEOUT if default_timeout is None else default_timeout,
+      _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout)
+
+  return Server(grpc_link, end_link, assembly_thread_pool)
diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py
new file mode 100644
index 0000000..178f06d
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_stub.py
@@ -0,0 +1,109 @@
+# 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.
+
+"""Beta API stub implementation."""
+
+import threading
+
+from grpc._links import invocation
+from grpc.framework.core import implementations as _core_implementations
+from grpc.framework.crust import implementations as _crust_implementations
+from grpc.framework.foundation import logging_pool
+from grpc.framework.interfaces.links import utilities
+
+_DEFAULT_POOL_SIZE = 6
+
+
+class _AutoIntermediary(object):
+
+  def __init__(self, delegate, on_deletion):
+    self._delegate = delegate
+    self._on_deletion = on_deletion
+
+  def __getattr__(self, attr):
+    return getattr(self._delegate, attr)
+
+  def __del__(self):
+    self._on_deletion()
+
+
+def _assemble(
+    channel, host, request_serializers, response_deserializers, thread_pool,
+    thread_pool_size):
+  end_link = _core_implementations.invocation_end_link()
+  grpc_link = invocation.invocation_link(
+      channel, host, request_serializers, response_deserializers)
+  if thread_pool is None:
+    invocation_pool = logging_pool.pool(
+        _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
+    assembly_pool = invocation_pool
+  else:
+    invocation_pool = thread_pool
+    assembly_pool = None
+  end_link.join_link(grpc_link)
+  grpc_link.join_link(end_link)
+  end_link.start()
+  grpc_link.start()
+  return end_link, grpc_link, invocation_pool, assembly_pool
+
+
+def _disassemble(end_link, grpc_link, pool):
+  end_link.stop(24 * 60 * 60).wait()
+  grpc_link.stop()
+  end_link.join_link(utilities.NULL_LINK)
+  grpc_link.join_link(utilities.NULL_LINK)
+  if pool is not None:
+    pool.shutdown(wait=True)
+
+
+def _wrap_assembly(stub, end_link, grpc_link, assembly_pool):
+  disassembly_thread = threading.Thread(
+      target=_disassemble, args=(end_link, grpc_link, assembly_pool))
+  return _AutoIntermediary(stub, disassembly_thread.start)
+
+
+def generic_stub(
+    channel, host, request_serializers, response_deserializers, thread_pool,
+    thread_pool_size):
+  end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+      channel, host, request_serializers, response_deserializers, thread_pool,
+      thread_pool_size)
+  stub = _crust_implementations.generic_stub(end_link, invocation_pool)
+  return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
+
+
+def dynamic_stub(
+    channel, host, service, cardinalities, request_serializers,
+    response_deserializers, thread_pool, thread_pool_size):
+  end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+      channel, host, request_serializers, response_deserializers, thread_pool,
+      thread_pool_size)
+  stub = _crust_implementations.dynamic_stub(
+      end_link, service, cardinalities, invocation_pool)
+  return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
diff --git a/src/python/grpcio/grpc/beta/beta.py b/src/python/grpcio/grpc/beta/beta.py
index 40cad5e..640e4eb 100644
--- a/src/python/grpcio/grpc/beta/beta.py
+++ b/src/python/grpcio/grpc/beta/beta.py
@@ -27,13 +27,21 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Entry points into gRPC Python Beta."""
+"""Entry points into the Beta API of gRPC Python."""
 
+# threading is referenced from specification in this module.
+import abc
 import enum
+import threading  # pylint: disable=unused-import
 
-from grpc._adapter import _low
+# cardinality and face are referenced from specification in this module.
+from grpc._adapter import _intermediary_low
 from grpc._adapter import _types
 from grpc.beta import _connectivity_channel
+from grpc.beta import _server
+from grpc.beta import _stub
+from grpc.framework.common import cardinality  # pylint: disable=unused-import
+from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
 
 _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
     'Exception calling channel subscription callback!')
@@ -65,6 +73,39 @@
 }
 
 
+class ClientCredentials(object):
+  """A value encapsulating the data required to create a secure Channel.
+
+  This class and its instances have no supported interface - it exists to define
+  the type of its instances and its instances exist to be passed to other
+  functions.
+  """
+
+  def __init__(self, low_credentials, intermediary_low_credentials):
+    self._low_credentials = low_credentials
+    self._intermediary_low_credentials = intermediary_low_credentials
+
+
+def ssl_client_credentials(root_certificates, private_key, certificate_chain):
+  """Creates a ClientCredentials for use with an SSL-enabled Channel.
+
+  Args:
+    root_certificates: The PEM-encoded root certificates or None to ask for
+      them to be retrieved from a default location.
+    private_key: The PEM-encoded private key to use or None if no private key
+      should be used.
+    certificate_chain: The PEM-encoded certificate chain to use or None if no
+      certificate chain should be used.
+
+  Returns:
+    A ClientCredentials for use with an SSL-enabled Channel.
+  """
+  intermediary_low_credentials = _intermediary_low.ClientCredentials(
+      root_certificates, private_key, certificate_chain)
+  return ClientCredentials(
+      intermediary_low_credentials._internal, intermediary_low_credentials)  # pylint: disable=protected-access
+
+
 class Channel(object):
   """A channel to a remote host through which RPCs may be conducted.
 
@@ -73,7 +114,9 @@
   unsupported.
   """
 
-  def __init__(self, low_channel):
+  def __init__(self, low_channel, intermediary_low_channel):
+    self._low_channel = low_channel
+    self._intermediary_low_channel = intermediary_low_channel
     self._connectivity_channel = _connectivity_channel.ConnectivityChannel(
         low_channel, _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY)
 
@@ -111,4 +154,336 @@
   Returns:
     A Channel to the remote host through which RPCs may be conducted.
   """
-  return Channel(_low.Channel('%s:%d' % (host, port), ()))
+  intermediary_low_channel = _intermediary_low.Channel(
+      '%s:%d' % (host, port), None)
+  return Channel(intermediary_low_channel._internal, intermediary_low_channel)  # pylint: disable=protected-access
+
+
+def create_secure_channel(host, port, client_credentials):
+  """Creates a secure Channel to a remote host.
+
+  Args:
+    host: The name of the remote host to which to connect.
+    port: The port of the remote host to which to connect.
+    client_credentials: A ClientCredentials.
+
+  Returns:
+    A secure Channel to the remote host through which RPCs may be conducted.
+  """
+  intermediary_low_channel = _intermediary_low.Channel(
+      '%s:%d' % (host, port), client_credentials.intermediary_low_credentials)
+  return Channel(intermediary_low_channel._internal, intermediary_low_channel)  # pylint: disable=protected-access
+
+
+class StubOptions(object):
+  """A value encapsulating the various options for creation of a Stub.
+
+  This class and its instances have no supported interface - it exists to define
+  the type of its instances and its instances exist to be passed to other
+  functions.
+  """
+
+  def __init__(
+      self, host, request_serializers, response_deserializers,
+      metadata_transformer, thread_pool, thread_pool_size):
+    self.host = host
+    self.request_serializers = request_serializers
+    self.response_deserializers = response_deserializers
+    self.metadata_transformer = metadata_transformer
+    self.thread_pool = thread_pool
+    self.thread_pool_size = thread_pool_size
+
+_EMPTY_STUB_OPTIONS = StubOptions(
+    None, None, None, None, None, None)
+
+
+def stub_options(
+    host=None, request_serializers=None, response_deserializers=None,
+    metadata_transformer=None, thread_pool=None, thread_pool_size=None):
+  """Creates a StubOptions value to be passed at stub creation.
+
+  All parameters are optional and should always be passed by keyword.
+
+  Args:
+    host: A host string to set on RPC calls.
+    request_serializers: A dictionary from service name-method name pair to
+      request serialization behavior.
+    response_deserializers: A dictionary from service name-method name pair to
+      response deserialization behavior.
+    metadata_transformer: A callable that given a metadata object produces
+      another metadata object to be used in the underlying communication on the
+      wire.
+    thread_pool: A thread pool to use in stubs.
+    thread_pool_size: The size of thread pool to create for use in stubs;
+      ignored if thread_pool has been passed.
+
+  Returns:
+    A StubOptions value created from the passed parameters.
+  """
+  return StubOptions(
+      host, request_serializers, response_deserializers,
+      metadata_transformer, thread_pool, thread_pool_size)
+
+
+def generic_stub(channel, options=None):
+  """Creates a face.GenericStub on which RPCs can be made.
+
+  Args:
+    channel: A Channel for use by the created stub.
+    options: A StubOptions customizing the created stub.
+
+  Returns:
+    A face.GenericStub on which RPCs can be made.
+  """
+  effective_options = _EMPTY_STUB_OPTIONS if options is None else options
+  return _stub.generic_stub(
+      channel._intermediary_low_channel, effective_options.host,  # pylint: disable=protected-access
+      effective_options.request_serializers,
+      effective_options.response_deserializers, effective_options.thread_pool,
+      effective_options.thread_pool_size)
+
+
+def dynamic_stub(channel, service, cardinalities, options=None):
+  """Creates a face.DynamicStub with which RPCs can be invoked.
+
+  Args:
+    channel: A Channel for the returned face.DynamicStub to use.
+    service: The package-qualified full name of the service.
+    cardinalities: A dictionary from RPC method name to cardinality.Cardinality
+      value identifying the cardinality of the RPC method.
+    options: An optional StubOptions value further customizing the functionality
+      of the returned face.DynamicStub.
+
+  Returns:
+    A face.DynamicStub with which RPCs can be invoked.
+  """
+  effective_options = StubOptions() if options is None else options
+  return _stub.dynamic_stub(
+      channel._intermediary_low_channel, effective_options.host, service,  # pylint: disable=protected-access
+      cardinalities, effective_options.request_serializers,
+      effective_options.response_deserializers, effective_options.thread_pool,
+      effective_options.thread_pool_size)
+
+
+class ServerCredentials(object):
+  """A value encapsulating the data required to open a secure port on a Server.
+
+  This class and its instances have no supported interface - it exists to define
+  the type of its instances and its instances exist to be passed to other
+  functions.
+  """
+
+  def __init__(self, low_credentials, intermediary_low_credentials):
+    self._low_credentials = low_credentials
+    self._intermediary_low_credentials = intermediary_low_credentials
+
+
+def ssl_server_credentials(
+    private_key_certificate_chain_pairs, root_certificates=None,
+    require_client_auth=False):
+  """Creates a ServerCredentials for use with an SSL-enabled Server.
+
+  Args:
+    private_key_certificate_chain_pairs: A nonempty sequence each element of
+      which is a pair the first element of which is a PEM-encoded private key
+      and the second element of which is the corresponding PEM-encoded
+      certificate chain.
+    root_certificates: PEM-encoded client root certificates to be used for
+      verifying authenticated clients. If omitted, require_client_auth must also
+      be omitted or be False.
+    require_client_auth: A boolean indicating whether or not to require clients
+      to be authenticated. May only be True if root_certificates is not None.
+
+  Returns:
+    A ServerCredentials for use with an SSL-enabled Server.
+  """
+  if len(private_key_certificate_chain_pairs) == 0:
+    raise ValueError(
+        'At least one private key-certificate chain pairis required!')
+  elif require_client_auth and root_certificates is None:
+    raise ValueError(
+        'Illegal to require client auth without providing root certificates!')
+  else:
+    intermediary_low_credentials = _intermediary_low.ServerCredentials(
+        root_certificates, private_key_certificate_chain_pairs,
+        require_client_auth)
+    return ServerCredentials(
+        intermediary_low_credentials._internal, intermediary_low_credentials)  # pylint: disable=protected-access
+
+
+class Server(object):
+  """Services RPCs."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def add_insecure_port(self, address):
+    """Reserves a port for insecure RPC service once this Server becomes active.
+
+    This method may only be called before calling this Server's start method is
+    called.
+
+    Args:
+      address: The address for which to open a port.
+
+    Returns:
+      An integer port on which RPCs will be serviced after this link has been
+        started. This is typically the same number as the port number contained
+        in the passed address, but will likely be different if the port number
+        contained in the passed address was zero.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def add_secure_port(self, address, server_credentials):
+    """Reserves a port for secure RPC service after this Server becomes active.
+
+    This method may only be called before calling this Server's start method is
+    called.
+
+    Args:
+      address: The address for which to open a port.
+      server_credentials: A ServerCredentials.
+
+    Returns:
+      An integer port on which RPCs will be serviced after this link has been
+        started. This is typically the same number as the port number contained
+        in the passed address, but will likely be different if the port number
+        contained in the passed address was zero.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def start(self):
+    """Starts this Server's service of RPCs.
+
+    This method may only be called while the server is not serving RPCs (i.e. it
+    is not idempotent).
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop(self, grace):
+    """Stops this Server's service of RPCs.
+
+    All calls to this method immediately stop service of new RPCs. When existing
+    RPCs are aborted is controlled by the grace period parameter passed to this
+    method.
+
+    This method may be called at any time and is idempotent. Passing a smaller
+    grace value than has been passed in a previous call will have the effect of
+    stopping the Server sooner. Passing a larger grace value than has been
+    passed in a previous call will not have the effect of stopping the sooner
+    later.
+
+    Args:
+      grace: A duration of time in seconds to allow existing RPCs to complete
+        before being aborted by this Server's stopping. May be zero for
+        immediate abortion of all in-progress RPCs.
+
+    Returns:
+      A threading.Event that will be set when this Server has completely
+      stopped. The returned event may not be set until after the full grace
+      period (if some ongoing RPC continues for the full length of the period)
+      of it may be set much sooner (such as if this Server had no RPCs underway
+      at the time it was stopped or if all RPCs that it had underway completed
+      very early in the grace period).
+    """
+    raise NotImplementedError()
+
+
+class ServerOptions(object):
+  """A value encapsulating the various options for creation of a Server.
+
+  This class and its instances have no supported interface - it exists to define
+  the type of its instances and its instances exist to be passed to other
+  functions.
+  """
+
+  def __init__(
+      self, multi_method_implementation, request_deserializers,
+      response_serializers, thread_pool, thread_pool_size, default_timeout,
+      maximum_timeout):
+    self.multi_method_implementation = multi_method_implementation
+    self.request_deserializers = request_deserializers
+    self.response_serializers = response_serializers
+    self.thread_pool = thread_pool
+    self.thread_pool_size = thread_pool_size
+    self.default_timeout = default_timeout
+    self.maximum_timeout = maximum_timeout
+
+_EMPTY_SERVER_OPTIONS = ServerOptions(
+    None, None, None, None, None, None, None)
+
+
+def server_options(
+    multi_method_implementation=None, request_deserializers=None,
+    response_serializers=None, thread_pool=None, thread_pool_size=None,
+    default_timeout=None, maximum_timeout=None):
+  """Creates a ServerOptions value to be passed at server creation.
+
+  All parameters are optional and should always be passed by keyword.
+
+  Args:
+    multi_method_implementation: A face.MultiMethodImplementation to be called
+      to service an RPC if the server has no specific method implementation for
+      the name of the RPC for which service was requested.
+    request_deserializers: A dictionary from service name-method name pair to
+      request deserialization behavior.
+    response_serializers: A dictionary from service name-method name pair to
+      response serialization behavior.
+    thread_pool: A thread pool to use in stubs.
+    thread_pool_size: The size of thread pool to create for use in stubs;
+      ignored if thread_pool has been passed.
+    default_timeout: A duration in seconds to allow for RPC service when
+      servicing RPCs that did not include a timeout value when invoked.
+    maximum_timeout: A duration in seconds to allow for RPC service when
+      servicing RPCs no matter what timeout value was passed when the RPC was
+      invoked.
+
+  Returns:
+    A StubOptions value created from the passed parameters.
+  """
+  return ServerOptions(
+      multi_method_implementation, request_deserializers, response_serializers,
+      thread_pool, thread_pool_size, default_timeout, maximum_timeout)
+
+
+class _Server(Server):
+
+  def __init__(self, underserver):
+    self._underserver = underserver
+
+  def add_insecure_port(self, address):
+    return self._underserver.add_insecure_port(address)
+
+  def add_secure_port(self, address, server_credentials):
+    return self._underserver.add_secure_port(
+        address, server_credentials._intermediary_low_credentials)  # pylint: disable=protected-access
+
+  def start(self):
+    self._underserver.start()
+
+  def stop(self, grace):
+    return self._underserver.stop(grace)
+
+
+def server(service_implementations, options=None):
+  """Creates a Server with which RPCs can be serviced.
+
+  Args:
+    service_implementations: A dictionary from service name-method name pair to
+      face.MethodImplementation.
+    options: An optional ServerOptions value further customizing the
+      functionality of the returned Server.
+
+  Returns:
+    A Server with which RPCs can be serviced.
+  """
+  effective_options = _EMPTY_SERVER_OPTIONS if options is None else options
+  underserver = _server.server(
+      service_implementations, effective_options.multi_method_implementation,
+      effective_options.request_deserializers,
+      effective_options.response_serializers, effective_options.thread_pool,
+      effective_options.thread_pool_size, effective_options.default_timeout,
+      effective_options.maximum_timeout)
+  return _Server(underserver)
diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py
index 5ef2f6d..f57cde4 100644
--- a/src/python/grpcio/grpc/framework/core/_end.py
+++ b/src/python/grpcio/grpc/framework/core/_end.py
@@ -203,11 +203,11 @@
   def accept_ticket(self, ticket):
     """See links.Link.accept_ticket for specification."""
     with self._lock:
-      if self._cycle is not None and not self._cycle.grace:
+      if self._cycle is not None:
         operation = self._cycle.operations.get(ticket.operation_id)
         if operation is not None:
           operation.handle_ticket(ticket)
-        elif self._servicer_package is not None:
+        elif self._servicer_package is not None and not self._cycle.grace:
           termination_action = _termination_action(
               self._lock, self._stats, ticket.operation_id, self._cycle)
           operation = _operation.service_operate(
diff --git a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py b/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
new file mode 100644
index 0000000..ce4c59c
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
@@ -0,0 +1,137 @@
+# 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.
+
+"""Tests Face interface compliance of the gRPC Python Beta API."""
+
+import collections
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc.beta import beta
+from grpc_test import resources
+from grpc_test import test_common as grpc_test_common
+from grpc_test.beta import test_utilities
+from grpc_test.framework.common import test_constants
+from grpc_test.framework.interfaces.face import test_cases
+from grpc_test.framework.interfaces.face import test_interfaces
+
+_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
+
+
+class _SerializationBehaviors(
+    collections.namedtuple(
+        '_SerializationBehaviors',
+        ('request_serializers', 'request_deserializers', 'response_serializers',
+         'response_deserializers',))):
+  pass
+
+
+def _serialization_behaviors_from_test_methods(test_methods):
+  request_serializers = {}
+  request_deserializers = {}
+  response_serializers = {}
+  response_deserializers = {}
+  for (group, method), test_method in test_methods.iteritems():
+    request_serializers[group, method] = test_method.serialize_request
+    request_deserializers[group, method] = test_method.deserialize_request
+    response_serializers[group, method] = test_method.serialize_response
+    response_deserializers[group, method] = test_method.deserialize_response
+  return _SerializationBehaviors(
+      request_serializers, request_deserializers, response_serializers,
+      response_deserializers)
+
+
+class _Implementation(test_interfaces.Implementation):
+
+  def instantiate(
+      self, methods, method_implementations, multi_method_implementation):
+    serialization_behaviors = _serialization_behaviors_from_test_methods(
+        methods)
+    # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
+    service = next(iter(methods))[0]
+    # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
+    # _digest.TestServiceDigest.
+    cardinalities = {
+        method: method_object.cardinality()
+        for (group, method), method_object in methods.iteritems()}
+
+    server_options = beta.server_options(
+        request_deserializers=serialization_behaviors.request_deserializers,
+        response_serializers=serialization_behaviors.response_serializers,
+        thread_pool_size=test_constants.POOL_SIZE)
+    server = beta.server(method_implementations, options=server_options)
+    server_credentials = beta.ssl_server_credentials(
+        [(resources.private_key(), resources.certificate_chain(),),])
+    port = server.add_secure_port('[::]:0', server_credentials)
+    server.start()
+    client_credentials = beta.ssl_client_credentials(
+        resources.test_root_certificates(), None, None)
+    channel = test_utilities.create_not_really_secure_channel(
+        'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE)
+    stub_options = beta.stub_options(
+        request_serializers=serialization_behaviors.request_serializers,
+        response_deserializers=serialization_behaviors.response_deserializers,
+        thread_pool_size=test_constants.POOL_SIZE)
+    generic_stub = beta.generic_stub(channel, options=stub_options)
+    dynamic_stub = beta.dynamic_stub(
+        channel, service, cardinalities, options=stub_options)
+    return generic_stub, {service: dynamic_stub}, server
+
+  def destantiate(self, memo):
+    memo.stop(test_constants.SHORT_TIMEOUT).wait()
+
+  def invocation_metadata(self):
+    return grpc_test_common.INVOCATION_INITIAL_METADATA
+
+  def initial_metadata(self):
+    return grpc_test_common.SERVICE_INITIAL_METADATA
+
+  def terminal_metadata(self):
+    return grpc_test_common.SERVICE_TERMINAL_METADATA
+
+  def code(self):
+    return _intermediary_low.Code.OK
+
+  def details(self):
+    return grpc_test_common.DETAILS
+
+  def metadata_transmitted(self, original_metadata, transmitted_metadata):
+    return original_metadata is None or grpc_test_common.metadata_transmitted(
+        original_metadata, transmitted_metadata)
+
+
+def load_tests(loader, tests, pattern):
+  return unittest.TestSuite(
+      tests=tuple(
+          loader.loadTestsFromTestCase(test_case_class)
+          for test_case_class in test_cases.test_cases(_Implementation())))
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/test_utilities.py b/src/python/grpcio_test/grpc_test/beta/test_utilities.py
new file mode 100644
index 0000000..3386704
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/test_utilities.py
@@ -0,0 +1,54 @@
+# 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.
+
+"""Test-appropriate entry points into the gRPC Python Beta API."""
+
+from grpc._adapter import _intermediary_low
+from grpc.beta import beta
+
+
+def create_not_really_secure_channel(
+    host, port, client_credentials, server_host_override):
+  """Creates an insecure Channel to a remote host.
+
+  Args:
+    host: The name of the remote host to which to connect.
+    port: The port of the remote host to which to connect.
+    client_credentials: The beta.ClientCredentials with which to connect.
+    server_host_override: The target name used for SSL host name checking.
+
+  Returns:
+    A beta.Channel to the remote host through which RPCs may be conducted.
+  """
+  hostport = '%s:%d' % (host, port)
+  intermediary_low_channel = _intermediary_low.Channel(
+      hostport, client_credentials._intermediary_low_credentials,
+      server_host_override=server_host_override)
+  return beta.Channel(
+      intermediary_low_channel._internal, intermediary_low_channel)
diff --git a/src/python/grpcio_test/grpc_test/credentials/README b/src/python/grpcio_test/grpc_test/credentials/README
new file mode 100644
index 0000000..cb20dcb
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/README
@@ -0,0 +1 @@
+These are test keys *NOT* to be used in production.
diff --git a/src/python/grpcio_test/grpc_test/credentials/ca.pem b/src/python/grpcio_test/grpc_test/credentials/ca.pem
new file mode 100755
index 0000000..6c8511a
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.key b/src/python/grpcio_test/grpc_test/credentials/server1.key
new file mode 100755
index 0000000..143a5b8
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio_test/grpc_test/credentials/server1.pem
new file mode 100755
index 0000000..8e582e5
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
index 8804f3f..b7dd5d4 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -73,6 +73,7 @@
 
     Overriding implementations must call this implementation.
     """
+    self._invoker = None
     self.implementation.destantiate(self._memo)
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
index 5a78b4b..7cb273b 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
@@ -74,6 +74,7 @@
 
     Overriding implementations must call this implementation.
     """
+    self._invoker = None
     self.implementation.destantiate(self._memo)
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index d1107e1..272a37f 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -103,6 +103,7 @@
 
     Overriding implementations must call this implementation.
     """
+    self._invoker = None
     self.implementation.destantiate(self._memo)
     self._digest_pool.shutdown(wait=True)
 
diff --git a/src/python/grpcio_test/grpc_test/resources.py b/src/python/grpcio_test/grpc_test/resources.py
new file mode 100644
index 0000000..2c30453
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/resources.py
@@ -0,0 +1,56 @@
+# 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.
+
+"""Constants and functions for data used in interoperability testing."""
+
+import os
+
+import pkg_resources
+
+_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem'
+_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
+_CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
+
+
+def test_root_certificates():
+  return pkg_resources.resource_string(
+      __name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
+
+
+def prod_root_certificates():
+  return open(os.environ['SSL_CERT_FILE'], mode='rb').read()
+
+
+def private_key():
+  return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH)
+
+
+def certificate_chain():
+  return pkg_resources.resource_string(
+      __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py
index 898ea20..802dd1e 100644
--- a/src/python/grpcio_test/setup.py
+++ b/src/python/grpcio_test/setup.py
@@ -55,6 +55,11 @@
     'grpc_protoc_plugin': [
         'test.proto',
     ],
+    'grpc_test': [
+        'credentials/ca.pem',
+        'credentials/server1.key',
+        'credentials/server1.pem',
+    ],
 }
 
 _SETUP_REQUIRES = (
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index fe5685f..977b02f 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -46,6 +46,7 @@
 # the team...
 "python"$PYVER -m grpc_test._core_over_links_base_interface_test
 "python"$PYVER -m grpc_test._crust_over_core_over_links_face_interface_test
+"python"$PYVER -m grpc_test.beta._face_interface_test
 "python"$PYVER -m grpc_test.framework._crust_over_core_face_interface_test
 "python"$PYVER -m grpc_test.framework.core._base_interface_test