From 2a0cb49152a4adeeffd1ee707650d332e4dd37b5 Mon Sep 17 00:00:00 2001
From: Masood Malekghassemi <soltanmm@users.noreply.github.com>
Date: Thu, 22 Oct 2015 17:43:33 -0700
Subject: [PATCH] Bring Python interop tests to the beta API

Also uses the .proto files for the service/stub definitions.
---
 src/python/grpcio_health_checking/commands.py |   8 +-
 src/python/grpcio_test/.gitignore             |   1 +
 src/python/grpcio_test/commands.py            |  49 ++
 .../grpc_interop/_insecure_interop_test.py    |  15 +-
 .../grpc_interop/_secure_interop_test.py      |  25 +-
 src/python/grpcio_test/grpc_interop/client.py |  22 +-
 .../grpcio_test/grpc_interop/empty.proto      |  43 ++
 .../grpcio_test/grpc_interop/empty_pb2.py     |  63 ---
 .../grpcio_test/grpc_interop/messages.proto   | 167 +++++++
 .../grpcio_test/grpc_interop/messages_pb2.py  | 447 ------------------
 .../grpcio_test/grpc_interop/methods.py       | 150 ++----
 src/python/grpcio_test/grpc_interop/server.py |  13 +-
 .../grpcio_test/grpc_interop/test.proto       |  86 ++++
 .../grpcio_test/grpc_interop/test_pb2.py      | 178 -------
 .../grpcio_test/grpc_protoc_plugin/test.proto |   2 +-
 src/python/grpcio_test/setup.py               |   4 +-
 16 files changed, 438 insertions(+), 835 deletions(-)
 create mode 100644 src/python/grpcio_test/grpc_interop/empty.proto
 delete mode 100644 src/python/grpcio_test/grpc_interop/empty_pb2.py
 create mode 100644 src/python/grpcio_test/grpc_interop/messages.proto
 delete mode 100644 src/python/grpcio_test/grpc_interop/messages_pb2.py
 create mode 100644 src/python/grpcio_test/grpc_interop/test.proto
 delete mode 100644 src/python/grpcio_test/grpc_interop/test_pb2.py

diff --git a/src/python/grpcio_health_checking/commands.py b/src/python/grpcio_health_checking/commands.py
index 6a95e679c4..3f4ea6e22f 100644
--- a/src/python/grpcio_health_checking/commands.py
+++ b/src/python/grpcio_health_checking/commands.py
@@ -50,7 +50,7 @@ class BuildProtoModules(setuptools.Command):
     pass
 
   def finalize_options(self):
-    self.protoc_command = 'protoc'
+    self.protoc_command = distutils.spawn.find_executable('protoc')
     self.grpc_python_plugin_command = distutils.spawn.find_executable(
         'grpc_python_plugin')
 
@@ -69,7 +69,11 @@ class BuildProtoModules(setuptools.Command):
         '--python_out={}'.format(root_directory),
         '--python-grpc_out={}'.format(root_directory),
     ] + paths
-    subprocess.check_call(' '.join(command), cwd=root_directory, shell=True)
+    try:
+      subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
+                              stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+      raise Exception('{}\nOutput:\n{}'.format(e.message, e.output))
 
 
 class BuildPy(build_py.build_py):
diff --git a/src/python/grpcio_test/.gitignore b/src/python/grpcio_test/.gitignore
index 4bb4d42dfe..6158313bde 100644
--- a/src/python/grpcio_test/.gitignore
+++ b/src/python/grpcio_test/.gitignore
@@ -5,6 +5,7 @@ dist/
 *.egg
 *.egg/
 *.eggs/
+*_pb2.py
 .coverage
 .coverage.*
 .cache/
diff --git a/src/python/grpcio_test/commands.py b/src/python/grpcio_test/commands.py
index c796d94c76..edaa2aa72d 100644
--- a/src/python/grpcio_test/commands.py
+++ b/src/python/grpcio_test/commands.py
@@ -29,11 +29,14 @@
 
 """Provides distutils command classes for the GRPC Python test setup process."""
 
+import distutils
 import os
 import os.path
+import subprocess
 import sys
 
 import setuptools
+from setuptools.command import build_py
 
 
 class RunTests(setuptools.Command):
@@ -52,6 +55,52 @@ class RunTests(setuptools.Command):
     # We import here to ensure that setup.py has had a chance to install the
     # relevant package eggs first.
     import pytest
+
+    self.run_command('build_proto_modules')
     result = pytest.main(self.pytest_args)
     if result != 0:
       raise SystemExit(result)
+
+
+class BuildProtoModules(setuptools.Command):
+  """Command to generate project *_pb2.py modules from proto files."""
+
+  description = ''
+  user_options = []
+
+  def initialize_options(self):
+    pass
+
+  def finalize_options(self):
+    self.protoc_command = distutils.spawn.find_executable('protoc')
+    self.grpc_python_plugin_command = distutils.spawn.find_executable(
+        'grpc_python_plugin')
+
+  def run(self):
+    paths = []
+    root_directory = os.getcwd()
+    for walk_root, directories, filenames in os.walk(root_directory):
+      for filename in filenames:
+        if filename.endswith('.proto'):
+          paths.append(os.path.join(walk_root, filename))
+    command = [
+        self.protoc_command,
+        '--plugin=protoc-gen-python-grpc={}'.format(
+            self.grpc_python_plugin_command),
+        '-I {}'.format(root_directory),
+        '--python_out={}'.format(root_directory),
+        '--python-grpc_out={}'.format(root_directory),
+    ] + paths
+    try:
+      subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
+                              stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+      raise Exception('{}\nOutput:\n{}'.format(e.message, e.output))
+
+
+class BuildPy(build_py.build_py):
+  """Custom project build command."""
+
+  def run(self):
+    self.run_command('build_proto_modules')
+    build_py.build_py.run(self)
diff --git a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py b/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
index 825988a072..5007be28ff 100644
--- a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
+++ b/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
@@ -31,10 +31,12 @@
 
 import unittest
 
-from grpc.early_adopter import implementations
+from grpc.beta import implementations
 
 from grpc_interop import _interop_test_case
 from grpc_interop import methods
+from grpc_interop import server
+from grpc_interop import test_pb2
 
 
 class InsecureInteropTest(
@@ -42,15 +44,14 @@ class InsecureInteropTest(
     unittest.TestCase):
 
   def setUp(self):
-    self.server = implementations.server(
-        methods.SERVICE_NAME, methods.SERVER_METHODS, 0)
+    self.server = test_pb2.beta_create_TestService_server(methods.TestService())
+    port = self.server.add_insecure_port('[::]:0')
     self.server.start()
-    port = self.server.port()
-    self.stub = implementations.stub(
-        methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port)
+    self.stub = test_pb2.beta_create_TestService_stub(
+        implementations.insecure_channel('[::]', port))
 
   def tearDown(self):
-    self.server.stop()
+    self.server.stop(0)
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py b/src/python/grpcio_test/grpc_interop/_secure_interop_test.py
index a2682dee99..108e15b0f9 100644
--- a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py
+++ b/src/python/grpcio_test/grpc_interop/_secure_interop_test.py
@@ -31,11 +31,14 @@
 
 import unittest
 
-from grpc.early_adopter import implementations
+from grpc.beta import implementations
+
+from grpc_test.beta import test_utilities
 
 from grpc_interop import _interop_test_case
 from grpc_interop import methods
 from grpc_interop import resources
+from grpc_interop import test_pb2
 
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
@@ -45,19 +48,19 @@ class SecureInteropTest(
     unittest.TestCase):
 
   def setUp(self):
-    self.server = implementations.server(
-        methods.SERVICE_NAME, methods.SERVER_METHODS, 0,
-        private_key=resources.private_key(),
-        certificate_chain=resources.certificate_chain())
+    self.server = test_pb2.beta_create_TestService_server(methods.TestService())
+    port = self.server.add_secure_port(
+        '[::]:0', implementations.ssl_server_credentials(
+            [(resources.private_key(), resources.certificate_chain())]))
     self.server.start()
-    port = self.server.port()
-    self.stub = implementations.stub(
-        methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port,
-        secure=True, root_certificates=resources.test_root_certificates(),
-        server_host_override=_SERVER_HOST_OVERRIDE)
+    self.stub = test_pb2.beta_create_TestService_stub(
+        test_utilities.not_really_secure_channel(
+            '[::]', port, implementations.ssl_client_credentials(
+                resources.test_root_certificates(), None, None),
+                _SERVER_HOST_OVERRIDE))
 
   def tearDown(self):
-    self.server.stop()
+    self.server.stop(0)
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio_test/grpc_interop/client.py
index 21e344ca35..b8d5047ca5 100644
--- a/src/python/grpcio_test/grpc_interop/client.py
+++ b/src/python/grpcio_test/grpc_interop/client.py
@@ -32,10 +32,13 @@
 import argparse
 from oauth2client import client as oauth2client_client
 
-from grpc.early_adopter import implementations
+from grpc.beta import implementations
+
+from grpc_test.beta import test_utilities
 
 from grpc_interop import methods
 from grpc_interop import resources
+from grpc_interop import test_pb2
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
@@ -90,15 +93,16 @@ def _stub(args):
     else:
       root_certificates = resources.prod_root_certificates()
 
-    stub = implementations.stub(
-        methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
-        args.server_port, metadata_transformer=metadata_transformer,
-        secure=True, root_certificates=root_certificates,
-        server_host_override=args.server_host_override)
+    channel = test_utilities.not_really_secure_channel(
+        args.server_host, args.server_port,
+        implementations.ssl_client_credentials(root_certificates, None, None),
+        args.server_host_override)
+    stub = test_pb2.beta_create_TestService_stub(
+        channel, metadata_transformer=metadata_transformer)
   else:
-    stub = implementations.stub(
-        methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
-        args.server_port, secure=False)
+    channel = implementations.insecure_channel(
+        args.server_host, args.server_port)
+    stub = test_pb2.beta_create_TestService_stub(channel)
   return stub
 
 
diff --git a/src/python/grpcio_test/grpc_interop/empty.proto b/src/python/grpcio_test/grpc_interop/empty.proto
new file mode 100644
index 0000000000..6d0eb937d6
--- /dev/null
+++ b/src/python/grpcio_test/grpc_interop/empty.proto
@@ -0,0 +1,43 @@
+
+// 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.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// An empty message that you can re-use to avoid defining duplicated empty
+// messages in your project. A typical example is to use it as argument or the
+// return value of a service API. For instance:
+//
+//   service Foo {
+//     rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
+//   };
+//
+message Empty {}
diff --git a/src/python/grpcio_test/grpc_interop/empty_pb2.py b/src/python/grpcio_test/grpc_interop/empty_pb2.py
deleted file mode 100644
index 8c1ce2f13e..0000000000
--- a/src/python/grpcio_test/grpc_interop/empty_pb2.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/empty.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='test/cpp/interop/empty.proto',
-  package='grpc.testing',
-  serialized_pb=_b('\n\x1ctest/cpp/interop/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05\x45mpty')
-)
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-
-
-
-_EMPTY = _descriptor.Descriptor(
-  name='Empty',
-  full_name='grpc.testing.Empty',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=46,
-  serialized_end=53,
-)
-
-DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
-
-Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict(
-  DESCRIPTOR = _EMPTY,
-  __module__ = 'test.cpp.interop.empty_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.Empty)
-  ))
-_sym_db.RegisterMessage(Empty)
-
-
-import abc
-from grpc.early_adopter import implementations
-from grpc.framework.alpha import utilities
-# @@protoc_insertion_point(module_scope)
diff --git a/src/python/grpcio_test/grpc_interop/messages.proto b/src/python/grpcio_test/grpc_interop/messages.proto
new file mode 100644
index 0000000000..193b6c4171
--- /dev/null
+++ b/src/python/grpcio_test/grpc_interop/messages.proto
@@ -0,0 +1,167 @@
+
+// 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.
+
+// Message definitions to be used by integration test service definitions.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// The type of payload that should be returned.
+enum PayloadType {
+  // Compressable text format.
+  COMPRESSABLE = 0;
+
+  // Uncompressable binary format.
+  UNCOMPRESSABLE = 1;
+
+  // Randomly chosen from all other formats defined in this enum.
+  RANDOM = 2;
+}
+
+// Compression algorithms
+enum CompressionType {
+  // No compression
+  NONE = 0;
+  GZIP = 1;
+  DEFLATE = 2;
+}
+
+// A block of data, to simply increase gRPC message size.
+message Payload {
+  // The type of data in body.
+  PayloadType type = 1;
+  // Primary contents of payload.
+  bytes body = 2;
+}
+
+// A protobuf representation for grpc status. This is used by test
+// clients to specify a status that the server should attempt to return.
+message EchoStatus {
+  int32 code = 1;
+  string message = 2;
+}
+
+// Unary request.
+message SimpleRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, server randomly chooses one from other formats.
+  PayloadType response_type = 1;
+
+  // Desired payload size in the response from the server.
+  // If response_type is COMPRESSABLE, this denotes the size before compression.
+  int32 response_size = 2;
+
+  // Optional input payload sent along with the request.
+  Payload payload = 3;
+
+  // Whether SimpleResponse should include username.
+  bool fill_username = 4;
+
+  // Whether SimpleResponse should include OAuth scope.
+  bool fill_oauth_scope = 5;
+
+  // Compression algorithm to be used by the server for the response (stream)
+  CompressionType response_compression = 6;
+
+  // Whether server should return a given status
+  EchoStatus response_status = 7;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+  // Payload to increase message size.
+  Payload payload = 1;
+  // The user the request came from, for verifying authentication was
+  // successful when the client expected it.
+  string username = 2;
+  // OAuth scope.
+  string oauth_scope = 3;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+  // Optional input payload sent along with the request.
+  Payload payload = 1;
+
+  // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+  // Aggregated size of payloads received from the client.
+  int32 aggregated_payload_size = 1;
+}
+
+// Configuration for a particular response.
+message ResponseParameters {
+  // Desired payload sizes in responses from the server.
+  // If response_type is COMPRESSABLE, this denotes the size before compression.
+  int32 size = 1;
+
+  // Desired interval between consecutive responses in the response stream in
+  // microseconds.
+  int32 interval_us = 2;
+}
+
+// Server-streaming request.
+message StreamingOutputCallRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, the payload from each response in the stream
+  // might be of different types. This is to simulate a mixed type of payload
+  // stream.
+  PayloadType response_type = 1;
+
+  // Configuration for each expected response message.
+  repeated ResponseParameters response_parameters = 2;
+
+  // Optional input payload sent along with the request.
+  Payload payload = 3;
+
+  // Compression algorithm to be used by the server for the response (stream)
+  CompressionType response_compression = 6;
+
+  // Whether server should return a given status
+  EchoStatus response_status = 7;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+  // Payload to increase response size.
+  Payload payload = 1;
+}
+
+// For reconnect interop test only.
+// Server tells client whether its reconnects are following the spec and the
+// reconnect backoffs it saw.
+message ReconnectInfo {
+  bool passed = 1;
+  repeated int32 backoff_ms = 2;
+}
diff --git a/src/python/grpcio_test/grpc_interop/messages_pb2.py b/src/python/grpcio_test/grpc_interop/messages_pb2.py
deleted file mode 100644
index 0bf3d86a31..0000000000
--- a/src/python/grpcio_test/grpc_interop/messages_pb2.py
+++ /dev/null
@@ -1,447 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/messages.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='test/cpp/interop/messages.proto',
-  package='grpc.testing',
-  serialized_pb=_b('\n\x1ftest/cpp/interop/messages.proto\x12\x0cgrpc.testing\"@\n\x07Payload\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\"\xb1\x01\n\rSimpleRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x15\n\rresponse_size\x18\x02 \x01(\x05\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x15\n\rfill_username\x18\x04 \x01(\x08\x12\x18\n\x10\x66ill_oauth_scope\x18\x05 \x01(\x08\"_\n\x0eSimpleResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x13\n\x0boauth_scope\x18\x03 \x01(\t\"C\n\x19StreamingInputCallRequest\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\"=\n\x1aStreamingInputCallResponse\x12\x1f\n\x17\x61ggregated_payload_size\x18\x01 \x01(\x05\"7\n\x12ResponseParameters\x12\x0c\n\x04size\x18\x01 \x01(\x05\x12\x13\n\x0binterval_us\x18\x02 \x01(\x05\"\xb5\x01\n\x1aStreamingOutputCallRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12=\n\x13response_parameters\x18\x02 \x03(\x0b\x32 .grpc.testing.ResponseParameters\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\"E\n\x1bStreamingOutputCallResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload*?\n\x0bPayloadType\x12\x10\n\x0c\x43OMPRESSABLE\x10\x00\x12\x12\n\x0eUNCOMPRESSABLE\x10\x01\x12\n\n\x06RANDOM\x10\x02')
-)
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-_PAYLOADTYPE = _descriptor.EnumDescriptor(
-  name='PayloadType',
-  full_name='grpc.testing.PayloadType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='COMPRESSABLE', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='UNCOMPRESSABLE', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='RANDOM', index=2, number=2,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=836,
-  serialized_end=899,
-)
-_sym_db.RegisterEnumDescriptor(_PAYLOADTYPE)
-
-PayloadType = enum_type_wrapper.EnumTypeWrapper(_PAYLOADTYPE)
-COMPRESSABLE = 0
-UNCOMPRESSABLE = 1
-RANDOM = 2
-
-
-
-_PAYLOAD = _descriptor.Descriptor(
-  name='Payload',
-  full_name='grpc.testing.Payload',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='type', full_name='grpc.testing.Payload.type', index=0,
-      number=1, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='body', full_name='grpc.testing.Payload.body', index=1,
-      number=2, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=49,
-  serialized_end=113,
-)
-
-
-_SIMPLEREQUEST = _descriptor.Descriptor(
-  name='SimpleRequest',
-  full_name='grpc.testing.SimpleRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='response_type', full_name='grpc.testing.SimpleRequest.response_type', index=0,
-      number=1, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='response_size', full_name='grpc.testing.SimpleRequest.response_size', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='payload', full_name='grpc.testing.SimpleRequest.payload', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='fill_username', full_name='grpc.testing.SimpleRequest.fill_username', index=3,
-      number=4, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='fill_oauth_scope', full_name='grpc.testing.SimpleRequest.fill_oauth_scope', index=4,
-      number=5, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=116,
-  serialized_end=293,
-)
-
-
-_SIMPLERESPONSE = _descriptor.Descriptor(
-  name='SimpleResponse',
-  full_name='grpc.testing.SimpleResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='payload', full_name='grpc.testing.SimpleResponse.payload', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='username', full_name='grpc.testing.SimpleResponse.username', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='oauth_scope', full_name='grpc.testing.SimpleResponse.oauth_scope', index=2,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=295,
-  serialized_end=390,
-)
-
-
-_STREAMINGINPUTCALLREQUEST = _descriptor.Descriptor(
-  name='StreamingInputCallRequest',
-  full_name='grpc.testing.StreamingInputCallRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='payload', full_name='grpc.testing.StreamingInputCallRequest.payload', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=392,
-  serialized_end=459,
-)
-
-
-_STREAMINGINPUTCALLRESPONSE = _descriptor.Descriptor(
-  name='StreamingInputCallResponse',
-  full_name='grpc.testing.StreamingInputCallResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='aggregated_payload_size', full_name='grpc.testing.StreamingInputCallResponse.aggregated_payload_size', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=461,
-  serialized_end=522,
-)
-
-
-_RESPONSEPARAMETERS = _descriptor.Descriptor(
-  name='ResponseParameters',
-  full_name='grpc.testing.ResponseParameters',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='size', full_name='grpc.testing.ResponseParameters.size', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='interval_us', full_name='grpc.testing.ResponseParameters.interval_us', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=524,
-  serialized_end=579,
-)
-
-
-_STREAMINGOUTPUTCALLREQUEST = _descriptor.Descriptor(
-  name='StreamingOutputCallRequest',
-  full_name='grpc.testing.StreamingOutputCallRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='response_type', full_name='grpc.testing.StreamingOutputCallRequest.response_type', index=0,
-      number=1, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='response_parameters', full_name='grpc.testing.StreamingOutputCallRequest.response_parameters', index=1,
-      number=2, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='payload', full_name='grpc.testing.StreamingOutputCallRequest.payload', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=582,
-  serialized_end=763,
-)
-
-
-_STREAMINGOUTPUTCALLRESPONSE = _descriptor.Descriptor(
-  name='StreamingOutputCallResponse',
-  full_name='grpc.testing.StreamingOutputCallResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='payload', full_name='grpc.testing.StreamingOutputCallResponse.payload', index=0,
-      number=1, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=765,
-  serialized_end=834,
-)
-
-_PAYLOAD.fields_by_name['type'].enum_type = _PAYLOADTYPE
-_SIMPLEREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
-_SIMPLEREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
-_SIMPLERESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
-_STREAMINGINPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
-_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
-_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_parameters'].message_type = _RESPONSEPARAMETERS
-_STREAMINGOUTPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
-_STREAMINGOUTPUTCALLRESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
-DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD
-DESCRIPTOR.message_types_by_name['SimpleRequest'] = _SIMPLEREQUEST
-DESCRIPTOR.message_types_by_name['SimpleResponse'] = _SIMPLERESPONSE
-DESCRIPTOR.message_types_by_name['StreamingInputCallRequest'] = _STREAMINGINPUTCALLREQUEST
-DESCRIPTOR.message_types_by_name['StreamingInputCallResponse'] = _STREAMINGINPUTCALLRESPONSE
-DESCRIPTOR.message_types_by_name['ResponseParameters'] = _RESPONSEPARAMETERS
-DESCRIPTOR.message_types_by_name['StreamingOutputCallRequest'] = _STREAMINGOUTPUTCALLREQUEST
-DESCRIPTOR.message_types_by_name['StreamingOutputCallResponse'] = _STREAMINGOUTPUTCALLRESPONSE
-DESCRIPTOR.enum_types_by_name['PayloadType'] = _PAYLOADTYPE
-
-Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict(
-  DESCRIPTOR = _PAYLOAD,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.Payload)
-  ))
-_sym_db.RegisterMessage(Payload)
-
-SimpleRequest = _reflection.GeneratedProtocolMessageType('SimpleRequest', (_message.Message,), dict(
-  DESCRIPTOR = _SIMPLEREQUEST,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.SimpleRequest)
-  ))
-_sym_db.RegisterMessage(SimpleRequest)
-
-SimpleResponse = _reflection.GeneratedProtocolMessageType('SimpleResponse', (_message.Message,), dict(
-  DESCRIPTOR = _SIMPLERESPONSE,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.SimpleResponse)
-  ))
-_sym_db.RegisterMessage(SimpleResponse)
-
-StreamingInputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingInputCallRequest', (_message.Message,), dict(
-  DESCRIPTOR = _STREAMINGINPUTCALLREQUEST,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallRequest)
-  ))
-_sym_db.RegisterMessage(StreamingInputCallRequest)
-
-StreamingInputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingInputCallResponse', (_message.Message,), dict(
-  DESCRIPTOR = _STREAMINGINPUTCALLRESPONSE,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallResponse)
-  ))
-_sym_db.RegisterMessage(StreamingInputCallResponse)
-
-ResponseParameters = _reflection.GeneratedProtocolMessageType('ResponseParameters', (_message.Message,), dict(
-  DESCRIPTOR = _RESPONSEPARAMETERS,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.ResponseParameters)
-  ))
-_sym_db.RegisterMessage(ResponseParameters)
-
-StreamingOutputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingOutputCallRequest', (_message.Message,), dict(
-  DESCRIPTOR = _STREAMINGOUTPUTCALLREQUEST,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallRequest)
-  ))
-_sym_db.RegisterMessage(StreamingOutputCallRequest)
-
-StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingOutputCallResponse', (_message.Message,), dict(
-  DESCRIPTOR = _STREAMINGOUTPUTCALLRESPONSE,
-  __module__ = 'test.cpp.interop.messages_pb2'
-  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallResponse)
-  ))
-_sym_db.RegisterMessage(StreamingOutputCallResponse)
-
-
-import abc
-from grpc.early_adopter import implementations
-from grpc.framework.alpha import utilities
-# @@protoc_insertion_point(module_scope)
diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio_test/grpc_interop/methods.py
index 8ab5bac302..3ef8545355 100644
--- a/src/python/grpcio_test/grpc_interop/methods.py
+++ b/src/python/grpcio_test/grpc_interop/methods.py
@@ -37,123 +37,53 @@ import time
 
 from oauth2client import client as oauth2client_client
 
-from grpc.framework.alpha import utilities
-from grpc.framework.alpha import exceptions
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import face
 
 from grpc_interop import empty_pb2
 from grpc_interop import messages_pb2
+from grpc_interop import test_pb2
 
 _TIMEOUT = 7
 
 
-def _empty_call(request, unused_context):
-  return empty_pb2.Empty()
+class TestService(test_pb2.BetaTestServiceServicer):
 
-_CLIENT_EMPTY_CALL = utilities.unary_unary_invocation_description(
-    empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString)
-_SERVER_EMPTY_CALL = utilities.unary_unary_service_description(
-    _empty_call, empty_pb2.Empty.FromString,
-    empty_pb2.Empty.SerializeToString)
+  def EmptyCall(self, request, context):
+    return empty_pb2.Empty()
 
-
-def _unary_call(request, unused_context):
-  return messages_pb2.SimpleResponse(
-      payload=messages_pb2.Payload(
-          type=messages_pb2.COMPRESSABLE,
-          body=b'\x00' * request.response_size))
-
-_CLIENT_UNARY_CALL = utilities.unary_unary_invocation_description(
-    messages_pb2.SimpleRequest.SerializeToString,
-    messages_pb2.SimpleResponse.FromString)
-_SERVER_UNARY_CALL = utilities.unary_unary_service_description(
-    _unary_call, messages_pb2.SimpleRequest.FromString,
-    messages_pb2.SimpleResponse.SerializeToString)
-
-
-def _streaming_output_call(request, unused_context):
-  for response_parameters in request.response_parameters:
-    yield messages_pb2.StreamingOutputCallResponse(
-        payload=messages_pb2.Payload(
-            type=request.response_type,
-            body=b'\x00' * response_parameters.size))
-
-_CLIENT_STREAMING_OUTPUT_CALL = utilities.unary_stream_invocation_description(
-    messages_pb2.StreamingOutputCallRequest.SerializeToString,
-    messages_pb2.StreamingOutputCallResponse.FromString)
-_SERVER_STREAMING_OUTPUT_CALL = utilities.unary_stream_service_description(
-    _streaming_output_call,
-    messages_pb2.StreamingOutputCallRequest.FromString,
-    messages_pb2.StreamingOutputCallResponse.SerializeToString)
-
-
-def _streaming_input_call(request_iterator, unused_context):
-  aggregate_size = 0
-  for request in request_iterator:
-    if request.payload and request.payload.body:
-      aggregate_size += len(request.payload.body)
-  return messages_pb2.StreamingInputCallResponse(
-      aggregated_payload_size=aggregate_size)
-
-_CLIENT_STREAMING_INPUT_CALL = utilities.stream_unary_invocation_description(
-    messages_pb2.StreamingInputCallRequest.SerializeToString,
-    messages_pb2.StreamingInputCallResponse.FromString)
-_SERVER_STREAMING_INPUT_CALL = utilities.stream_unary_service_description(
-    _streaming_input_call,
-    messages_pb2.StreamingInputCallRequest.FromString,
-    messages_pb2.StreamingInputCallResponse.SerializeToString)
-
-
-def _full_duplex_call(request_iterator, unused_context):
-  for request in request_iterator:
-    yield messages_pb2.StreamingOutputCallResponse(
+  def UnaryCall(self, request, context):
+    return messages_pb2.SimpleResponse(
         payload=messages_pb2.Payload(
-            type=request.payload.type,
-            body=b'\x00' * request.response_parameters[0].size))
-
-_CLIENT_FULL_DUPLEX_CALL = utilities.stream_stream_invocation_description(
-    messages_pb2.StreamingOutputCallRequest.SerializeToString,
-    messages_pb2.StreamingOutputCallResponse.FromString)
-_SERVER_FULL_DUPLEX_CALL = utilities.stream_stream_service_description(
-    _full_duplex_call,
-    messages_pb2.StreamingOutputCallRequest.FromString,
-    messages_pb2.StreamingOutputCallResponse.SerializeToString)
-
-# NOTE(nathaniel): Apparently this is the same as the full-duplex call?
-_CLIENT_HALF_DUPLEX_CALL = utilities.stream_stream_invocation_description(
-    messages_pb2.StreamingOutputCallRequest.SerializeToString,
-    messages_pb2.StreamingOutputCallResponse.FromString)
-_SERVER_HALF_DUPLEX_CALL = utilities.stream_stream_service_description(
-    _full_duplex_call,
-    messages_pb2.StreamingOutputCallRequest.FromString,
-    messages_pb2.StreamingOutputCallResponse.SerializeToString)
-
-
-SERVICE_NAME = 'grpc.testing.TestService'
-
-_EMPTY_CALL_METHOD_NAME = 'EmptyCall'
-_UNARY_CALL_METHOD_NAME = 'UnaryCall'
-_STREAMING_OUTPUT_CALL_METHOD_NAME = 'StreamingOutputCall'
-_STREAMING_INPUT_CALL_METHOD_NAME = 'StreamingInputCall'
-_FULL_DUPLEX_CALL_METHOD_NAME = 'FullDuplexCall'
-_HALF_DUPLEX_CALL_METHOD_NAME = 'HalfDuplexCall'
-
-CLIENT_METHODS = {
-    _EMPTY_CALL_METHOD_NAME: _CLIENT_EMPTY_CALL,
-    _UNARY_CALL_METHOD_NAME: _CLIENT_UNARY_CALL,
-    _STREAMING_OUTPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_OUTPUT_CALL,
-    _STREAMING_INPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_INPUT_CALL,
-    _FULL_DUPLEX_CALL_METHOD_NAME: _CLIENT_FULL_DUPLEX_CALL,
-    _HALF_DUPLEX_CALL_METHOD_NAME: _CLIENT_HALF_DUPLEX_CALL,
-}
-
-SERVER_METHODS = {
-    _EMPTY_CALL_METHOD_NAME: _SERVER_EMPTY_CALL,
-    _UNARY_CALL_METHOD_NAME: _SERVER_UNARY_CALL,
-    _STREAMING_OUTPUT_CALL_METHOD_NAME: _SERVER_STREAMING_OUTPUT_CALL,
-    _STREAMING_INPUT_CALL_METHOD_NAME: _SERVER_STREAMING_INPUT_CALL,
-    _FULL_DUPLEX_CALL_METHOD_NAME: _SERVER_FULL_DUPLEX_CALL,
-    _HALF_DUPLEX_CALL_METHOD_NAME: _SERVER_HALF_DUPLEX_CALL,
-}
+            type=messages_pb2.COMPRESSABLE,
+            body=b'\x00' * request.response_size))
+
+  def StreamingOutputCall(self, request, context):
+    for response_parameters in request.response_parameters:
+      yield messages_pb2.StreamingOutputCallResponse(
+          payload=messages_pb2.Payload(
+              type=request.response_type,
+              body=b'\x00' * response_parameters.size))
+
+  def StreamingInputCall(self, request_iterator, context):
+    aggregate_size = 0
+    for request in request_iterator:
+      if request.payload and request.payload.body:
+        aggregate_size += len(request.payload.body)
+    return messages_pb2.StreamingInputCallResponse(
+        aggregated_payload_size=aggregate_size)
+
+  def FullDuplexCall(self, request_iterator, context):
+    for request in request_iterator:
+      yield messages_pb2.StreamingOutputCallResponse(
+          payload=messages_pb2.Payload(
+              type=request.payload.type,
+              body=b'\x00' * request.response_parameters[0].size))
+
+  # NOTE(nathaniel): Apparently this is the same as the full-duplex call?
+  # NOTE(atash): It isn't even called in the interop spec (Oct 22 2015)...
+  def HalfDuplexCall(self, request_iterator, context):
+    return self.FullDuplexCall(request_iterator, context)
 
 
 def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope):
@@ -162,7 +92,7 @@ def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope):
         response_type=messages_pb2.COMPRESSABLE, response_size=314159,
         payload=messages_pb2.Payload(body=b'\x00' * 271828),
         fill_username=fill_username, fill_oauth_scope=fill_oauth_scope)
-    response_future = stub.UnaryCall.async(request, _TIMEOUT)
+    response_future = stub.UnaryCall.future(request, _TIMEOUT)
     response = response_future.result()
     if response.payload.type is not messages_pb2.COMPRESSABLE:
       raise ValueError(
@@ -227,7 +157,7 @@ def _cancel_after_begin(stub):
     payloads = [messages_pb2.Payload(body=b'\x00' * size) for size in sizes]
     requests = [messages_pb2.StreamingInputCallRequest(payload=payload)
                 for payload in payloads]
-    responses = stub.StreamingInputCall.async(requests, _TIMEOUT)
+    responses = stub.StreamingInputCall.future(requests, _TIMEOUT)
     responses.cancel()
     if not responses.cancelled():
       raise ValueError('expected call to be cancelled')
@@ -332,7 +262,7 @@ def _timeout_on_sleeping_server(stub):
     time.sleep(0.1)
     try:
       next(response_iterator)
-    except exceptions.ExpirationError:
+    except face.ExpirationError:
       pass
     else:
       raise ValueError('expected call to exceed deadline')
diff --git a/src/python/grpcio_test/grpc_interop/server.py b/src/python/grpcio_test/grpc_interop/server.py
index d4c1b4dbf6..b541087663 100644
--- a/src/python/grpcio_test/grpc_interop/server.py
+++ b/src/python/grpcio_test/grpc_interop/server.py
@@ -33,10 +33,11 @@ import argparse
 import logging
 import time
 
-from grpc.early_adopter import implementations
+from grpc.beta import implementations
 
 from grpc_interop import methods
 from grpc_interop import resources
+from grpc_interop import test_pb2
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
@@ -50,15 +51,15 @@ def serve():
       default=False, type=resources.parse_bool)
   args = parser.parse_args()
 
+  server = test_pb2.beta_create_TestService_server(methods.TestService())
   if args.use_tls:
     private_key = resources.private_key()
     certificate_chain = resources.certificate_chain()
-    server = implementations.server(
-        methods.SERVICE_NAME, methods.SERVER_METHODS, args.port,
-        private_key=private_key, certificate_chain=certificate_chain)
+    credentials = implementations.ssl_server_credentials(
+        [(private_key, certificate_chain)])
+    server.add_secure_port('[::]:{}'.format(args.port), credentials)
   else:
-    server = implementations.server(
-        methods.SERVICE_NAME, methods.SERVER_METHODS, args.port)
+    server.add_insecure_port('[::]:{}'.format(args.port))
 
   server.start()
   logging.info('Server serving.')
diff --git a/src/python/grpcio_test/grpc_interop/test.proto b/src/python/grpcio_test/grpc_interop/test.proto
new file mode 100644
index 0000000000..b499813e56
--- /dev/null
+++ b/src/python/grpcio_test/grpc_interop/test.proto
@@ -0,0 +1,86 @@
+
+// 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.
+
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+
+syntax = "proto3";
+
+import "grpc_interop/empty.proto";
+import "grpc_interop/messages.proto";
+
+package grpc.testing;
+
+// A simple service to test the various types of RPCs and experiment with
+// performance with various types of payload.
+service TestService {
+  // One empty request followed by one empty response.
+  rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
+
+  // One request followed by one response.
+  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+  // One request followed by a sequence of responses (streamed download).
+  // The server returns the payload with client desired type and sizes.
+  rpc StreamingOutputCall(StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by one response (streamed upload).
+  // The server returns the aggregated size of client payload as the result.
+  rpc StreamingInputCall(stream StreamingInputCallRequest)
+      returns (StreamingInputCallResponse);
+
+  // A sequence of requests with each request served by the server immediately.
+  // As one request could lead to multiple responses, this interface
+  // demonstrates the idea of full duplexing.
+  rpc FullDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by a sequence of responses.
+  // The server buffers all the client requests and then serves them in order. A
+  // stream of responses are returned to the client when the server starts with
+  // first request.
+  rpc HalfDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+}
+
+
+// A simple service NOT implemented at servers so clients can test for
+// that case.
+service UnimplementedService {
+  // A call that no server should implement
+  rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty);  
+}
+
+// A service used to control reconnect server.
+service ReconnectService {
+  rpc Start(grpc.testing.Empty) returns (grpc.testing.Empty);
+  rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);
+}
diff --git a/src/python/grpcio_test/grpc_interop/test_pb2.py b/src/python/grpcio_test/grpc_interop/test_pb2.py
deleted file mode 100644
index 71325d5a9f..0000000000
--- a/src/python/grpcio_test/grpc_interop/test_pb2.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-from test.cpp.interop import empty_pb2 as test_dot_cpp_dot_interop_dot_empty__pb2
-from test.cpp.interop import messages_pb2 as test_dot_cpp_dot_interop_dot_messages__pb2
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='test/cpp/interop/test.proto',
-  package='grpc.testing',
-  serialized_pb=_b('\n\x1btest/cpp/interop/test.proto\x12\x0cgrpc.testing\x1a\x1ctest/cpp/interop/empty.proto\x1a\x1ftest/cpp/interop/messages.proto2\xbb\x04\n\x0bTestService\x12\x35\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\x12\x46\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12\'.grpc.testing.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallResponse(\x01\x12i\n\x0e\x46ullDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01\x12i\n\x0eHalfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01')
-  ,
-  dependencies=[test_dot_cpp_dot_interop_dot_empty__pb2.DESCRIPTOR,test_dot_cpp_dot_interop_dot_messages__pb2.DESCRIPTOR,])
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-
-
-
-
-import abc
-from grpc.early_adopter import implementations
-from grpc.framework.alpha import utilities
-class EarlyAdopterTestServiceServicer(object):
-  """<fill me in later!>"""
-  __metaclass__ = abc.ABCMeta
-  @abc.abstractmethod
-  def EmptyCall(self, request, context):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def UnaryCall(self, request, context):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def StreamingOutputCall(self, request, context):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def StreamingInputCall(self, request_iterator, context):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def FullDuplexCall(self, request_iterator, context):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def HalfDuplexCall(self, request_iterator, context):
-    raise NotImplementedError()
-class EarlyAdopterTestServiceServer(object):
-  """<fill me in later!>"""
-  __metaclass__ = abc.ABCMeta
-  @abc.abstractmethod
-  def start(self):
-    raise NotImplementedError()
-  @abc.abstractmethod
-  def stop(self):
-    raise NotImplementedError()
-class EarlyAdopterTestServiceStub(object):
-  """<fill me in later!>"""
-  __metaclass__ = abc.ABCMeta
-  @abc.abstractmethod
-  def EmptyCall(self, request):
-    raise NotImplementedError()
-  EmptyCall.async = None
-  @abc.abstractmethod
-  def UnaryCall(self, request):
-    raise NotImplementedError()
-  UnaryCall.async = None
-  @abc.abstractmethod
-  def StreamingOutputCall(self, request):
-    raise NotImplementedError()
-  StreamingOutputCall.async = None
-  @abc.abstractmethod
-  def StreamingInputCall(self, request_iterator):
-    raise NotImplementedError()
-  StreamingInputCall.async = None
-  @abc.abstractmethod
-  def FullDuplexCall(self, request_iterator):
-    raise NotImplementedError()
-  FullDuplexCall.async = None
-  @abc.abstractmethod
-  def HalfDuplexCall(self, request_iterator):
-    raise NotImplementedError()
-  HalfDuplexCall.async = None
-def early_adopter_create_TestService_server(servicer, port, private_key=None, certificate_chain=None):
-  import test.cpp.interop.empty_pb2
-  import test.cpp.interop.empty_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  method_service_descriptions = {
-    "EmptyCall": utilities.unary_unary_service_description(
-      servicer.EmptyCall,
-      test.cpp.interop.empty_pb2.Empty.FromString,
-      test.cpp.interop.empty_pb2.Empty.SerializeToString,
-    ),
-    "FullDuplexCall": utilities.stream_stream_service_description(
-      servicer.FullDuplexCall,
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
-    ),
-    "HalfDuplexCall": utilities.stream_stream_service_description(
-      servicer.HalfDuplexCall,
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
-    ),
-    "StreamingInputCall": utilities.stream_unary_service_description(
-      servicer.StreamingInputCall,
-      test.cpp.interop.messages_pb2.StreamingInputCallRequest.FromString,
-      test.cpp.interop.messages_pb2.StreamingInputCallResponse.SerializeToString,
-    ),
-    "StreamingOutputCall": utilities.unary_stream_service_description(
-      servicer.StreamingOutputCall,
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
-    ),
-    "UnaryCall": utilities.unary_unary_service_description(
-      servicer.UnaryCall,
-      test.cpp.interop.messages_pb2.SimpleRequest.FromString,
-      test.cpp.interop.messages_pb2.SimpleResponse.SerializeToString,
-    ),
-  }
-  return implementations.server("grpc.testing.TestService", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
-def early_adopter_create_TestService_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
-  import test.cpp.interop.empty_pb2
-  import test.cpp.interop.empty_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  import test.cpp.interop.messages_pb2
-  method_invocation_descriptions = {
-    "EmptyCall": utilities.unary_unary_invocation_description(
-      test.cpp.interop.empty_pb2.Empty.SerializeToString,
-      test.cpp.interop.empty_pb2.Empty.FromString,
-    ),
-    "FullDuplexCall": utilities.stream_stream_invocation_description(
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
-    ),
-    "HalfDuplexCall": utilities.stream_stream_invocation_description(
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
-    ),
-    "StreamingInputCall": utilities.stream_unary_invocation_description(
-      test.cpp.interop.messages_pb2.StreamingInputCallRequest.SerializeToString,
-      test.cpp.interop.messages_pb2.StreamingInputCallResponse.FromString,
-    ),
-    "StreamingOutputCall": utilities.unary_stream_invocation_description(
-      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
-      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
-    ),
-    "UnaryCall": utilities.unary_unary_invocation_description(
-      test.cpp.interop.messages_pb2.SimpleRequest.SerializeToString,
-      test.cpp.interop.messages_pb2.SimpleResponse.FromString,
-    ),
-  }
-  return implementations.stub("grpc.testing.TestService", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
-# @@protoc_insertion_point(module_scope)
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/test.proto b/src/python/grpcio_test/grpc_protoc_plugin/test.proto
index ed7c6a7b79..6762a8e7f3 100644
--- a/src/python/grpcio_test/grpc_protoc_plugin/test.proto
+++ b/src/python/grpcio_test/grpc_protoc_plugin/test.proto
@@ -32,7 +32,7 @@
 // This file is duplicated around the code base. See GitHub issue #526.
 syntax = "proto2";
 
-package grpc.testing;
+package grpc_protoc_plugin;
 
 enum PayloadType {
   // Compressable text format.
diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py
index 0f43b4a638..e9ee45a92a 100644
--- a/src/python/grpcio_test/setup.py
+++ b/src/python/grpcio_test/setup.py
@@ -77,7 +77,9 @@ _INSTALL_REQUIRES = (
 )
 
 _COMMAND_CLASS = {
-    'test': commands.RunTests
+    'test': commands.RunTests,
+    'build_proto_modules': commands.BuildProtoModules,
+    'build_py': commands.BuildPy,
 }
 
 setuptools.setup(
-- 
GitLab