Merge branch 'master' into grpc_trace_granularity
diff --git a/Makefile b/Makefile
index 13bc2f1..9be3e57 100644
--- a/Makefile
+++ b/Makefile
@@ -1946,12 +1946,12 @@
 $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1961,12 +1961,12 @@
 $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1976,12 +1976,12 @@
 $(GENDIR)/src/proto/grpc/testing/control.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1991,12 +1991,12 @@
 $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2006,12 +2006,12 @@
 $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2021,12 +2021,12 @@
 $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2036,12 +2036,12 @@
 $(GENDIR)/src/proto/grpc/testing/empty.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2051,12 +2051,12 @@
 $(GENDIR)/src/proto/grpc/testing/messages.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2066,12 +2066,12 @@
 $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2081,12 +2081,12 @@
 $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2096,12 +2096,12 @@
 $(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2111,12 +2111,12 @@
 $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2126,12 +2126,12 @@
 $(GENDIR)/src/proto/grpc/testing/test.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
 $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 
@@ -4376,7 +4376,7 @@
     $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
-    test/cpp/interop/server_main.cc \
+    test/cpp/interop/interop_server.cc \
 
 PUBLIC_HEADERS_CXX += \
 
@@ -4422,7 +4422,7 @@
 -include $(LIBINTEROP_SERVER_MAIN_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/server_main.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_server.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
 
 
 LIBQPS_SRC = \
@@ -6389,6 +6389,7 @@
     test/core/end2end/tests/simple_delayed_request.c \
     test/core/end2end/tests/simple_metadata.c \
     test/core/end2end/tests/simple_request.c \
+    test/core/end2end/tests/streaming_error_response.c \
     test/core/end2end/tests/trailing_metadata.c \
 
 PUBLIC_HEADERS_C += \
@@ -6465,6 +6466,7 @@
     test/core/end2end/tests/simple_delayed_request.c \
     test/core/end2end/tests/simple_metadata.c \
     test/core/end2end/tests/simple_request.c \
+    test/core/end2end/tests/streaming_error_response.c \
     test/core/end2end/tests/trailing_metadata.c \
 
 PUBLIC_HEADERS_C += \
@@ -14937,8 +14939,8 @@
 test/cpp/interop/client.cc: $(OPENSSL_DEP)
 test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
+test/cpp/interop/interop_server.cc: $(OPENSSL_DEP)
 test/cpp/interop/server_helper.cc: $(OPENSSL_DEP)
-test/cpp/interop/server_main.cc: $(OPENSSL_DEP)
 test/cpp/qps/client_async.cc: $(OPENSSL_DEP)
 test/cpp/qps/client_sync.cc: $(OPENSSL_DEP)
 test/cpp/qps/driver.cc: $(OPENSSL_DEP)
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 534f4c1..3ebba6e 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -1,6 +1,7 @@
 recursive-include src/python/grpcio/grpc *.c *.h *.py *.pyx *.pxd *.pxi *.python *.pem
 recursive-exclude src/python/grpcio/grpc/_cython *.so *.pyd
 graft src/python/grpcio/tests
+graft src/python/grpcio/grpcio.egg-info
 graft src/core
 graft src/boringssl
 graft include/grpc
diff --git a/Rakefile b/Rakefile
index f208a24..f44946f 100755
--- a/Rakefile
+++ b/Rakefile
@@ -77,7 +77,7 @@
   grpc_config = ENV['GRPC_CONFIG'] || 'opt'
   verbose = ENV['V'] || '0'
 
-  env = 'CPPFLAGS="-D_WIN32_WINNT=0x600 -DUNICODE -D_UNICODE" '
+  env = 'CPPFLAGS="-D_WIN32_WINNT=0x600 -DUNICODE -D_UNICODE -Wno-unused-variable -Wno-unused-result" '
   env += 'LDFLAGS=-static '
   env += 'SYSTEM=MINGW32 '
   env += 'EMBED_ZLIB=true '
diff --git a/build.yaml b/build.yaml
index 7ca7fd3..fbc0a7b 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1116,7 +1116,7 @@
   - src/proto/grpc/testing/empty.proto
   - src/proto/grpc/testing/messages.proto
   - src/proto/grpc/testing/test.proto
-  - test/cpp/interop/server_main.cc
+  - test/cpp/interop/interop_server.cc
   deps:
   - interop_server_helper
   - grpc++_test_util
diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md
index 357ea72..31d694b 100644
--- a/doc/PROTOCOL-HTTP2.md
+++ b/doc/PROTOCOL-HTTP2.md
@@ -38,7 +38,7 @@
 * **Nanosecond** → "n"
 * **Content-Type** → "content-type" "application/grpc" [("+proto" / "+json" / {_custom_})]
 * **Content-Coding** → "identity" / "gzip" / "deflate" / "snappy" / {_custom_}
-* **Message-Encoding** → "grpc-encoding" Content-Coding
+* <a name="message-encoding"></a>**Message-Encoding** → "grpc-encoding" Content-Coding
 * **Message-Accept-Encoding** → "grpc-accept-encoding" Content-Coding \*("," Content-Coding)
 * **User-Agent** → "user-agent" {_structured user-agent string_}
 * **Message-Type** → "grpc-message-type" {_type name for message schema_}
@@ -83,7 +83,7 @@
 The repeated sequence of **Length-Prefixed-Message** items is delivered in DATA frames
 
 * **Length-Prefixed-Message** → Compressed-Flag Message-Length Message
-* **Compressed-Flag** → 0 / 1   # encoded as 1 byte unsigned integer
+* <a name="compressed-flag"></a>**Compressed-Flag** → 0 / 1   # encoded as 1 byte unsigned integer
 * **Message-Length** → {_length of Message_}  # encoded as 4 byte unsigned integer
 * **Message** → \*{binary octet}
 
diff --git a/doc/compression.md b/doc/compression.md
new file mode 100644
index 0000000..15fae4d
--- /dev/null
+++ b/doc/compression.md
@@ -0,0 +1,111 @@
+## **gRPC Compression**
+
+The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
+"SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to be
+interpreted as described in [RFC 2119](http://www.ietf.org/rfc/rfc2119.txt).
+
+### Intent
+
+Compression is used to reduce the amount of bandwidth used between peers. The
+compression supported by gRPC acts _at the individual message level_, taking
+_message_ [as defined in the wire format
+document](PROTOCOL-HTTP2.md).
+
+The implementation supports different compression algorithms. A _default
+compression level_, to be used in the absence of message-specific settings, MAY
+be specified for during channel creation.
+
+The ability to control compression settings per call and to enable/disable
+compression on a per message basis MAY be used to prevent CRIME/BEAST attacks.
+It also allows for asymmetric compression communication, whereby a response MAY
+be compressed differently, if at all.
+
+### Specification
+
+Compression MAY be configured by the Client Application by calling the
+appropriate API method. There are two scenarios where compression MAY be
+configured:
+
++  At channel creation time, which sets the channel default compression and
+   therefore the compression that SHALL be used in the absence of per-RPC
+   compression configuration.
++  At response time, via:
+   +  For unary RPCs, the {Client,Server}Context instance. 
+   +  For streaming RPCs, the {Client,Server}Writer instance. In this case,
+      configuration is reduced to disabling compression altogether.
+
+### Compression Method Asymmetry Between Peers
+
+A gRPC peer MAY choose to respond using a different compression method to that
+of the request, including not performing any compression, regardless of channel
+and RPC settings (for example, if compression would result in small or negative
+gains).
+
+When a message from a client compressed with an unsupported algorithm is
+processed by a server, it WILL result in an INVALID\_ARGUMENT error on the
+server. The server will then include in its response a `grpc-accept-encoding`
+header specifying the algorithms it does accept. If an INTERNAL error is
+returned from the server despite having used one of the algorithms from the
+`grpc-accept-encoding` header, the cause MUST NOT be related to compression.
+Data sent from a server compressed with an algorithm not supported by the client
+WILL result in an INTERNAL error on the client side.
+
+Note that a peer MAY choose to not disclose all the encodings it supports.
+However, if it receives a message compressed in an undisclosed but supported
+encoding, it MUST include said encoding in the response's `grpc-accept-encoding
+h`eader.
+
+For every message a server is requested to compress using an algorithm it knows
+the client doesn't support (as indicated by the last `grpc-accept-encoding`
+header received from the client), it SHALL send the message uncompressed. 
+
+### Specific Disabling of Compression
+
+If the user (through the previously described mechanisms) requests to disable
+compression the next message MUST be sent uncompressed. This is instrumental in
+preventing BEAST/CRIME attacks. This applies to both the the unary and streaming
+cases.
+
+### Compression Levels and Algorithms
+
+The set of supported algorithm is implementation dependent. In order to simplify
+the public API and to operate seamlessly across implementations (both in terms
+of languages but also different version of the same one), we introduce the idea
+of _compression levels_ (such as "low", "medium", "high").
+
+Levels map to concrete algorithms and/or their settings (such as "low" mapping
+to "gzip -3" and "high" mapping to "gzip -9") automatically depending on what a
+peer is known to support. A server is always aware of what its clients support,
+as clients disclose it in their Message-Accept-Encoding header as part of their
+initial call. A client doesn't a priori (presently) know which algorithms a
+server supports. This issue can be addressed with an initial negotiation of
+capabilities or an automatic retry mechanism. These features will be implemented
+in the future. Currently however, compression levels are only supported at the
+server side, which is aware of the client's capabilities through the incoming
+Message-Accept-Encoding header.
+
+### Propagation to child RPCs
+
+The inheritance of the compression configuration by child RPCs is left up to the
+implementation. Note that in the absence of changes to the parent channel, its
+configuration will be used.
+
+### Test cases
+
+1. When a compression level is not specified for either the channel or the
+message, the default channel level _none_ is considered: data MUST NOT be
+compressed.
+1. When per-RPC compression configuration isn't present for a message, the
+channel compression configuration MUST be used.
+1. When a compression method (including no compression) is specified for an
+outgoing message, the message MUST be compressed accordingly.
+1. A message compressed in a way not supported by its endpoint MUST fail with
+INVALID\_ARGUMENT status, its associated description indicating the unsupported
+condition as well as the supported ones. The returned `grpc-accept-encoding`
+header MUST NOT contain the compression method (encoding) used.
+1. An ill-constructed message with its [Compressed-Flag
+bit](PROTOCOL-HTTP2.md#compressed-flag)
+set but lacking a
+"[grpc-encoding](PROTOCOL-HTTP2.md#message-encoding)"
+entry different from _identity_ in its metadata MUST fail with INTERNAL status,
+its associated description indicating the invalid Compressed-Flag condition.
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 7fd21c7..a4f9abe 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -68,14 +68,12 @@
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
 
 Procedure:
  1. Client calls UnaryCall with:
 
     ```
     {
-      response_type: COMPRESSABLE
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -85,33 +83,106 @@
 
 Client asserts:
 * call was successful
-* response payload type is COMPRESSABLE
 * response payload body is 314159 bytes in size
 * clients are free to assert that the response payload body contents are zero
   and comparing the entire response message against a golden response
 
-### large_compressed_unary
+### client_compressed_unary
 
-This test verifies compressed unary calls succeed in sending messages. It
-sends one unary request for every payload type, with and without requesting a
-compressed response from the server.
+This test verifies the client can compress unary messages by sending two unary
+calls, for compressed and uncompressed payloads. It also sends an initial
+probing request to verify whether the server supports the [CompressedRequest][]
+feature by checking if the probing call fails with an `INVALID_ARGUMENT` status.
 
-In all scenarios, whether compression was actually performed is determined by
-the compression bit in the response's message flags.
+Server features:
+* [UnaryCall][]
+* [CompressedRequest][]
+
+Procedure:
+ 1. Client calls UnaryCall with the feature probe, an *uncompressed* message:
+    ```
+    {
+      expect_compressed:{
+        value: true
+      }
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+ 1. Client calls UnaryCall with the *compressed* message:
+
+    ```
+    {
+      expect_compressed:{
+        value: true
+      }
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+ 1. Client calls UnaryCall with the *uncompressed* message:
+
+    ```
+    {
+      expect_compressed:{
+        value: false
+      }
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+    Client asserts:
+    * First call failed with `INVALID_ARGUMENT` status.
+    * Subsequent calls were successful.
+    * Response payload body is 314159 bytes in size.
+    * Clients are free to assert that the response payload body contents are
+      zeros and comparing the entire response message against a golden response.
+
+
+### server_compressed_unary
+
+This test verifies the server can compress unary messages. It sends two unary
+requests, expecting the server's response to be compressed or not according to
+the `response_compressed` boolean.
+
+Whether compression was actually performed is determined by the compression bit
+in the response's message flags. *Note that some languages may not have access
+to the message flags*.
 
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
-* [Uncompressable Payload][]
+* [CompressedResponse][]
 
 Procedure:
- 1. Client calls UnaryCall with:
+ 1. Client calls UnaryCall with `SimpleRequest`:
 
     ```
     {
-      request_compressed_response: bool
-      response_type: COMPRESSABLE
+      response_compressed:{
+        value: true
+      }
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+    ```
+    {
+      response_compressed:{
+        value: false
+      }
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -120,43 +191,21 @@
     ```
     Client asserts:
     * call was successful
-    * response payload type is COMPRESSABLE
-    * if `request_compressed_response` is false, the response MUST NOT have the
+    * when `response_compressed` is true, the response MUST have the
       compressed message flag set.
-    * if `request_compressed_response` is true, the response MUST have the
-      compressed message flag set.
-    * response payload body is 314159 bytes in size
+    * when `response_compressed` is false, the response MUST NOT have
+      the compressed message flag set.
+    * response payload body is 314159 bytes in size in both cases.
     * clients are free to assert that the response payload body contents are
       zero and comparing the entire response message against a golden response
 
 
- 2. Client calls UnaryCall with:
-    ```
-    {
-      request_compressed_response: bool
-      response_type: UNCOMPRESSABLE
-      response_size: 314159
-      payload:{
-        body: 271828 bytes of zeros
-      }
-    }
-    ```
-    Client asserts:
-    * call was successful
-    * response payload type is UNCOMPRESSABLE
-    * the response MAY have the compressed message flag set. Some
-      implementations will choose to compress the payload even when the output
-      size if larger than the input.
-    * response payload body is 314159 bytes in size
-
-
 ### client_streaming
 
 This test verifies that client-only streaming succeeds.
 
 Server features:
 * [StreamingInputCall][]
-* [Compressable Payload][]
 
 Procedure:
  1. Client calls StreamingInputCall
@@ -206,25 +255,81 @@
 * call was successful
 * response aggregated_payload_size is 74922
 
+
+### client_compressed_streaming
+
+This test verifies the client can compress requests on per-message basis by
+performing a two-request streaming call. It also sends an initial probing
+request to verify whether the server supports the [CompressedRequest][] feature
+by checking if the probing call fails with an `INVALID_ARGUMENT` status.
+
+Procedure:
+ 1. Client calls `StreamingInputCall` and sends the following feature-probing
+    *uncompressed* `StreamingInputCallRequest` message
+
+    ```
+    {
+      expect_compressed:{
+        value: true
+      }
+      payload:{
+        body: 27182 bytes of zeros
+      }
+    }
+    ```
+    If the call fails with `INVALID_ARGUMENT`, the test fails. Otherwise, we
+    continue.
+
+ 1. Client calls `StreamingInputCall` again, sending the *compressed* message
+
+    ```
+    {
+      expect_compressed:{
+        value: true
+      }
+      payload:{
+        body: 27182 bytes of zeros
+      }
+    }
+    ```
+
+ 1. And finally, the *uncompressed* message
+    ```
+    {
+      expect_compressed:{
+        value: false
+      }
+      payload:{
+        body: 45904 bytes of zeros
+      }
+    }
+    ```
+
+ 1. Client half-closes
+
+Client asserts:
+* First call fails with `INVALID_ARGUMENT`.
+* Next calls succeeds.
+* Response aggregated payload size is 73086.
+
+
 ### server_streaming
 
 This test verifies that server-only streaming succeeds.
 
 Server features:
 * [StreamingOutputCall][]
-* [Compressable Payload][]
 
 Procedure:
- 1. Client calls StreamingOutputCall with:
+ 1. Client calls StreamingOutputCall with `StreamingOutputCallRequest`:
 
     ```
     {
-      response_type:COMPRESSABLE
       response_parameters:{
         size: 31415
       }
       response_parameters:{
-        size: 59
+        size: 9
       }
       response_parameters:{
         size: 2653
@@ -238,103 +343,64 @@
 Client asserts:
 * call was successful
 * exactly four responses
-* response payloads are COMPRESSABLE
 * response payload bodies are sized (in order): 31415, 9, 2653, 58979
 * clients are free to assert that the response payload body contents are zero
   and comparing the entire response messages against golden responses
 
 ### server_compressed_streaming
 
-This test verifies that server-only compressed streaming succeeds.
+This test verifies that the server can compress streaming messages and disable
+compression on individual messages.
 
 Server features:
 * [StreamingOutputCall][]
-* [Compressable Payload][]
-* [Uncompressable Payload][]
+* [CompressedResponse][]
 
 
 Procedure:
- 1. Client calls StreamingOutputCall with:
+ 1. Client calls StreamingOutputCall with `StreamingOutputCallRequest`:
 
     ```
     {
-      request_compressed_response: bool
-      response_type:COMPRESSABLE
       response_parameters:{
+        compressed: {
+          value: true
+        }
         size: 31415
       }
       response_parameters:{
-        size: 59
-      }
-      response_parameters:{
-        size: 2653
-      }
-      response_parameters:{
-        size: 58979
+        compressed: {
+          value: false
+        }
+        size: 92653
       }
     }
     ```
 
     Client asserts:
     * call was successful
-    * exactly four responses
-    * response payloads are COMPRESSABLE
-    * if `request_compressed_response` is false, the response's messages MUST
+    * exactly two responses
+    * when `response_compressed` is false, the response's messages MUST
       NOT have the compressed message flag set.
-    * if `request_compressed_response` is true, the response's messages MUST
+    * when `response_compressed` is true, the response's messages MUST
       have the compressed message flag set.
-    * response payload bodies are sized (in order): 31415, 59, 2653, 58979
+    * response payload bodies are sized (in order): 31415, 92653
     * clients are free to assert that the response payload body contents are
       zero and comparing the entire response messages against golden responses
 
 
- 2. Client calls StreamingOutputCall with:
-
-    ```
-    {
-      request_compressed_response: bool
-      response_type:UNCOMPRESSABLE
-      response_parameters:{
-        size: 31415
-      }
-      response_parameters:{
-        size: 59
-      }
-      response_parameters:{
-        size: 2653
-      }
-      response_parameters:{
-        size: 58979
-      }
-    }
-    ```
-
-    Client asserts:
-    * call was successful
-    * exactly four responses
-    * response payloads are UNCOMPRESSABLE
-    * the response MAY have the compressed message flag set. Some
-      implementations will choose to compress the payload even when the output
-      size if larger than the input.
-    * response payload bodies are sized (in order): 31415, 59, 2653, 58979
-    * clients are free to assert that the body of the responses are identical to
-      the golden uncompressable data at `test/cpp/interop/rnd.dat`.
-
-
 ### ping_pong
 
 This test verifies that full duplex bidi is supported.
 
 Server features:
 * [FullDuplexCall][]
-* [Compressable Payload][]
 
 Procedure:
  1. Client calls FullDuplexCall with:
 
     ```
     {
-      response_type: COMPRESSABLE
       response_parameters:{
         size: 31415
       }
@@ -348,9 +414,8 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_parameters:{
-        size: 59
+        size: 9
       }
       payload:{
         body: 8 bytes of zeros
@@ -362,7 +427,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_parameters:{
         size: 2653
       }
@@ -376,7 +440,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_parameters:{
         size: 58979
       }
@@ -391,7 +454,6 @@
 Client asserts:
 * call was successful
 * exactly four responses
-* response payloads are COMPRESSABLE
 * response payload bodies are sized (in order): 31415, 9, 2653, 58979
 * clients are free to assert that the response payload body contents are zero
   and comparing the entire response messages against golden responses
@@ -421,12 +483,12 @@
 
 The test uses `--default_service_account` with GCE service account email and
 `--oauth_scope` with the OAuth scope to use. For testing against
-grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo" should
+grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo"
+should
 be passed in as `--oauth_scope`.
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
 * [Echo Authenticated Username][]
 * [Echo OAuth Scope][]
 
@@ -436,7 +498,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -448,7 +509,8 @@
 
 Client asserts:
 * call was successful
-* received SimpleResponse.username equals the value of `--default_service_account` flag
+* received SimpleResponse.username equals the value of
+  `--default_service_account` flag
 * received SimpleResponse.oauth_scope is in `--oauth_scope`
 * response payload body is 314159 bytes in size
 * clients are free to assert that the response payload body contents are zero
@@ -469,7 +531,6 @@
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
 * [Echo Authenticated Username][]
 * [Echo OAuth Scope][]
 
@@ -479,7 +540,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -492,7 +552,8 @@
 * call was successful
 * received SimpleResponse.username is not empty and is in the json key file used
 by the auth library. The client can optionally check the username matches the
-email address in the key file or equals the value of `--default_service_account` flag.
+email address in the key file or equals the value of `--default_service_account`
+flag.
 * response payload body is 314159 bytes in size
 * clients are free to assert that the response payload body contents are zero
   and comparing the entire response message against a golden response
@@ -518,18 +579,18 @@
 fetch the token, `--default_service_account` can be used to pass in GCE service
 account email.
 - uses the flag `--oauth_scope` for the oauth scope.  For testing against
-grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo" should
-be passed as the `--oauth_scope`.
+grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo"
+should be passed as the `--oauth_scope`.
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
 * [Echo Authenticated Username][]
 * [Echo OAuth Scope][]
 
 Procedure:
  1. Client uses the auth library to obtain an authorization token
- 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1
+ 2. Client configures the channel to use AccessTokenCredentials with the access
+    token obtained in step 1
  3. Client calls UnaryCall with the following message
 
     ```
@@ -550,22 +611,21 @@
 
 Similar to the other auth tests, this test is only for cloud-to-prod path.
 
-This test verifies unary calls succeed in sending messages using a JWT or a service account
-credentials set on the RPC.
+This test verifies unary calls succeed in sending messages using a JWT or a
+service account credentials set on the RPC.
 
 The test
 - uses the flag `--service_account_key_file` with the path to a json key file
 downloaded from https://console.developers.google.com. Alternately, if using a
 usable auth implementation, it may specify the file location in the environment
 variable GOOGLE_APPLICATION_CREDENTIALS
-- optionally uses the flag `--oauth_scope` for the oauth scope if implementator 
+- optionally uses the flag `--oauth_scope` for the oauth scope if implementator
 wishes to use service account credential instead of JWT credential. For testing
-against grpc-test.sandbox.googleapis.com, oauth scope 
+against grpc-test.sandbox.googleapis.com, oauth scope
 "https://www.googleapis.com/auth/xapi.zoo" should be used.
 
 Server features:
 * [UnaryCall][]
-* [Compressable Payload][]
 * [Echo Authenticated Username][]
 * [Echo OAuth Scope][]
 
@@ -596,7 +656,6 @@
 Server features:
 * [UnaryCall][]
 * [FullDuplexCall][]
-* [Compressable Payload][]
 * [Echo Metadata][]
 
 Procedure:
@@ -611,7 +670,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -630,7 +688,6 @@
 
     ```
     {
-      response_type: COMPRESSABLE
       response_size: 314159
       payload:{
         body: 271828 bytes of zeros
@@ -736,14 +793,12 @@
 
 Server features:
 * [FullDuplexCall][]
-* [Compressable Payload][]
 
 Procedure:
  1. Client starts FullDuplexCall with
 
     ```
     {
-      response_type: COMPRESSABLE
       response_parameters:{
         size: 31415
       }
@@ -887,6 +942,21 @@
 for the `SimpleRequest.response_type`. If the server does not support the
 `response_type`, then it should fail the RPC with `INVALID_ARGUMENT`.
 
+### CompressedResponse
+[CompressedResponse]: #compressedresponse
+
+When the client sets `response_compressed` to true, the server's response is
+sent back compressed. Note that `response_compressed` is present on both
+`SimpleRequest` (unary) and `StreamingOutputCallRequest` (streaming).
+
+### CompressedRequest
+[CompressedRequest]: #compressedrequest
+
+When the client sets `expect_compressed` to true, the server expects the client
+request to be compressed. If it's not, it fails the RPC with `INVALID_ARGUMENT`.
+Note that `response_compressed` is present on both `SimpleRequest` (unary) and
+`StreamingOutputCallRequest` (streaming).
+
 ### StreamingInputCall
 [StreamingInputCall]: #streaminginputcall
 
@@ -913,20 +983,6 @@
 respective ResponseParameters. After receiving half close and sending all
 responses, it closes with OK.
 
-### Compressable Payload
-[Compressable Payload]: #compressable-payload
-
-When the client requests COMPRESSABLE payload, the response includes a payload
-of the size requested containing all zeros and the payload type is
-COMPRESSABLE.
-
-### Uncompressable Payload
-[Uncompressable Payload]: #uncompressable-payload
-
-When the client requests UNCOMPRESSABLE payload, the response includes a payload
-of the size requested containing uncompressable data and the payload type is
-UNCOMPRESSABLE.
-
 ### Echo Status
 [Echo Status]: #echo-status
 When the client sends a response_status in the request payload, the server closes
diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
index 51a39c5..ab7419c 100644
--- a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
+++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
@@ -116,11 +116,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */;
 			buildPhases = (
-				DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */,
+				DAABBA7B5788A39108D7CA83 /* [CP] Check Pods Manifest.lock */,
 				63E1E9781B28CB2000EF0978 /* Sources */,
 				63E1E9791B28CB2000EF0978 /* Frameworks */,
 				63E1E97A1B28CB2000EF0978 /* Resources */,
-				AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */,
+				AEFCCC69DD59CE8F6EB769D7 /* [CP] Copy Pods Resources */,
+				D24F6598302C412D4B863D6F /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -177,14 +178,14 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */ = {
+		AEFCCC69DD59CE8F6EB769D7 /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Copy Pods Resources";
+			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -192,14 +193,29 @@
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */ = {
+		D24F6598302C412D4B863D6F /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Check Pods Manifest.lock";
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		DAABBA7B5788A39108D7CA83 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec
index e935626..d246653 100644
--- a/examples/objective-c/auth_sample/AuthTestService.podspec
+++ b/examples/objective-c/auth_sample/AuthTestService.podspec
@@ -2,6 +2,10 @@
   s.name     = "AuthTestService"
   s.version  = "0.0.1"
   s.license  = "New BSD"
+  s.authors  = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+  s.homepage = "http://www.grpc.io/"
+  s.summary = "AuthTestService example"
+  s.source = { :git => 'https://github.com/grpc/grpc.git' }
 
   s.ios.deployment_target = "7.1"
   s.osx.deployment_target = "10.9"
diff --git a/examples/objective-c/helloworld/HelloWorld.podspec b/examples/objective-c/helloworld/HelloWorld.podspec
index bdf782f..17b016b 100644
--- a/examples/objective-c/helloworld/HelloWorld.podspec
+++ b/examples/objective-c/helloworld/HelloWorld.podspec
@@ -2,6 +2,10 @@
   s.name     = "HelloWorld"
   s.version  = "0.0.1"
   s.license  = "New BSD"
+  s.authors  = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+  s.homepage = "http://www.grpc.io/"
+  s.summary = "HelloWorld example"
+  s.source = { :git => 'https://github.com/grpc/grpc.git' }
 
   s.ios.deployment_target = "7.1"
   s.osx.deployment_target = "10.9"
diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
index 250f009..df5c40c 100644
--- a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
+++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
@@ -7,7 +7,6 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		3EF35C14BDC2B65E21837F02 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 43AB08B32839A6700EA00DD4 /* libPods.a */; };
 		5E3690661B2A23800040F884 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690651B2A23800040F884 /* main.m */; };
 		5E3690691B2A23800040F884 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690681B2A23800040F884 /* AppDelegate.m */; };
 		5E36906C1B2A23800040F884 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E36906B1B2A23800040F884 /* ViewController.m */; };
@@ -18,7 +17,6 @@
 
 /* Begin PBXFileReference section */
 		0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
-		43AB08B32839A6700EA00DD4 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5E3690601B2A23800040F884 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		5E3690641B2A23800040F884 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		5E3690651B2A23800040F884 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -37,7 +35,6 @@
 			buildActionMask = 2147483647;
 			files = (
 				EF61CF6AE2536A31D47F0E63 /* libPods-HelloWorld.a in Frameworks */,
-				3EF35C14BDC2B65E21837F02 /* libPods.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -88,7 +85,6 @@
 			isa = PBXGroup;
 			children = (
 				6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */,
-				43AB08B32839A6700EA00DD4 /* libPods.a */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -109,12 +105,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 5E3690831B2A23810040F884 /* Build configuration list for PBXNativeTarget "HelloWorld" */;
 			buildPhases = (
-				ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */,
+				ACF9162361FB8F24C70657DE /* [CP] Check Pods Manifest.lock */,
 				5E36905C1B2A23800040F884 /* Sources */,
 				5E36905D1B2A23800040F884 /* Frameworks */,
 				5E36905E1B2A23800040F884 /* Resources */,
-				4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */,
-				BB76529986A8BFAF19A385B1 /* Embed Pods Frameworks */,
+				4C7D815378D98AB3BFC1A7D5 /* [CP] Copy Pods Resources */,
+				BB76529986A8BFAF19A385B1 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -170,14 +166,14 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */ = {
+		4C7D815378D98AB3BFC1A7D5 /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Copy Pods Resources";
+			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -185,14 +181,14 @@
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */ = {
+		ACF9162361FB8F24C70657DE /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Check Pods Manifest.lock";
+			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -200,19 +196,19 @@
 			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
-		BB76529986A8BFAF19A385B1 /* Embed Pods Frameworks */ = {
+		BB76529986A8BFAF19A385B1 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Embed Pods Frameworks";
+			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective-c/route_guide/RouteGuide.podspec
index 4bc2c42..97a61ff 100644
--- a/examples/objective-c/route_guide/RouteGuide.podspec
+++ b/examples/objective-c/route_guide/RouteGuide.podspec
@@ -2,6 +2,10 @@
   s.name     = "RouteGuide"
   s.version  = "0.0.1"
   s.license  = "New BSD"
+  s.authors  = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+  s.homepage = "http://www.grpc.io/"
+  s.summary = "RouteGuide example"
+  s.source = { :git => 'https://github.com/grpc/grpc.git' }
 
   s.ios.deployment_target = "7.1"
   s.osx.deployment_target = "10.9"
diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
index f997755..0bb84b3 100644
--- a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
+++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
@@ -116,12 +116,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 632527A31B1D0396003073D9 /* Build configuration list for PBXNativeTarget "RouteGuideClient" */;
 			buildPhases = (
-				C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */,
+				C6FC30AD2376EC04317237C5 /* [CP] Check Pods Manifest.lock */,
 				632527791B1D0395003073D9 /* Sources */,
 				6325277A1B1D0395003073D9 /* Frameworks */,
 				6325277B1B1D0395003073D9 /* Resources */,
-				FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */,
-				B5388EC5A25E89021740B916 /* Embed Pods Frameworks */,
+				FFE0BCF30339E7A50A989EAB /* [CP] Copy Pods Resources */,
+				B5388EC5A25E89021740B916 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -178,14 +178,14 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		B5388EC5A25E89021740B916 /* Embed Pods Frameworks */ = {
+		B5388EC5A25E89021740B916 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Embed Pods Frameworks";
+			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -193,14 +193,14 @@
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */ = {
+		C6FC30AD2376EC04317237C5 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Check Pods Manifest.lock";
+			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -208,14 +208,14 @@
 			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
-		FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */ = {
+		FFE0BCF30339E7A50A989EAB /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Copy Pods Resources";
+			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index e23fd4e..a132c9a 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -193,7 +193,7 @@
   ///
   /// \return A multimap of initial metadata key-value pairs from the server.
   const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerInitialMetadata() {
+  GetServerInitialMetadata() const {
     GPR_CODEGEN_ASSERT(initial_metadata_received_);
     return recv_initial_metadata_;
   }
@@ -205,7 +205,7 @@
   ///
   /// \return A multimap of metadata trailing key-value pairs from the server.
   const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerTrailingMetadata() {
+  GetServerTrailingMetadata() const {
     // TODO(yangg) check finished
     return trailing_metadata_;
   }
@@ -230,13 +230,13 @@
 
 #ifndef GRPC_CXX0X_NO_CHRONO
   /// Return the deadline for the client call.
-  std::chrono::system_clock::time_point deadline() {
+  std::chrono::system_clock::time_point deadline() const {
     return Timespec2Timepoint(deadline_);
   }
 #endif  // !GRPC_CXX0X_NO_CHRONO
 
   /// Return a \a gpr_timespec representation of the client call's deadline.
-  gpr_timespec raw_deadline() { return deadline_; }
+  gpr_timespec raw_deadline() const { return deadline_; }
 
   /// Set the per call authority header (see
   /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
@@ -337,7 +337,7 @@
                                   const InputMessage& request,
                                   OutputMessage* result);
 
-  grpc_call* call() { return call_; }
+  grpc_call* call() const { return call_; }
   void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
 
   uint32_t initial_metadata_flags() const {
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index a1e1ed1..cea13a5 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -94,12 +94,12 @@
   ~ServerContext();
 
 #ifndef GRPC_CXX0X_NO_CHRONO
-  std::chrono::system_clock::time_point deadline() {
+  std::chrono::system_clock::time_point deadline() const {
     return Timespec2Timepoint(deadline_);
   }
 #endif  // !GRPC_CXX0X_NO_CHRONO
 
-  gpr_timespec raw_deadline() { return deadline_; }
+  gpr_timespec raw_deadline() const { return deadline_; }
 
   void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
   void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
@@ -122,7 +122,8 @@
   // was called.
   void TryCancel() const;
 
-  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata() {
+  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
+      const {
     return client_metadata_;
   }
 
diff --git a/setup.py b/setup.py
index e2de96d..f73501b 100644
--- a/setup.py
+++ b/setup.py
@@ -246,7 +246,6 @@
   ext_modules=CYTHON_EXTENSION_MODULES,
   packages=list(PACKAGES),
   package_dir=PACKAGE_DIRECTORIES,
-  namespace_packages=['grpc'],
   package_data=PACKAGE_DATA,
   install_requires=INSTALL_REQUIRES,
   setup_requires=SETUP_REQUIRES,
diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc
index 986b97c..1fe090d 100644
--- a/src/compiler/node_generator.cc
+++ b/src/compiler/node_generator.cc
@@ -74,8 +74,16 @@
 
 // Given a filename like foo/bar/baz.proto, returns the root directory
 // path ../../
-grpc::string GetRootPath(const grpc::string& filename) {
-  size_t slashes = std::count(filename.begin(), filename.end(), '/');
+grpc::string GetRootPath(const grpc::string& from_filename,
+                         const grpc::string& to_filename) {
+  if (to_filename.find("google/protobuf") == 0) {
+    // Well-known types (.proto files in the google/protobuf directory) are
+    // assumed to come from the 'google-protobuf' npm package.  We may want to
+    // generalize this exception later by letting others put generated code in
+    // their own npm packages.
+    return "google-protobuf/";
+  }
+  size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
   if (slashes == 0) {
     return "./";
   }
@@ -90,7 +98,7 @@
 // from_file, assuming that both paths are relative to the same directory
 grpc::string GetRelativePath(const grpc::string& from_file,
                              const grpc::string& to_file) {
-  return GetRootPath(from_file) + to_file;
+  return GetRootPath(from_file, to_file) + to_file;
 }
 
 /* Finds all message types used in all services in the file, and returns them
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 9aa39ba..9c99ff8 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -264,6 +264,7 @@
   t->parsing.is_client = is_client;
   t->parsing.deframe_state =
       is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
+  t->parsing.is_first_frame = true;
   t->writing.is_client = is_client;
   t->optional_drop_message = gpr_empty_slice();
   grpc_connectivity_state_init(
@@ -643,8 +644,7 @@
 
   for (;;) {
     if (!t->executor.writing_active && !t->closed &&
-        grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
-                                           t->executor.parsing_active)) {
+        grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
       t->executor.writing_active = 1;
       REF_TRANSPORT(t, "writing");
       prevent_endpoint_shutdown(t);
@@ -1093,6 +1093,7 @@
     stream_global->recv_trailing_metadata_finished =
         add_closure_barrier(on_complete);
     stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
+    stream_global->final_metadata_requested = true;
     grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
   }
 
@@ -1246,7 +1247,8 @@
       stream_global->recv_initial_metadata_ready = NULL;
     }
     if (stream_global->recv_message_ready != NULL) {
-      while (stream_global->seen_error &&
+      while (stream_global->final_metadata_requested &&
+             stream_global->seen_error &&
              (bs = grpc_chttp2_incoming_frame_queue_pop(
                   &stream_global->incoming_frames)) != NULL) {
         incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
@@ -1805,7 +1807,7 @@
     UNREF_TRANSPORT(exec_ctx, t, "reading_action");
   }
 
-  GRPC_ERROR_UNREF(error);
+  GRPC_LOG_IF_ERROR("close_transport", error);
 }
 
 /*******************************************************************************
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index a7aefb9..e3a3c9e 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -102,12 +102,14 @@
   if (p->byte == 4) {
     GPR_ASSERT(is_last);
     stream_parsing->received_close = 1;
-    stream_parsing->forced_close_error = grpc_error_set_int(
-        GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
-        (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
-                   (((uint32_t)p->reason_bytes[1]) << 16) |
-                   (((uint32_t)p->reason_bytes[2]) << 8) |
-                   (((uint32_t)p->reason_bytes[3]))));
+    if (stream_parsing->forced_close_error == GRPC_ERROR_NONE) {
+      stream_parsing->forced_close_error = grpc_error_set_int(
+          GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
+          (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
+                     (((uint32_t)p->reason_bytes[1]) << 16) |
+                     (((uint32_t)p->reason_bytes[2]) << 8) |
+                     (((uint32_t)p->reason_bytes[3]))));
+    }
   }
 
   return GRPC_ERROR_NONE;
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 54e72eb..d63170e 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -265,6 +265,7 @@
   uint8_t incoming_frame_type;
   uint8_t incoming_frame_flags;
   uint8_t header_eof;
+  bool is_first_frame;
   uint32_t expect_continuation_stream_id;
   uint32_t incoming_frame_size;
   uint32_t incoming_stream_id;
@@ -440,6 +441,7 @@
 
   bool published_initial_metadata;
   bool published_trailing_metadata;
+  bool final_metadata_requested;
 
   grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
   grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@@ -524,8 +526,7 @@
     are required, and schedule them if so */
 int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx,
                                        grpc_chttp2_transport_global *global,
-                                       grpc_chttp2_transport_writing *writing,
-                                       int is_parsing);
+                                       grpc_chttp2_transport_writing *writing);
 void grpc_chttp2_perform_writes(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
     grpc_endpoint *endpoint);
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 7851340..991d772 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -468,6 +468,17 @@
 
 static grpc_error *init_frame_parser(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+  if (transport_parsing->is_first_frame &&
+      transport_parsing->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
+    char *msg;
+    gpr_asprintf(
+        &msg, "Expected SETTINGS frame as the first frame, got frame type %d",
+        transport_parsing->incoming_frame_type);
+    grpc_error *err = GRPC_ERROR_CREATE(msg);
+    gpr_free(msg);
+    return err;
+  }
+  transport_parsing->is_first_frame = false;
   if (transport_parsing->expect_continuation_stream_id != 0) {
     if (transport_parsing->incoming_frame_type !=
         GRPC_CHTTP2_FRAME_CONTINUATION) {
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index add7678..b19f5f0 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -45,7 +45,7 @@
 
 int grpc_chttp2_unlocking_check_writes(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
+    grpc_chttp2_transport_writing *transport_writing) {
   grpc_chttp2_stream_global *stream_global;
   grpc_chttp2_stream_writing *stream_writing;
 
@@ -61,7 +61,7 @@
                                 [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
 
   if (transport_global->dirtied_local_settings &&
-      !transport_global->sent_local_settings && !is_parsing) {
+      !transport_global->sent_local_settings) {
     gpr_slice_buffer_add(
         &transport_writing->outbuf,
         grpc_chttp2_settings_create(
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 2a51671..86982bc 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -396,7 +396,7 @@
                                         size_t addr_len, unsigned port_index,
                                         grpc_tcp_listener **listener) {
   grpc_tcp_listener *sp = NULL;
-  int port;
+  int port = -1;
   int status;
   GUID guid = WSAID_ACCEPTEX;
   DWORD ioctl_num_bytes;
diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore
index 0f96a48..fc2875a 100644
--- a/src/csharp/.gitignore
+++ b/src/csharp/.gitignore
@@ -1,5 +1,7 @@
+*.xproj.user
 *.userprefs
 *.csproj.user
+*.lock.json
 StyleCop.Cache
 test-results
 packages
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 3acea7d..1fa14fc 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -81,6 +81,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="Grpc.Auth.nuspec" />
+    <None Include="Grpc.Auth.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.project.json b/src/csharp/Grpc.Auth/Grpc.Auth.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.xproj b/src/csharp/Grpc.Auth/Grpc.Auth.xproj
new file mode 100644
index 0000000..dd3d94c
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>c82631ed-06d1-4458-87bc-8257d12307a8</ProjectGuid>
+    <RootNamespace>Grpc.Auth</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\Grpc.Core\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
new file mode 100644
index 0000000..1677565
--- /dev/null
+++ b/src/csharp/Grpc.Auth/project.json
@@ -0,0 +1,32 @@
+{
+  "version": "0.15.0-dev",
+  "title": "gRPC C# Auth",
+  "authors": [ "Google Inc." ],
+  "copyright": "Copyright 2015, Google Inc.",
+  "packOptions": {
+    "summary": "Auth library for C# implementation of gRPC - an RPC library and framework",
+    "description": "Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+    "owners": [ "grpc-packages" ],
+    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+    "projectUrl": "https://github.com/grpc/grpc",
+    "requireLicenseAcceptance": false,
+    "tags": [ "gRPC RPC Protocol HTTP/2 Auth OAuth2" ],
+  },
+  "dependencies": {
+    "Grpc.Core": "0.15.0-dev",
+    "Google.Apis.Auth": "1.11.1"
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "net45"
+      ],
+      "dependencies": {
+        "Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027",
+        "NETStandard.Library": "1.5.0-rc2-24027",
+        "System.Threading.Tasks": "4.0.11-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
index e605a31..064bc13 100644
--- a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
+++ b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
@@ -32,13 +32,7 @@
 #endregion
 
 using System;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
 using System.Threading.Tasks;
-using Grpc.Core;
-using Grpc.Core.Internal;
 using Grpc.Core.Utils;
 using NUnit.Framework;
 
@@ -46,6 +40,13 @@
 {
     public class AppDomainUnloadTest
     {
+#if NETSTANDARD1_5
+        [Test]
+        [Ignore("Not supported for CoreCLR")]
+        public void AppDomainUnloadHookCanCleanupAbandonedCall()
+        {
+        }
+#else
         [Test]
         public void AppDomainUnloadHookCanCleanupAbandonedCall()
         {
@@ -86,5 +87,6 @@
                 readyToShutdown.Task.Wait();  // make sure handler is running
             }
         }
+#endif
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
index 378c818..16be210 100644
--- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
@@ -34,6 +34,7 @@
 using System;
 using System.Diagnostics;
 using System.Linq;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core;
@@ -118,5 +119,30 @@
 
             await call.ResponseStream.ToListAsync();
         }
+
+        [Test]
+        public void CanReadCompressedMessages()
+        {
+            var compressionMetadata = new Metadata
+            {
+                { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, "gzip") }
+            };
+
+            helper.UnaryHandler = new UnaryServerMethod<string, string>(async (req, context) =>
+            {
+                await context.WriteResponseHeadersAsync(compressionMetadata);
+                return req;
+            });
+
+            var stringBuilder = new StringBuilder();
+            for (int i = 0; i < 200000; i++)
+            {
+                stringBuilder.Append('a');
+            }
+            var request = stringBuilder.ToString();
+            var response = Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(compressionMetadata)), request);
+
+            Assert.AreEqual(request, response);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 074c960..f6c2265 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -99,6 +99,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.Core.Tests.project.json" />
     <None Include="packages.config">
       <SubType>Designer</SubType>
     </None>
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj
new file mode 100644
index 0000000..0582329
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>759e23b2-fc04-4695-902d-b073cded3599</ProjectGuid>
+    <RootNamespace>Grpc.Core.Tests</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/NUnitMain.cs b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
index 9c1d7bf..24a9f84 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if DOTNET5_4
+#if NETSTANDARD1_5
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
index 3fa6ad0..1a9e441 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
@@ -56,7 +56,7 @@
                 Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " +
                 "This test has failed to indicate that.");
                 Console.Error.Flush();
-                Environment.Exit(1);
+                throw new Exception("NUnitVersionTest has failed.");
             }
         }
 
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 3830f0c..501992c 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -45,6 +45,8 @@
 {
     public class SanityTest
     {
+        // TODO: make sanity test work for CoreCLR as well
+#if !NETSTANDARD1_5
         /// <summary>
         /// Because we depend on a native library, sometimes when things go wrong, the
         /// entire NUnit test process crashes. To be able to track down problems better,
@@ -121,5 +123,6 @@
             }
             return result;
         }
+#endif
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
new file mode 100644
index 0000000..3ad081d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/project.json
@@ -0,0 +1,56 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.Core": {
+      "target": "project"
+    },
+    "Newtonsoft.Json": "8.0.3",
+    "NUnit": "3.2.0",
+    "NUnitLite": "3.2.0-*"
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  },
+}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index a796911..1952ee3 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -141,6 +141,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="Grpc.Core.nuspec" />
+    <None Include="Grpc.Core.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="NativeDeps.targets" />
@@ -148,7 +149,7 @@
   <ItemGroup />
   <ItemGroup>
     <EmbeddedResource Include="..\..\..\etc\roots.pem">
-      <Link>Resources\roots.pem</Link>
+      <Link>roots.pem</Link>
     </EmbeddedResource>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 0ada004..fa2c1fb 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -24,11 +24,11 @@
     <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
     <file src="**\*.cs" target="src" />
     <file src="Grpc.Core.targets" target="\build\net45\Grpc.Core.targets" />
-    <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
-    <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
-    <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
-    <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
-    <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
-    <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
+    <file src="../nativelibs/windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
+    <file src="../nativelibs/windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
+    <file src="../nativelibs/linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
+    <file src="../nativelibs/linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
+    <file src="../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
+    <file src="../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
   </files>
 </package>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.project.json b/src/csharp/Grpc.Core/Grpc.Core.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Core/Grpc.Core.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.xproj b/src/csharp/Grpc.Core/Grpc.Core.xproj
new file mode 100644
index 0000000..137236f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Grpc.Core.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>dc9908b6-f291-4fc8-a46d-2ea2551790ec</ProjectGuid>
+    <RootNamespace>Grpc.Core</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index e9e4cb4..eeed699 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -105,7 +105,7 @@
 
             if (instanceToShutdown != null)
             {
-                await instanceToShutdown.ShutdownAsync();
+                await instanceToShutdown.ShutdownAsync().ConfigureAwait(false);
             }
         }
 
@@ -352,8 +352,12 @@
                 {
                     if (!hooksRegistered)
                     {
+                        // TODO(jtattermusch): register shutdownhooks for CoreCLR as well
+#if !NETSTANDARD1_5
+
                         AppDomain.CurrentDomain.ProcessExit += ShutdownHookHandler;
                         AppDomain.CurrentDomain.DomainUnload += ShutdownHookHandler;
+#endif
                     }
                     hooksRegistered = true;
                 }
diff --git a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
index aa4dafd..2a96e99 100644
--- a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
+++ b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
@@ -46,7 +46,7 @@
     /// </summary>
     internal static class DefaultSslRootsOverride
     {
-        const string RootsPemResourceName = "Grpc.Core.Resources.roots.pem";
+        const string RootsPemResourceName = "Grpc.Core.roots.pem";
         static object staticLock = new object();
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index b45ba19..a6d7925 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -117,8 +117,8 @@
         private static string GetAssemblyPath()
         {
             var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
-#if DOTNET5_4
-            // Assembly.EscapedCodeBase does not exit under CoreCLR, but assemblies imported from a nuget package
+#if NETSTANDARD1_5
+            // Assembly.EscapedCodeBase does not exist under CoreCLR, but assemblies imported from a nuget package
             // don't seem to be shadowed by DNX-based projects at all.
             return assembly.Location;
 #else
@@ -136,7 +136,7 @@
 #endif
         }
 
-#if !DOTNET5_4
+#if !NETSTANDARD1_5
         private static bool IsFileUri(string uri)
         {
             return uri.ToLowerInvariant().StartsWith(Uri.UriSchemeFile);
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index 5d8c44b..15391dd 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -53,7 +53,7 @@
 
         static PlatformApis()
         {
-#if DNXCORE50
+#if NETSTANDARD1_5
             isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
             isMacOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
             isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
diff --git a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
index 702aea2..230faac 100644
--- a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
+++ b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
@@ -39,7 +39,7 @@
     /// <summary>
     /// Safe handle to wrap native objects.
     /// </summary>
-    internal abstract class SafeHandleZeroIsInvalid : SafeHandle
+    internal abstract class SafeHandleZeroIsInvalid : System.Runtime.InteropServices.SafeHandle
     {
         public SafeHandleZeroIsInvalid() : base(IntPtr.Zero, true)
         {
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index f73f720..915bec1 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -63,6 +63,13 @@
         /// </summary>
         public static readonly Metadata Empty = new Metadata().Freeze();
 
+        /// <summary>
+        /// To be used in initial metadata to request specific compression algorithm
+        /// for given call. Direct selection of compression algorithms is an internal
+        /// feature and is not part of public API.
+        /// </summary>
+        internal const string CompressionRequestAlgorithmMetadataKey = "grpc-internal-encoding-request";
+
         readonly List<Entry> entries;
         bool readOnly;
 
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
new file mode 100644
index 0000000..7253107
--- /dev/null
+++ b/src/csharp/Grpc.Core/project.json
@@ -0,0 +1,42 @@
+{
+  "version": "0.15.0-dev",
+  "title": "gRPC C# Core",
+  "authors": [ "Google Inc." ],
+  "copyright": "Copyright 2015, Google Inc.",
+  "packOptions": {
+    "summary": "Core C# implementation of gRPC - an RPC library and framework",
+    "description": "Core C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+    "owners": [ "grpc-packages" ],
+    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+    "projectUrl": "https://github.com/grpc/grpc",
+    "requireLicenseAcceptance": false,
+    "tags": [ "gRPC RPC Protocol HTTP/2" ],
+    "files": {
+      "build/net45/": "Grpc.Core.targets",
+      "build/native/bin/windows_x86/": "../nativelibs/windows_x86/grpc_csharp_ext.dll",
+      "build/native/bin/windows_x64/": "../nativelibs/windows_x64/grpc_csharp_ext.dll",
+      "build/native/bin/linux_x86/": "../nativelibs/linux_x86/libgrpc_csharp_ext.so",
+      "build/native/bin/linux_x64/": "../nativelibs/linux_x64/libgrpc_csharp_ext.so",
+      "build/native/bin/macosx_x86/": "../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib",
+      "build/native/bin/macosx_x64/": "../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib"
+    }
+  },
+  "buildOptions": {
+    "embed": [ "../../../etc/roots.pem" ]
+  },
+  "dependencies": {
+    "Ix-Async": "1.2.5"
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027",
+        "System.Threading.Thread": "4.0.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Dotnet.sln b/src/csharp/Grpc.Dotnet.sln
new file mode 100644
index 0000000..98b3cd5
--- /dev/null
+++ b/src/csharp/Grpc.Dotnet.sln
@@ -0,0 +1,100 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core", "Grpc.Core\Grpc.Core.xproj", "{DC9908B6-F291-4FC8-A46D-2EA2551790EC}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.xproj", "{C82631ED-06D1-4458-87BC-8257D12307A8}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.xproj", "{759E23B2-FC04-4695-902D-B073CDED3599}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.xproj", "{C77B792D-FC78-4CE2-9522-B40B0803C636}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.xproj", "{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.xproj", "{58579368-5372-4E67-ACD6-9B59CB9FA698}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.xproj", "{C61714A6-F633-44FB-97F4-C91F425C1D15}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.xproj", "{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.xproj", "{43DAFAC6-5343-4621-960E-A8A977EA3F0B}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.xproj", "{20354386-3E71-4046-A269-3BC2A06F3EC8}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.xproj", "{48EA5BBE-70E2-4198-869D-D7E59C45F30D}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.xproj", "{661B70D7-F56A-46E0-9B81-6227B591B5E7}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.xproj", "{881F7AD1-A84E-47A2-9402-115C63C4031E}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.xproj", "{0EBC910B-8867-4D3E-8686-91F34183D839}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 35c0646..65bf236 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -57,4 +57,7 @@
       <Name>Grpc.Examples</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.Examples.MathClient.project.json" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj
new file mode 100644
index 0000000..4655bd4
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>fd48deca-1622-4173-b1d9-2101cf5e7c5f</ProjectGuid>
+    <RootNamespace>Grpc.Examples.MathClient</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
new file mode 100644
index 0000000..b254f15
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/project.json
@@ -0,0 +1,53 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.Examples": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index 74d79b4..26b42b6 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -57,4 +57,7 @@
       <Name>Grpc.Examples</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.Examples.MathServer.project.json" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj
new file mode 100644
index 0000000..38a449e
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>58579368-5372-4e67-acd6-9b59cb9fa698</ProjectGuid>
+    <RootNamespace>Grpc.Examples.MathServer</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
new file mode 100644
index 0000000..b254f15
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/project.json
@@ -0,0 +1,53 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.Examples": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 3fd28c6..4c7d893 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -69,6 +69,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.Examples.Tests.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj
new file mode 100644
index 0000000..9cecd18
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>c61714a6-f633-44fb-97f4-c91f425c1d15</ProjectGuid>
+    <RootNamespace>Grpc.Examples.Tests</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index ee11105..324c209 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -110,7 +110,7 @@
             {
                 var responses = await call.ResponseStream.ToListAsync();
                 CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
-                    responses.ConvertAll((n) => n.Num_));
+                    responses.Select((n) => n.Num_));
             }
         }
 
@@ -162,7 +162,7 @@
         {
             using (var call = client.Sum())
             {
-                var numbers = new List<long> { 10, 20, 30 }.ConvertAll(n => new Num { Num_ = n });
+                var numbers = new List<long> { 10, 20, 30 }.Select(n => new Num { Num_ = n });
 
                 await call.RequestStream.WriteAllAsync(numbers);
                 var result = await call.ResponseAsync;
@@ -185,8 +185,8 @@
                 await call.RequestStream.WriteAllAsync(divArgsList);
                 var result = await call.ResponseStream.ToListAsync();
 
-                CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
-                CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
+                CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.Select((divReply) => divReply.Quotient));
+                CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.Select((divReply) => divReply.Remainder));
             }
         }
     }
diff --git a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
index ea87802..1a522ca 100644
--- a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if DOTNET5_4
+#if NETSTANDARD1_5
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Examples.Tests/project.json b/src/csharp/Grpc.Examples.Tests/project.json
new file mode 100644
index 0000000..d2779e8
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/project.json
@@ -0,0 +1,55 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.Examples": {
+      "target": "project"
+    },
+    "NUnit": "3.2.0",
+    "NUnitLite": "3.2.0-*"
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 30170ab..3dfa84e 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -69,6 +69,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.Examples.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.project.json b/src/csharp/Grpc.Examples/Grpc.Examples.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.xproj b/src/csharp/Grpc.Examples/Grpc.Examples.xproj
new file mode 100644
index 0000000..d1d7e6d
--- /dev/null
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>c77b792d-fc78-4ce2-9522-b40b0803c636</ProjectGuid>
+    <RootNamespace>Grpc.Examples</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/project.json b/src/csharp/Grpc.Examples/project.json
new file mode 100644
index 0000000..7d3f4dc
--- /dev/null
+++ b/src/csharp/Grpc.Examples/project.json
@@ -0,0 +1,27 @@
+{
+  "buildOptions": {
+  },
+
+  "dependencies": {
+    "Grpc.Core": {
+      "target": "project"
+    },
+    "Google.Protobuf": "3.0.0-beta3"
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      }
+    },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index a5ee4fd..aefacfb 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -74,6 +74,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.HealthCheck.Tests.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj
new file mode 100644
index 0000000..724c5b2
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>43dafac6-5343-4621-960e-a8a977ea3f0b</ProjectGuid>
+    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
index 0820523..4463467 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if DOTNET5_4
+#if NETSTANDARD1_5
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.HealthCheck.Tests/project.json b/src/csharp/Grpc.HealthCheck.Tests/project.json
new file mode 100644
index 0000000..74599bd
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/project.json
@@ -0,0 +1,55 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.HealthCheck": {
+      "target": "project"
+    },
+    "NUnit": "3.2.0",
+    "NUnitLite": "3.2.0-*"
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 2697b74..7db8b2d 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -65,6 +65,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="Grpc.HealthCheck.nuspec" />
+    <None Include="Grpc.HealthCheck.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj
new file mode 100644
index 0000000..5806a7a
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>3be4ad0b-2bf0-4d68-b625-f6018ef0dcfa</ProjectGuid>
+    <RootNamespace>Grpc.HealthCheck</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
new file mode 100644
index 0000000..eb57608
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -0,0 +1,35 @@
+{
+  "version": "0.15.0-dev",
+  "title": "gRPC C# Healthchecking",
+  "authors": [ "Google Inc." ],
+  "copyright": "Copyright 2015, Google Inc.",
+  "packOptions": {
+    "summary": "Implementation of gRPC health service",
+    "description": "Example implementation of grpc.health.v1 service that can be used for health-checking.",
+    "owners": [ "grpc-packages" ],
+    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+    "projectUrl": "https://github.com/grpc/grpc",
+    "requireLicenseAcceptance": false,
+    "tags": [ "gRPC health check" ]
+  },
+  "dependencies": {
+    "Grpc.Core": "0.15.0-dev",
+    "Google.Protobuf": "3.0.0-beta3"
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      }
+    },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 339a754..91fb3ce 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -83,6 +83,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.IntegrationTesting.Client.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj
new file mode 100644
index 0000000..7f456cf
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>48ea5bbe-70e2-4198-869d-d7e59c45f30d</ProjectGuid>
+    <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/project.json b/src/csharp/Grpc.IntegrationTesting.Client/project.json
new file mode 100644
index 0000000..e5ba04d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/project.json
@@ -0,0 +1,56 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.IntegrationTesting": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45",
+        "net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
index 0dc2751..dda26a6 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -59,5 +59,6 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />
+    <None Include="Grpc.IntegrationTesting.QpsWorker.project.json" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj
new file mode 100644
index 0000000..15bec44
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>661b70d7-f56a-46e0-9b81-6227b591b5e7</ProjectGuid>
+    <RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
new file mode 100644
index 0000000..e5ba04d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
@@ -0,0 +1,56 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.IntegrationTesting": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45",
+        "net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 27a5650..f73d99d 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -83,6 +83,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.IntegrationTesting.Server.project.json" />
     <None Include="packages.config" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj
new file mode 100644
index 0000000..689eb0b
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>881f7ad1-a84e-47a2-9402-115c63c4031e</ProjectGuid>
+    <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/project.json b/src/csharp/Grpc.IntegrationTesting.Server/project.json
new file mode 100644
index 0000000..e5ba04d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/project.json
@@ -0,0 +1,56 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.IntegrationTesting": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45",
+        "net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
index d6eba74..8bd3d78 100644
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -57,4 +57,7 @@
       <Name>Grpc.IntegrationTesting</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.IntegrationTesting.StressClient.project.json" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
new file mode 100644
index 0000000..2f4fdcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>0ebc910b-8867-4d3e-8686-91f34183d839</ProjectGuid>
+    <RootNamespace>Grpc.IntegrationTesting.StressClient</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
new file mode 100644
index 0000000..e5ba04d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
@@ -0,0 +1,56 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.IntegrationTesting": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": { },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45",
+        "net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
index 37786b6..eb7b55a 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
@@ -40,7 +40,6 @@
 using Grpc.Core;
 using Grpc.Core.Utils;
 using Grpc.Testing;
-using Moq;
 using NUnit.Framework;
 
 namespace Grpc.IntegrationTesting
@@ -49,14 +48,16 @@
     {
         TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
 
+        // TODO: replace Moq by some mocking library with CoreCLR support.
+#if !NETSTANDARD1_5
         [Test]
         public void ExpandedParamOverloadCanBeMocked()
         {
             var expected = new SimpleResponse();
 
-            var mockClient = new Mock<TestService.TestServiceClient>();
+            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
             // mocking is relatively clumsy because one needs to specify value for all the optional params.
-            mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
+            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
 
             Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest()));
         }
@@ -66,11 +67,12 @@
         {
             var expected = new SimpleResponse();
 
-            var mockClient = new Mock<TestService.TestServiceClient>();
-            mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<CallOptions>())).Returns(expected);
+            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
+            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
 
             Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest(), new CallOptions()));
         }
+#endif
 
         [Test]
         public void DefaultMethodStubThrows_UnaryCall()
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
index 5fd0e14..001533c 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
@@ -40,7 +40,6 @@
 using Grpc.Core;
 using Grpc.Core.Utils;
 using Grpc.Testing;
-using Moq;
 using NUnit.Framework;
 
 namespace Grpc.IntegrationTesting
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 0089049..3a07642 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -129,6 +129,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.IntegrationTesting.project.json" />
     <None Include="packages.config">
       <SubType>Designer</SubType>
     </None>
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj
new file mode 100644
index 0000000..357300e
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>20354386-3e71-4046-a269-3bc2a06f3ec8</ProjectGuid>
+    <RootNamespace>Grpc.IntegrationTesting</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index aea40af..e27fe5b 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -145,16 +145,26 @@
 
             if (options.TestCase == "jwt_token_creds")
             {
+#if !NETSTANDARD1_5
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsTrue(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+#else
+                // TODO(jtattermusch): implement this
+                throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
             }
 
             if (options.TestCase == "compute_engine_creds")
             {
+#if !NETSTANDARD1_5
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsFalse(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+#else
+                // TODO(jtattermusch): implement this
+                throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
             }
             return credentials;
         }
@@ -212,6 +222,12 @@
                 case "unimplemented_method":
                     RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel));
                     break;
+                case "client_compressed_unary":
+                    RunClientCompressedUnary(client);
+                    break;
+                case "client_compressed_streaming":
+                    await RunClientCompressedStreamingAsync(client);
+                    break;
                 default:
                     throw new ArgumentException("Unknown test case " + options.TestCase);
             }
@@ -230,13 +246,11 @@
             Console.WriteLine("running large_unary");
             var request = new SimpleRequest
             {
-                ResponseType = PayloadType.Compressable,
                 ResponseSize = 314159,
                 Payload = CreateZerosPayload(271828)
             };
             var response = client.UnaryCall(request);
 
-            Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
             Assert.AreEqual(314159, response.Payload.Body.Length);
             Console.WriteLine("Passed!");
         }
@@ -245,7 +259,7 @@
         {
             Console.WriteLine("running client_streaming");
 
-            var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
+            var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.Select((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
 
             using (var call = client.StreamingInputCall())
             {
@@ -265,18 +279,13 @@
 
             var request = new StreamingOutputCallRequest
             {
-                ResponseType = PayloadType.Compressable,
-                ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) }
+                ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) }
             };
 
             using (var call = client.StreamingOutputCall(request))
             {
                 var responseList = await call.ResponseStream.ToListAsync();
-                foreach (var res in responseList)
-                {
-                    Assert.AreEqual(PayloadType.Compressable, res.Payload.Type);
-                }
-                CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+                CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length));
             }
             Console.WriteLine("Passed!");
         }
@@ -289,46 +298,38 @@
             {
                 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 31415 } },
                     Payload = CreateZerosPayload(27182)
                 });
 
                 Assert.IsTrue(await call.ResponseStream.MoveNext());
-                Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
                 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
 
                 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 9 } },
                     Payload = CreateZerosPayload(8)
                 });
 
                 Assert.IsTrue(await call.ResponseStream.MoveNext());
-                Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
                 Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
 
                 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 2653 } },
                     Payload = CreateZerosPayload(1828)
                 });
 
                 Assert.IsTrue(await call.ResponseStream.MoveNext());
-                Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
                 Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
 
                 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 58979 } },
                     Payload = CreateZerosPayload(45904)
                 });
 
                 Assert.IsTrue(await call.ResponseStream.MoveNext());
-                Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
                 Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
 
                 await call.RequestStream.CompleteAsync();
@@ -357,7 +358,6 @@
 
             var request = new SimpleRequest
             {
-                ResponseType = PayloadType.Compressable,
                 ResponseSize = 314159,
                 Payload = CreateZerosPayload(271828),
                 FillUsername = true,
@@ -367,7 +367,6 @@
             // not setting credentials here because they were set on channel already
             var response = client.UnaryCall(request);
 
-            Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
             Assert.AreEqual(314159, response.Payload.Body.Length);
             Assert.False(string.IsNullOrEmpty(response.OauthScope));
             Assert.True(oauthScope.Contains(response.OauthScope));
@@ -381,7 +380,6 @@
            
             var request = new SimpleRequest
             {
-                ResponseType = PayloadType.Compressable,
                 ResponseSize = 314159,
                 Payload = CreateZerosPayload(271828),
                 FillUsername = true,
@@ -390,7 +388,6 @@
             // not setting credentials here because they were set on channel already
             var response = client.UnaryCall(request);
 
-            Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
             Assert.AreEqual(314159, response.Payload.Body.Length);
             Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
             Console.WriteLine("Passed!");
@@ -398,6 +395,7 @@
 
         public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
         {
+#if !NETSTANDARD1_5
             Console.WriteLine("running oauth2_auth_token");
             ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
             string oauth2Token = await credential.GetAccessTokenForRequestAsync();
@@ -415,10 +413,15 @@
             Assert.True(oauthScope.Contains(response.OauthScope));
             Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
             Console.WriteLine("Passed!");
+#else
+            // TODO(jtattermusch): implement this
+            throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
         }
 
         public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
         {
+#if !NETSTANDARD1_5
             Console.WriteLine("running per_rpc_creds");
             ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
 
@@ -432,6 +435,10 @@
 
             Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
             Console.WriteLine("Passed!");
+#else
+            // TODO(jtattermusch): implement this
+            throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
         }
 
         public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client)
@@ -460,13 +467,11 @@
             {
                 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 31415 } },
                     Payload = CreateZerosPayload(27182)
                 });
 
                 Assert.IsTrue(await call.ResponseStream.MoveNext());
-                Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
                 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
 
                 cts.Cancel();
@@ -526,7 +531,6 @@
                 // step 1: test unary call
                 var request = new SimpleRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseSize = 314159,
                     Payload = CreateZerosPayload(271828)
                 };
@@ -545,7 +549,6 @@
                 // step 2: test full duplex call
                 var request = new StreamingOutputCallRequest
                 {
-                    ResponseType = PayloadType.Compressable,
                     ResponseParameters = { new ResponseParameters { Size = 31415 } },
                     Payload = CreateZerosPayload(27182)
                 };
@@ -618,21 +621,127 @@
             Console.WriteLine("Passed!");
         }
 
+        public static void RunClientCompressedUnary(TestService.TestServiceClient client)
+        {
+            Console.WriteLine("running client_compressed_unary");
+            var probeRequest = new SimpleRequest
+            {
+                ExpectCompressed = new BoolValue
+                {
+                    Value = true  // lie about compression
+                },
+                ResponseSize = 314159,
+                Payload = CreateZerosPayload(271828)
+            };
+            var e = Assert.Throws<RpcException>(() => client.UnaryCall(probeRequest, CreateClientCompressionMetadata(false)));
+            Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode);
+
+            var compressedRequest = new SimpleRequest
+            {
+                ExpectCompressed = new BoolValue
+                {
+                    Value = true
+                },
+                ResponseSize = 314159,
+                Payload = CreateZerosPayload(271828)
+            };
+            var response1 = client.UnaryCall(compressedRequest, CreateClientCompressionMetadata(true));
+            Assert.AreEqual(314159, response1.Payload.Body.Length);
+
+            var uncompressedRequest = new SimpleRequest
+            {
+                ExpectCompressed = new BoolValue
+                {
+                    Value = false
+                },
+                ResponseSize = 314159,
+                Payload = CreateZerosPayload(271828)
+            };
+            var response2 = client.UnaryCall(uncompressedRequest, CreateClientCompressionMetadata(false));
+            Assert.AreEqual(314159, response2.Payload.Body.Length);
+
+            Console.WriteLine("Passed!");
+        }
+
+        public static async Task RunClientCompressedStreamingAsync(TestService.TestServiceClient client)
+        {
+            Console.WriteLine("running client_compressed_streaming");
+            try
+            {
+                var probeCall = client.StreamingInputCall(CreateClientCompressionMetadata(false));
+                await probeCall.RequestStream.WriteAsync(new StreamingInputCallRequest
+                {
+                    ExpectCompressed = new BoolValue
+                    {
+                        Value = true
+                    },
+                    Payload = CreateZerosPayload(27182)
+                });
+
+                // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+                await probeCall;
+                Assert.Fail();
+            }
+            catch (RpcException e)
+            {
+                Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode);
+            }
+
+            var call = client.StreamingInputCall(CreateClientCompressionMetadata(true));
+            await call.RequestStream.WriteAsync(new StreamingInputCallRequest
+            {
+                ExpectCompressed = new BoolValue
+                {
+                    Value = true
+                },
+                Payload = CreateZerosPayload(27182)
+            });
+
+            call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
+            await call.RequestStream.WriteAsync(new StreamingInputCallRequest
+            {
+                ExpectCompressed = new BoolValue
+                {
+                    Value = false
+                },
+                Payload = CreateZerosPayload(45904)
+            });
+            await call.RequestStream.CompleteAsync();
+
+            var response = await call.ResponseAsync;
+            Assert.AreEqual(73086, response.AggregatedPayloadSize);
+
+            Console.WriteLine("Passed!");
+        }
+
         private static Payload CreateZerosPayload(int size)
         {
             return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
         }
 
+        private static Metadata CreateClientCompressionMetadata(bool compressed)
+        {
+            var algorithmName = compressed ? "gzip" : "identity";
+            return new Metadata
+            {
+                { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, algorithmName) }
+            };
+        }
+
         // extracts the client_email field from service account file used for auth test cases
         private static string GetEmailFromServiceAccountFile()
         {
+#if !NETSTANDARD1_5
             string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
             Assert.IsNotNull(keyFile);
-
             var jobject = JObject.Parse(File.ReadAllText(keyFile));
             string email = jobject.GetValue("client_email").Value<string>();
             Assert.IsTrue(email.Length > 0);  // spec requires nonempty client email.
             return email;
+#else
+            // TODO(jtattermusch): implement this
+            throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
         }
 
         private static Metadata CreateTestMetadata()
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index d42501a..1240db1 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -24,46 +24,48 @@
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "CiVzcmMvcHJvdG8vZ3JwYy90ZXN0aW5nL21lc3NhZ2VzLnByb3RvEgxncnBj",
-            "LnRlc3RpbmciQAoHUGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0",
-            "aW5nLlBheWxvYWRUeXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIM",
-            "CgRjb2RlGAEgASgFEg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVl",
-            "c3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXls",
-            "b2FkVHlwZRIVCg1yZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyAB",
-            "KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQg",
-            "ASgIEhgKEGZpbGxfb2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29t",
-            "cHJlc3Npb24YBiABKA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBl",
-            "EjEKD3Jlc3BvbnNlX3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hv",
-            "U3RhdHVzIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
-            "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
-            "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
-            "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
-            "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
-            "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
-            "BRITCgtpbnRlcnZhbF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
-            "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
-            "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
-            "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
-            "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJl",
-            "c3Npb24YBiABKA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEK",
-            "D3Jlc3BvbnNlX3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3Rh",
-            "dHVzIkUKG1N0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2Fk",
-            "GAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiMwoPUmVjb25uZWN0UGFy",
-            "YW1zEiAKGG1heF9yZWNvbm5lY3RfYmFja29mZl9tcxgBIAEoBSIzCg1SZWNv",
-            "bm5lY3RJbmZvEg4KBnBhc3NlZBgBIAEoCBISCgpiYWNrb2ZmX21zGAIgAygF",
-            "Kj8KC1BheWxvYWRUeXBlEhAKDENPTVBSRVNTQUJMRRAAEhIKDlVOQ09NUFJF",
-            "U1NBQkxFEAESCgoGUkFORE9NEAIqMgoPQ29tcHJlc3Npb25UeXBlEggKBE5P",
-            "TkUQABIICgRHWklQEAESCwoHREVGTEFURRACYgZwcm90bzM="));
+            "LnRlc3RpbmciGgoJQm9vbFZhbHVlEg0KBXZhbHVlGAEgASgIIkAKB1BheWxv",
+            "YWQSJwoEdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIM",
+            "CgRib2R5GAIgASgMIisKCkVjaG9TdGF0dXMSDAoEY29kZRgBIAEoBRIPCgdt",
+            "ZXNzYWdlGAIgASgJIs4CCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5",
+            "cGUYASABKA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9u",
+            "c2Vfc2l6ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5n",
+            "LlBheWxvYWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRo",
+            "X3Njb3BlGAUgASgIEjQKE3Jlc3BvbnNlX2NvbXByZXNzZWQYBiABKAsyFy5n",
+            "cnBjLnRlc3RpbmcuQm9vbFZhbHVlEjEKD3Jlc3BvbnNlX3N0YXR1cxgHIAEo",
+            "CzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzEjIKEWV4cGVjdF9jb21wcmVz",
+            "c2VkGAggASgLMhcuZ3JwYy50ZXN0aW5nLkJvb2xWYWx1ZSJfCg5TaW1wbGVS",
+            "ZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
+            "YWQSEAoIdXNlcm5hbWUYAiABKAkSEwoLb2F1dGhfc2NvcGUYAyABKAkidwoZ",
+            "U3RyZWFtaW5nSW5wdXRDYWxsUmVxdWVzdBImCgdwYXlsb2FkGAEgASgLMhUu",
+            "Z3JwYy50ZXN0aW5nLlBheWxvYWQSMgoRZXhwZWN0X2NvbXByZXNzZWQYAiAB",
+            "KAsyFy5ncnBjLnRlc3RpbmcuQm9vbFZhbHVlIj0KGlN0cmVhbWluZ0lucHV0",
+            "Q2FsbFJlc3BvbnNlEh8KF2FnZ3JlZ2F0ZWRfcGF5bG9hZF9zaXplGAEgASgF",
+            "ImQKElJlc3BvbnNlUGFyYW1ldGVycxIMCgRzaXplGAEgASgFEhMKC2ludGVy",
+            "dmFsX3VzGAIgASgFEisKCmNvbXByZXNzZWQYAyABKAsyFy5ncnBjLnRlc3Rp",
+            "bmcuQm9vbFZhbHVlIugBChpTdHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBIw",
+            "Cg1yZXNwb25zZV90eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU",
+            "eXBlEj0KE3Jlc3BvbnNlX3BhcmFtZXRlcnMYAiADKAsyIC5ncnBjLnRlc3Rp",
+            "bmcuUmVzcG9uc2VQYXJhbWV0ZXJzEiYKB3BheWxvYWQYAyABKAsyFS5ncnBj",
+            "LnRlc3RpbmcuUGF5bG9hZBIxCg9yZXNwb25zZV9zdGF0dXMYByABKAsyGC5n",
+            "cnBjLnRlc3RpbmcuRWNob1N0YXR1cyJFChtTdHJlYW1pbmdPdXRwdXRDYWxs",
+            "UmVzcG9uc2USJgoHcGF5bG9hZBgBIAEoCzIVLmdycGMudGVzdGluZy5QYXls",
+            "b2FkIjMKD1JlY29ubmVjdFBhcmFtcxIgChhtYXhfcmVjb25uZWN0X2JhY2tv",
+            "ZmZfbXMYASABKAUiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQYASABKAgS",
+            "EgoKYmFja29mZl9tcxgCIAMoBSofCgtQYXlsb2FkVHlwZRIQCgxDT01QUkVT",
+            "U0FCTEUQAGIGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedClrTypeInfo[] {
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.BoolValue), global::Grpc.Testing.BoolValue.Parser, new[]{ "Value" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Payload), global::Grpc.Testing.Payload.Parser, new[]{ "Type", "Body" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EchoStatus), global::Grpc.Testing.EchoStatus.Parser, new[]{ "Code", "Message" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompressed", "ResponseStatus", "ExpectCompressed" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleResponse), global::Grpc.Testing.SimpleResponse.Parser, new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload", "ExpectCompressed" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), global::Grpc.Testing.StreamingInputCallResponse.Parser, new[]{ "AggregatedPayloadSize" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs", "Compressed" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseStatus" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), global::Grpc.Testing.StreamingOutputCallResponse.Parser, new[]{ "Payload" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectParams), global::Grpc.Testing.ReconnectParams.Parser, new[]{ "MaxReconnectBackoffMs" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectInfo), global::Grpc.Testing.ReconnectInfo.Parser, new[]{ "Passed", "BackoffMs" }, null, null, null)
@@ -74,6 +76,7 @@
   }
   #region Enums
   /// <summary>
+  ///  DEPRECATED, don't use. To be removed shortly.
   ///  The type of payload that should be returned.
   /// </summary>
   public enum PayloadType {
@@ -81,32 +84,123 @@
     ///  Compressable text format.
     /// </summary>
     [pbr::OriginalName("COMPRESSABLE")] Compressable = 0,
-    /// <summary>
-    ///  Uncompressable binary format.
-    /// </summary>
-    [pbr::OriginalName("UNCOMPRESSABLE")] Uncompressable = 1,
-    /// <summary>
-    ///  Randomly chosen from all other formats defined in this enum.
-    /// </summary>
-    [pbr::OriginalName("RANDOM")] Random = 2,
-  }
-
-  /// <summary>
-  ///  Compression algorithms
-  /// </summary>
-  public enum CompressionType {
-    /// <summary>
-    ///  No compression
-    /// </summary>
-    [pbr::OriginalName("NONE")] None = 0,
-    [pbr::OriginalName("GZIP")] Gzip = 1,
-    [pbr::OriginalName("DEFLATE")] Deflate = 2,
   }
 
   #endregion
 
   #region Messages
   /// <summary>
+  ///  TODO(dgq): Go back to using well-known types once
+  ///  https://github.com/grpc/grpc/issues/6980 has been fixed.
+  ///  import "google/protobuf/wrappers.proto";
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BoolValue : pb::IMessage<BoolValue> {
+    private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue());
+    public static pb::MessageParser<BoolValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BoolValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BoolValue(BoolValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public BoolValue Clone() {
+      return new BoolValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private bool value_;
+    /// <summary>
+    ///  The bool value.
+    /// </summary>
+    public bool Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BoolValue);
+    }
+
+    public bool Equals(BoolValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != false) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(BoolValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != false) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
   ///  A block of data, to simply increase gRPC message size.
   /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -115,7 +209,7 @@
     public static pb::MessageParser<Payload> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[0]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -141,6 +235,7 @@
     public const int TypeFieldNumber = 1;
     private global::Grpc.Testing.PayloadType type_ = 0;
     /// <summary>
+    ///  DEPRECATED, don't use. To be removed shortly.
     ///  The type of data in body.
     /// </summary>
     public global::Grpc.Testing.PayloadType Type {
@@ -255,7 +350,7 @@
     public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[1]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -388,7 +483,7 @@
     public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[2]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -407,8 +502,9 @@
       Payload = other.payload_ != null ? other.Payload.Clone() : null;
       fillUsername_ = other.fillUsername_;
       fillOauthScope_ = other.fillOauthScope_;
-      responseCompression_ = other.responseCompression_;
+      ResponseCompressed = other.responseCompressed_ != null ? other.ResponseCompressed.Clone() : null;
       ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
+      ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null;
     }
 
     public SimpleRequest Clone() {
@@ -419,6 +515,7 @@
     public const int ResponseTypeFieldNumber = 1;
     private global::Grpc.Testing.PayloadType responseType_ = 0;
     /// <summary>
+    ///  DEPRECATED, don't use. To be removed shortly.
     ///  Desired payload type in the response from the server.
     ///  If response_type is RANDOM, server randomly chooses one from other formats.
     /// </summary>
@@ -434,7 +531,6 @@
     private int responseSize_;
     /// <summary>
     ///  Desired payload size in the response from the server.
-    ///  If response_type is COMPRESSABLE, this denotes the size before compression.
     /// </summary>
     public int ResponseSize {
       get { return responseSize_; }
@@ -482,16 +578,19 @@
       }
     }
 
-    /// <summary>Field number for the "response_compression" field.</summary>
-    public const int ResponseCompressionFieldNumber = 6;
-    private global::Grpc.Testing.CompressionType responseCompression_ = 0;
+    /// <summary>Field number for the "response_compressed" field.</summary>
+    public const int ResponseCompressedFieldNumber = 6;
+    private global::Grpc.Testing.BoolValue responseCompressed_;
     /// <summary>
-    ///  Compression algorithm to be used by the server for the response (stream)
+    ///  Whether to request the server to compress the response. This field is
+    ///  "nullable" in order to interoperate seamlessly with clients not able to
+    ///  implement the full compression tests by introspecting the call to verify
+    ///  the response's compression status.
     /// </summary>
-    public global::Grpc.Testing.CompressionType ResponseCompression {
-      get { return responseCompression_; }
+    public global::Grpc.Testing.BoolValue ResponseCompressed {
+      get { return responseCompressed_; }
       set {
-        responseCompression_ = value;
+        responseCompressed_ = value;
       }
     }
 
@@ -508,6 +607,19 @@
       }
     }
 
+    /// <summary>Field number for the "expect_compressed" field.</summary>
+    public const int ExpectCompressedFieldNumber = 8;
+    private global::Grpc.Testing.BoolValue expectCompressed_;
+    /// <summary>
+    ///  Whether the server should expect this request to be compressed.
+    /// </summary>
+    public global::Grpc.Testing.BoolValue ExpectCompressed {
+      get { return expectCompressed_; }
+      set {
+        expectCompressed_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as SimpleRequest);
     }
@@ -524,8 +636,9 @@
       if (!object.Equals(Payload, other.Payload)) return false;
       if (FillUsername != other.FillUsername) return false;
       if (FillOauthScope != other.FillOauthScope) return false;
-      if (ResponseCompression != other.ResponseCompression) return false;
+      if (!object.Equals(ResponseCompressed, other.ResponseCompressed)) return false;
       if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
+      if (!object.Equals(ExpectCompressed, other.ExpectCompressed)) return false;
       return true;
     }
 
@@ -536,8 +649,9 @@
       if (payload_ != null) hash ^= Payload.GetHashCode();
       if (FillUsername != false) hash ^= FillUsername.GetHashCode();
       if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
-      if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
+      if (responseCompressed_ != null) hash ^= ResponseCompressed.GetHashCode();
       if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
+      if (expectCompressed_ != null) hash ^= ExpectCompressed.GetHashCode();
       return hash;
     }
 
@@ -566,14 +680,18 @@
         output.WriteRawTag(40);
         output.WriteBool(FillOauthScope);
       }
-      if (ResponseCompression != 0) {
-        output.WriteRawTag(48);
-        output.WriteEnum((int) ResponseCompression);
+      if (responseCompressed_ != null) {
+        output.WriteRawTag(50);
+        output.WriteMessage(ResponseCompressed);
       }
       if (responseStatus_ != null) {
         output.WriteRawTag(58);
         output.WriteMessage(ResponseStatus);
       }
+      if (expectCompressed_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(ExpectCompressed);
+      }
     }
 
     public int CalculateSize() {
@@ -593,12 +711,15 @@
       if (FillOauthScope != false) {
         size += 1 + 1;
       }
-      if (ResponseCompression != 0) {
-        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+      if (responseCompressed_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseCompressed);
       }
       if (responseStatus_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
       }
+      if (expectCompressed_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExpectCompressed);
+      }
       return size;
     }
 
@@ -624,8 +745,11 @@
       if (other.FillOauthScope != false) {
         FillOauthScope = other.FillOauthScope;
       }
-      if (other.ResponseCompression != 0) {
-        ResponseCompression = other.ResponseCompression;
+      if (other.responseCompressed_ != null) {
+        if (responseCompressed_ == null) {
+          responseCompressed_ = new global::Grpc.Testing.BoolValue();
+        }
+        ResponseCompressed.MergeFrom(other.ResponseCompressed);
       }
       if (other.responseStatus_ != null) {
         if (responseStatus_ == null) {
@@ -633,6 +757,12 @@
         }
         ResponseStatus.MergeFrom(other.ResponseStatus);
       }
+      if (other.expectCompressed_ != null) {
+        if (expectCompressed_ == null) {
+          expectCompressed_ = new global::Grpc.Testing.BoolValue();
+        }
+        ExpectCompressed.MergeFrom(other.ExpectCompressed);
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -665,8 +795,11 @@
             FillOauthScope = input.ReadBool();
             break;
           }
-          case 48: {
-            responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+          case 50: {
+            if (responseCompressed_ == null) {
+              responseCompressed_ = new global::Grpc.Testing.BoolValue();
+            }
+            input.ReadMessage(responseCompressed_);
             break;
           }
           case 58: {
@@ -676,6 +809,13 @@
             input.ReadMessage(responseStatus_);
             break;
           }
+          case 66: {
+            if (expectCompressed_ == null) {
+              expectCompressed_ = new global::Grpc.Testing.BoolValue();
+            }
+            input.ReadMessage(expectCompressed_);
+            break;
+          }
         }
       }
     }
@@ -691,7 +831,7 @@
     public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[3]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -867,7 +1007,7 @@
     public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[4]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -882,6 +1022,7 @@
 
     public StreamingInputCallRequest(StreamingInputCallRequest other) : this() {
       Payload = other.payload_ != null ? other.Payload.Clone() : null;
+      ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null;
     }
 
     public StreamingInputCallRequest Clone() {
@@ -901,6 +1042,22 @@
       }
     }
 
+    /// <summary>Field number for the "expect_compressed" field.</summary>
+    public const int ExpectCompressedFieldNumber = 2;
+    private global::Grpc.Testing.BoolValue expectCompressed_;
+    /// <summary>
+    ///  Whether the server should expect this request to be compressed. This field
+    ///  is "nullable" in order to interoperate seamlessly with servers not able to
+    ///  implement the full compression tests by introspecting the call to verify
+    ///  the request's compression status.
+    /// </summary>
+    public global::Grpc.Testing.BoolValue ExpectCompressed {
+      get { return expectCompressed_; }
+      set {
+        expectCompressed_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as StreamingInputCallRequest);
     }
@@ -913,12 +1070,14 @@
         return true;
       }
       if (!object.Equals(Payload, other.Payload)) return false;
+      if (!object.Equals(ExpectCompressed, other.ExpectCompressed)) return false;
       return true;
     }
 
     public override int GetHashCode() {
       int hash = 1;
       if (payload_ != null) hash ^= Payload.GetHashCode();
+      if (expectCompressed_ != null) hash ^= ExpectCompressed.GetHashCode();
       return hash;
     }
 
@@ -931,6 +1090,10 @@
         output.WriteRawTag(10);
         output.WriteMessage(Payload);
       }
+      if (expectCompressed_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(ExpectCompressed);
+      }
     }
 
     public int CalculateSize() {
@@ -938,6 +1101,9 @@
       if (payload_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
       }
+      if (expectCompressed_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExpectCompressed);
+      }
       return size;
     }
 
@@ -951,6 +1117,12 @@
         }
         Payload.MergeFrom(other.Payload);
       }
+      if (other.expectCompressed_ != null) {
+        if (expectCompressed_ == null) {
+          expectCompressed_ = new global::Grpc.Testing.BoolValue();
+        }
+        ExpectCompressed.MergeFrom(other.ExpectCompressed);
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -967,6 +1139,13 @@
             input.ReadMessage(payload_);
             break;
           }
+          case 18: {
+            if (expectCompressed_ == null) {
+              expectCompressed_ = new global::Grpc.Testing.BoolValue();
+            }
+            input.ReadMessage(expectCompressed_);
+            break;
+          }
         }
       }
     }
@@ -982,7 +1161,7 @@
     public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[5]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1091,7 +1270,7 @@
     public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[6]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[7]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1107,6 +1286,7 @@
     public ResponseParameters(ResponseParameters other) : this() {
       size_ = other.size_;
       intervalUs_ = other.intervalUs_;
+      Compressed = other.compressed_ != null ? other.Compressed.Clone() : null;
     }
 
     public ResponseParameters Clone() {
@@ -1118,7 +1298,6 @@
     private int size_;
     /// <summary>
     ///  Desired payload sizes in responses from the server.
-    ///  If response_type is COMPRESSABLE, this denotes the size before compression.
     /// </summary>
     public int Size {
       get { return size_; }
@@ -1141,6 +1320,22 @@
       }
     }
 
+    /// <summary>Field number for the "compressed" field.</summary>
+    public const int CompressedFieldNumber = 3;
+    private global::Grpc.Testing.BoolValue compressed_;
+    /// <summary>
+    ///  Whether to request the server to compress the response. This field is
+    ///  "nullable" in order to interoperate seamlessly with clients not able to
+    ///  implement the full compression tests by introspecting the call to verify
+    ///  the response's compression status.
+    /// </summary>
+    public global::Grpc.Testing.BoolValue Compressed {
+      get { return compressed_; }
+      set {
+        compressed_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as ResponseParameters);
     }
@@ -1154,6 +1349,7 @@
       }
       if (Size != other.Size) return false;
       if (IntervalUs != other.IntervalUs) return false;
+      if (!object.Equals(Compressed, other.Compressed)) return false;
       return true;
     }
 
@@ -1161,6 +1357,7 @@
       int hash = 1;
       if (Size != 0) hash ^= Size.GetHashCode();
       if (IntervalUs != 0) hash ^= IntervalUs.GetHashCode();
+      if (compressed_ != null) hash ^= Compressed.GetHashCode();
       return hash;
     }
 
@@ -1177,6 +1374,10 @@
         output.WriteRawTag(16);
         output.WriteInt32(IntervalUs);
       }
+      if (compressed_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Compressed);
+      }
     }
 
     public int CalculateSize() {
@@ -1187,6 +1388,9 @@
       if (IntervalUs != 0) {
         size += 1 + pb::CodedOutputStream.ComputeInt32Size(IntervalUs);
       }
+      if (compressed_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Compressed);
+      }
       return size;
     }
 
@@ -1200,6 +1404,12 @@
       if (other.IntervalUs != 0) {
         IntervalUs = other.IntervalUs;
       }
+      if (other.compressed_ != null) {
+        if (compressed_ == null) {
+          compressed_ = new global::Grpc.Testing.BoolValue();
+        }
+        Compressed.MergeFrom(other.Compressed);
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -1217,6 +1427,13 @@
             IntervalUs = input.ReadInt32();
             break;
           }
+          case 26: {
+            if (compressed_ == null) {
+              compressed_ = new global::Grpc.Testing.BoolValue();
+            }
+            input.ReadMessage(compressed_);
+            break;
+          }
         }
       }
     }
@@ -1232,7 +1449,7 @@
     public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[7]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[8]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1249,7 +1466,6 @@
       responseType_ = other.responseType_;
       responseParameters_ = other.responseParameters_.Clone();
       Payload = other.payload_ != null ? other.Payload.Clone() : null;
-      responseCompression_ = other.responseCompression_;
       ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
     }
 
@@ -1261,6 +1477,7 @@
     public const int ResponseTypeFieldNumber = 1;
     private global::Grpc.Testing.PayloadType responseType_ = 0;
     /// <summary>
+    ///  DEPRECATED, don't use. To be removed shortly.
     ///  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
@@ -1298,19 +1515,6 @@
       }
     }
 
-    /// <summary>Field number for the "response_compression" field.</summary>
-    public const int ResponseCompressionFieldNumber = 6;
-    private global::Grpc.Testing.CompressionType responseCompression_ = 0;
-    /// <summary>
-    ///  Compression algorithm to be used by the server for the response (stream)
-    /// </summary>
-    public global::Grpc.Testing.CompressionType ResponseCompression {
-      get { return responseCompression_; }
-      set {
-        responseCompression_ = value;
-      }
-    }
-
     /// <summary>Field number for the "response_status" field.</summary>
     public const int ResponseStatusFieldNumber = 7;
     private global::Grpc.Testing.EchoStatus responseStatus_;
@@ -1338,7 +1542,6 @@
       if (ResponseType != other.ResponseType) return false;
       if(!responseParameters_.Equals(other.responseParameters_)) return false;
       if (!object.Equals(Payload, other.Payload)) return false;
-      if (ResponseCompression != other.ResponseCompression) return false;
       if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
       return true;
     }
@@ -1348,7 +1551,6 @@
       if (ResponseType != 0) hash ^= ResponseType.GetHashCode();
       hash ^= responseParameters_.GetHashCode();
       if (payload_ != null) hash ^= Payload.GetHashCode();
-      if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
       if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
       return hash;
     }
@@ -1367,10 +1569,6 @@
         output.WriteRawTag(26);
         output.WriteMessage(Payload);
       }
-      if (ResponseCompression != 0) {
-        output.WriteRawTag(48);
-        output.WriteEnum((int) ResponseCompression);
-      }
       if (responseStatus_ != null) {
         output.WriteRawTag(58);
         output.WriteMessage(ResponseStatus);
@@ -1386,9 +1584,6 @@
       if (payload_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
       }
-      if (ResponseCompression != 0) {
-        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
-      }
       if (responseStatus_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
       }
@@ -1409,9 +1604,6 @@
         }
         Payload.MergeFrom(other.Payload);
       }
-      if (other.ResponseCompression != 0) {
-        ResponseCompression = other.ResponseCompression;
-      }
       if (other.responseStatus_ != null) {
         if (responseStatus_ == null) {
           responseStatus_ = new global::Grpc.Testing.EchoStatus();
@@ -1442,10 +1634,6 @@
             input.ReadMessage(payload_);
             break;
           }
-          case 48: {
-            responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
-            break;
-          }
           case 58: {
             if (responseStatus_ == null) {
               responseStatus_ = new global::Grpc.Testing.EchoStatus();
@@ -1468,7 +1656,7 @@
     public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[8]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1584,7 +1772,7 @@
     public static pb::MessageParser<ReconnectParams> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1692,7 +1880,7 @@
     public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; }
+      get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[11]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index f95af50..9fd575f 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -40,7 +40,6 @@
 using Grpc.Core;
 using Grpc.Core.Utils;
 using Grpc.Testing;
-using Moq;
 using NUnit.Framework;
 
 namespace Grpc.IntegrationTesting
@@ -52,19 +51,14 @@
         Channel channel;
         TestService.TestServiceClient client;
         List<ChannelOption> options;
-        Mock<TestService.TestServiceBase> serviceMock;
         AsyncAuthInterceptor asyncAuthInterceptor;
 
         [SetUp]
         public void Init()
         {
-            serviceMock = new Mock<TestService.TestServiceBase>();
-            serviceMock.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<ServerCallContext>()))
-                .Returns(new Func<SimpleRequest, ServerCallContext, Task<SimpleResponse>>(UnaryCallHandler));
-
             server = new Server
             {
-                Services = { TestService.BindService(serviceMock.Object) },
+                Services = { TestService.BindService(new FakeTestService()) },
                 Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateSslServerCredentials() } }
             };
             server.Start();
@@ -96,7 +90,7 @@
             channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
             client = TestService.NewClient(channel);
 
-            client.UnaryCall(new SimpleRequest {});
+            client.UnaryCall(new SimpleRequest { });
         }
 
         [Test]
@@ -109,11 +103,14 @@
             client.UnaryCall(new SimpleRequest { }, new CallOptions(credentials: callCredentials));
         }
 
-        private Task<SimpleResponse> UnaryCallHandler(SimpleRequest request, ServerCallContext context)
+        private class FakeTestService : TestService.TestServiceBase
         {
-            var authToken = context.RequestHeaders.First((entry) => entry.Key == "authorization").Value;
-            Assert.AreEqual("SECRET_TOKEN", authToken);
-            return Task.FromResult(new SimpleResponse());
+            public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+            {
+                var authToken = context.RequestHeaders.First((entry) => entry.Key == "authorization").Value;
+                Assert.AreEqual("SECRET_TOKEN", authToken);
+                return Task.FromResult(new SimpleResponse());
+            }
         }
     }
 }
diff --git a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
index d8902de..100ff0b 100644
--- a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
+++ b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if DOTNET5_4
+#if NETSTANDARD1_5
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index 774563d..60b9cf4 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -90,7 +90,7 @@
 
         private static string GetPath(string relativePath)
         {
-            var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+            var assemblyDir = Path.GetDirectoryName(typeof(TestCredentials).GetTypeInfo().Assembly.Location);
             return Path.Combine(assemblyDir, relativePath);
         }
     }
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
new file mode 100644
index 0000000..3493ab0
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/project.json
@@ -0,0 +1,72 @@
+{
+  "buildOptions": {
+    "emitEntryPoint": true
+  },
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          "include": "data/*",
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+
+  "dependencies": {
+    "Grpc.Auth": {
+      "target": "project"
+    },
+    "Grpc.Core": {
+      "target": "project"
+    },
+    "Google.Protobuf": "3.0.0-beta3",
+    "CommandLineParser": "1.9.71",
+    "NUnit": "3.2.0",
+    "NUnitLite": "3.2.0-*"
+  },
+  "frameworks": {
+    "net45": {
+      "dependencies": {
+        "Moq": "4.2.1510.2205"
+      },
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      }
+    },
+    "netstandard1.5": {
+      "imports": [
+        "portable-net45",
+        "net45"
+      ],
+      "dependencies": {
+        "NETStandard.Library": "1.5.0-rc2-24027",
+        "System.Linq.Expressions": "4.0.11-rc2-24027"
+      }
+    }
+  }
+}
diff --git a/src/csharp/README.md b/src/csharp/README.md
index 201c5ab..8639413 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -19,33 +19,13 @@
 HOW TO USE
 --------------
 
-**Windows**
+**Windows, Linux, Mac OS X**
 
-- Open Visual Studio and start a new project/solution.
+- Open Visual Studio / MonoDevelop / Xamarin Studio and start a new project/solution.
 
 - Add NuGet package `Grpc` as a dependency (Project options -> Manage NuGet Packages).
-  That will also pull all the transitive dependencies (including the gRPC native library that
-  gRPC C# is using internally).
 
-**Linux (Debian)**
-
-- Open MonoDevelop and start a new project/solution.
-
-- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
-  That will also pull all the transitive dependencies (including the gRPC native library that
-  gRPC C# is using internally).
-
-- NOTE: gRPC C# doesn't have a good story yet for shipping precompiled Linux version of Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin. You can install them using [gRPC Linuxbrew instructions][].
-
-**Mac OS X**
-
-- Open Xamarin Studio and start a new project/solution.
-
-- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
-  That will also pull all the transitive dependencies (including the gRPC native library that
-  gRPC C# is using internally).
-
-- NOTE: gRPC C# doesn't have a good story yet for shipping precompiled Mac OS X version of Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin. You can install them using [gRPC Homebrew instructions][].
+- To be able to generate code from Protocol Buffer (`.proto`) file definitions, add NuGet package `Grpc.Tools` that contains Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin.
 
 BUILD FROM SOURCE
 -----------------
@@ -61,26 +41,15 @@
 - Open `src\csharp\Grpc.sln` (path is relative to gRPC repository root)
   using Visual Studio
 
-**Linux**
+**Linux and Mac OS X**
 
 - The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution:
   ```sh
   # from the gRPC repository root
-  $ make CONFIG=dbg grpc_csharp_ext
-  ```
-
-- Use MonoDevelop to open the solution Grpc.sln
-
-**Mac OS X**
-
-- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution.
-
-  ```sh
-  # from the gRPC repository root
   $ tools/run_tests/run_tests.py -c dbg -l csharp --build_only
   ```
 
-- Use Xamarin Studio to open the solution Grpc.sln
+- Use MonoDevelop / Xamarin Studio to open the solution Grpc.sln
 
 RUNNING TESTS
 -------------
@@ -100,10 +69,17 @@
 tools/run_tests/run_tests.py -l csharp
 ```
 
+ON .NET CORE SUPPORT
+------------------
+
+We are committed to providing full support for [.NET Core](https://dotnet.github.io/) in near future,
+but currently, the support is for .NET Core is experimental/work-in-progress.
+
 DOCUMENTATION
 -------------
-- the gRPC C# reference documentation is available online at [grpc.io][]
-- [Helloworld example][]
+- [API Reference][]
+- [Helloworld Example][]
+- [RouteGuide Tutorial][]
 
 CONTENTS
 --------
@@ -111,15 +87,15 @@
 - ext:
   The extension library that wraps C API to be more digestible by C#.
 - Grpc.Auth:
-  gRPC OAuth2 support.
+  gRPC OAuth2/JWT support.
 - Grpc.Core:
   The main gRPC C# library.
 - Grpc.Examples:
   API examples for math.proto
 - Grpc.Examples.MathClient:
-  An example client that sends some requests to math server.
+  An example client that sends requests to math server.
 - Grpc.Examples.MathServer:
-  An example client that sends some requests to math server.
+  An example server that implements a simple math service.
 - Grpc.IntegrationTesting:
   Cross-language gRPC implementation testing (interop testing).
 
@@ -130,10 +106,6 @@
 
 Prior to version 0.13, installing `grpc_csharp_ext` was required to make gRPC work on Linux and MacOS. Starting with version 0.13, we have improved the packaging story significantly and precompiled versions of the native library for all supported platforms are now shipped with the NuGet package. Just installing the `Grpc` NuGet package should be the only step needed to use gRPC C#, regardless of your platform (Windows, Linux or Mac) and the bitness (32 or 64bit).
 
-[gRPC Linuxbrew instructions]:https://github.com/grpc/homebrew-grpc#quick-install-linux
-[gRPC Homebrew instructions]:https://github.com/grpc/homebrew-grpc#quick-install-linux
-[homebrew]:http://brew.sh
-[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
-[grpc.io]: http://www.grpc.io/docs/installation/csharp.html
-[Debian jessie-backports]:http://backports.debian.org/Instructions/
-[Helloworld example]:../../examples/csharp/helloworld
+[API Reference]: http://www.grpc.io/grpc/csharp/
+[Helloworld Example]: ../../examples/csharp/helloworld
+[RouteGuide Tutorial]: http://www.grpc.io/docs/tutorials/basic/csharp.html 
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 1cc63da..63f8c30 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -41,12 +41,12 @@
 
 @rem Collect the artifacts built by the previous build step if running on Jenkins
 @rem TODO(jtattermusch): is there a better way to do this?
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64\
 
 @rem Collect protoc artifacts built by the previous build step
 xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 4782654..9b8d050 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -249,10 +249,12 @@
 
 GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
     const grpcsharp_batch_context *ctx) {
+  grpc_byte_buffer_reader reader;
   if (!ctx->recv_message) {
     return -1;
   }
-  return (intptr_t)grpc_byte_buffer_length(ctx->recv_message);
+  grpc_byte_buffer_reader_init(&reader, ctx->recv_message);
+  return (intptr_t)grpc_byte_buffer_length(reader.buffer_out);
 }
 
 /*
diff --git a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec b/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
deleted file mode 100644
index cc688e2..0000000
--- a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package>
-  <metadata>
-    <id>grpc.native.csharp</id>
-    <version>$version$</version>
-    <authors>Google Inc.</authors>
-    <owners>grpc-packages</owners>
-    <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
-    <projectUrl>http://github.com/grpc/grpc</projectUrl>
-    <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <description>Native extension needed by gRPC C# library. This is not the package you are looking for, it is only meant to be used as a dependency.</description>
-    <releaseNotes>Release of gRPC C core $version$ libraries.</releaseNotes>
-    <copyright>Copyright 2015</copyright>
-    <title>gRPC C# Native Extension</title>
-    <summary>Native library required by gRPC C#</summary>
-    <tags>gRPC native</tags>
-  </metadata>
-  <files>
-    <file src="grpc.native.csharp.targets" target="\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets" />
-    <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
-    <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
-    <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
-    <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
-    <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
-    <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
-  </files>
-</package>
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 7280762..05f52a1 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -45,9 +45,6 @@
 var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
 var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
 
-var incompressible_data = fs.readFileSync(
-    __dirname + '/../../../test/cpp/interop/rnd.dat');
-
 /**
  * Create a buffer filled with size zeroes
  * @param {number} size The length of the buffer
@@ -88,15 +85,7 @@
 }
 
 function getPayload(payload_type, size) {
-  if (payload_type === 'RANDOM') {
-    payload_type = ['COMPRESSABLE',
-                    'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
-  }
-  var body;
-  switch (payload_type) {
-    case 'COMPRESSABLE': body = zeroBuffer(size); break;
-    case 'UNCOMPRESSABLE': incompressible_data.slice(size); break;
-  }
+  var body = zeroBuffer(size);
   return {type: payload_type, body: body};
 }
 
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index d4849c2..c34b259 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -34,6 +34,7 @@
     "index.js",
     "bin/protoc.js",
     "bin/protoc_plugin.js",
+    "bin/google/protobuf",
     "LICENSE"
   ],
   "main": "index.js"
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
index 343dd48..ac2a37d 100644
--- a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
@@ -41,7 +41,7 @@
  */
 + (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert
                    forHost:(nonnull NSString *)host
-                     error:(NSError **)errorPtr;
+                     error:(NSError * _Nullable * _Nullable)errorPtr;
 /**
  * Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate
  * Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be
@@ -51,6 +51,6 @@
             withPrivateKey:(nullable NSString *)pemPrivateKey
              withCertChain:(nullable NSString *)pemCertChain
                    forHost:(nonnull NSString *)host
-                     error:(NSError **)errorPtr;
+                     error:(NSError * _Nullable * _Nullable)errorPtr;
 
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoMethod.h b/src/objective-c/ProtoRPC/ProtoMethod.h
index f9fdbb3..ae3a272 100644
--- a/src/objective-c/ProtoRPC/ProtoMethod.h
+++ b/src/objective-c/ProtoRPC/ProtoMethod.h
@@ -54,6 +54,9 @@
  * This subclass is empty now. Eventually we'll remove ProtoMethod class
  * to avoid potential naming conflict
  */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 @interface GRPCProtoMethod : ProtoMethod
+#pragma clang diagnostic pop
 
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index 5f91f6b..04fc1e4 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -56,6 +56,9 @@
  * This subclass is empty now. Eventually we'll remove ProtoRPC class
  * to avoid potential naming conflict
  */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 @interface GRPCProtoCall : ProtoRPC
+#pragma clang diagnostic pop
 
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
index 87d06e1..7faae1b 100644
--- a/src/objective-c/ProtoRPC/ProtoService.h
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -55,6 +55,9 @@
  * This subclass is empty now. Eventually we'll remove ProtoService class
  * to avoid potential naming conflict
  */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 @interface GRPCProtoService : ProtoService
+#pragma clang diagnostic pop
 
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index 597c3cf..9740190 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -69,9 +69,9 @@
            requestsWriter:(GRXWriter *)requestsWriter
             responseClass:(Class)responseClass
        responsesWriteable:(id<GRXWriteable>)responsesWriteable {
-  ProtoMethod *methodName = [[ProtoMethod alloc] initWithPackage:_packageName
-                                                         service:_serviceName
-                                                          method:method];
+  GRPCProtoMethod *methodName = [[GRPCProtoMethod alloc] initWithPackage:_packageName
+                                                                 service:_serviceName
+                                                                  method:method];
   return [[ProtoRPC alloc] initWithHost:_host
                                  method:methodName
                          requestsWriter:requestsWriter
diff --git a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
index 5addf26f..107e6de 100644
--- a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
@@ -2,6 +2,10 @@
   s.name     = "RemoteTest"
   s.version  = "0.0.1"
   s.license  = "New BSD"
+  s.authors  = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+  s.homepage = "http://www.grpc.io/"
+  s.summary = "RemoteTest example"
+  s.source = { :git => 'https://github.com/grpc/grpc.git' }
 
   s.ios.deployment_target = '7.1'
   s.osx.deployment_target = '10.9'
diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
index 611eb60..5c2a6d1 100644
--- a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
+++ b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
@@ -7,16 +7,16 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C20055928615A6F8434E26B4 /* libPods-Sample.a */; };
 		6369A2701A9322E20015FC5C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A26F1A9322E20015FC5C /* main.m */; };
 		6369A2731A9322E20015FC5C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2721A9322E20015FC5C /* AppDelegate.m */; };
 		6369A2761A9322E20015FC5C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2751A9322E20015FC5C /* ViewController.m */; };
 		6369A2791A9322E20015FC5C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6369A2771A9322E20015FC5C /* Main.storyboard */; };
 		6369A27B1A9322E20015FC5C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6369A27A1A9322E20015FC5C /* Images.xcassets */; };
-		FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC7B7C4C0410F43B9621631 /* libPods.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		2DC7B7C4C0410F43B9621631 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
 		6369A26A1A9322E20015FC5C /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		6369A26E1A9322E20015FC5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		6369A26F1A9322E20015FC5C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -26,8 +26,8 @@
 		6369A2751A9322E20015FC5C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
 		6369A2781A9322E20015FC5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		6369A27A1A9322E20015FC5C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
-		AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
-		C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+		C20055928615A6F8434E26B4 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -35,7 +35,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */,
+				426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -86,8 +86,8 @@
 		AB3331C9AE6488E61B2B094E /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */,
-				C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */,
+				E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */,
+				5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */,
 			);
 			name = Pods;
 			sourceTree = "<group>";
@@ -95,7 +95,7 @@
 		C4C2C5219053E079C9EFB930 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				2DC7B7C4C0410F43B9621631 /* libPods.a */,
+				C20055928615A6F8434E26B4 /* libPods-Sample.a */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -107,11 +107,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 6369A28D1A9322E20015FC5C /* Build configuration list for PBXNativeTarget "Sample" */;
 			buildPhases = (
-				41F7486D8F66994B0BFB84AF /* Check Pods Manifest.lock */,
+				41F7486D8F66994B0BFB84AF /* [CP] Check Pods Manifest.lock */,
 				6369A2661A9322E20015FC5C /* Sources */,
 				6369A2671A9322E20015FC5C /* Frameworks */,
 				6369A2681A9322E20015FC5C /* Resources */,
-				04554623324BE4A838846086 /* Copy Pods Resources */,
+				04554623324BE4A838846086 /* [CP] Copy Pods Resources */,
+				C7FAD018D05AB5F0B0FE81E2 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -167,29 +168,29 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		04554623324BE4A838846086 /* Copy Pods Resources */ = {
+		04554623324BE4A838846086 /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Copy Pods Resources";
+			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		41F7486D8F66994B0BFB84AF /* Check Pods Manifest.lock */ = {
+		41F7486D8F66994B0BFB84AF /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Check Pods Manifest.lock";
+			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -197,6 +198,21 @@
 			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
+		C7FAD018D05AB5F0B0FE81E2 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -304,7 +320,7 @@
 		};
 		6369A28E1A9322E20015FC5C /* Debug */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */;
+			baseConfigurationReference = E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				INFOPLIST_FILE = Sample/Info.plist;
@@ -315,7 +331,7 @@
 		};
 		6369A28F1A9322E20015FC5C /* Release */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */;
+			baseConfigurationReference = 5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				INFOPLIST_FILE = Sample/Info.plist;
diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
index 2f57160..2a1b30f 100644
--- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
+++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
@@ -7,15 +7,14 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		253D3A297105CA46DA960A11 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC58ACA18DCCB1553531B885 /* libPods.a */; };
 		633BFFC81B950B210007E424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC71B950B210007E424 /* AppDelegate.swift */; };
 		633BFFCA1B950B210007E424 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC91B950B210007E424 /* ViewController.swift */; };
 		633BFFCD1B950B210007E424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCB1B950B210007E424 /* Main.storyboard */; };
 		633BFFCF1B950B210007E424 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCE1B950B210007E424 /* Images.xcassets */; };
+		92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
 		633BFFC21B950B210007E424 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		633BFFC61B950B210007E424 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		633BFFC71B950B210007E424 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -23,8 +22,9 @@
 		633BFFCC1B950B210007E424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		633BFFCE1B950B210007E424 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
 		6367AD231B951655007FD3A4 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
-		C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
-		DC58ACA18DCCB1553531B885 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.debug.xcconfig"; sourceTree = "<group>"; };
+		C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.release.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -32,7 +32,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				253D3A297105CA46DA960A11 /* libPods.a in Frameworks */,
+				92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -42,8 +42,8 @@
 		31F283C976AE97586C17CCD9 /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */,
-				C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */,
+				A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */,
+				C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */,
 			);
 			name = Pods;
 			sourceTree = "<group>";
@@ -90,7 +90,7 @@
 		9D63A7F6423989BA306810CA /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				DC58ACA18DCCB1553531B885 /* libPods.a */,
+				69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -102,12 +102,12 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */;
 			buildPhases = (
-				6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */,
+				6BEEB33CA2705D7D2F2210E6 /* [CP] Check Pods Manifest.lock */,
 				633BFFBE1B950B210007E424 /* Sources */,
 				633BFFBF1B950B210007E424 /* Frameworks */,
 				633BFFC01B950B210007E424 /* Resources */,
-				AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */,
-				A1738A987353B0BF2C64F0F7 /* Embed Pods Frameworks */,
+				AC2F6F9AB1C090BB0BEE6E4D /* [CP] Copy Pods Resources */,
+				A1738A987353B0BF2C64F0F7 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -164,14 +164,14 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */ = {
+		6BEEB33CA2705D7D2F2210E6 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Check Pods Manifest.lock";
+			name = "[CP] Check Pods Manifest.lock";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -179,34 +179,34 @@
 			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
-		A1738A987353B0BF2C64F0F7 /* Embed Pods Frameworks */ = {
+		A1738A987353B0BF2C64F0F7 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Embed Pods Frameworks";
+			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */ = {
+		AC2F6F9AB1C090BB0BEE6E4D /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Copy Pods Resources";
+			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
@@ -320,7 +320,7 @@
 		};
 		633BFFE21B950B210007E424 /* Debug */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */;
+			baseConfigurationReference = A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				INFOPLIST_FILE = Info.plist;
@@ -333,7 +333,7 @@
 		};
 		633BFFE31B950B210007E424 /* Release */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */;
+			baseConfigurationReference = C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				INFOPLIST_FILE = Info.plist;
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 9a8d425..1167a71 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -48,9 +48,9 @@
 static NSString * const kService = @"TestService";
 static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
 
-static ProtoMethod *kInexistentMethod;
-static ProtoMethod *kEmptyCallMethod;
-static ProtoMethod *kUnaryCallMethod;
+static GRPCProtoMethod *kInexistentMethod;
+static GRPCProtoMethod *kEmptyCallMethod;
+static GRPCProtoMethod *kUnaryCallMethod;
 
 /** Observer class for testing that responseMetadata is KVO-compliant */
 @interface PassthroughObserver : NSObject
@@ -109,15 +109,15 @@
   [GRPCCall useInsecureConnectionsForHost:kHostAddress];
 
   // This method isn't implemented by the remote server.
-  kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
-                                                   service:kService
-                                                    method:@"Inexistent"];
-  kEmptyCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
-                                                  service:kService
-                                                   method:@"EmptyCall"];
-  kUnaryCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
-                                                  service:kService
-                                                   method:@"UnaryCall"];
+  kInexistentMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+                                                       service:kService
+                                                        method:@"Inexistent"];
+  kEmptyCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+                                                      service:kService
+                                                       method:@"EmptyCall"];
+  kUnaryCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+                                                      service:kService
+                                                       method:@"UnaryCall"];
 }
 
 - (void)testConnectionToRemoteServer {
@@ -303,9 +303,9 @@
 
   // Try to set parameters to nil for GRPCCall. This should cause an exception
   @try {
-    GRPCCall *call = [[GRPCCall alloc] initWithHost:nil
-                                               path:nil
-                                     requestsWriter:nil];
+    (void)[[GRPCCall alloc] initWithHost:nil
+                                    path:nil
+                          requestsWriter:nil];
     XCTFail(@"Did not receive an exception when parameters are nil");
   } @catch(NSException *theException) {
     NSLog(@"Received exception as expected: %@", theException.name);
@@ -316,9 +316,9 @@
   GRXWriter *requestsWriter = [GRXWriter emptyWriter];
   [requestsWriter finishWithError:nil];
   @try {
-    GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                               path:kUnaryCallMethod.HTTPPath
-                                     requestsWriter:requestsWriter];
+    (void)[[GRPCCall alloc] initWithHost:kHostAddress
+                                    path:kUnaryCallMethod.HTTPPath
+                          requestsWriter:requestsWriter];
     XCTFail(@"Did not receive an exception when GRXWriter has incorrect state.");
   } @catch(NSException *theException) {
     NSLog(@"Received exception as expected: %@", theException.name);
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 781c500..15ce120 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -58,7 +58,7 @@
                  requestedResponseSize:(NSNumber *)responseSize {
   RMTStreamingOutputCallRequest *request = [self message];
   RMTResponseParameters *parameters = [RMTResponseParameters message];
-  parameters.size = responseSize.integerValue;
+  parameters.size = (int)responseSize.integerValue;
   [request.responseParametersArray addObject:parameters];
   request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
   return request;
@@ -80,7 +80,9 @@
 
 #pragma mark Tests
 
+#ifdef GRPC_COMPILE_WITH_CRONET
 static cronet_engine *cronetEngine = NULL;
+#endif
 
 @implementation InteropTests {
   RMTTestService *_service;
@@ -186,7 +188,7 @@
   RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
   for (NSNumber *size in expectedSizes) {
     RMTResponseParameters *parameters = [RMTResponseParameters message];
-    parameters.size = [size integerValue];
+    parameters.size = (int)[size integerValue];
     [request.responseParametersArray addObject:parameters];
   }
 
@@ -282,9 +284,9 @@
   // A buffered pipe to which we never write any value acts as a writer that just hangs.
   GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
 
-  ProtoRPC *call = [_service RPCToStreamingInputCallWithRequestsWriter:requestsBuffer
-                                                               handler:^(RMTStreamingInputCallResponse *response,
-                                                                         NSError *error) {
+  GRPCProtoCall *call = [_service RPCToStreamingInputCallWithRequestsWriter:requestsBuffer
+                                                                    handler:^(RMTStreamingInputCallResponse *response,
+                                                                              NSError *error) {
     XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
     [expectation fulfill];
   }];
@@ -313,7 +315,7 @@
 
   [requestsBuffer writeValue:request];
 
-  __block ProtoRPC *call =
+  __block GRPCProtoCall *call =
       [_service RPCToFullDuplexCallWithRequestsWriter:requestsBuffer
                                          eventHandler:^(BOOL done,
                                                         RMTStreamingOutputCallResponse *response,
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index a7a88a3..6d5f94c 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -4,11 +4,11 @@
 install! 'cocoapods', :deterministic_uuids => false
 
 def shared_pods
-	pod 'Protobuf', :path => "../../../third_party/protobuf"
-	pod 'BoringSSL', :podspec => ".."
-	pod 'CronetFramework', :podspec => ".."
-	pod 'gRPC', :path => "../../.."
-	pod 'RemoteTest', :path => "RemoteTestClient"
+  pod 'Protobuf', :path => "../../../third_party/protobuf", :inhibit_warnings => true
+  pod 'BoringSSL', :podspec => "..", :inhibit_warnings => true
+  pod 'CronetFramework', :podspec => ".."
+  pod 'gRPC', :path => "../../.."
+  pod 'RemoteTest', :path => "RemoteTestClient"
 end
 
 target 'Tests' do
@@ -34,3 +34,19 @@
 target 'InteropTestsLocalCleartext' do
 	shared_pods
 end
+
+post_install do |installer|
+  installer.pods_project.targets.each do |target|
+    target.build_configurations.each do |config|
+      config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES'
+    end
+    if target.name == 'gRPC'
+      target.build_configurations.each do |config|
+        # TODO(zyc) Remove this setting after the issue is resolved
+        # GPR_UNREACHABLE_CODE causes "Control may reach end of non-void
+        # function" warning
+        config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO'
+      end
+    end
+  end
+end
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 89e0ea6..e895fe6 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -893,6 +893,7 @@
 					"$(inherited)",
 				);
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -929,6 +930,7 @@
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -946,6 +948,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */;
 			buildSettings = {
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
@@ -955,6 +958,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */;
 			buildSettings = {
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index 5c53737..b76fb10 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -47,11 +47,23 @@
 #include <zend_exceptions.h>
 #include <zend_hash.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_channel_credentials;
 
+static char *default_pem_root_certs = NULL;
+
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+    char **pem_root_certs) {
+  *pem_root_certs = default_pem_root_certs;
+  if (default_pem_root_certs == NULL) {
+    return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  }
+  return GRPC_SSL_ROOTS_OVERRIDE_OK;
+}
+
 /* Frees and destroys an instance of wrapped_grpc_channel_credentials */
 void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
   wrapped_grpc_channel_credentials *creds =
@@ -94,6 +106,24 @@
 }
 
 /**
+ * Set default roots pem.
+ * @param string pem_roots PEM encoding of the server root certificates
+ * @return void
+ */
+PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
+  char *pem_roots;
+  int pem_roots_length;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pem_roots,
+                            &pem_roots_length) == FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "setDefaultRootsPem expects 1 string", 1 TSRMLS_CC);
+    return;
+  }
+  default_pem_root_certs = gpr_malloc((pem_roots_length + 1) * sizeof(char));
+  memcpy(default_pem_root_certs, pem_roots, pem_roots_length + 1);
+}
+
+/**
  * Create a default channel credentials object.
  * @return ChannelCredentials The new default channel credentials object
  */
@@ -178,6 +208,8 @@
 }
 
 static zend_function_entry channel_credentials_methods[] = {
+  PHP_ME(ChannelCredentials, setDefaultRootsPem, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   PHP_ME(ChannelCredentials, createDefault, NULL,
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   PHP_ME(ChannelCredentials, createSsl, NULL,
@@ -192,6 +224,7 @@
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\ChannelCredentials",
                    channel_credentials_methods);
+  grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
   ce.create_object = create_wrapped_grpc_channel_credentials;
   grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
 }
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 70644fa..df3fe85 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -56,6 +56,10 @@
      */
     public function __construct($hostname, $opts, $channel = null)
     {
+        $ssl_roots = file_get_contents(
+            dirname(__FILE__).'/../../../../etc/roots.pem');
+        ChannelCredentials::setDefaultRootsPem($ssl_roots);
+
         $this->hostname = $hostname;
         $this->update_metadata = null;
         if (isset($opts['update_metadata'])) {
diff --git a/src/proto/grpc/binary_log/v1alpha/log.proto b/src/proto/grpc/binary_log/v1alpha/log.proto
index 83166cd..4665610 100644
--- a/src/proto/grpc/binary_log/v1alpha/log.proto
+++ b/src/proto/grpc/binary_log/v1alpha/log.proto
@@ -29,20 +29,20 @@
 
 syntax = "proto3";
 
-import "google/protobuf/timestamp.proto"
+import "google/protobuf/timestamp.proto";
 
 package grpc.binary_log.v1alpha;
 
 enum Direction {
-  SERVER_SEND;
-  SERVER_RECV;
-  CLIENT_SEND;
-  CLIENT_RECV;
+  SERVER_SEND = 0;
+  SERVER_RECV = 1;
+  CLIENT_SEND = 2;
+  CLIENT_RECV = 3;
 }
 
 message KeyValuePair {
-  string key;
-  string value;
+  string key = 1;
+  string value = 2;
 }
 
 // Any sort of metadata that may be sent in either direction during a call
diff --git a/src/proto/grpc/testing/messages.proto b/src/proto/grpc/testing/messages.proto
index e109015..64998c2 100644
--- a/src/proto/grpc/testing/messages.proto
+++ b/src/proto/grpc/testing/messages.proto
@@ -34,17 +34,24 @@
 
 package grpc.testing;
 
+// TODO(dgq): Go back to using well-known types once
+// https://github.com/grpc/grpc/issues/6980 has been fixed.
+// import "google/protobuf/wrappers.proto";
+message BoolValue {
+  // The bool value.
+  bool value = 1;
+}
+
+// DEPRECATED, don't use. To be removed shortly.
 // The type of payload that should be returned.
 enum PayloadType {
   // Compressable text format.
   COMPRESSABLE = 0;
-
-  // Uncompressable binary format.
-  UNCOMPRESSABLE = 1;
 }
 
 // A block of data, to simply increase gRPC message size.
 message Payload {
+  // DEPRECATED, don't use. To be removed shortly.
   // The type of data in body.
   PayloadType type = 1;
   // Primary contents of payload.
@@ -60,12 +67,12 @@
 
 // Unary request.
 message SimpleRequest {
+  // DEPRECATED, don't use. To be removed shortly.
   // 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.
@@ -77,11 +84,17 @@
   // Whether SimpleResponse should include OAuth scope.
   bool fill_oauth_scope = 5;
 
-  // Whether to request the server to compress the response.
-  bool request_compressed_response = 6;
+  // Whether to request the server to compress the response. This field is
+  // "nullable" in order to interoperate seamlessly with clients not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the response's compression status.
+  BoolValue response_compressed = 6;
 
   // Whether server should return a given status
   EchoStatus response_status = 7;
+
+  // Whether the server should expect this request to be compressed.
+  BoolValue expect_compressed = 8;
 }
 
 // Unary response, as configured by the request.
@@ -100,6 +113,12 @@
   // Optional input payload sent along with the request.
   Payload payload = 1;
 
+  // Whether the server should expect this request to be compressed. This field
+  // is "nullable" in order to interoperate seamlessly with servers not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the request's compression status.
+  BoolValue expect_compressed = 2;
+
   // Not expecting any payload from the response.
 }
 
@@ -112,16 +131,22 @@
 // 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;
+
+  // Whether to request the server to compress the response. This field is
+  // "nullable" in order to interoperate seamlessly with clients not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the response's compression status.
+  BoolValue compressed = 3;
 }
 
 // Server-streaming request.
 message StreamingOutputCallRequest {
+  // DEPRECATED, don't use. To be removed shortly.
   // 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
@@ -134,9 +159,6 @@
   // Optional input payload sent along with the request.
   Payload payload = 3;
 
-  // Whether to request the server to compress the response.
-  bool request_compressed_response = 6;
-
   // Whether server should return a given status
   EchoStatus response_status = 7;
 }
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 3e974eb..f498ed4 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -182,6 +182,8 @@
           '--plugin=protoc-gen-python-grpc={}'.format(
               self.grpc_python_plugin_command),
           '-I {}'.format(GRPC_STEM),
+          '-I .',
+          '-I {}/third_party/protobuf/src'.format(GRPC_STEM),
           '--python_out={}'.format(PROTO_GEN_STEM),
           '--python-grpc_out={}'.format(PROTO_GEN_STEM),
       ] + [path]
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 28adca3..b3eeaad 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -29,8 +29,6 @@
 
 """gRPC's Python API."""
 
-__import__('pkg_resources').declare_namespace(__name__)
-
 import abc
 import enum
 
@@ -438,9 +436,7 @@
   """Affords invoking a unary-unary RPC."""
 
   @abc.abstractmethod
-  def __call__(
-      self, request, timeout=None, metadata=None, credentials=None,
-      with_call=False):
+  def __call__(self, request, timeout=None, metadata=None, credentials=None):
     """Synchronously invokes the underlying RPC.
 
     Args:
@@ -449,12 +445,30 @@
       metadata: An optional sequence of pairs of bytes to be transmitted to the
         service-side of the RPC.
       credentials: An optional CallCredentials for the RPC.
-      with_call: Whether or not to include return a Call for the RPC in addition
-        to the response.
 
     Returns:
-      The response value for the RPC, and a Call for the RPC if with_call was
-        set to True at invocation.
+      The response value for the RPC.
+
+    Raises:
+      RpcError: Indicating that the RPC terminated with non-OK status. The
+        raised RpcError will also be a Call for the RPC affording the RPC's
+        metadata, status code, and details.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def with_call(self, request, timeout=None, metadata=None, credentials=None):
+    """Synchronously invokes the underlying RPC.
+
+    Args:
+      request: The request value for the RPC.
+      timeout: An optional durating of time in seconds to allow for the RPC.
+      metadata: An optional sequence of pairs of bytes to be transmitted to the
+        service-side of the RPC.
+      credentials: An optional CallCredentials for the RPC.
+
+    Returns:
+      The response value for the RPC and a Call value for the RPC.
 
     Raises:
       RpcError: Indicating that the RPC terminated with non-OK status. The
@@ -510,8 +524,7 @@
 
   @abc.abstractmethod
   def __call__(
-      self, request_iterator, timeout=None, metadata=None, credentials=None,
-      with_call=False):
+      self, request_iterator, timeout=None, metadata=None, credentials=None):
     """Synchronously invokes the underlying RPC.
 
     Args:
@@ -520,8 +533,6 @@
       metadata: An optional sequence of pairs of bytes to be transmitted to the
         service-side of the RPC.
       credentials: An optional CallCredentials for the RPC.
-      with_call: Whether or not to include return a Call for the RPC in addition
-        to the response.
 
     Returns:
       The response value for the RPC, and a Call for the RPC if with_call was
@@ -535,6 +546,28 @@
     raise NotImplementedError()
 
   @abc.abstractmethod
+  def with_call(
+      self, request_iterator, timeout=None, metadata=None, credentials=None):
+    """Synchronously invokes the underlying RPC.
+
+    Args:
+      request_iterator: An iterator that yields request values for the RPC.
+      timeout: An optional duration of time in seconds to allow for the RPC.
+      metadata: An optional sequence of pairs of bytes to be transmitted to the
+        service-side of the RPC.
+      credentials: An optional CallCredentials for the RPC.
+
+    Returns:
+      The response value for the RPC and a Call for the RPC.
+
+    Raises:
+      RpcError: Indicating that the RPC terminated with non-OK status. The
+        raised RpcError will also be a Call for the RPC affording the RPC's
+        metadata, status code, and details.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
   def future(
       self, request_iterator, timeout=None, metadata=None, credentials=None):
     """Asynchronously invokes the underlying RPC.
@@ -1171,7 +1204,7 @@
     A Channel to the target through which RPCs may be conducted.
   """
   from grpc import _channel
-  return _channel.Channel(target, options, credentials)
+  return _channel.Channel(target, options, credentials._credentials)
 
 
 def server(generic_rpc_handlers, thread_pool, options=None):
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index d9315d2..1f34bee 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -449,9 +449,7 @@
       )
       return state, operations, deadline, deadline_timespec, None
 
-  def __call__(
-      self, request, timeout=None, metadata=None, credentials=None,
-      with_call=False):
+  def _blocking(self, request, timeout, metadata, credentials):
     state, operations, deadline, deadline_timespec, rendezvous = self._prepare(
         request, timeout, metadata)
     if rendezvous:
@@ -464,7 +462,15 @@
         call.set_credentials(credentials._credentials)
       call.start_batch(cygrpc.Operations(operations), None)
       _handle_event(completion_queue.poll(), state, self._response_deserializer)
-      return _end_unary_response_blocking(state, with_call, deadline)
+      return state, deadline
+
+  def __call__(self, request, timeout=None, metadata=None, credentials=None):
+    state, deadline, = self._blocking(request, timeout, metadata, credentials)
+    return _end_unary_response_blocking(state, False, deadline)
+
+  def with_call(self, request, timeout=None, metadata=None, credentials=None):
+    state, deadline, = self._blocking(request, timeout, metadata, credentials)
+    return _end_unary_response_blocking(state, True, deadline)
 
   def future(self, request, timeout=None, metadata=None, credentials=None):
     state, operations, deadline, deadline_timespec, rendezvous = self._prepare(
@@ -532,9 +538,7 @@
     self._request_serializer = request_serializer
     self._response_deserializer = response_deserializer
 
-  def __call__(
-      self, request_iterator, timeout=None, metadata=None, credentials=None,
-      with_call=False):
+  def _blocking(self, request_iterator, timeout, metadata, credentials):
     deadline, deadline_timespec = _deadline(timeout)
     state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
     completion_queue = cygrpc.CompletionQueue()
@@ -563,7 +567,19 @@
         state.condition.notify_all()
         if not state.due:
           break
-    return _end_unary_response_blocking(state, with_call, deadline)
+    return state, deadline
+
+  def __call__(
+      self, request_iterator, timeout=None, metadata=None, credentials=None):
+    state, deadline, = self._blocking(
+        request_iterator, timeout, metadata, credentials)
+    return _end_unary_response_blocking(state, False, deadline)
+
+  def with_call(
+      self, request_iterator, timeout=None, metadata=None, credentials=None):
+    state, deadline, = self._blocking(
+        request_iterator, timeout, metadata, credentials)
+    return _end_unary_response_blocking(state, True, deadline)
 
   def future(
       self, request_iterator, timeout=None, metadata=None, credentials=None):
@@ -814,6 +830,13 @@
 class Channel(grpc.Channel):
 
   def __init__(self, target, options, credentials):
+    """Constructor.
+
+    Args:
+      target: The target to which to connect.
+      options: Configuration options for the channel.
+      credentials: A cygrpc.ChannelCredentials or None.
+    """
     self._channel = cygrpc.Channel(target, _options(options), credentials)
     self._call_state = _ChannelCallState(self._channel)
     self._connectivity_state = _ChannelConnectivityState(self._channel)
diff --git a/src/python/grpcio/grpc/beta/_client_adaptations.py b/src/python/grpcio/grpc/beta/_client_adaptations.py
index 024808c..56456cc 100644
--- a/src/python/grpcio/grpc/beta/_client_adaptations.py
+++ b/src/python/grpcio/grpc/beta/_client_adaptations.py
@@ -186,9 +186,9 @@
         response_deserializer=response_deserializer)
     effective_metadata = _effective_metadata(metadata, metadata_transformer)
     if with_call:
-      response, call = multi_callable(
+      response, call = multi_callable.with_call(
           request, timeout=timeout, metadata=effective_metadata,
-          credentials=_credentials(protocol_options), with_call=True)
+          credentials=_credentials(protocol_options))
       return response, _Rendezvous(None, None, call)
     else:
       return multi_callable(
@@ -237,9 +237,9 @@
         response_deserializer=response_deserializer)
     effective_metadata = _effective_metadata(metadata, metadata_transformer)
     if with_call:
-      response, call = multi_callable(
+      response, call = multi_callable.with_call(
           request_iterator, timeout=timeout, metadata=effective_metadata,
-          credentials=_credentials(protocol_options), with_call=True)
+          credentials=_credentials(protocol_options))
       return response, _Rendezvous(None, None, call)
     else:
       return multi_callable(
diff --git a/src/python/grpcio/tests/tests.json b/src/python/grpcio/tests/tests.json
index 20d11b2..e384a2f 100644
--- a/src/python/grpcio/tests/tests.json
+++ b/src/python/grpcio/tests/tests.json
@@ -1,12 +1,9 @@
 [
   "_api_test.AllTest",
   "_api_test.ChannelConnectivityTest",
+  "_api_test.ChannelTest",
   "_auth_test.AccessTokenCallCredentialsTest",
   "_auth_test.GoogleCallCredentialsTest",
-  "_base_interface_test.AsyncEasyTest", 
-  "_base_interface_test.AsyncPeasyTest", 
-  "_base_interface_test.SyncEasyTest", 
-  "_base_interface_test.SyncPeasyTest", 
   "_beta_features_test.BetaFeaturesTest", 
   "_beta_features_test.ContextManagementAndLifecycleTest", 
   "_cancel_many_calls_test.CancelManyCallsTest",
@@ -15,22 +12,6 @@
   "_channel_test.ChannelTest", 
   "_connectivity_channel_test.ChannelConnectivityTest", 
   "_connectivity_channel_test.ConnectivityStatesTest",
-  "_core_over_links_base_interface_test.AsyncEasyTest", 
-  "_core_over_links_base_interface_test.AsyncPeasyTest", 
-  "_core_over_links_base_interface_test.SyncEasyTest", 
-  "_core_over_links_base_interface_test.SyncPeasyTest", 
-  "_crust_over_core_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
-  "_crust_over_core_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
-  "_crust_over_core_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_empty_message_test.EmptyMessageTest",
   "_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
   "_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
@@ -42,15 +23,8 @@
   "_implementations_test.CallCredentialsTest",
   "_implementations_test.ChannelCredentialsTest", 
   "_insecure_interop_test.InsecureInteropTest", 
-  "_intermediary_low_test.CancellationTest", 
-  "_intermediary_low_test.EchoTest", 
-  "_intermediary_low_test.ExpirationTest", 
-  "_intermediary_low_test.LonelyClientTest", 
-  "_later_test.LaterTest", 
   "_logging_pool_test.LoggingPoolTest", 
-  "_lonely_invocation_link_test.LonelyInvocationLinkTest", 
-  "_low_test.HangingServerShutdown", 
-  "_low_test.InsecureServerInsecureClient", 
+  "_metadata_code_details_test.MetadataCodeDetailsTest",
   "_metadata_test.MetadataTest",
   "_not_found_test.NotFoundTest", 
   "_python_plugin_test.PythonPluginTest",
@@ -59,8 +33,6 @@
   "_sanity_test.Sanity", 
   "_secure_interop_test.SecureInteropTest", 
   "_thread_cleanup_test.CleanupThreadTest",
-  "_transmission_test.RoundTripTest", 
-  "_transmission_test.TransmissionTest", 
   "_utilities_test.ChannelConnectivityTest", 
   "beta_python_plugin_test.PythonPluginTest", 
   "cygrpc_test.InsecureServerInsecureClient", 
diff --git a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
deleted file mode 100644
index 09ebdef..0000000
--- a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
+++ /dev/null
@@ -1,429 +0,0 @@
-# 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 for the old '_low'."""
-
-import threading
-import time
-import unittest
-
-import six
-from six.moves import queue
-
-from grpc._adapter import _intermediary_low as _low
-
-_STREAM_LENGTH = 300
-_TIMEOUT = 5
-_AFTER_DELAY = 2
-_FUTURE = time.time() + 60 * 60 * 24
-_BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200
-_BYTE_SEQUENCE_SEQUENCE = tuple(
-    bytes(bytearray((row + column) % 256 for column in range(row)))
-    for row in range(_STREAM_LENGTH))
-
-
-class LonelyClientTest(unittest.TestCase):
-
-  def testLonelyClient(self):
-    host = 'nosuchhostexists'
-    port = 54321
-    method = 'test method'
-    deadline = time.time() + _TIMEOUT
-    after_deadline = deadline + _AFTER_DELAY
-    metadata_tag = object()
-    finish_tag = object()
-
-    completion_queue = _low.CompletionQueue()
-    channel = _low.Channel('%s:%d' % (host, port), None)
-    client_call = _low.Call(channel, completion_queue, method, host, deadline)
-
-    client_call.invoke(completion_queue, metadata_tag, finish_tag)
-    first_event = completion_queue.get(after_deadline)
-    self.assertIsNotNone(first_event)
-    second_event = completion_queue.get(after_deadline)
-    self.assertIsNotNone(second_event)
-    kinds = [event.kind for event in (first_event, second_event)]
-    six.assertCountEqual(self,
-        (_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH),
-        kinds)
-
-    self.assertIsNone(completion_queue.get(after_deadline))
-
-    completion_queue.stop()
-    stop_event = completion_queue.get(_FUTURE)
-    self.assertEqual(_low.Event.Kind.STOP, stop_event.kind)
-
-    del client_call
-    del channel
-    del completion_queue
-
-
-def _drive_completion_queue(completion_queue, event_queue):
-  while True:
-    event = completion_queue.get(_FUTURE)
-    if event.kind is _low.Event.Kind.STOP:
-      break
-    event_queue.put(event)
-
-
-class EchoTest(unittest.TestCase):
-
-  def setUp(self):
-    self.host = 'localhost'
-
-    self.server_completion_queue = _low.CompletionQueue()
-    self.server = _low.Server(self.server_completion_queue)
-    port = self.server.add_http2_addr('[::]:0')
-    self.server.start()
-    self.server_events = queue.Queue()
-    self.server_completion_queue_thread = threading.Thread(
-        target=_drive_completion_queue,
-        args=(self.server_completion_queue, self.server_events))
-    self.server_completion_queue_thread.start()
-
-    self.client_completion_queue = _low.CompletionQueue()
-    self.channel = _low.Channel('%s:%d' % (self.host, port), None)
-    self.client_events = queue.Queue()
-    self.client_completion_queue_thread = threading.Thread(
-        target=_drive_completion_queue,
-        args=(self.client_completion_queue, self.client_events))
-    self.client_completion_queue_thread.start()
-
-  def tearDown(self):
-    self.server.stop()
-    self.server.cancel_all_calls()
-    self.server_completion_queue.stop()
-    self.client_completion_queue.stop()
-    self.server_completion_queue_thread.join()
-    self.client_completion_queue_thread.join()
-    del self.server
-
-  def _perform_echo_test(self, test_data):
-    method = 'test method'
-    details = 'test details'
-    server_leading_metadata_key = 'my_server_leading_key'
-    server_leading_metadata_value = 'my_server_leading_value'
-    server_trailing_metadata_key = 'my_server_trailing_key'
-    server_trailing_metadata_value = 'my_server_trailing_value'
-    client_metadata_key = 'my_client_key'
-    client_metadata_value = 'my_client_value'
-    server_leading_binary_metadata_key = 'my_server_leading_key-bin'
-    server_leading_binary_metadata_value = b'\0'*2047
-    server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
-    server_trailing_binary_metadata_value = b'\0'*2047
-    client_binary_metadata_key = 'my_client_key-bin'
-    client_binary_metadata_value = b'\0'*2047
-    deadline = _FUTURE
-    metadata_tag = object()
-    finish_tag = object()
-    write_tag = object()
-    complete_tag = object()
-    service_tag = object()
-    read_tag = object()
-    status_tag = object()
-
-    server_data = []
-    client_data = []
-
-    client_call = _low.Call(self.channel, self.client_completion_queue,
-                            method, self.host, deadline)
-    client_call.add_metadata(client_metadata_key, client_metadata_value)
-    client_call.add_metadata(client_binary_metadata_key,
-                             client_binary_metadata_value)
-
-    client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
-
-    self.server.service(service_tag)
-    service_accepted = self.server_events.get()
-    self.assertIsNotNone(service_accepted)
-    self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED)
-    self.assertIs(service_accepted.tag, service_tag)
-    self.assertEqual(method.encode(), service_accepted.service_acceptance.method)
-    self.assertEqual(self.host.encode(), service_accepted.service_acceptance.host)
-    self.assertIsNotNone(service_accepted.service_acceptance.call)
-    metadata = dict(service_accepted.metadata)
-    self.assertIn(client_metadata_key.encode(), metadata)
-    self.assertEqual(client_metadata_value.encode(), metadata[client_metadata_key.encode()])
-    self.assertIn(client_binary_metadata_key.encode(), metadata)
-    self.assertEqual(client_binary_metadata_value,
-                     metadata[client_binary_metadata_key.encode()])
-    server_call = service_accepted.service_acceptance.call
-    server_call.accept(self.server_completion_queue, finish_tag)
-    server_call.add_metadata(server_leading_metadata_key,
-                             server_leading_metadata_value)
-    server_call.add_metadata(server_leading_binary_metadata_key,
-                             server_leading_binary_metadata_value)
-    server_call.premetadata()
-
-    metadata_accepted = self.client_events.get()
-    self.assertIsNotNone(metadata_accepted)
-    self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
-    self.assertEqual(metadata_tag, metadata_accepted.tag)
-    metadata = dict(metadata_accepted.metadata)
-    self.assertIn(server_leading_metadata_key.encode(), metadata)
-    self.assertEqual(server_leading_metadata_value.encode(),
-                     metadata[server_leading_metadata_key.encode()])
-    self.assertIn(server_leading_binary_metadata_key.encode(), metadata)
-    self.assertEqual(server_leading_binary_metadata_value,
-                     metadata[server_leading_binary_metadata_key.encode()])
-
-    for datum in test_data:
-      client_call.write(datum, write_tag, _low.WriteFlags.WRITE_NO_COMPRESS)
-      write_accepted = self.client_events.get()
-      self.assertIsNotNone(write_accepted)
-      self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
-      self.assertIs(write_accepted.tag, write_tag)
-      self.assertIs(write_accepted.write_accepted, True)
-
-      server_call.read(read_tag)
-      read_accepted = self.server_events.get()
-      self.assertIsNotNone(read_accepted)
-      self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
-      self.assertEqual(read_tag, read_accepted.tag)
-      self.assertIsNotNone(read_accepted.bytes)
-      server_data.append(read_accepted.bytes)
-
-      server_call.write(read_accepted.bytes, write_tag, 0)
-      write_accepted = self.server_events.get()
-      self.assertIsNotNone(write_accepted)
-      self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
-      self.assertEqual(write_tag, write_accepted.tag)
-      self.assertTrue(write_accepted.write_accepted)
-
-      client_call.read(read_tag)
-      read_accepted = self.client_events.get()
-      self.assertIsNotNone(read_accepted)
-      self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
-      self.assertEqual(read_tag, read_accepted.tag)
-      self.assertIsNotNone(read_accepted.bytes)
-      client_data.append(read_accepted.bytes)
-
-    client_call.complete(complete_tag)
-    complete_accepted = self.client_events.get()
-    self.assertIsNotNone(complete_accepted)
-    self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED)
-    self.assertIs(complete_accepted.tag, complete_tag)
-    self.assertIs(complete_accepted.complete_accepted, True)
-
-    server_call.read(read_tag)
-    read_accepted = self.server_events.get()
-    self.assertIsNotNone(read_accepted)
-    self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
-    self.assertEqual(read_tag, read_accepted.tag)
-    self.assertIsNone(read_accepted.bytes)
-
-    server_call.add_metadata(server_trailing_metadata_key,
-                             server_trailing_metadata_value)
-    server_call.add_metadata(server_trailing_binary_metadata_key,
-                             server_trailing_binary_metadata_value)
-
-    server_call.status(_low.Status(_low.Code.OK, details), status_tag)
-    server_terminal_event_one = self.server_events.get()
-    server_terminal_event_two = self.server_events.get()
-    if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED:
-      status_accepted = server_terminal_event_one
-      rpc_accepted = server_terminal_event_two
-    else:
-      status_accepted = server_terminal_event_two
-      rpc_accepted = server_terminal_event_one
-    self.assertIsNotNone(status_accepted)
-    self.assertIsNotNone(rpc_accepted)
-    self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind)
-    self.assertEqual(status_tag, status_accepted.tag)
-    self.assertTrue(status_accepted.complete_accepted)
-    self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
-    self.assertEqual(finish_tag, rpc_accepted.tag)
-    self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status)
-
-    client_call.read(read_tag)
-    client_terminal_event_one = self.client_events.get()
-    client_terminal_event_two = self.client_events.get()
-    if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
-      read_accepted = client_terminal_event_one
-      finish_accepted = client_terminal_event_two
-    else:
-      read_accepted = client_terminal_event_two
-      finish_accepted = client_terminal_event_one
-    self.assertIsNotNone(read_accepted)
-    self.assertIsNotNone(finish_accepted)
-    self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
-    self.assertEqual(read_tag, read_accepted.tag)
-    self.assertIsNone(read_accepted.bytes)
-    self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
-    self.assertEqual(finish_tag, finish_accepted.tag)
-    self.assertEqual(_low.Status(_low.Code.OK, details.encode()), finish_accepted.status)
-    metadata = dict(finish_accepted.metadata)
-    self.assertIn(server_trailing_metadata_key.encode(), metadata)
-    self.assertEqual(server_trailing_metadata_value.encode(),
-                     metadata[server_trailing_metadata_key.encode()])
-    self.assertIn(server_trailing_binary_metadata_key.encode(), metadata)
-    self.assertEqual(server_trailing_binary_metadata_value,
-                     metadata[server_trailing_binary_metadata_key.encode()])
-    self.assertSetEqual(set(key for key, _ in finish_accepted.metadata),
-                        set((server_trailing_metadata_key.encode(),
-                             server_trailing_binary_metadata_key.encode(),)))
-
-    self.assertSequenceEqual(test_data, server_data)
-    self.assertSequenceEqual(test_data, client_data)
-
-  def testNoEcho(self):
-    self._perform_echo_test(())
-
-  def testOneByteEcho(self):
-    self._perform_echo_test([b'\x07'])
-
-  def testOneManyByteEcho(self):
-    self._perform_echo_test([_BYTE_SEQUENCE])
-
-  def testManyOneByteEchoes(self):
-    self._perform_echo_test(
-        [_BYTE_SEQUENCE[i:i+1] for i in range(len(_BYTE_SEQUENCE))])
-
-  def testManyManyByteEchoes(self):
-    self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE)
-
-
-class CancellationTest(unittest.TestCase):
-
-  def setUp(self):
-    self.host = 'localhost'
-
-    self.server_completion_queue = _low.CompletionQueue()
-    self.server = _low.Server(self.server_completion_queue)
-    port = self.server.add_http2_addr('[::]:0')
-    self.server.start()
-    self.server_events = queue.Queue()
-    self.server_completion_queue_thread = threading.Thread(
-        target=_drive_completion_queue,
-        args=(self.server_completion_queue, self.server_events))
-    self.server_completion_queue_thread.start()
-
-    self.client_completion_queue = _low.CompletionQueue()
-    self.channel = _low.Channel('%s:%d' % (self.host, port), None)
-    self.client_events = queue.Queue()
-    self.client_completion_queue_thread = threading.Thread(
-        target=_drive_completion_queue,
-        args=(self.client_completion_queue, self.client_events))
-    self.client_completion_queue_thread.start()
-
-  def tearDown(self):
-    self.server.stop()
-    self.server.cancel_all_calls()
-    self.server_completion_queue.stop()
-    self.client_completion_queue.stop()
-    self.server_completion_queue_thread.join()
-    self.client_completion_queue_thread.join()
-    del self.server
-
-  def testCancellation(self):
-    method = 'test method'
-    deadline = _FUTURE
-    metadata_tag = object()
-    finish_tag = object()
-    write_tag = object()
-    service_tag = object()
-    read_tag = object()
-    test_data = _BYTE_SEQUENCE_SEQUENCE
-
-    server_data = []
-    client_data = []
-
-    client_call = _low.Call(self.channel, self.client_completion_queue,
-                            method, self.host, deadline)
-
-    client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
-
-    self.server.service(service_tag)
-    service_accepted = self.server_events.get()
-    server_call = service_accepted.service_acceptance.call
-
-    server_call.accept(self.server_completion_queue, finish_tag)
-    server_call.premetadata()
-
-    metadata_accepted = self.client_events.get()
-    self.assertIsNotNone(metadata_accepted)
-
-    for datum in test_data:
-      client_call.write(datum, write_tag, 0)
-      write_accepted = self.client_events.get()
-
-      server_call.read(read_tag)
-      read_accepted = self.server_events.get()
-      server_data.append(read_accepted.bytes)
-
-      server_call.write(read_accepted.bytes, write_tag, 0)
-      write_accepted = self.server_events.get()
-      self.assertIsNotNone(write_accepted)
-
-      client_call.read(read_tag)
-      read_accepted = self.client_events.get()
-      client_data.append(read_accepted.bytes)
-
-    client_call.cancel()
-    # cancel() is idempotent.
-    client_call.cancel()
-    client_call.cancel()
-    client_call.cancel()
-
-    server_call.read(read_tag)
-
-    server_terminal_event_one = self.server_events.get()
-    server_terminal_event_two = self.server_events.get()
-    if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
-      read_accepted = server_terminal_event_one
-      rpc_accepted = server_terminal_event_two
-    else:
-      read_accepted = server_terminal_event_two
-      rpc_accepted = server_terminal_event_one
-    self.assertIsNotNone(read_accepted)
-    self.assertIsNotNone(rpc_accepted)
-    self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
-    self.assertIsNone(read_accepted.bytes)
-    self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
-    self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status)
-
-    finish_event = self.client_events.get()
-    self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
-    self.assertEqual(_low.Status(_low.Code.CANCELLED, b'Cancelled'),
-                                 finish_event.status)
-
-    self.assertSequenceEqual(test_data, server_data)
-    self.assertSequenceEqual(test_data, client_data)
-
-
-class ExpirationTest(unittest.TestCase):
-
-  @unittest.skip('TODO(nathaniel): Expiration test!')
-  def testExpiration(self):
-    pass
-
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
-
diff --git a/src/python/grpcio/tests/unit/_adapter/_low_test.py b/src/python/grpcio/tests/unit/_adapter/_low_test.py
deleted file mode 100644
index e09a1f2..0000000
--- a/src/python/grpcio/tests/unit/_adapter/_low_test.py
+++ /dev/null
@@ -1,319 +0,0 @@
-# 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.
-
-import threading
-import time
-import unittest
-
-from grpc import _grpcio_metadata
-from grpc._adapter import _types
-from grpc._adapter import _low
-from tests.unit import test_common
-
-
-def wait_for_events(completion_queues, deadline):
-  """
-  Args:
-    completion_queues: list of completion queues to wait for events on
-    deadline: absolute deadline to wait until
-
-  Returns:
-    a sequence of events of length len(completion_queues).
-  """
-
-  results = [None] * len(completion_queues)
-  lock = threading.Lock()
-  threads = []
-  def set_ith_result(i, completion_queue):
-    result = completion_queue.next(deadline)
-    with lock:
-      results[i] = result
-  for i, completion_queue in enumerate(completion_queues):
-    thread = threading.Thread(target=set_ith_result,
-                              args=[i, completion_queue])
-    thread.start()
-    threads.append(thread)
-  for thread in threads:
-    thread.join()
-  return results
-
-
-class InsecureServerInsecureClient(unittest.TestCase):
-
-  def setUp(self):
-    self.server_completion_queue = _low.CompletionQueue()
-    self.server = _low.Server(self.server_completion_queue, [])
-    self.port = self.server.add_http2_port('[::]:0')
-    self.client_completion_queue = _low.CompletionQueue()
-    self.client_channel = _low.Channel('localhost:%d'%self.port, [])
-
-    self.server.start()
-
-  def tearDown(self):
-    self.server.shutdown()
-    del self.client_channel
-
-    self.client_completion_queue.shutdown()
-    while (self.client_completion_queue.next(float('+inf')).type !=
-           _types.EventType.QUEUE_SHUTDOWN):
-      pass
-    self.server_completion_queue.shutdown()
-    while (self.server_completion_queue.next(float('+inf')).type !=
-           _types.EventType.QUEUE_SHUTDOWN):
-      pass
-
-    del self.client_completion_queue
-    del self.server_completion_queue
-    del self.server
-
-  def testEcho(self):
-    deadline = time.time() + 5
-    event_time_tolerance = 2
-    deadline_tolerance = 0.25
-    client_metadata_ascii_key = 'key'
-    client_metadata_ascii_value = 'val'
-    client_metadata_bin_key = 'key-bin'
-    client_metadata_bin_value = b'\0'*1000
-    server_initial_metadata_key = 'init_me_me_me'
-    server_initial_metadata_value = 'whodawha?'
-    server_trailing_metadata_key = 'california_is_in_a_drought'
-    server_trailing_metadata_value = 'zomg it is'
-    server_status_code = _types.StatusCode.OK
-    server_status_details = 'our work is never over'
-    request = 'blarghaflargh'
-    response = 'his name is robert paulson'
-    method = 'twinkies'
-    host = 'hostess'
-    server_request_tag = object()
-    request_call_result = self.server.request_call(self.server_completion_queue,
-                                                   server_request_tag)
-
-    self.assertEqual(_types.CallError.OK, request_call_result)
-
-    client_call_tag = object()
-    client_call = self.client_channel.create_call(
-        self.client_completion_queue, method, host, deadline)
-    client_initial_metadata = [
-        (client_metadata_ascii_key, client_metadata_ascii_value),
-        (client_metadata_bin_key, client_metadata_bin_value)
-    ]
-    client_start_batch_result = client_call.start_batch([
-        _types.OpArgs.send_initial_metadata(client_initial_metadata),
-        _types.OpArgs.send_message(request, 0),
-        _types.OpArgs.send_close_from_client(),
-        _types.OpArgs.recv_initial_metadata(),
-        _types.OpArgs.recv_message(),
-        _types.OpArgs.recv_status_on_client()
-    ], client_call_tag)
-    self.assertEqual(_types.CallError.OK, client_start_batch_result)
-
-    client_no_event, request_event, = wait_for_events(
-        [self.client_completion_queue, self.server_completion_queue],
-        time.time() + event_time_tolerance)
-    self.assertEqual(client_no_event, None)
-    self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
-    self.assertIsInstance(request_event.call, _low.Call)
-    self.assertIs(server_request_tag, request_event.tag)
-    self.assertEqual(1, len(request_event.results))
-    received_initial_metadata = request_event.results[0].initial_metadata
-    # Check that our metadata were transmitted
-    self.assertTrue(test_common.metadata_transmitted(client_initial_metadata,
-                                                     received_initial_metadata))
-    # Check that Python's user agent string is a part of the full user agent
-    # string
-    received_initial_metadata_dict = dict(received_initial_metadata)
-    self.assertIn(b'user-agent', received_initial_metadata_dict)
-    self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__).encode(),
-                  received_initial_metadata_dict[b'user-agent'])
-    self.assertEqual(method.encode(), request_event.call_details.method)
-    self.assertEqual(host.encode(), request_event.call_details.host)
-    self.assertLess(abs(deadline - request_event.call_details.deadline),
-                    deadline_tolerance)
-
-    # Check that the channel is connected, and that both it and the call have
-    # the proper target and peer; do this after the first flurry of messages to
-    # avoid the possibility that connection was delayed by the core until the
-    # first message was sent.
-    self.assertEqual(_types.ConnectivityState.READY,
-                     self.client_channel.check_connectivity_state(False))
-    self.assertIsNotNone(self.client_channel.target())
-    self.assertIsNotNone(client_call.peer())
-
-    server_call_tag = object()
-    server_call = request_event.call
-    server_initial_metadata = [
-        (server_initial_metadata_key, server_initial_metadata_value)
-    ]
-    server_trailing_metadata = [
-        (server_trailing_metadata_key, server_trailing_metadata_value)
-    ]
-    server_start_batch_result = server_call.start_batch([
-        _types.OpArgs.send_initial_metadata(server_initial_metadata),
-        _types.OpArgs.recv_message(),
-        _types.OpArgs.send_message(response, 0),
-        _types.OpArgs.recv_close_on_server(),
-        _types.OpArgs.send_status_from_server(
-            server_trailing_metadata, server_status_code, server_status_details)
-    ], server_call_tag)
-    self.assertEqual(_types.CallError.OK, server_start_batch_result)
-
-    client_event, server_event, = wait_for_events(
-        [self.client_completion_queue, self.server_completion_queue],
-        time.time() + event_time_tolerance)
-
-    self.assertEqual(6, len(client_event.results))
-    found_client_op_types = set()
-    for client_result in client_event.results:
-      # we expect each op type to be unique
-      self.assertNotIn(client_result.type, found_client_op_types)
-      found_client_op_types.add(client_result.type)
-      if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
-        self.assertTrue(
-            test_common.metadata_transmitted(server_initial_metadata,
-                                             client_result.initial_metadata))
-      elif client_result.type == _types.OpType.RECV_MESSAGE:
-        self.assertEqual(response.encode(), client_result.message)
-      elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
-        self.assertTrue(
-            test_common.metadata_transmitted(server_trailing_metadata,
-                                             client_result.trailing_metadata))
-        self.assertEqual(server_status_details.encode(), client_result.status.details)
-        self.assertEqual(server_status_code, client_result.status.code)
-    self.assertEqual(set([
-          _types.OpType.SEND_INITIAL_METADATA,
-          _types.OpType.SEND_MESSAGE,
-          _types.OpType.SEND_CLOSE_FROM_CLIENT,
-          _types.OpType.RECV_INITIAL_METADATA,
-          _types.OpType.RECV_MESSAGE,
-          _types.OpType.RECV_STATUS_ON_CLIENT
-      ]), found_client_op_types)
-
-    self.assertEqual(5, len(server_event.results))
-    found_server_op_types = set()
-    for server_result in server_event.results:
-      self.assertNotIn(client_result.type, found_server_op_types)
-      found_server_op_types.add(server_result.type)
-      if server_result.type == _types.OpType.RECV_MESSAGE:
-        self.assertEqual(request.encode(), server_result.message)
-      elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
-        self.assertFalse(server_result.cancelled)
-    self.assertEqual(set([
-          _types.OpType.SEND_INITIAL_METADATA,
-          _types.OpType.RECV_MESSAGE,
-          _types.OpType.SEND_MESSAGE,
-          _types.OpType.RECV_CLOSE_ON_SERVER,
-          _types.OpType.SEND_STATUS_FROM_SERVER
-      ]), found_server_op_types)
-
-    del client_call
-    del server_call
-
-
-class HangingServerShutdown(unittest.TestCase):
-
-  def setUp(self):
-    self.server_completion_queue = _low.CompletionQueue()
-    self.server = _low.Server(self.server_completion_queue, [])
-    self.port = self.server.add_http2_port('[::]:0')
-    self.client_completion_queue = _low.CompletionQueue()
-    self.client_channel = _low.Channel('localhost:%d'%self.port, [])
-
-    self.server.start()
-
-  def tearDown(self):
-    self.server.shutdown()
-    del self.client_channel
-
-    self.client_completion_queue.shutdown()
-    self.server_completion_queue.shutdown()
-    while True:
-      client_event, server_event = wait_for_events(
-          [self.client_completion_queue, self.server_completion_queue],
-          float("+inf"))
-      if (client_event.type == _types.EventType.QUEUE_SHUTDOWN and
-          server_event.type == _types.EventType.QUEUE_SHUTDOWN):
-        break
-
-    del self.client_completion_queue
-    del self.server_completion_queue
-    del self.server
-
-  def testHangingServerCall(self):
-    deadline = time.time() + 5
-    deadline_tolerance = 0.25
-    event_time_tolerance = 2
-    cancel_all_calls_time_tolerance = 0.5
-    request = 'blarghaflargh'
-    method = 'twinkies'
-    host = 'hostess'
-    server_request_tag = object()
-    request_call_result = self.server.request_call(self.server_completion_queue,
-                                                   server_request_tag)
-
-    client_call_tag = object()
-    client_call = self.client_channel.create_call(self.client_completion_queue,
-                                                  method, host, deadline)
-    client_start_batch_result = client_call.start_batch([
-        _types.OpArgs.send_initial_metadata([]),
-        _types.OpArgs.send_message(request, 0),
-        _types.OpArgs.send_close_from_client(),
-        _types.OpArgs.recv_initial_metadata(),
-        _types.OpArgs.recv_message(),
-        _types.OpArgs.recv_status_on_client()
-    ], client_call_tag)
-
-    client_no_event, request_event, = wait_for_events(
-        [self.client_completion_queue, self.server_completion_queue],
-        time.time() + event_time_tolerance)
-
-    # Now try to shutdown the server and expect that we see server shutdown
-    # almost immediately after calling cancel_all_calls.
-
-    # First attempt to cancel all calls before shutting down, and expect
-    # our state machine to catch the erroneous API use.
-    with self.assertRaises(RuntimeError):
-      self.server.cancel_all_calls()
-
-    shutdown_tag = object()
-    self.server.shutdown(shutdown_tag)
-    pre_cancel_timestamp = time.time()
-    self.server.cancel_all_calls()
-    finish_shutdown_timestamp = None
-    client_call_event, server_shutdown_event = wait_for_events(
-        [self.client_completion_queue, self.server_completion_queue],
-        time.time() + event_time_tolerance)
-    self.assertIs(shutdown_tag, server_shutdown_event.tag)
-    self.assertGreater(pre_cancel_timestamp + cancel_all_calls_time_tolerance,
-                       time.time())
-
-    del client_call
-
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_api_test.py b/src/python/grpcio/tests/unit/_api_test.py
index 1501ec2..2fe8949 100644
--- a/src/python/grpcio/tests/unit/_api_test.py
+++ b/src/python/grpcio/tests/unit/_api_test.py
@@ -100,5 +100,12 @@
         tuple(grpc.ChannelConnectivity))
 
 
+class ChannelTest(unittest.TestCase):
+
+  def test_secure_channel(self):
+    channel_credentials = grpc.ssl_channel_credentials()
+    channel = grpc.secure_channel('google.com:443', channel_credentials)
+
+
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_channel_connectivity_test.py b/src/python/grpcio/tests/unit/_channel_connectivity_test.py
index a1575ef..ae8de52 100644
--- a/src/python/grpcio/tests/unit/_channel_connectivity_test.py
+++ b/src/python/grpcio/tests/unit/_channel_connectivity_test.py
@@ -135,12 +135,12 @@
     self.assertNotIn(
         grpc.ChannelConnectivity.TRANSIENT_FAILURE, third_connectivities)
     self.assertNotIn(
-        grpc.ChannelConnectivity.FATAL_FAILURE, third_connectivities)
+        grpc.ChannelConnectivity.SHUTDOWN, third_connectivities)
     self.assertNotIn(
         grpc.ChannelConnectivity.TRANSIENT_FAILURE,
         fourth_connectivities)
     self.assertNotIn(
-        grpc.ChannelConnectivity.FATAL_FAILURE, fourth_connectivities)
+        grpc.ChannelConnectivity.SHUTDOWN, fourth_connectivities)
 
   def test_reachable_then_unreachable_channel_connectivity(self):
     server = _server.Server((), futures.ThreadPoolExecutor(max_workers=0))
diff --git a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
deleted file mode 100644
index 2b8981c..0000000
--- a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# 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 Base interface compliance of the core-over-gRPC-links stack."""
-
-import collections
-import logging
-import random
-import time
-import unittest
-
-import six
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.core import implementations
-from grpc.framework.interfaces.base import utilities
-from tests.unit import test_common as grpc_test_common
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.base import test_cases
-from tests.unit.framework.interfaces.base import test_interfaces
-
-
-class _SerializationBehaviors(
-    collections.namedtuple(
-        '_SerializationBehaviors',
-        ('request_serializers', 'request_deserializers', 'response_serializers',
-         'response_deserializers',))):
-  pass
-
-
-class _Links(
-    collections.namedtuple(
-        '_Links',
-        ('invocation_end_link', 'invocation_grpc_link', 'service_grpc_link',
-         'service_end_link'))):
-  pass
-
-
-def _serialization_behaviors_from_serializations(serializations):
-  request_serializers = {}
-  request_deserializers = {}
-  response_serializers = {}
-  response_deserializers = {}
-  for (group, method), serialization in six.iteritems(serializations):
-    request_serializers[group, method] = serialization.serialize_request
-    request_deserializers[group, method] = serialization.deserialize_request
-    response_serializers[group, method] = serialization.serialize_response
-    response_deserializers[group, method] = serialization.deserialize_response
-  return _SerializationBehaviors(
-      request_serializers, request_deserializers, response_serializers,
-      response_deserializers)
-
-
-class _Implementation(test_interfaces.Implementation):
-
-  def instantiate(self, serializations, servicer):
-    serialization_behaviors = _serialization_behaviors_from_serializations(
-        serializations)
-    invocation_end_link = implementations.invocation_end_link()
-    service_end_link = implementations.service_end_link(
-        servicer, test_constants.DEFAULT_TIMEOUT,
-        test_constants.MAXIMUM_TIMEOUT)
-    service_grpc_link = service.service_link(
-        serialization_behaviors.request_deserializers,
-        serialization_behaviors.response_serializers)
-    port = service_grpc_link.add_port('[::]:0', None)
-    channel = _intermediary_low.Channel('localhost:%d' % port, None)
-    invocation_grpc_link = invocation.invocation_link(
-        channel, b'localhost', None,
-        serialization_behaviors.request_serializers,
-        serialization_behaviors.response_deserializers)
-
-    invocation_end_link.join_link(invocation_grpc_link)
-    invocation_grpc_link.join_link(invocation_end_link)
-    service_end_link.join_link(service_grpc_link)
-    service_grpc_link.join_link(service_end_link)
-    invocation_grpc_link.start()
-    service_grpc_link.start()
-    return invocation_end_link, service_end_link, (
-        invocation_grpc_link, service_grpc_link)
-
-  def destantiate(self, memo):
-    invocation_grpc_link, service_grpc_link = memo
-    invocation_grpc_link.stop()
-    service_grpc_link.begin_stop()
-    service_grpc_link.end_stop()
-
-  def invocation_initial_metadata(self):
-    return grpc_test_common.INVOCATION_INITIAL_METADATA
-
-  def service_initial_metadata(self):
-    return grpc_test_common.SERVICE_INITIAL_METADATA
-
-  def invocation_completion(self):
-    return utilities.completion(None, None, None)
-
-  def service_completion(self):
-    return utilities.completion(
-        grpc_test_common.SERVICE_TERMINAL_METADATA,
-        beta_interfaces.StatusCode.OK, 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 completion_transmitted(self, original_completion, transmitted_completion):
-    if (original_completion.terminal_metadata is not None and
-        not grpc_test_common.metadata_transmitted(
-            original_completion.terminal_metadata,
-            transmitted_completion.terminal_metadata)):
-        return False
-    elif original_completion.code is not transmitted_completion.code:
-      return False
-    elif original_completion.message != transmitted_completion.message:
-      return False
-    else:
-      return True
-
-
-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/tests/unit/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
deleted file mode 100644
index 50b9a5a..0000000
--- a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
+++ /dev/null
@@ -1,163 +0,0 @@
-# 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 compliance of the crust-over-core-over-gRPC-links stack."""
-
-import collections
-import unittest
-
-import six
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-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
-from tests.unit import test_common as grpc_test_common
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import test_cases
-from tests.unit.framework.interfaces.face import test_interfaces
-
-
-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 six.iteritems(test_methods):
-    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):
-    pool = logging_pool.pool(test_constants.POOL_SIZE)
-    servicer = crust_implementations.servicer(
-        method_implementations, multi_method_implementation, pool)
-    serialization_behaviors = _serialization_behaviors_from_test_methods(
-        methods)
-    invocation_end_link = core_implementations.invocation_end_link()
-    service_end_link = core_implementations.service_end_link(
-        servicer, test_constants.DEFAULT_TIMEOUT,
-        test_constants.MAXIMUM_TIMEOUT)
-    service_grpc_link = service.service_link(
-        serialization_behaviors.request_deserializers,
-        serialization_behaviors.response_serializers)
-    port = service_grpc_link.add_port('[::]:0', None)
-    channel = _intermediary_low.Channel('localhost:%d' % port, None)
-    invocation_grpc_link = invocation.invocation_link(
-        channel, b'localhost', None,
-        serialization_behaviors.request_serializers,
-        serialization_behaviors.response_deserializers)
-
-    invocation_end_link.join_link(invocation_grpc_link)
-    invocation_grpc_link.join_link(invocation_end_link)
-    service_grpc_link.join_link(service_end_link)
-    service_end_link.join_link(service_grpc_link)
-    service_end_link.start()
-    invocation_end_link.start()
-    invocation_grpc_link.start()
-    service_grpc_link.start()
-
-    generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
-    # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
-    group = 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 six.iteritems(methods)}
-    dynamic_stub = crust_implementations.dynamic_stub(
-        invocation_end_link, group, cardinalities, pool)
-
-    return generic_stub, {group: dynamic_stub}, (
-        invocation_end_link, invocation_grpc_link, service_grpc_link,
-        service_end_link, pool)
-
-  def destantiate(self, memo):
-    (invocation_end_link, invocation_grpc_link, service_grpc_link,
-     service_end_link, pool) = memo
-    invocation_end_link.stop(0).wait()
-    invocation_grpc_link.stop()
-    service_grpc_link.begin_stop()
-    service_end_link.stop(0).wait()
-    service_grpc_link.end_stop()
-    invocation_end_link.join_link(utilities.NULL_LINK)
-    invocation_grpc_link.join_link(utilities.NULL_LINK)
-    service_grpc_link.join_link(utilities.NULL_LINK)
-    service_end_link.join_link(utilities.NULL_LINK)
-    pool.shutdown(wait=True)
-
-  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 beta_interfaces.StatusCode.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/tests/unit/_links/_lonely_invocation_link_test.py b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
deleted file mode 100644
index 890755f..0000000
--- a/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# 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.
-
-"""A test of invocation-side code unconnected to an RPC server."""
-
-import unittest
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc.framework.interfaces.links import links
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.links import test_cases
-from tests.unit.framework.interfaces.links import test_utilities
-
-_NULL_BEHAVIOR = lambda unused_argument: None
-
-
-class LonelyInvocationLinkTest(unittest.TestCase):
-
-  def testUpAndDown(self):
-    channel = _intermediary_low.Channel('nonexistent:54321', None)
-    invocation_link = invocation.invocation_link(
-        channel, 'nonexistent', None, {}, {})
-
-    invocation_link.start()
-    invocation_link.stop()
-
-  def _test_lonely_invocation_with_termination(self, termination):
-    test_operation_id = object()
-    test_group = 'test package.Test Service'
-    test_method = 'test method'
-    invocation_link_mate = test_utilities.RecordingLink()
-
-    channel = _intermediary_low.Channel('nonexistent:54321', None)
-    invocation_link = invocation.invocation_link(
-        channel, 'nonexistent', None, {}, {})
-    invocation_link.join_link(invocation_link_mate)
-    invocation_link.start()
-
-    ticket = links.Ticket(
-        test_operation_id, 0, test_group, test_method,
-        links.Ticket.Subscription.FULL, test_constants.SHORT_TIMEOUT, 1, None,
-        None, None, None, None, termination, None)
-    invocation_link.accept_ticket(ticket)
-    invocation_link_mate.block_until_tickets_satisfy(test_cases.terminated)
-
-    invocation_link.stop()
-
-    self.assertIsNot(
-        invocation_link_mate.tickets()[-1].termination,
-        links.Ticket.Termination.COMPLETION)
-
-  def testLonelyInvocationLinkWithCommencementTicket(self):
-    self._test_lonely_invocation_with_termination(None)
-
-  def testLonelyInvocationLinkWithEntireTicket(self):
-    self._test_lonely_invocation_with_termination(
-        links.Ticket.Termination.COMPLETION)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/src/python/grpcio/tests/unit/_links/_transmission_test.py b/src/python/grpcio/tests/unit/_links/_transmission_test.py
deleted file mode 100644
index 1f6edd1..0000000
--- a/src/python/grpcio/tests/unit/_links/_transmission_test.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# 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 transmission of tickets across gRPC-on-the-wire."""
-
-import unittest
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.interfaces.links import links
-from tests.unit import test_common
-from tests.unit._links import _proto_scenarios
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.links import test_cases
-from tests.unit.framework.interfaces.links import test_utilities
-
-_IDENTITY = lambda x: x
-
-
-class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
-
-  def create_transmitting_links(self):
-    service_link = service.service_link(
-        {self.group_and_method(): self.deserialize_request},
-        {self.group_and_method(): self.serialize_response})
-    port = service_link.add_port('[::]:0', None)
-    service_link.start()
-    channel = _intermediary_low.Channel('localhost:%d' % port, None)
-    invocation_link = invocation.invocation_link(
-        channel, 'localhost', None,
-        {self.group_and_method(): self.serialize_request},
-        {self.group_and_method(): self.deserialize_response})
-    invocation_link.start()
-    return invocation_link, service_link
-
-  def destroy_transmitting_links(self, invocation_side_link, service_side_link):
-    invocation_side_link.stop()
-    service_side_link.begin_stop()
-    service_side_link.end_stop()
-
-  def create_invocation_initial_metadata(self):
-    return (
-        ('first_invocation_initial_metadata_key', 'just a string value'),
-        ('second_invocation_initial_metadata_key', '0123456789'),
-        ('third_invocation_initial_metadata_key-bin', '\x00\x57' * 100),
-    )
-
-  def create_invocation_terminal_metadata(self):
-    return None
-
-  def create_service_initial_metadata(self):
-    return (
-        ('first_service_initial_metadata_key', 'just another string value'),
-        ('second_service_initial_metadata_key', '9876543210'),
-        ('third_service_initial_metadata_key-bin', '\x00\x59\x02' * 100),
-    )
-
-  def create_service_terminal_metadata(self):
-    return (
-        ('first_service_terminal_metadata_key', 'yet another string value'),
-        ('second_service_terminal_metadata_key', 'abcdefghij'),
-        ('third_service_terminal_metadata_key-bin', '\x00\x37' * 100),
-    )
-
-  def create_invocation_completion(self):
-    return None, None
-
-  def create_service_completion(self):
-    return (
-        beta_interfaces.StatusCode.OK, b'An exuberant test "details" message!')
-
-  def assertMetadataTransmitted(self, original_metadata, transmitted_metadata):
-    self.assertTrue(
-        test_common.metadata_transmitted(
-            original_metadata, transmitted_metadata),
-        '%s erroneously transmitted as %s' % (
-            original_metadata, transmitted_metadata))
-
-
-class RoundTripTest(unittest.TestCase):
-
-  def testZeroMessageRoundTrip(self):
-    test_operation_id = object()
-    test_group = 'test package.Test Group'
-    test_method = 'test method'
-    identity_transformation = {(test_group, test_method): _IDENTITY}
-    test_code = beta_interfaces.StatusCode.OK
-    test_message = 'a test message'
-
-    service_link = service.service_link(
-        identity_transformation, identity_transformation)
-    service_mate = test_utilities.RecordingLink()
-    service_link.join_link(service_mate)
-    port = service_link.add_port('[::]:0', None)
-    service_link.start()
-    channel = _intermediary_low.Channel('localhost:%d' % port, None)
-    invocation_link = invocation.invocation_link(
-        channel, None, None, identity_transformation, identity_transformation)
-    invocation_mate = test_utilities.RecordingLink()
-    invocation_link.join_link(invocation_mate)
-    invocation_link.start()
-
-    invocation_ticket = links.Ticket(
-        test_operation_id, 0, test_group, test_method,
-        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
-        None, None, None, None, links.Ticket.Termination.COMPLETION, None)
-    invocation_link.accept_ticket(invocation_ticket)
-    service_mate.block_until_tickets_satisfy(test_cases.terminated)
-
-    service_ticket = links.Ticket(
-        service_mate.tickets()[-1].operation_id, 0, None, None, None, None,
-        None, None, None, None, test_code, test_message,
-        links.Ticket.Termination.COMPLETION, None)
-    service_link.accept_ticket(service_ticket)
-    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
-
-    invocation_link.stop()
-    service_link.begin_stop()
-    service_link.end_stop()
-
-    self.assertIs(
-        service_mate.tickets()[-1].termination,
-        links.Ticket.Termination.COMPLETION)
-    self.assertIs(
-        invocation_mate.tickets()[-1].termination,
-        links.Ticket.Termination.COMPLETION)
-    self.assertIs(invocation_mate.tickets()[-1].code, test_code)
-    self.assertEqual(invocation_mate.tickets()[-1].message, test_message.encode())
-
-  def _perform_scenario_test(self, scenario):
-    test_operation_id = object()
-    test_group, test_method = scenario.group_and_method()
-    test_code = beta_interfaces.StatusCode.OK
-    test_message = 'a scenario test message'
-
-    service_link = service.service_link(
-        {(test_group, test_method): scenario.deserialize_request},
-        {(test_group, test_method): scenario.serialize_response})
-    service_mate = test_utilities.RecordingLink()
-    service_link.join_link(service_mate)
-    port = service_link.add_port('[::]:0', None)
-    service_link.start()
-    channel = _intermediary_low.Channel('localhost:%d' % port, None)
-    invocation_link = invocation.invocation_link(
-        channel, 'localhost', None,
-        {(test_group, test_method): scenario.serialize_request},
-        {(test_group, test_method): scenario.deserialize_response})
-    invocation_mate = test_utilities.RecordingLink()
-    invocation_link.join_link(invocation_mate)
-    invocation_link.start()
-
-    invocation_ticket = links.Ticket(
-        test_operation_id, 0, test_group, test_method,
-        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
-        None, None, None, None, None, None)
-    invocation_link.accept_ticket(invocation_ticket)
-    requests = scenario.requests()
-    for request_index, request in enumerate(requests):
-      request_ticket = links.Ticket(
-          test_operation_id, 1 + request_index, None, None, None, None, 1, None,
-          request, None, None, None, None, None)
-      invocation_link.accept_ticket(request_ticket)
-      service_mate.block_until_tickets_satisfy(
-          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
-      response_ticket = links.Ticket(
-          service_mate.tickets()[0].operation_id, request_index, None, None,
-          None, None, 1, None, scenario.response_for_request(request), None,
-          None, None, None, None)
-      service_link.accept_ticket(response_ticket)
-      invocation_mate.block_until_tickets_satisfy(
-          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
-    request_count = len(requests)
-    invocation_completion_ticket = links.Ticket(
-        test_operation_id, request_count + 1, None, None, None, None, None,
-        None, None, None, None, None, links.Ticket.Termination.COMPLETION,
-        None)
-    invocation_link.accept_ticket(invocation_completion_ticket)
-    service_mate.block_until_tickets_satisfy(test_cases.terminated)
-    service_completion_ticket = links.Ticket(
-        service_mate.tickets()[0].operation_id, request_count, None, None, None,
-        None, None, None, None, None, test_code, test_message,
-        links.Ticket.Termination.COMPLETION, None)
-    service_link.accept_ticket(service_completion_ticket)
-    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
-
-    invocation_link.stop()
-    service_link.begin_stop()
-    service_link.end_stop()
-
-    observed_requests = tuple(
-        ticket.payload for ticket in service_mate.tickets()
-        if ticket.payload is not None)
-    observed_responses = tuple(
-        ticket.payload for ticket in invocation_mate.tickets()
-        if ticket.payload is not None)
-    self.assertTrue(scenario.verify_requests(observed_requests))
-    self.assertTrue(scenario.verify_responses(observed_responses))
-
-  def testEmptyScenario(self):
-    self._perform_scenario_test(_proto_scenarios.EmptyScenario())
-
-  def testBidirectionallyUnaryScenario(self):
-    self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario())
-
-  def testBidirectionallyStreamingScenario(self):
-    self._perform_scenario_test(
-        _proto_scenarios.BidirectionallyStreamingScenario())
-
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_metadata_code_details_test.py b/src/python/grpcio/tests/unit/_metadata_code_details_test.py
new file mode 100644
index 0000000..dd74268
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_metadata_code_details_test.py
@@ -0,0 +1,523 @@
+# Copyright 2016, 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 application-provided metadata, status code, and details."""
+
+import threading
+import unittest
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+
+_SERIALIZED_REQUEST = b'\x46\x47\x48'
+_SERIALIZED_RESPONSE = b'\x49\x50\x51'
+
+_REQUEST_SERIALIZER = lambda unused_request: _SERIALIZED_REQUEST
+_REQUEST_DESERIALIZER = lambda unused_serialized_request: object()
+_RESPONSE_SERIALIZER = lambda unused_response: _SERIALIZED_RESPONSE
+_RESPONSE_DESERIALIZER = lambda unused_serialized_resopnse: object()
+
+_SERVICE = b'test.TestService'
+_UNARY_UNARY = b'UnaryUnary'
+_UNARY_STREAM = b'UnaryStream'
+_STREAM_UNARY = b'StreamUnary'
+_STREAM_STREAM = b'StreamStream'
+
+_CLIENT_METADATA = (
+    (b'client-md-key', b'client-md-key'),
+    (b'client-md-key-bin', b'\x00\x01')
+)
+
+_SERVER_INITIAL_METADATA = (
+    (b'server-initial-md-key', b'server-initial-md-value'),
+    (b'server-initial-md-key-bin', b'\x00\x02')
+)
+
+_SERVER_TRAILING_METADATA = (
+    (b'server-trailing-md-key', b'server-trailing-md-value'),
+    (b'server-trailing-md-key-bin', b'\x00\x03')
+)
+
+_NON_OK_CODE = grpc.StatusCode.NOT_FOUND
+_DETAILS = b'Test details!'
+
+
+class _Servicer(object):
+
+  def __init__(self):
+    self._lock = threading.Lock()
+    self._code = None
+    self._details = None
+    self._exception = False
+    self._return_none = False
+    self._received_client_metadata = None
+
+  def unary_unary(self, request, context):
+    with self._lock:
+      self._received_client_metadata = context.invocation_metadata()
+      context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+      context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+      if self._code is not None:
+        context.set_code(self._code)
+      if self._details is not None:
+        context.set_details(self._details)
+      if self._exception:
+        raise test_control.Defect()
+      else:
+        return None if self._return_none else object()
+
+  def unary_stream(self, request, context):
+    with self._lock:
+      self._received_client_metadata = context.invocation_metadata()
+      context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+      context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+      if self._code is not None:
+        context.set_code(self._code)
+      if self._details is not None:
+        context.set_details(self._details)
+      for _ in range(test_constants.STREAM_LENGTH // 2):
+        yield _SERIALIZED_RESPONSE
+      if self._exception:
+        raise test_control.Defect()
+
+  def stream_unary(self, request_iterator, context):
+    with self._lock:
+      self._received_client_metadata = context.invocation_metadata()
+      context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+      context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+      if self._code is not None:
+        context.set_code(self._code)
+      if self._details is not None:
+        context.set_details(self._details)
+      # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
+      # request iterator.
+      for ignored_request in request_iterator:
+        pass
+      if self._exception:
+        raise test_control.Defect()
+      else:
+        return None if self._return_none else _SERIALIZED_RESPONSE
+
+  def stream_stream(self, request_iterator, context):
+    with self._lock:
+      self._received_client_metadata = context.invocation_metadata()
+      context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+      context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+      if self._code is not None:
+        context.set_code(self._code)
+      if self._details is not None:
+        context.set_details(self._details)
+      # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
+      # request iterator.
+      for ignored_request in request_iterator:
+        pass
+      for _ in range(test_constants.STREAM_LENGTH // 3):
+        yield object()
+      if self._exception:
+        raise test_control.Defect()
+
+  def set_code(self, code):
+    with self._lock:
+      self._code = code
+
+  def set_details(self, details):
+    with self._lock:
+      self._details = details
+
+  def set_exception(self):
+    with self._lock:
+      self._exception = True
+
+  def set_return_none(self):
+    with self._lock:
+      self._return_none = True
+
+  def received_client_metadata(self):
+    with self._lock:
+      return self._received_client_metadata
+
+
+def _generic_handler(servicer):
+  method_handlers = {
+      _UNARY_UNARY: grpc.unary_unary_rpc_method_handler(
+          servicer.unary_unary, request_deserializer=_REQUEST_DESERIALIZER,
+          response_serializer=_RESPONSE_SERIALIZER),
+      _UNARY_STREAM: grpc.unary_stream_rpc_method_handler(
+          servicer.unary_stream),
+      _STREAM_UNARY: grpc.stream_unary_rpc_method_handler(
+          servicer.stream_unary),
+      _STREAM_STREAM: grpc.stream_stream_rpc_method_handler(
+          servicer.stream_stream, request_deserializer=_REQUEST_DESERIALIZER,
+          response_serializer=_RESPONSE_SERIALIZER),
+  }
+  return grpc.method_handlers_generic_handler(_SERVICE, method_handlers)
+
+
+class MetadataCodeDetailsTest(unittest.TestCase):
+
+  def setUp(self):
+    self._servicer = _Servicer()
+    self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+    self._server = grpc.server(
+        (_generic_handler(self._servicer),), self._server_pool)
+    port = self._server.add_insecure_port('[::]:0')
+    self._server.start()
+
+    channel = grpc.insecure_channel('localhost:{}'.format(port))
+    self._unary_unary = channel.unary_unary(
+        b'/'.join((b'', _SERVICE, _UNARY_UNARY,)),
+        request_serializer=_REQUEST_SERIALIZER,
+        response_deserializer=_RESPONSE_DESERIALIZER,)
+    self._unary_stream = channel.unary_stream(
+        b'/'.join((b'', _SERVICE, _UNARY_STREAM,)),)
+    self._stream_unary = channel.stream_unary(
+        b'/'.join((b'', _SERVICE, _STREAM_UNARY,)),)
+    self._stream_stream = channel.stream_stream(
+        b'/'.join((b'', _SERVICE, _STREAM_STREAM,)),
+        request_serializer=_REQUEST_SERIALIZER,
+        response_deserializer=_RESPONSE_DESERIALIZER,)
+
+
+  def testSuccessfulUnaryUnary(self):
+    self._servicer.set_details(_DETAILS)
+
+    unused_response, call = self._unary_unary.with_call(
+        object(), metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, call.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(grpc.StatusCode.OK, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testSuccessfulUnaryStream(self):
+    self._servicer.set_details(_DETAILS)
+
+    call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    for _ in call:
+      pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(grpc.StatusCode.OK, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testSuccessfulStreamUnary(self):
+    self._servicer.set_details(_DETAILS)
+
+    unused_response, call = self._stream_unary.with_call(
+        iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+        metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, call.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(grpc.StatusCode.OK, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testSuccessfulStreamStream(self):
+    self._servicer.set_details(_DETAILS)
+
+    call = self._stream_stream(
+        iter([object()] * test_constants.STREAM_LENGTH),
+        metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    for _ in call:
+      pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(grpc.StatusCode.OK, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testCustomCodeUnaryUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA,
+            exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeUnaryStream(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+
+    call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    with self.assertRaises(grpc.RpcError):
+      for _ in call:
+        pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testCustomCodeStreamUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      self._stream_unary.with_call(
+          iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+          metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+          _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+          _SERVER_INITIAL_METADATA,
+          exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+          _SERVER_TRAILING_METADATA,
+          exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeStreamStream(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+
+    call = self._stream_stream(
+        iter([object()] * test_constants.STREAM_LENGTH),
+        metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      for _ in call:
+        pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+          _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeExceptionUnaryUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_exception()
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+     self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA,
+            exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeExceptionUnaryStream(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_exception()
+
+    call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    with self.assertRaises(grpc.RpcError):
+      for _ in call:
+        pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testCustomCodeExceptionStreamUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_exception()
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      self._stream_unary.with_call(
+          iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+          metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA,
+            exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeExceptionStreamStream(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_exception()
+
+    call = self._stream_stream(
+        iter([object()] * test_constants.STREAM_LENGTH),
+        metadata=_CLIENT_METADATA)
+    received_initial_metadata = call.initial_metadata()
+    with self.assertRaises(grpc.RpcError):
+      for _ in call:
+        pass
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA, received_initial_metadata))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, call.code())
+    self.assertEqual(_DETAILS, call.details())
+
+  def testCustomCodeReturnNoneUnaryUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_return_none()
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA,
+            exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+  def testCustomCodeReturnNoneStreamUnary(self):
+    self._servicer.set_code(_NON_OK_CODE)
+    self._servicer.set_details(_DETAILS)
+    self._servicer.set_return_none()
+
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      self._stream_unary.with_call(
+          iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+          metadata=_CLIENT_METADATA)
+
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _CLIENT_METADATA, self._servicer.received_client_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_INITIAL_METADATA,
+            exception_context.exception.initial_metadata()))
+    self.assertTrue(
+        test_common.metadata_transmitted(
+            _SERVER_TRAILING_METADATA,
+            exception_context.exception.trailing_metadata()))
+    self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+    self.assertEqual(_DETAILS, exception_context.exception.details())
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_metadata_test.py b/src/python/grpcio/tests/unit/_metadata_test.py
index 77b3901..2cb13f2 100644
--- a/src/python/grpcio/tests/unit/_metadata_test.py
+++ b/src/python/grpcio/tests/unit/_metadata_test.py
@@ -173,8 +173,8 @@
 
   def testUnaryUnary(self):
     multi_callable = self._channel.unary_unary(_UNARY_UNARY)
-    unused_response, call = multi_callable(
-        _REQUEST, metadata=_CLIENT_METADATA, with_call=True)
+    unused_response, call = multi_callable.with_call(
+        _REQUEST, metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
     self.assertTrue(test_common.metadata_transmitted(
@@ -192,9 +192,9 @@
 
   def testStreamUnary(self):
     multi_callable = self._channel.stream_unary(_STREAM_UNARY)
-    unused_response, call = multi_callable(
+    unused_response, call = multi_callable.with_call(
         [_REQUEST] * test_constants.STREAM_LENGTH,
-        metadata=_CLIENT_METADATA, with_call=True)
+        metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
     self.assertTrue(test_common.metadata_transmitted(
diff --git a/src/python/grpcio/tests/unit/_rpc_test.py b/src/python/grpcio/tests/unit/_rpc_test.py
index 8407593..9814504 100644
--- a/src/python/grpcio/tests/unit/_rpc_test.py
+++ b/src/python/grpcio/tests/unit/_rpc_test.py
@@ -27,7 +27,7 @@
 # (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 of gRPC Python's application-layer API."""
+"""Test of RPCs made against gRPC Python's application-layer API."""
 
 import itertools
 import threading
@@ -216,10 +216,9 @@
     expected_response = self._handler.handle_unary_unary(request, None)
 
     multi_callable = _unary_unary_multi_callable(self._channel)
-    response, call = multi_callable(
+    response, call = multi_callable.with_call(
         request, metadata=(
-            (b'test', b'SuccessfulUnaryRequestBlockingUnaryResponseWithCall'),),
-        with_call=True)
+            (b'test', b'SuccessfulUnaryRequestBlockingUnaryResponseWithCall'),))
 
     self.assertEqual(expected_response, response)
     self.assertIs(grpc.StatusCode.OK, call.code())
@@ -266,11 +265,11 @@
     request_iterator = iter(requests)
 
     multi_callable = _stream_unary_multi_callable(self._channel)
-    response, call = multi_callable(
+    response, call = multi_callable.with_call(
         request_iterator,
         metadata=(
             (b'test', b'SuccessfulStreamRequestBlockingUnaryResponseWithCall'),
-        ), with_call=True)
+        ))
 
     self.assertEqual(expected_response, response)
     self.assertIs(grpc.StatusCode.OK, call.code())
@@ -525,10 +524,9 @@
     multi_callable = _unary_unary_multi_callable(self._channel)
     with self._control.pause():
       with self.assertRaises(grpc.RpcError) as exception_context:
-        multi_callable(
+        multi_callable.with_call(
             request, timeout=test_constants.SHORT_TIMEOUT,
-            metadata=((b'test', b'ExpiredUnaryRequestBlockingUnaryResponse'),),
-            with_call=True)
+            metadata=((b'test', b'ExpiredUnaryRequestBlockingUnaryResponse'),))
 
     self.assertIsNotNone(exception_context.exception.initial_metadata())
     self.assertIs(
@@ -640,10 +638,9 @@
     multi_callable = _unary_unary_multi_callable(self._channel)
     with self._control.fail():
       with self.assertRaises(grpc.RpcError) as exception_context:
-        multi_callable(
+        multi_callable.with_call(
             request,
-            metadata=((b'test', b'FailedUnaryRequestBlockingUnaryResponse'),),
-            with_call=True)
+            metadata=((b'test', b'FailedUnaryRequestBlockingUnaryResponse'),))
 
     self.assertIs(grpc.StatusCode.UNKNOWN, exception_context.exception.code())
 
diff --git a/src/python/grpcio/tests/unit/beta/test_utilities.py b/src/python/grpcio/tests/unit/beta/test_utilities.py
index e374b20..8ccad04 100644
--- a/src/python/grpcio/tests/unit/beta/test_utilities.py
+++ b/src/python/grpcio/tests/unit/beta/test_utilities.py
@@ -50,6 +50,6 @@
   """
   target = '%s:%d' % (host, port)
   channel = grpc.secure_channel(
-      target, channel_credentials._credentials,
+      target, channel_credentials,
       ((b'grpc.ssl_target_name_override', server_host_override,),))
   return implementations.Channel(channel)
diff --git a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
deleted file mode 100644
index 43457be..0000000
--- a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# 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 crust-over-core stack."""
-
-import collections
-import unittest
-
-import six
-
-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
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import test_cases
-from tests.unit.framework.interfaces.face import test_interfaces
-from tests.unit.framework.interfaces.links import test_utilities
-
-
-class _Implementation(test_interfaces.Implementation):
-
-  def instantiate(
-      self, methods, method_implementations, multi_method_implementation):
-    pool = logging_pool.pool(test_constants.POOL_SIZE)
-    servicer = crust_implementations.servicer(
-        method_implementations, multi_method_implementation, pool)
-
-    service_end_link = core_implementations.service_end_link(
-        servicer, test_constants.DEFAULT_TIMEOUT,
-        test_constants.MAXIMUM_TIMEOUT)
-    invocation_end_link = core_implementations.invocation_end_link()
-    invocation_end_link.join_link(service_end_link)
-    service_end_link.join_link(invocation_end_link)
-    service_end_link.start()
-    invocation_end_link.start()
-
-    generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
-    # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
-    group = 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 six.iteritems(methods)}
-    dynamic_stub = crust_implementations.dynamic_stub(
-        invocation_end_link, group, cardinalities, pool)
-
-    return generic_stub, {group: dynamic_stub}, (
-        invocation_end_link, service_end_link, pool)
-
-  def destantiate(self, memo):
-    invocation_end_link, service_end_link, pool = memo
-    invocation_end_link.stop(0).wait()
-    service_end_link.stop(0).wait()
-    invocation_end_link.join_link(utilities.NULL_LINK)
-    service_end_link.join_link(utilities.NULL_LINK)
-    pool.shutdown(wait=True)
-
-  def invocation_metadata(self):
-    return object()
-
-  def initial_metadata(self):
-    return object()
-
-  def terminal_metadata(self):
-    return object()
-
-  def code(self):
-    return object()
-
-  def details(self):
-    return object()
-
-  def metadata_transmitted(self, original_metadata, transmitted_metadata):
-    return original_metadata is 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/tests/unit/framework/core/_base_interface_test.py b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
deleted file mode 100644
index 1310292..0000000
--- a/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# 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 the RPC Framework Core's implementation of the Base interface."""
-
-import logging
-import random
-import time
-import unittest
-
-from grpc.framework.core import implementations
-from grpc.framework.interfaces.base import utilities
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.base import test_cases
-from tests.unit.framework.interfaces.base import test_interfaces
-
-
-class _Implementation(test_interfaces.Implementation):
-
-  def __init__(self):
-    self._invocation_initial_metadata = object()
-    self._service_initial_metadata = object()
-    self._invocation_terminal_metadata = object()
-    self._service_terminal_metadata = object()
-
-  def instantiate(self, serializations, servicer):
-    invocation = implementations.invocation_end_link()
-    service = implementations.service_end_link(
-        servicer, test_constants.DEFAULT_TIMEOUT,
-        test_constants.MAXIMUM_TIMEOUT)
-    invocation.join_link(service)
-    service.join_link(invocation)
-    return invocation, service, None
-
-  def destantiate(self, memo):
-    pass
-
-  def invocation_initial_metadata(self):
-    return self._invocation_initial_metadata
-
-  def service_initial_metadata(self):
-    return self._service_initial_metadata
-
-  def invocation_completion(self):
-    return utilities.completion(self._invocation_terminal_metadata, None, None)
-
-  def service_completion(self):
-    return utilities.completion(self._service_terminal_metadata, None, None)
-
-  def metadata_transmitted(self, original_metadata, transmitted_metadata):
-    return transmitted_metadata is original_metadata
-
-  def completion_transmitted(self, original_completion, transmitted_completion):
-    return (
-        (original_completion.terminal_metadata is
-         transmitted_completion.terminal_metadata) and
-        original_completion.code is transmitted_completion.code and
-        original_completion.message is transmitted_completion.message
-    )
-
-
-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/tests/unit/framework/foundation/_later_test.py b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
deleted file mode 100644
index 6c2459e..0000000
--- a/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# 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 of the later module."""
-
-import threading
-import time
-import unittest
-
-from grpc.framework.foundation import later
-
-TICK = 0.1
-
-
-class LaterTest(unittest.TestCase):
-
-  def test_simple_delay(self):
-    lock = threading.Lock()
-    cell = [0]
-    return_value = object()
-
-    def computation():
-      with lock:
-        cell[0] += 1
-      return return_value
-    computation_future = later.later(TICK * 2, computation)
-
-    self.assertFalse(computation_future.done())
-    self.assertFalse(computation_future.cancelled())
-    time.sleep(TICK)
-    self.assertFalse(computation_future.done())
-    self.assertFalse(computation_future.cancelled())
-    with lock:
-      self.assertEqual(0, cell[0])
-    time.sleep(TICK * 2)
-    self.assertTrue(computation_future.done())
-    self.assertFalse(computation_future.cancelled())
-    with lock:
-      self.assertEqual(1, cell[0])
-    self.assertEqual(return_value, computation_future.result())
-
-  def test_callback(self):
-    lock = threading.Lock()
-    cell = [0]
-    callback_called = [False]
-    future_passed_to_callback = [None]
-    def computation():
-      with lock:
-        cell[0] += 1
-    computation_future = later.later(TICK * 2, computation)
-    def callback(outcome):
-      with lock:
-        callback_called[0] = True
-        future_passed_to_callback[0] = outcome
-    computation_future.add_done_callback(callback)
-    time.sleep(TICK)
-    with lock:
-      self.assertFalse(callback_called[0])
-    time.sleep(TICK * 2)
-    with lock:
-      self.assertTrue(callback_called[0])
-      self.assertTrue(future_passed_to_callback[0].done())
-
-      callback_called[0] = False
-      future_passed_to_callback[0] = None
-
-    computation_future.add_done_callback(callback)
-    with lock:
-      self.assertTrue(callback_called[0])
-      self.assertTrue(future_passed_to_callback[0].done())
-
-  def test_cancel(self):
-    lock = threading.Lock()
-    cell = [0]
-    callback_called = [False]
-    future_passed_to_callback = [None]
-    def computation():
-      with lock:
-        cell[0] += 1
-    computation_future = later.later(TICK * 2, computation)
-    def callback(outcome):
-      with lock:
-        callback_called[0] = True
-        future_passed_to_callback[0] = outcome
-    computation_future.add_done_callback(callback)
-    time.sleep(TICK)
-    with lock:
-      self.assertFalse(callback_called[0])
-    computation_future.cancel()
-    self.assertTrue(computation_future.cancelled())
-    self.assertFalse(computation_future.running())
-    self.assertTrue(computation_future.done())
-    with lock:
-      self.assertTrue(callback_called[0])
-      self.assertTrue(future_passed_to_callback[0].cancelled())
-
-  def test_result(self):
-    lock = threading.Lock()
-    cell = [0]
-    callback_called = [False]
-    future_passed_to_callback_cell = [None]
-    return_value = object()
-
-    def computation():
-      with lock:
-        cell[0] += 1
-      return return_value
-    computation_future = later.later(TICK * 2, computation)
-
-    def callback(future_passed_to_callback):
-      with lock:
-        callback_called[0] = True
-        future_passed_to_callback_cell[0] = future_passed_to_callback
-    computation_future.add_done_callback(callback)
-    returned_value = computation_future.result()
-    self.assertEqual(return_value, returned_value)
-
-    # The callback may not yet have been called! Sleep a tick.
-    time.sleep(TICK)
-    with lock:
-      self.assertTrue(callback_called[0])
-      self.assertEqual(return_value, future_passed_to_callback_cell[0].result())
-
-if __name__ == '__main__':
-  unittest.main(verbosity=2)
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 0203954..0e3b992 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -1251,12 +1251,12 @@
   $(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc' % q for q in proto_deps.get(p, []))}
   	$(E) "[PROTOC]  Generating protobuf CC file from $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+  	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
   $(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
   	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+  	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
   endif
 
   % endfor
diff --git a/templates/src/csharp/Grpc.Auth/project.json.template b/templates/src/csharp/Grpc.Auth/project.json.template
new file mode 100644
index 0000000..90ad0eb
--- /dev/null
+++ b/templates/src/csharp/Grpc.Auth/project.json.template
@@ -0,0 +1,34 @@
+%YAML 1.2
+--- |
+  {
+    "version": "${settings.csharp_version}",
+    "title": "gRPC C# Auth",
+    "authors": [ "Google Inc." ],
+    "copyright": "Copyright 2015, Google Inc.",
+    "packOptions": {
+      "summary": "Auth library for C# implementation of gRPC - an RPC library and framework",
+      "description": "Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+      "owners": [ "grpc-packages" ],
+      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+      "projectUrl": "https://github.com/grpc/grpc",
+      "requireLicenseAcceptance": false,
+      "tags": [ "gRPC RPC Protocol HTTP/2 Auth OAuth2" ],
+    },
+    "dependencies": {
+      "Grpc.Core": "${settings.csharp_version}",
+      "Google.Apis.Auth": "1.11.1"
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "net45"
+        ],
+        "dependencies": {
+          "Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027",
+          "NETStandard.Library": "1.5.0-rc2-24027",
+          "System.Threading.Tasks": "4.0.11-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.Core.Tests/project.json.template b/templates/src/csharp/Grpc.Core.Tests/project.json.template
new file mode 100644
index 0000000..bc9fa3e
--- /dev/null
+++ b/templates/src/csharp/Grpc.Core.Tests/project.json.template
@@ -0,0 +1,24 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True"/>
+    "dependencies": {
+      "Grpc.Core": {
+        "target": "project"
+      },
+      "Newtonsoft.Json": "8.0.3",
+      "NUnit": "3.2.0",
+      "NUnitLite": "3.2.0-*"
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    },
+  }
diff --git a/templates/src/csharp/Grpc.Core/project.json.template b/templates/src/csharp/Grpc.Core/project.json.template
new file mode 100644
index 0000000..6f9197f
--- /dev/null
+++ b/templates/src/csharp/Grpc.Core/project.json.template
@@ -0,0 +1,44 @@
+%YAML 1.2
+--- |
+  {
+    "version": "${settings.csharp_version}",
+    "title": "gRPC C# Core",
+    "authors": [ "Google Inc." ],
+    "copyright": "Copyright 2015, Google Inc.",
+    "packOptions": {
+      "summary": "Core C# implementation of gRPC - an RPC library and framework",
+      "description": "Core C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+      "owners": [ "grpc-packages" ],
+      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+      "projectUrl": "https://github.com/grpc/grpc",
+      "requireLicenseAcceptance": false,
+      "tags": [ "gRPC RPC Protocol HTTP/2" ],
+      "files": {
+        "build/net45/": "Grpc.Core.targets",
+        "build/native/bin/windows_x86/": "../nativelibs/windows_x86/grpc_csharp_ext.dll",
+        "build/native/bin/windows_x64/": "../nativelibs/windows_x64/grpc_csharp_ext.dll",
+        "build/native/bin/linux_x86/": "../nativelibs/linux_x86/libgrpc_csharp_ext.so",
+        "build/native/bin/linux_x64/": "../nativelibs/linux_x64/libgrpc_csharp_ext.so",
+        "build/native/bin/macosx_x86/": "../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib",
+        "build/native/bin/macosx_x64/": "../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib"
+      }
+    },
+    "buildOptions": {
+      "embed": [ "../../../etc/roots.pem" ]
+    },
+    "dependencies": {
+      "Ix-Async": "1.2.5"
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027",
+          "System.Threading.Thread": "4.0.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
new file mode 100644
index 0000000..fba401c
--- /dev/null
+++ b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
@@ -0,0 +1,21 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True"/>
+    "dependencies": {
+      "Grpc.Examples": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
new file mode 100644
index 0000000..fba401c
--- /dev/null
+++ b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
@@ -0,0 +1,21 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True"/>
+    "dependencies": {
+      "Grpc.Examples": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.Examples.Tests/project.json.template b/templates/src/csharp/Grpc.Examples.Tests/project.json.template
new file mode 100644
index 0000000..21765f0
--- /dev/null
+++ b/templates/src/csharp/Grpc.Examples.Tests/project.json.template
@@ -0,0 +1,23 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True"/>
+    "dependencies": {
+      "Grpc.Examples": {
+        "target": "project"
+      },
+      "NUnit": "3.2.0",
+      "NUnitLite": "3.2.0-*"
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.Examples/project.json.template b/templates/src/csharp/Grpc.Examples/project.json.template
new file mode 100644
index 0000000..715fc08
--- /dev/null
+++ b/templates/src/csharp/Grpc.Examples/project.json.template
@@ -0,0 +1,27 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=False"/>
+    "dependencies": {
+      "Grpc.Core": {
+        "target": "project"
+      },
+      "Google.Protobuf": "3.0.0-beta3"
+    },
+    "frameworks": {
+      "net45": {
+        "frameworkAssemblies": {
+          "System.Runtime": "",
+          "System.IO": ""
+        }
+      },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template b/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
new file mode 100644
index 0000000..79e6722
--- /dev/null
+++ b/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
@@ -0,0 +1,23 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True"/>
+    "dependencies": {
+      "Grpc.HealthCheck": {
+        "target": "project"
+      },
+      "NUnit": "3.2.0",
+      "NUnitLite": "3.2.0-*"
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.HealthCheck/project.json.template b/templates/src/csharp/Grpc.HealthCheck/project.json.template
new file mode 100644
index 0000000..59073af
--- /dev/null
+++ b/templates/src/csharp/Grpc.HealthCheck/project.json.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+  {
+    "version": "${settings.csharp_version}",
+    "title": "gRPC C# Healthchecking",
+    "authors": [ "Google Inc." ],
+    "copyright": "Copyright 2015, Google Inc.",
+    "packOptions": {
+      "summary": "Implementation of gRPC health service",
+      "description": "Example implementation of grpc.health.v1 service that can be used for health-checking.",
+      "owners": [ "grpc-packages" ],
+      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+      "projectUrl": "https://github.com/grpc/grpc",
+      "requireLicenseAcceptance": false,
+      "tags": [ "gRPC health check" ]
+    },
+    "dependencies": {
+      "Grpc.Core": "${settings.csharp_version}",
+      "Google.Protobuf": "3.0.0-beta3"
+    },
+    "frameworks": {
+      "net45": {
+        "frameworkAssemblies": {
+          "System.Runtime": "",
+          "System.IO": ""
+        }
+      },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
new file mode 100644
index 0000000..10ed549
--- /dev/null
+++ b/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
+    "dependencies": {
+      "Grpc.IntegrationTesting": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45",
+          "net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
new file mode 100644
index 0000000..10ed549
--- /dev/null
+++ b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
+    "dependencies": {
+      "Grpc.IntegrationTesting": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45",
+          "net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
new file mode 100644
index 0000000..10ed549
--- /dev/null
+++ b/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
+    "dependencies": {
+      "Grpc.IntegrationTesting": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45",
+          "net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
new file mode 100644
index 0000000..10ed549
--- /dev/null
+++ b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
+    "dependencies": {
+      "Grpc.IntegrationTesting": {
+        "target": "project"
+      }
+    },
+    "frameworks": {
+      "net45": { },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45",
+          "net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
new file mode 100644
index 0000000..3181511
--- /dev/null
+++ b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
@@ -0,0 +1,38 @@
+%YAML 1.2
+--- |
+  {
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
+    "dependencies": {
+      "Grpc.Auth": {
+        "target": "project"
+      },
+      "Grpc.Core": {
+        "target": "project"
+      },
+      "Google.Protobuf": "3.0.0-beta3",
+      "CommandLineParser": "1.9.71",
+      "NUnit": "3.2.0",
+      "NUnitLite": "3.2.0-*"
+    },
+    "frameworks": {
+      "net45": {
+        "dependencies": {
+          "Moq": "4.2.1510.2205"
+        },
+        "frameworkAssemblies": {
+          "System.Runtime": "",
+          "System.IO": ""
+        }
+      },
+      "netstandard1.5": {
+        "imports": [
+          "portable-net45",
+          "net45"
+        ],
+        "dependencies": {
+          "NETStandard.Library": "1.5.0-rc2-24027",
+          "System.Linq.Expressions": "4.0.11-rc2-24027"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/build_options.include b/templates/src/csharp/build_options.include
new file mode 100644
index 0000000..468d281
--- /dev/null
+++ b/templates/src/csharp/build_options.include
@@ -0,0 +1,45 @@
+<%page args="executable=False,includeData=False"/>\
+"buildOptions": {
+  % if executable:
+    "emitEntryPoint": true
+  % endif
+  },
+  % if executable:
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "copyToOutput": {
+          % if includeData:
+          "include": "data/*",
+          % endif
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "copyToOutput": {
+          % if includeData:
+          "include": "data/*",
+          % endif
+          "mappings": {
+            "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+            "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+            "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+            "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+          }
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
+  % endif
\ No newline at end of file
diff --git a/templates/src/csharp/build_packages.bat.template b/templates/src/csharp/build_packages.bat.template
index 122435a..ea2acb6 100644
--- a/templates/src/csharp/build_packages.bat.template
+++ b/templates/src/csharp/build_packages.bat.template
@@ -43,12 +43,12 @@
   
   @rem Collect the artifacts built by the previous build step if running on Jenkins
   @rem TODO(jtattermusch): is there a better way to do this?
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64${"\\"}
   
   @rem Collect protoc artifacts built by the previous build step
   xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86${"\\"}
diff --git a/templates/src/node/tools/package.json.template b/templates/src/node/tools/package.json.template
index 69ad71a..0282425 100644
--- a/templates/src/node/tools/package.json.template
+++ b/templates/src/node/tools/package.json.template
@@ -36,6 +36,7 @@
       "index.js",
       "bin/protoc.js",
       "bin/protoc_plugin.js",
+      "bin/google/protobuf",
       "LICENSE"
     ],
     "main": "index.js"
diff --git a/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
new file mode 100644
index 0000000..35782d6
--- /dev/null
+++ b/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
@@ -0,0 +1,38 @@
+%YAML 1.2
+--- |
+  # 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.
+  
+  FROM microsoft/dotnet:1.0.0-preview1
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index b71299c..2893bdd 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -115,6 +115,8 @@
 extern void simple_metadata_pre_init(void);
 extern void simple_request(grpc_end2end_test_config config);
 extern void simple_request_pre_init(void);
+extern void streaming_error_response(grpc_end2end_test_config config);
+extern void streaming_error_response_pre_init(void);
 extern void trailing_metadata(grpc_end2end_test_config config);
 extern void trailing_metadata_pre_init(void);
 
@@ -157,6 +159,7 @@
   simple_delayed_request_pre_init();
   simple_metadata_pre_init();
   simple_request_pre_init();
+  streaming_error_response_pre_init();
   trailing_metadata_pre_init();
 }
 
@@ -203,6 +206,7 @@
     simple_delayed_request(config);
     simple_metadata(config);
     simple_request(config);
+    streaming_error_response(config);
     trailing_metadata(config);
     return;
   }
@@ -352,6 +356,10 @@
       simple_request(config);
       continue;
     }
+    if (0 == strcmp("streaming_error_response", argv[i])) {
+      streaming_error_response(config);
+      continue;
+    }
     if (0 == strcmp("trailing_metadata", argv[i])) {
       trailing_metadata(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 00c9c44..96a38e7 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -117,6 +117,8 @@
 extern void simple_metadata_pre_init(void);
 extern void simple_request(grpc_end2end_test_config config);
 extern void simple_request_pre_init(void);
+extern void streaming_error_response(grpc_end2end_test_config config);
+extern void streaming_error_response_pre_init(void);
 extern void trailing_metadata(grpc_end2end_test_config config);
 extern void trailing_metadata_pre_init(void);
 
@@ -160,6 +162,7 @@
   simple_delayed_request_pre_init();
   simple_metadata_pre_init();
   simple_request_pre_init();
+  streaming_error_response_pre_init();
   trailing_metadata_pre_init();
 }
 
@@ -207,6 +210,7 @@
     simple_delayed_request(config);
     simple_metadata(config);
     simple_request(config);
+    streaming_error_response(config);
     trailing_metadata(config);
     return;
   }
@@ -360,6 +364,10 @@
       simple_request(config);
       continue;
     }
+    if (0 == strcmp("streaming_error_response", argv[i])) {
+      streaming_error_response(config);
+      continue;
+    }
     if (0 == strcmp("trailing_metadata", argv[i])) {
       trailing_metadata(config);
       continue;
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2c452818a10ddef09b90c89a53db14b9b56b21f3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2c452818a10ddef09b90c89a53db14b9b56b21f3
new file mode 100644
index 0000000..059634f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2c452818a10ddef09b90c89a53db14b9b56b21f3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/42ead79c94eccdf8a8c3d8036be73e14fa260dd5 b/test/core/end2end/fuzzers/client_fuzzer_corpus/42ead79c94eccdf8a8c3d8036be73e14fa260dd5
new file mode 100644
index 0000000..b9c53b2
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/42ead79c94eccdf8a8c3d8036be73e14fa260dd5
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/4e05d6cf1c3f0c04f6ee92d09a53ee0fe35c085a b/test/core/end2end/fuzzers/client_fuzzer_corpus/4e05d6cf1c3f0c04f6ee92d09a53ee0fe35c085a
new file mode 100644
index 0000000..8a4a279
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/4e05d6cf1c3f0c04f6ee92d09a53ee0fe35c085a
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/8f980dd25f1c77e3536131c2c620aa32e8c13180 b/test/core/end2end/fuzzers/client_fuzzer_corpus/8f980dd25f1c77e3536131c2c620aa32e8c13180
new file mode 100644
index 0000000..fcebab7
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/8f980dd25f1c77e3536131c2c620aa32e8c13180
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/aef36c49d7dec0dcf8cdc224d9e9221fa2cb1db0 b/test/core/end2end/fuzzers/client_fuzzer_corpus/aef36c49d7dec0dcf8cdc224d9e9221fa2cb1db0
new file mode 100644
index 0000000..6b015fe
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/aef36c49d7dec0dcf8cdc224d9e9221fa2cb1db0
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-14ed70cd9ea7987cdd0c8f6e39398ee7c60ee2ff b/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-14ed70cd9ea7987cdd0c8f6e39398ee7c60ee2ff
new file mode 100644
index 0000000..be63660
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-14ed70cd9ea7987cdd0c8f6e39398ee7c60ee2ff
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/dcb06a6e34cbed15515e5b3581ca666f704777bd b/test/core/end2end/fuzzers/client_fuzzer_corpus/dcb06a6e34cbed15515e5b3581ca666f704777bd
new file mode 100644
index 0000000..92750f9
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/dcb06a6e34cbed15515e5b3581ca666f704777bd
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/ea46b684f1e67a27c231f2d536c41da631189b9c b/test/core/end2end/fuzzers/client_fuzzer_corpus/ea46b684f1e67a27c231f2d536c41da631189b9c
new file mode 100644
index 0000000..c891d9a
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/ea46b684f1e67a27c231f2d536c41da631189b9c
Binary files differ
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 325d9b3..6d3d8f8 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -126,6 +126,7 @@
     'simple_delayed_request': connectivity_test_options,
     'simple_metadata': default_test_options,
     'simple_request': default_test_options,
+    'streaming_error_response': default_test_options,
     'trailing_metadata': default_test_options,
 }
 
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
new file mode 100644
index 0000000..e15c132
--- /dev/null
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -0,0 +1,278 @@
+/*
+ *
+ * Copyright 2016, 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.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "test/core/end2end/cq_verifier.h"
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char *test_name,
+                                            grpc_channel_args *client_args,
+                                            grpc_channel_args *server_args,
+                                            bool request_status_early) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "%s/%s/request_status_early=%s", test_name, config.name,
+          request_status_early ? "true" : "false");
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+/* Client sends a request with payload, server reads then returns status. */
+static void test(grpc_end2end_test_config config, bool request_status_early) {
+  grpc_call *c;
+  grpc_call *s;
+  gpr_slice response_payload1_slice = gpr_slice_from_copied_string("hello");
+  grpc_byte_buffer *response_payload1 =
+      grpc_raw_byte_buffer_create(&response_payload1_slice, 1);
+  gpr_slice response_payload2_slice = gpr_slice_from_copied_string("world");
+  grpc_byte_buffer *response_payload2 =
+      grpc_raw_byte_buffer_create(&response_payload2_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, "streaming_error_response",
+                                           NULL, NULL, request_status_early);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *response_payload1_recv = NULL;
+  grpc_byte_buffer *response_payload2_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  char *details = NULL;
+  size_t details_capacity = 0;
+  int was_cancelled = 2;
+
+  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               "/foo", "foo.test.google.fr", deadline, NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &response_payload1_recv;
+  op++;
+  if (request_status_early) {
+    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+    op->data.recv_status_on_client.status = &status;
+    op->data.recv_status_on_client.status_details = &details;
+    op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+    op++;
+  }
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = response_payload1;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = response_payload2;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(103), 1);
+  if (!request_status_early) {
+    cq_expect_completion(cqv, tag(1), 1);
+  }
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_FAILED_PRECONDITION;
+  op->data.send_status_from_server.status_details = "xyz";
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  if (!request_status_early) {
+    memset(ops, 0, sizeof(ops));
+    op = ops;
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->data.recv_message = &response_payload2_recv;
+    op++;
+    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+  }
+
+  cq_expect_completion(cqv, tag(104), 1);
+  if (request_status_early) {
+    cq_expect_completion(cqv, tag(1), 1);
+  } else {
+    cq_expect_completion(cqv, tag(2), 1);
+  }
+  cq_verify(cqv);
+
+  if (!request_status_early) {
+    memset(ops, 0, sizeof(ops));
+    op = ops;
+    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+    op->data.recv_status_on_client.status = &status;
+    op->data.recv_status_on_client.status_details = &details;
+    op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+    op++;
+    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+
+    cq_expect_completion(cqv, tag(3), 1);
+    cq_verify(cqv);
+
+    GPR_ASSERT(response_payload1_recv != NULL);
+    GPR_ASSERT(response_payload2_recv != NULL);
+  }
+
+  GPR_ASSERT(status == GRPC_STATUS_FAILED_PRECONDITION);
+  GPR_ASSERT(0 == strcmp(details, "xyz"));
+  GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
+  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  GPR_ASSERT(was_cancelled == 1);
+
+  gpr_free(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(response_payload1);
+  grpc_byte_buffer_destroy(response_payload2);
+  grpc_byte_buffer_destroy(response_payload1_recv);
+  grpc_byte_buffer_destroy(response_payload2_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void streaming_error_response(grpc_end2end_test_config config) {
+  test(config, false);
+  test(config, true);
+}
+
+void streaming_error_response_pre_init(void) {}
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index addaf17..e8ae6ee 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -40,7 +40,9 @@
 #include <grpc++/client_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 
+#include "src/core/lib/support/string.h"
 #include "test/cpp/interop/client_helper.h"
 #include "test/cpp/interop/interop_client.h"
 #include "test/cpp/util/test_config.h"
@@ -52,30 +54,31 @@
 DEFINE_string(server_host_override, "foo.test.google.fr",
               "Override the server host which is sent in HTTP header");
 DEFINE_string(test_case, "large_unary",
-              "Configure different test cases. Valid options are: "
-              "empty_unary : empty (zero bytes) request and response; "
-              "large_unary : single request and (large) response; "
-              "large_compressed_unary : single request and compressed (large) "
-              "response; "
-              "client_streaming : request streaming with single response; "
-              "server_streaming : single request with response streaming; "
+              "Configure different test cases. Valid options are:\n\n"
+              "all : all test cases;\n"
+              "cancel_after_begin : cancel stream after starting it;\n"
+              "cancel_after_first_response: cancel on first response;\n"
+              "client_compressed_streaming : compressed request streaming with "
+              "client_compressed_unary : single compressed request;\n"
+              "client_streaming : request streaming with single response;\n"
+              "compute_engine_creds: large_unary with compute engine auth;\n"
+              "custom_metadata: server will echo custom metadata;\n"
+              "empty_stream : bi-di stream with no request/response;\n"
+              "empty_unary : empty (zero bytes) request and response;\n"
+              "half_duplex : half-duplex streaming;\n"
+              "jwt_token_creds: large_unary with JWT token auth;\n"
+              "large_unary : single request and (large) response;\n"
+              "oauth2_auth_token: raw oauth2 access token auth;\n"
+              "per_rpc_creds: raw oauth2 access token on a single rpc;\n"
+              "ping_pong : full-duplex streaming;\n"
+              "response streaming;\n"
               "server_compressed_streaming : single request with compressed "
-              "response streaming; "
-              "slow_consumer : single request with response; "
-              " streaming with slow client consumer; "
-              "half_duplex : half-duplex streaming; "
-              "ping_pong : full-duplex streaming; "
-              "cancel_after_begin : cancel stream after starting it; "
-              "cancel_after_first_response: cancel on first response; "
-              "timeout_on_sleeping_server: deadline exceeds on stream; "
-              "empty_stream : bi-di stream with no request/response; "
-              "compute_engine_creds: large_unary with compute engine auth; "
-              "jwt_token_creds: large_unary with JWT token auth; "
-              "oauth2_auth_token: raw oauth2 access token auth; "
-              "per_rpc_creds: raw oauth2 access token on a single rpc; "
-              "status_code_and_message: verify status code & message; "
-              "custom_metadata: server will echo custom metadata;"
-              "all : all of above.");
+              "server_compressed_unary : single compressed response;\n"
+              "server_streaming : single request with response streaming;\n"
+              "slow_consumer : single request with response streaming with "
+              "slow client consumer;\n"
+              "status_code_and_message: verify status code & message;\n"
+              "timeout_on_sleeping_server: deadline exceeds on stream;\n");
 DEFINE_string(default_service_account, "",
               "Email of GCE default service account");
 DEFINE_string(service_account_key_file, "",
@@ -104,14 +107,18 @@
     client.DoEmpty();
   } else if (FLAGS_test_case == "large_unary") {
     client.DoLargeUnary();
-  } else if (FLAGS_test_case == "large_compressed_unary") {
-    client.DoLargeCompressedUnary();
+  } else if (FLAGS_test_case == "server_compressed_unary") {
+    client.DoServerCompressedUnary();
+  } else if (FLAGS_test_case == "client_compressed_unary") {
+    client.DoClientCompressedUnary();
   } else if (FLAGS_test_case == "client_streaming") {
     client.DoRequestStreaming();
   } else if (FLAGS_test_case == "server_streaming") {
     client.DoResponseStreaming();
   } else if (FLAGS_test_case == "server_compressed_streaming") {
-    client.DoResponseCompressedStreaming();
+    client.DoServerCompressedStreaming();
+  } else if (FLAGS_test_case == "client_compressed_streaming") {
+    client.DoClientCompressedStreaming();
   } else if (FLAGS_test_case == "slow_consumer") {
     client.DoResponseStreamingWithSlowConsumer();
   } else if (FLAGS_test_case == "half_duplex") {
@@ -144,9 +151,12 @@
   } else if (FLAGS_test_case == "all") {
     client.DoEmpty();
     client.DoLargeUnary();
+    client.DoClientCompressedUnary();
+    client.DoServerCompressedUnary();
     client.DoRequestStreaming();
     client.DoResponseStreaming();
-    client.DoResponseCompressedStreaming();
+    client.DoClientCompressedStreaming();
+    client.DoServerCompressedStreaming();
     client.DoHalfDuplex();
     client.DoPingPong();
     client.DoCancelAfterBegin();
@@ -165,15 +175,35 @@
     }
     // compute_engine_creds only runs in GCE.
   } else {
-    gpr_log(
-        GPR_ERROR,
-        "Unsupported test case %s. Valid options are all|empty_unary|"
-        "large_unary|large_compressed_unary|client_streaming|server_streaming|"
-        "server_compressed_streaming|half_duplex|ping_pong|cancel_after_begin|"
-        "cancel_after_first_response|timeout_on_sleeping_server|empty_stream|"
-        "compute_engine_creds|jwt_token_creds|oauth2_auth_token|per_rpc_creds|"
-        "status_code_and_message|custom_metadata",
-        FLAGS_test_case.c_str());
+    const char* testcases[] = {"all",
+                               "cancel_after_begin",
+                               "cancel_after_first_response",
+                               "client_compressed_streaming",
+                               "client_compressed_unary",
+                               "client_streaming",
+                               "compute_engine_creds",
+                               "custom_metadata",
+                               "empty_stream",
+                               "empty_unary",
+                               "half_duplex",
+                               "jwt_token_creds",
+                               "large_unary",
+                               "oauth2_auth_token",
+                               "oauth2_auth_token",
+                               "per_rpc_creds",
+                               "per_rpc_creds",
+                               "ping_pong",
+                               "server_compressed_streaming",
+                               "server_compressed_unary",
+                               "server_streaming",
+                               "status_code_and_message",
+                               "timeout_on_sleeping_server"};
+    char* joined_testcases =
+        gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", NULL);
+
+    gpr_log(GPR_ERROR, "Unsupported test case %s. Valid options are\n%s",
+            FLAGS_test_case.c_str(), joined_testcases);
+    gpr_free(joined_testcases);
     ret = 1;
   }
 
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 608f902..89f841d 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,7 @@
 namespace {
 // The same value is defined by the Java client.
 const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
-const std::vector<int> response_stream_sizes = {31415, 59, 2653, 58979};
+const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
 const int kNumResponseMessages = 2000;
 const int kResponseMessageSize = 1030;
 const int kReceiveDelayMilliSeconds = 20;
@@ -67,28 +67,23 @@
 void NoopChecks(const InteropClientContextInspector& inspector,
                 const SimpleRequest* request, const SimpleResponse* response) {}
 
-void CompressionChecks(const InteropClientContextInspector& inspector,
-                       const SimpleRequest* request,
-                       const SimpleResponse* response) {
+void UnaryCompressionChecks(const InteropClientContextInspector& inspector,
+                            const SimpleRequest* request,
+                            const SimpleResponse* response) {
   const grpc_compression_algorithm received_compression =
       inspector.GetCallCompressionAlgorithm();
-  if (request->request_compressed_response() &&
-      received_compression == GRPC_COMPRESS_NONE) {
-    if (request->request_compressed_response() &&
-        received_compression == GRPC_COMPRESS_NONE) {
+  if (request->response_compressed().value()) {
+    if (received_compression == GRPC_COMPRESS_NONE) {
       // Requested some compression, got NONE. This is an error.
       gpr_log(GPR_ERROR,
               "Failure: Requested compression but got uncompressed response "
               "from server.");
       abort();
     }
-  }
-  if (!request->request_compressed_response()) {
-    GPR_ASSERT(!(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS));
-  } else if (request->response_type() == PayloadType::COMPRESSABLE) {
-    // requested compression and compressable response => results should always
-    // be compressed.
     GPR_ASSERT(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS);
+  } else {
+    // Didn't request compression -> make sure the response is uncompressed
+    GPR_ASSERT(!(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS));
   }
 }
 }  // namespace
@@ -190,11 +185,16 @@
                                       CheckerFn custom_checks_fn) {
   ClientContext context;
   InteropClientContextInspector inspector(context);
-  // If the request doesn't already specify the response type, default to
-  // COMPRESSABLE.
   request->set_response_size(kLargeResponseSize);
   grpc::string payload(kLargeRequestSize, '\0');
   request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+  if (request->has_expect_compressed()) {
+    if (request->expect_compressed().value()) {
+      context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
+    } else {
+      context.set_compression_algorithm(GRPC_COMPRESS_NONE);
+    }
+  }
 
   Status s = serviceStub_.Get()->UnaryCall(&context, *request, response);
   if (!AssertStatusOk(s)) {
@@ -204,27 +204,8 @@
   custom_checks_fn(inspector, request, response);
 
   // Payload related checks.
-  GPR_ASSERT(response->payload().type() == request->response_type());
-  switch (response->payload().type()) {
-    case PayloadType::COMPRESSABLE:
-      GPR_ASSERT(response->payload().body() ==
-                 grpc::string(kLargeResponseSize, '\0'));
-      break;
-    case PayloadType::UNCOMPRESSABLE: {
-      // We don't really check anything: We can't assert that the payload is
-      // uncompressed because it's the server's prerogative to decide on that,
-      // and different implementations decide differently (ie, Java always
-      // compresses when requested to do so, whereas C core throws away the
-      // compressed payload if the output is larger than the input).
-      // In addition, we don't compare the actual random bytes received because
-      // asserting that data is sent/received properly isn't the purpose of this
-      // test. Moreover, different implementations are also free to use
-      // different sets of random bytes.
-    } break;
-    default:
-      GPR_ASSERT(false);
-  }
-
+  GPR_ASSERT(response->payload().body() ==
+             grpc::string(kLargeResponseSize, '\0'));
   return true;
 }
 
@@ -237,7 +218,6 @@
   SimpleResponse response;
   request.set_fill_username(true);
   request.set_fill_oauth_scope(true);
-  request.set_response_type(PayloadType::COMPRESSABLE);
 
   if (!PerformLargeUnary(&request, &response)) {
     return false;
@@ -311,7 +291,6 @@
   SimpleRequest request;
   SimpleResponse response;
   request.set_fill_username(true);
-  request.set_response_type(PayloadType::COMPRESSABLE);
 
   if (!PerformLargeUnary(&request, &response)) {
     return false;
@@ -327,7 +306,6 @@
   gpr_log(GPR_DEBUG, "Sending a large unary rpc...");
   SimpleRequest request;
   SimpleResponse response;
-  request.set_response_type(PayloadType::COMPRESSABLE);
   if (!PerformLargeUnary(&request, &response)) {
     return false;
   }
@@ -335,32 +313,73 @@
   return true;
 }
 
-bool InteropClient::DoLargeCompressedUnary() {
-  const bool request_compression[] = {false, true};
-  const PayloadType payload_types[] = {COMPRESSABLE, UNCOMPRESSABLE};
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(payload_types); i++) {
-    for (size_t j = 0; j < GPR_ARRAY_SIZE(request_compression); j++) {
-      char* log_suffix;
-      gpr_asprintf(&log_suffix, "(compression=%s; payload=%s)",
-                   request_compression[j] ? "true" : "false",
-                   PayloadType_Name(payload_types[i]).c_str());
+bool InteropClient::DoClientCompressedUnary() {
+  // Probing for compression-checks support.
+  ClientContext probe_context;
+  SimpleRequest probe_req;
+  SimpleResponse probe_res;
 
-      gpr_log(GPR_DEBUG, "Sending a large compressed unary rpc %s.",
-              log_suffix);
-      SimpleRequest request;
-      SimpleResponse response;
-      request.set_response_type(payload_types[i]);
-      request.set_request_compressed_response(request_compression[j]);
+  probe_context.set_compression_algorithm(GRPC_COMPRESS_NONE);
+  probe_req.mutable_expect_compressed()->set_value(true);  // lies!
 
-      if (!PerformLargeUnary(&request, &response, CompressionChecks)) {
-        gpr_log(GPR_ERROR, "Large compressed unary failed %s", log_suffix);
-        gpr_free(log_suffix);
-        return false;
-      }
+  probe_req.set_response_size(kLargeResponseSize);
+  probe_req.mutable_payload()->set_body(grpc::string(kLargeRequestSize, '\0'));
 
-      gpr_log(GPR_DEBUG, "Large compressed unary done %s.", log_suffix);
+  gpr_log(GPR_DEBUG, "Sending probe for compressed unary request.");
+  const Status s =
+      serviceStub_.Get()->UnaryCall(&probe_context, probe_req, &probe_res);
+  if (s.error_code() != grpc::StatusCode::INVALID_ARGUMENT) {
+    // The server isn't able to evaluate incoming compression, making the rest
+    // of this test moot.
+    gpr_log(GPR_DEBUG, "Compressed unary request probe failed");
+    return false;
+  }
+  gpr_log(GPR_DEBUG, "Compressed unary request probe succeeded. Proceeding.");
+
+  const std::vector<bool> compressions = {true, false};
+  for (size_t i = 0; i < compressions.size(); i++) {
+    char* log_suffix;
+    gpr_asprintf(&log_suffix, "(compression=%s)",
+                 compressions[i] ? "true" : "false");
+
+    gpr_log(GPR_DEBUG, "Sending compressed unary request %s.", log_suffix);
+    SimpleRequest request;
+    SimpleResponse response;
+    request.mutable_expect_compressed()->set_value(compressions[i]);
+    if (!PerformLargeUnary(&request, &response, UnaryCompressionChecks)) {
+      gpr_log(GPR_ERROR, "Compressed unary request failed %s", log_suffix);
       gpr_free(log_suffix);
+      return false;
     }
+
+    gpr_log(GPR_DEBUG, "Compressed unary request failed %s", log_suffix);
+    gpr_free(log_suffix);
+  }
+
+  return true;
+}
+
+bool InteropClient::DoServerCompressedUnary() {
+  const std::vector<bool> compressions = {true, false};
+  for (size_t i = 0; i < compressions.size(); i++) {
+    char* log_suffix;
+    gpr_asprintf(&log_suffix, "(compression=%s)",
+                 compressions[i] ? "true" : "false");
+
+    gpr_log(GPR_DEBUG, "Sending unary request for compressed response %s.",
+            log_suffix);
+    SimpleRequest request;
+    SimpleResponse response;
+    request.mutable_response_compressed()->set_value(compressions[i]);
+
+    if (!PerformLargeUnary(&request, &response, UnaryCompressionChecks)) {
+      gpr_log(GPR_ERROR, "Request for compressed unary failed %s", log_suffix);
+      gpr_free(log_suffix);
+      return false;
+    }
+
+    gpr_log(GPR_DEBUG, "Request for compressed unary failed %s", log_suffix);
+    gpr_free(log_suffix);
   }
 
   return true;
@@ -387,7 +406,7 @@
       serviceStub_.Get()->StreamingInputCall(&context, &response));
 
   int aggregated_payload_size = 0;
-  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
+  for (size_t i = 0; i < request_stream_sizes.size(); ++i) {
     Payload* payload = request.mutable_payload();
     payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
     if (!stream->Write(request)) {
@@ -396,7 +415,7 @@
     }
     aggregated_payload_size += request_stream_sizes[i];
   }
-  stream->WritesDone();
+  GPR_ASSERT(stream->WritesDone());
 
   Status s = stream->Finish();
   if (!AssertStatusOk(s)) {
@@ -446,92 +465,129 @@
   return true;
 }
 
-bool InteropClient::DoResponseCompressedStreaming() {
-  const bool request_compression[] = {false, true};
-  const PayloadType payload_types[] = {COMPRESSABLE, UNCOMPRESSABLE};
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(payload_types); i++) {
-    for (size_t j = 0; j < GPR_ARRAY_SIZE(request_compression); j++) {
-      ClientContext context;
-      InteropClientContextInspector inspector(context);
-      StreamingOutputCallRequest request;
+bool InteropClient::DoClientCompressedStreaming() {
+  // Probing for compression-checks support.
+  ClientContext probe_context;
+  StreamingInputCallRequest probe_req;
+  StreamingInputCallResponse probe_res;
 
-      char* log_suffix;
-      gpr_asprintf(&log_suffix, "(compression=%s; payload=%s)",
-                   request_compression[j] ? "true" : "false",
-                   PayloadType_Name(payload_types[i]).c_str());
+  probe_context.set_compression_algorithm(GRPC_COMPRESS_NONE);
+  probe_req.mutable_expect_compressed()->set_value(true);  // lies!
+  probe_req.mutable_payload()->set_body(grpc::string(27182, '\0'));
 
-      gpr_log(GPR_DEBUG, "Receiving response streaming rpc %s.", log_suffix);
+  gpr_log(GPR_DEBUG, "Sending probe for compressed streaming request.");
 
-      request.set_response_type(payload_types[i]);
-      request.set_request_compressed_response(request_compression[j]);
+  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> probe_stream(
+      serviceStub_.Get()->StreamingInputCall(&probe_context, &probe_res));
 
-      for (size_t k = 0; k < response_stream_sizes.size(); ++k) {
-        ResponseParameters* response_parameter =
-            request.add_response_parameters();
-        response_parameter->set_size(response_stream_sizes[k]);
-      }
-      StreamingOutputCallResponse response;
+  if (!probe_stream->Write(probe_req)) {
+    gpr_log(GPR_ERROR, "%s(): stream->Write() failed", __func__);
+    return TransientFailureOrAbort();
+  }
+  Status s = probe_stream->Finish();
+  if (s.error_code() != grpc::StatusCode::INVALID_ARGUMENT) {
+    // The server isn't able to evaluate incoming compression, making the rest
+    // of this test moot.
+    gpr_log(GPR_DEBUG, "Compressed streaming request probe failed");
+    return false;
+  }
+  gpr_log(GPR_DEBUG,
+          "Compressed streaming request probe succeeded. Proceeding.");
 
-      std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
-          serviceStub_.Get()->StreamingOutputCall(&context, request));
+  ClientContext context;
+  StreamingInputCallRequest request;
+  StreamingInputCallResponse response;
 
-      size_t k = 0;
-      while (stream->Read(&response)) {
-        // Payload related checks.
-        GPR_ASSERT(response.payload().type() == request.response_type());
-        switch (response.payload().type()) {
-          case PayloadType::COMPRESSABLE:
-            GPR_ASSERT(response.payload().body() ==
-                       grpc::string(response_stream_sizes[k], '\0'));
-            break;
-          case PayloadType::UNCOMPRESSABLE:
-            break;
-          default:
-            GPR_ASSERT(false);
-        }
+  context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
+  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
+      serviceStub_.Get()->StreamingInputCall(&context, &response));
 
-        // Compression related checks.
-        if (request.request_compressed_response()) {
-          GPR_ASSERT(inspector.GetCallCompressionAlgorithm() >
-                     GRPC_COMPRESS_NONE);
-          if (request.response_type() == PayloadType::COMPRESSABLE) {
-            // requested compression and compressable response => results should
-            // always be compressed.
-            GPR_ASSERT(inspector.GetMessageFlags() &
-                       GRPC_WRITE_INTERNAL_COMPRESS);
-          }
-        } else {
-          // requested *no* compression.
-          GPR_ASSERT(
-              !(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS));
-        }
-
-        ++k;
-      }
-
-      gpr_log(GPR_DEBUG, "Response streaming done %s.", log_suffix);
-      gpr_free(log_suffix);
-
-      if (k < response_stream_sizes.size()) {
-        // stream->Read() failed before reading all the expected messages. This
-        // is most likely due to a connection failure.
-        gpr_log(GPR_ERROR,
-                "DoResponseCompressedStreaming(): Responses read (k=%" PRIuPTR
-                ") is "
-                "less than the expected messages (i.e "
-                "response_stream_sizes.size() (%" PRIuPTR ")). (i=%" PRIuPTR
-                ", j=%" PRIuPTR ")",
-                k, response_stream_sizes.size(), i, j);
-        return TransientFailureOrAbort();
-      }
-
-      Status s = stream->Finish();
-      if (!AssertStatusOk(s)) {
-        return false;
-      }
-    }
+  request.mutable_payload()->set_body(grpc::string(27182, '\0'));
+  request.mutable_expect_compressed()->set_value(true);
+  gpr_log(GPR_DEBUG, "Sending streaming request with compression enabled");
+  if (!stream->Write(request)) {
+    gpr_log(GPR_ERROR, "%s(): stream->Write() failed", __func__);
+    return TransientFailureOrAbort();
   }
 
+  WriteOptions wopts;
+  wopts.set_no_compression();
+  request.mutable_payload()->set_body(grpc::string(45904, '\0'));
+  request.mutable_expect_compressed()->set_value(false);
+  gpr_log(GPR_DEBUG, "Sending streaming request with compression disabled");
+  if (!stream->Write(request, wopts)) {
+    gpr_log(GPR_ERROR, "%s(): stream->Write() failed", __func__);
+    return TransientFailureOrAbort();
+  }
+  GPR_ASSERT(stream->WritesDone());
+
+  s = stream->Finish();
+  if (!AssertStatusOk(s)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool InteropClient::DoServerCompressedStreaming() {
+  const std::vector<bool> compressions = {true, false};
+  const std::vector<int> sizes = {31415, 92653};
+
+  ClientContext context;
+  InteropClientContextInspector inspector(context);
+  StreamingOutputCallRequest request;
+
+  GPR_ASSERT(compressions.size() == sizes.size());
+  for (size_t i = 0; i < sizes.size(); i++) {
+    char* log_suffix;
+    gpr_asprintf(&log_suffix, "(compression=%s; size=%d)",
+                 compressions[i] ? "true" : "false", sizes[i]);
+
+    gpr_log(GPR_DEBUG, "Sending request streaming rpc %s.", log_suffix);
+    gpr_free(log_suffix);
+
+    ResponseParameters* const response_parameter =
+        request.add_response_parameters();
+    response_parameter->mutable_compressed()->set_value(compressions[i]);
+    response_parameter->set_size(sizes[i]);
+  }
+  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
+      serviceStub_.Get()->StreamingOutputCall(&context, request));
+
+  size_t k = 0;
+  StreamingOutputCallResponse response;
+  while (stream->Read(&response)) {
+    // Payload size checks.
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(request.response_parameters(k).size(), '\0'));
+
+    // Compression checks.
+    GPR_ASSERT(request.response_parameters(k).has_compressed());
+    if (request.response_parameters(k).compressed().value()) {
+      GPR_ASSERT(inspector.GetCallCompressionAlgorithm() > GRPC_COMPRESS_NONE);
+      GPR_ASSERT(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS);
+    } else {
+      // requested *no* compression.
+      GPR_ASSERT(!(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS));
+    }
+    ++k;
+  }
+
+  if (k < sizes.size()) {
+    // stream->Read() failed before reading all the expected messages. This
+    // is most likely due to a connection failure.
+    gpr_log(GPR_ERROR, "%s(): Responses read (k=%" PRIuPTR
+                       ") is "
+                       "less than the expected messages (i.e "
+                       "response_stream_sizes.size() (%" PRIuPTR ")).",
+            __func__, k, response_stream_sizes.size());
+    return TransientFailureOrAbort();
+  }
+
+  Status s = stream->Finish();
+  if (!AssertStatusOk(s)) {
+    return false;
+  }
   return true;
 }
 
@@ -632,7 +688,6 @@
       stream(serviceStub_.Get()->FullDuplexCall(&context));
 
   StreamingOutputCallRequest request;
-  request.set_response_type(PayloadType::COMPRESSABLE);
   ResponseParameters* response_parameter = request.add_response_parameters();
   Payload* payload = request.mutable_payload();
   StreamingOutputCallResponse response;
@@ -699,7 +754,6 @@
       stream(serviceStub_.Get()->FullDuplexCall(&context));
 
   StreamingOutputCallRequest request;
-  request.set_response_type(PayloadType::COMPRESSABLE);
   ResponseParameters* response_parameter = request.add_response_parameters();
   response_parameter->set_size(31415);
   request.mutable_payload()->set_body(grpc::string(27182, '\0'));
@@ -839,7 +893,6 @@
         stream(serviceStub_.Get()->FullDuplexCall(&context));
 
     StreamingOutputCallRequest request;
-    request.set_response_type(PayloadType::COMPRESSABLE);
     ResponseParameters* response_parameter = request.add_response_parameters();
     response_parameter->set_size(kLargeResponseSize);
     grpc::string payload(kLargeRequestSize, '\0');
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index c8d6810..eb886fc 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -64,12 +64,14 @@
 
   bool DoEmpty();
   bool DoLargeUnary();
-  bool DoLargeCompressedUnary();
+  bool DoServerCompressedUnary();
+  bool DoClientCompressedUnary();
   bool DoPingPong();
   bool DoHalfDuplex();
   bool DoRequestStreaming();
   bool DoResponseStreaming();
-  bool DoResponseCompressedStreaming();
+  bool DoServerCompressedStreaming();
+  bool DoClientCompressedStreaming();
   bool DoResponseStreamingWithSlowConsumer();
   bool DoCancelAfterBegin();
   bool DoCancelAfterFirstResponse();
diff --git a/test/cpp/interop/server_main.cc b/test/cpp/interop/interop_server.cc
similarity index 72%
rename from test/cpp/interop/server_main.cc
rename to test/cpp/interop/interop_server.cc
index 062857f..ebef000 100644
--- a/test/cpp/interop/server_main.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/transport/byte_stream.h"
 #include "src/proto/grpc/testing/empty.grpc.pb.h"
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
 #include "src/proto/grpc/testing/test.grpc.pb.h"
@@ -64,10 +65,10 @@
 using grpc::ServerReader;
 using grpc::ServerReaderWriter;
 using grpc::ServerWriter;
+using grpc::WriteOptions;
 using grpc::SslServerCredentialsOptions;
 using grpc::testing::InteropServerContextInspector;
 using grpc::testing::Payload;
-using grpc::testing::PayloadType;
 using grpc::testing::SimpleRequest;
 using grpc::testing::SimpleResponse;
 using grpc::testing::StreamingInputCallRequest;
@@ -78,7 +79,6 @@
 using grpc::Status;
 
 static bool got_sigint = false;
-static const char* kRandomFile = "test/cpp/interop/rnd.dat";
 
 const char kEchoInitialMetadataKey[] = "x-grpc-test-echo-initial";
 const char kEchoTrailingBinMetadataKey[] = "x-grpc-test-echo-trailing-bin";
@@ -110,34 +110,41 @@
   }
 }
 
-bool SetPayload(PayloadType response_type, int size, Payload* payload) {
-  payload->set_type(response_type);
-  switch (response_type) {
-    case PayloadType::COMPRESSABLE: {
-      std::unique_ptr<char[]> body(new char[size]());
-      payload->set_body(body.get(), size);
-    } break;
-    case PayloadType::UNCOMPRESSABLE: {
-      std::unique_ptr<char[]> body(new char[size]());
-      std::ifstream rnd_file(kRandomFile);
-      GPR_ASSERT(rnd_file.good());
-      rnd_file.read(body.get(), size);
-      GPR_ASSERT(!rnd_file.eof());  // Requested more rnd bytes than available
-      payload->set_body(body.get(), size);
-    } break;
-    default:
-      GPR_ASSERT(false);
-  }
+bool SetPayload(int size, Payload* payload) {
+  std::unique_ptr<char[]> body(new char[size]());
+  payload->set_body(body.get(), size);
   return true;
 }
 
-template <typename RequestType>
-void SetResponseCompression(ServerContext* context,
-                            const RequestType& request) {
-  if (request.request_compressed_response()) {
-    // Any level would do, let's go for HIGH because we are overachievers.
-    context->set_compression_level(GRPC_COMPRESS_LEVEL_HIGH);
+bool CheckExpectedCompression(const ServerContext& context,
+                              const bool compression_expected) {
+  const InteropServerContextInspector inspector(context);
+  const grpc_compression_algorithm received_compression =
+      inspector.GetCallCompressionAlgorithm();
+
+  if (compression_expected) {
+    if (received_compression == GRPC_COMPRESS_NONE) {
+      // Expected some compression, got NONE. This is an error.
+      gpr_log(GPR_ERROR,
+              "Expected compression but got uncompressed request from client.");
+      return false;
+    }
+    if (!(inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS)) {
+      gpr_log(GPR_ERROR,
+              "Failure: Requested compression in a compressable request, but "
+              "compression bit in message flags not set.");
+      return false;
+    }
+  } else {
+    // Didn't expect compression -> make sure the request is uncompressed
+    if (inspector.GetMessageFlags() & GRPC_WRITE_INTERNAL_COMPRESS) {
+      gpr_log(GPR_ERROR,
+              "Failure: Didn't requested compression, but compression bit in "
+              "message flags set.");
+      return false;
+    }
   }
+  return true;
 }
 
 class TestServiceImpl : public TestService::Service {
@@ -151,11 +158,26 @@
   Status UnaryCall(ServerContext* context, const SimpleRequest* request,
                    SimpleResponse* response) {
     MaybeEchoMetadata(context);
-    SetResponseCompression(context, *request);
+    if (request->has_response_compressed()) {
+      const bool compression_requested = request->response_compressed().value();
+      gpr_log(GPR_DEBUG, "Request for compression (%s) present for %s",
+              compression_requested ? "enabled" : "disabled", __func__);
+      if (compression_requested) {
+        // Any level would do, let's go for HIGH because we are overachievers.
+        context->set_compression_level(GRPC_COMPRESS_LEVEL_HIGH);
+      } else {
+        context->set_compression_level(GRPC_COMPRESS_LEVEL_NONE);
+      }
+    }
+    if (!CheckExpectedCompression(*context,
+                                  request->expect_compressed().value())) {
+      return Status(grpc::StatusCode::INVALID_ARGUMENT,
+                    "Compressed request expectation not met.");
+    }
     if (request->response_size() > 0) {
-      if (!SetPayload(request->response_type(), request->response_size(),
-                      response->mutable_payload())) {
-        return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
+      if (!SetPayload(request->response_size(), response->mutable_payload())) {
+        return Status(grpc::StatusCode::INVALID_ARGUMENT,
+                      "Error creating payload.");
       }
     }
 
@@ -171,15 +193,26 @@
   Status StreamingOutputCall(
       ServerContext* context, const StreamingOutputCallRequest* request,
       ServerWriter<StreamingOutputCallResponse>* writer) {
-    SetResponseCompression(context, *request);
     StreamingOutputCallResponse response;
     bool write_success = true;
     for (int i = 0; write_success && i < request->response_parameters_size();
          i++) {
-      if (!SetPayload(request->response_type(),
-                      request->response_parameters(i).size(),
+      if (!SetPayload(request->response_parameters(i).size(),
                       response.mutable_payload())) {
-        return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
+        return Status(grpc::StatusCode::INVALID_ARGUMENT,
+                      "Error creating payload.");
+      }
+      WriteOptions wopts;
+      if (request->response_parameters(i).has_compressed()) {
+        // Compress by default. Disabled on a per-message basis.
+        context->set_compression_level(GRPC_COMPRESS_LEVEL_HIGH);
+        const bool compression_requested =
+            request->response_parameters(i).compressed().value();
+        gpr_log(GPR_DEBUG, "Request for compression (%s) present for %s",
+                compression_requested ? "enabled" : "disabled", __func__);
+        if (!compression_requested) {
+          wopts.set_no_compression();
+        }  // else, compression is already enabled via the context.
       }
       int time_us;
       if ((time_us = request->response_parameters(i).interval_us()) > 0) {
@@ -189,7 +222,7 @@
                          gpr_time_from_micros(time_us, GPR_TIMESPAN));
         gpr_sleep_until(sleep_time);
       }
-      write_success = writer->Write(response);
+      write_success = writer->Write(response, wopts);
     }
     if (write_success) {
       return Status::OK;
@@ -204,6 +237,11 @@
     StreamingInputCallRequest request;
     int aggregated_payload_size = 0;
     while (reader->Read(&request)) {
+      if (!CheckExpectedCompression(*context,
+                                    request.expect_compressed().value())) {
+        return Status(grpc::StatusCode::INVALID_ARGUMENT,
+                      "Compressed request expectation not met.");
+      }
       if (request.has_payload()) {
         aggregated_payload_size += request.payload().body().size();
       }
@@ -221,7 +259,6 @@
     StreamingOutputCallResponse response;
     bool write_success = true;
     while (write_success && stream->Read(&request)) {
-      SetResponseCompression(context, request);
       if (request.response_parameters_size() != 0) {
         response.mutable_payload()->set_type(request.payload().type());
         response.mutable_payload()->set_body(
diff --git a/test/cpp/interop/rnd.dat b/test/cpp/interop/rnd.dat
deleted file mode 100644
index 8c7f38f..0000000
--- a/test/cpp/interop/rnd.dat
+++ /dev/null
Binary files differ
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
index c6d891a..8b0b511 100644
--- a/test/cpp/interop/server_helper.cc
+++ b/test/cpp/interop/server_helper.cc
@@ -72,6 +72,10 @@
   return grpc_call_test_only_get_encodings_accepted_by_peer(context_.call_);
 }
 
+uint32_t InteropServerContextInspector::GetMessageFlags() const {
+  return grpc_call_test_only_get_message_flags(context_.call_);
+}
+
 std::shared_ptr<const AuthContext>
 InteropServerContextInspector::GetAuthContext() const {
   return context_.auth_context();
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index 12865e4..a1da14a 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -54,6 +54,7 @@
   bool IsCancelled() const;
   grpc_compression_algorithm GetCallCompressionAlgorithm() const;
   uint32_t GetEncodingsAcceptedByClient() const;
+  uint32_t GetMessageFlags() const;
 
  private:
   const ::grpc::ServerContext& context_;
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index aa95682..1d5fc80 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -138,8 +138,12 @@
       is_success = interop_client_->DoLargeUnary();
       break;
     }
-    case LARGE_COMPRESSED_UNARY: {
-      is_success = interop_client_->DoLargeCompressedUnary();
+    case CLIENT_COMPRESSED_UNARY: {
+      is_success = interop_client_->DoClientCompressedUnary();
+      break;
+    }
+    case CLIENT_COMPRESSED_STREAMING: {
+      is_success = interop_client_->DoClientCompressedStreaming();
       break;
     }
     case CLIENT_STREAMING: {
@@ -150,8 +154,12 @@
       is_success = interop_client_->DoResponseStreaming();
       break;
     }
+    case SERVER_COMPRESSED_UNARY: {
+      is_success = interop_client_->DoServerCompressedUnary();
+      break;
+    }
     case SERVER_COMPRESSED_STREAMING: {
-      is_success = interop_client_->DoResponseCompressedStreaming();
+      is_success = interop_client_->DoServerCompressedStreaming();
       break;
     }
     case SLOW_CONSUMER: {
diff --git a/test/cpp/interop/stress_interop_client.h b/test/cpp/interop/stress_interop_client.h
index aa93b58..cf6a713 100644
--- a/test/cpp/interop/stress_interop_client.h
+++ b/test/cpp/interop/stress_interop_client.h
@@ -51,29 +51,33 @@
 
 enum TestCaseType {
   UNKNOWN_TEST = -1,
-  EMPTY_UNARY = 0,
-  LARGE_UNARY = 1,
-  LARGE_COMPRESSED_UNARY = 2,
-  CLIENT_STREAMING = 3,
-  SERVER_STREAMING = 4,
-  SERVER_COMPRESSED_STREAMING = 5,
-  SLOW_CONSUMER = 6,
-  HALF_DUPLEX = 7,
-  PING_PONG = 8,
-  CANCEL_AFTER_BEGIN = 9,
-  CANCEL_AFTER_FIRST_RESPONSE = 10,
-  TIMEOUT_ON_SLEEPING_SERVER = 11,
-  EMPTY_STREAM = 12,
-  STATUS_CODE_AND_MESSAGE = 13,
-  CUSTOM_METADATA = 14
+  EMPTY_UNARY,
+  LARGE_UNARY,
+  CLIENT_COMPRESSED_UNARY,
+  CLIENT_COMPRESSED_STREAMING,
+  CLIENT_STREAMING,
+  SERVER_STREAMING,
+  SERVER_COMPRESSED_UNARY,
+  SERVER_COMPRESSED_STREAMING,
+  SLOW_CONSUMER,
+  HALF_DUPLEX,
+  PING_PONG,
+  CANCEL_AFTER_BEGIN,
+  CANCEL_AFTER_FIRST_RESPONSE,
+  TIMEOUT_ON_SLEEPING_SERVER,
+  EMPTY_STREAM,
+  STATUS_CODE_AND_MESSAGE,
+  CUSTOM_METADATA
 };
 
 const vector<pair<TestCaseType, grpc::string>> kTestCaseList = {
     {EMPTY_UNARY, "empty_unary"},
     {LARGE_UNARY, "large_unary"},
-    {LARGE_COMPRESSED_UNARY, "large_compressed_unary"},
+    {CLIENT_COMPRESSED_UNARY, "client_compressed_unary"},
+    {CLIENT_COMPRESSED_STREAMING, "client_compressed_streaming"},
     {CLIENT_STREAMING, "client_streaming"},
     {SERVER_STREAMING, "server_streaming"},
+    {SERVER_COMPRESSED_UNARY, "server_compressed_unary"},
     {SERVER_COMPRESSED_STREAMING, "server_compressed_streaming"},
     {SLOW_CONSUMER, "slow_consumer"},
     {HALF_DUPLEX, "half_duplex"},
diff --git a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
index 87262f1..a84a450 100755
--- a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
@@ -40,8 +40,6 @@
 cd /var/local/git/grpc
 rvm --default use ruby-2.1
 
-make install-certs
-
 # gRPC core and protobuf need to be installed
 make install
 
diff --git a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
new file mode 100644
index 0000000..9dfc040
--- /dev/null
+++ b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
@@ -0,0 +1,82 @@
+# 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.
+
+FROM microsoft/dotnet:1.0.0-preview1
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/profiling/latency_profile/run_latency_profile.sh b/tools/profiling/latency_profile/run_latency_profile.sh
index 54a25a9..618db20 100755
--- a/tools/profiling/latency_profile/run_latency_profile.sh
+++ b/tools/profiling/latency_profile/run_latency_profile.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,17 +28,61 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+# format argument via
+# $ echo '{...}' | python -mjson.tool
+read -r -d '' SCENARIOS_JSON_ARG <<'EOF'
+{
+    "scenarios": [
+        {
+            "benchmark_seconds": 5,
+            "client_config": {
+                "client_channels": 1,
+                "client_type": "SYNC_CLIENT",
+                "histogram_params": {
+                    "max_possible": 60000000000.0,
+                    "resolution": 0.01
+                },
+                "load_params": {
+                    "closed_loop": {}
+                },
+                "outstanding_rpcs_per_channel": 1,
+                "payload_config": {
+                    "simple_params": {
+                        "req_size": 0,
+                        "resp_size": 0
+                    }
+                },
+                "rpc_type": "UNARY",
+                "security_params": {
+                    "server_host_override": "foo.test.google.fr",
+                    "use_test_ca": true
+                }
+            },
+            "name": "cpp_protobuf_sync_unary_ping_pong_secure",
+            "num_clients": 1,
+            "num_servers": 1,
+            "server_config": {
+                "core_limit": 1,
+                "security_params": {
+                    "server_host_override": "foo.test.google.fr",
+                    "use_test_ca": true
+                },
+                "server_type": "SYNC_SERVER"
+            },
+            "spawn_local_worker_count": 2,
+            "warmup_seconds": 5
+        }
+    ]
+}
+
+EOF
+
 set -ex
 
 cd $(dirname $0)/../../..
 
-BINS="sync_unary_ping_pong_test sync_streaming_ping_pong_test"
 CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
 
-make CONFIG=basicprof -j$CPUS $BINS
-
-mkdir -p reports
-
 # try to use pypy for generating reports
 # each trace dumps 7-8gig of text to disk, and processing this into a report is
 # heavyweight - so any speed boost is worthwhile
@@ -49,35 +93,14 @@
   PYTHON=python2.7
 fi
 
-# start processes, interleaving report index generation
-echo '<html><head></head><body>' > reports/index.html
-for bin in $BINS
-do
-  bins/basicprof/$bin
-  mv latency_trace.txt $bin.trace
-  echo "<a href='$bin.txt'>$bin</a><br/>" >> reports/index.html
-done
-pids=""
-# generate report pages... this will take some time
-# run them in parallel: they take 1 cpu each
-for bin in $BINS
-do
-  $PYTHON tools/profiling/latency_profile/profile_analyzer.py \
-    --source=$bin.trace --fmt=simple > reports/$bin.txt &
-  pids+=" $!"
-done
-echo '</body></html>' >> reports/index.html
+make CONFIG=basicprof -j$CPUS qps_json_driver
 
-# make sure we kill the report generation if something goes wrong
-trap "kill $pids || true" 0
+mkdir -p reports
+bins/basicprof/qps_json_driver --scenarios_json="$SCENARIOS_JSON_ARG"
 
-# finally, wait for the background report generation to finish
-for pid in $pids
-do
-	if wait $pid
-	then
-		echo "Finished $pid"
-	else
-		exit 1
-	fi
-done
+echo '<html><head></head><body>Latency profile for:<br/>' > reports/index.html
+echo "<p><pre>${SCENARIOS_JSON_ARG}</pre></p>" >> reports/index.html
+echo '<p><pre>' >> reports/index.html
+$PYTHON tools/profiling/latency_profile/profile_analyzer.py \
+    --source=latency_trace.txt --fmt=simple >> reports/index.html
+echo '</pre></p></body></html>' >> reports/index.html
diff --git a/tools/run_tests/build_artifact_python.bat b/tools/run_tests/build_artifact_python.bat
index fea0275..295347e 100644
--- a/tools/run_tests/build_artifact_python.bat
+++ b/tools/run_tests/build_artifact_python.bat
@@ -37,10 +37,11 @@
 
 mkdir src\python\grpcio\grpc\_cython\_windows
 
+@rem TODO(atash): maybe we could avoid the grpc_c.(32|64).python shim below if
+@rem this used the right python build?
 copy /Y vsprojects\Release\grpc_dll.dll src\python\grpcio\grpc\_cython\_windows\grpc_c.32.python || goto :error
 copy /Y vsprojects\x64\Release\grpc_dll.dll src\python\grpcio\grpc\_cython\_windows\grpc_c.64.python || goto :error
 
-
 set PATH=C:\%1;C:\%1\scripts;C:\msys64\mingw%2\bin;%PATH%
 
 pip install --upgrade six
@@ -50,12 +51,6 @@
 set GRPC_PYTHON_USE_CUSTOM_BDIST=0
 set GRPC_PYTHON_BUILD_WITH_CYTHON=1
 
-@rem TODO(atash): maybe we could avoid the grpc_c.(32|64).python shim above if
-@rem this used the right python build?
-python setup.py bdist_wheel
-
-@rem Build gRPC Python tools
-@rem
 @rem Because this is windows and *everything seems to hate Windows* we have to
 @rem set all of these flags ourselves because Python won't help us (see the
 @rem setup.py of the grpcio_tools project).
@@ -70,6 +65,18 @@
 python -c "from distutils.cygwinccompiler import get_msvcr; print(get_msvcr()[0])" > temp.txt
 set /p PYTHON_MSVCR=<temp.txt
 set GRPC_PYTHON_LDFLAGS=-static-libgcc -static-libstdc++ -mcrtdll=%PYTHON_MSVCR% -static -lpthread
+
+
+@rem Build gRPC
+if %2 == 32 (
+  python setup.py build_ext -c mingw32
+) else (
+  python setup.py build_ext -c mingw32 -DMS_WIN64
+)
+python setup.py bdist_wheel
+
+
+@rem Build gRPC Python tools
 python tools\distrib\python\make_grpcio_tools.py
 if %2 == 32 (
   python tools\distrib\python\grpcio_tools\setup.py build_ext -c mingw32
diff --git a/tools/run_tests/build_csharp_coreclr.bat b/tools/run_tests/build_csharp_coreclr.bat
new file mode 100644
index 0000000..cead6d0
--- /dev/null
+++ b/tools/run_tests/build_csharp_coreclr.bat
@@ -0,0 +1,44 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+setlocal
+
+cd /d %~dp0\..\..\src\csharp
+
+dotnet restore . || goto :error
+
+dotnet build -f netstandard1.5 --configuration %MSBUILD_CONFIG% "**/project.json" || goto :error
+
+endlocal
+
+goto :EOF
+
+:error
+echo Failed!
+exit /b %errorlevel%
diff --git a/tools/run_tests/build_csharp_coreclr.sh b/tools/run_tests/build_csharp_coreclr.sh
new file mode 100755
index 0000000..68c19cb
--- /dev/null
+++ b/tools/run_tests/build_csharp_coreclr.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# 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.
+
+set -ex
+
+cd $(dirname $0)/../../src/csharp
+
+# TODO(jtattermusch): introduce caching
+dotnet restore .
+
+dotnet build -f netstandard1.5 --configuration $MSBUILD_CONFIG '**/project.json'
+
+# Grpc.IntegrationTesting doesn't get built by the previous command for some reason.
+# TODO(jtattermusch): get rid of the hack
+dotnet build -f netstandard1.5 --configuration $MSBUILD_CONFIG Grpc.IntegrationTesting/project.json
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/build_package_node.sh
index 4646072..6f7211b 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -58,6 +58,8 @@
 output_dir=$artifacts/grpc-precompiled-binaries/node/grpc-tools/v$tools_version
 mkdir -p $output_dir
 
+well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers )
+
 for arch in {x86,x64}; do
   case arch in
     x86)
@@ -79,10 +81,14 @@
         node_plat=$plat
         ;;
     esac
-    rm bin/*
+    rm -r bin/*
     input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
     cp $input_dir/protoc* bin/
     cp $input_dir/grpc_node_plugin* bin/
+    mkdir -p bin/google/protobuf
+    for proto in "${well_known_protos[@]}"; do
+      cp $base/third_party/protobuf/src/google/protobuf/$proto.proto bin/google/protobuf/$proto.proto
+    done
     tar -czf $output_dir/$node_plat-$node_arch.tar.gz bin/
   done
 done
diff --git a/tools/run_tests/build_package_ruby.sh b/tools/run_tests/build_package_ruby.sh
index e44428b..4116e29 100755
--- a/tools/run_tests/build_package_ruby.sh
+++ b/tools/run_tests/build_package_ruby.sh
@@ -40,6 +40,8 @@
 # and we only collect them here to deliver them to the distribtest phase.
 cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,linux,macos}/artifacts/* artifacts/ || true
 
+well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers )
+
 # TODO: all the artifact builder configurations generate a grpc-VERSION.gem
 # source distribution package, and only one of them will end up
 # in the artifacts/ directory. They should be all equivalent though.
@@ -56,9 +58,12 @@
   for plat in {windows,linux,macos}; do
     input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
     output_dir="$base/src/ruby/tools/bin/${ruby_arch}-${plat}"
-    mkdir -p $output_dir
+    mkdir -p $output_dir/google/protobuf
     cp $input_dir/protoc* $output_dir/
     cp $input_dir/grpc_ruby_plugin* $output_dir/
+    for proto in "${well_known_protos[@]}"; do
+      cp $base/third_party/protobuf/src/google/protobuf/$proto.proto $output_dir/google/protobuf/$proto.proto
+    done
   done
 done
 
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 0787637..d76dd4b 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -54,8 +54,13 @@
 
 _DEFAULT_SERVER_PORT=8080
 
-_SKIP_COMPRESSION = ['large_compressed_unary',
-                     'server_compressed_streaming']
+_SKIP_CLIENT_COMPRESSION = ['client_compressed_unary',
+                            'client_compressed_streaming']
+
+_SKIP_SERVER_COMPRESSION = ['server_compressed_unary',
+                            'server_compressed_streaming']
+
+_SKIP_COMPRESSION = _SKIP_CLIENT_COMPRESSION + _SKIP_SERVER_COMPRESSION
 
 _SKIP_ADVANCED = ['custom_metadata', 'status_code_and_message',
                   'unimplemented_method']
@@ -111,7 +116,7 @@
     return {}
 
   def unimplemented_test_cases(self):
-    return _SKIP_COMPRESSION
+    return _SKIP_SERVER_COMPRESSION
 
   def unimplemented_test_cases_server(self):
     return _SKIP_COMPRESSION
@@ -345,7 +350,8 @@
                'cancel_after_begin', 'cancel_after_first_response',
                'timeout_on_sleeping_server', 'custom_metadata',
                'status_code_and_message', 'unimplemented_method',
-               'large_compressed_unary', 'server_compressed_streaming']
+               'client_compressed_unary', 'server_compressed_unary',
+               'client_compressed_streaming', 'server_compressed_streaming']
 
 _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
                     'oauth2_auth_token', 'per_rpc_creds']
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 9ef12c5..e4779e3 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -500,15 +500,23 @@
     if self.platform == 'windows':
       # Explicitly choosing between x86 and x64 arch doesn't work yet
       _check_arch(self.args.arch, ['default'])
+      # CoreCLR use 64bit runtime by default.
+      arch_option = 'x64' if self.args.compiler == 'coreclr' else self.args.arch
       self._make_options = [_windows_toolset_option(self.args.compiler),
-                            _windows_arch_option(self.args.arch)]
+                            _windows_arch_option(arch_option)]
     else:
-      _check_compiler(self.args.compiler, ['default'])
+      _check_compiler(self.args.compiler, ['default', 'coreclr'])
+      if self.platform == 'linux' and self.args.compiler == 'coreclr':
+        self._docker_distro = 'coreclr'
+      else:
+        self._docker_distro = 'jessie'
+
       if self.platform == 'mac':
-        # On Mac, official distribution of mono is 32bit.
         # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
-        self._make_options = ['EMBED_OPENSSL=true',
-                              'CFLAGS=-m32', 'LDFLAGS=-m32']
+        self._make_options = ['EMBED_OPENSSL=true']
+        if self.args.compiler != 'coreclr':
+          # On Mac, official distribution of mono is 32bit.
+          self._make_options += ['CFLAGS=-m32', 'LDFLAGS=-m32']
       else:
         self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
 
@@ -517,17 +525,33 @@
       tests_by_assembly = json.load(f)
 
     msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
-    nunit_args = ['--labels=All',
-                  '--noresult',
-                  '--workers=1']
-    if self.platform == 'windows':
+    nunit_args = ['--labels=All']
+    assembly_subdir = 'bin/%s' % msbuild_config
+    assembly_extension = '.exe'
+
+    if self.args.compiler == 'coreclr':
+      if self.platform == 'linux':
+        assembly_subdir += '/netstandard1.5/debian.8-x64'
+        assembly_extension = ''
+      if self.platform == 'mac':
+        assembly_subdir += '/netstandard1.5/osx.10.11-x64'
+        assembly_extension = ''
+      else:
+        assembly_subdir += '/netstandard1.5/win7-x64'
       runtime_cmd = []
     else:
-      runtime_cmd = ['mono']
+      nunit_args += ['--noresult', '--workers=1']
+      if self.platform == 'windows':
+        runtime_cmd = []
+      else:
+        runtime_cmd = ['mono']
 
     specs = []
     for assembly in tests_by_assembly.iterkeys():
-      assembly_file = 'src/csharp/%s/bin/%s/%s.exe' % (assembly, msbuild_config, assembly)
+      assembly_file = 'src/csharp/%s/%s/%s%s' % (assembly,
+                                                 assembly_subdir,
+                                                 assembly,
+                                                 assembly_extension)
       if self.config.build_config != 'gcov' or self.platform != 'windows':
         # normally, run each test as a separate process
         for test in tests_by_assembly[assembly]:
@@ -570,12 +594,18 @@
     return self._make_options;
 
   def build_steps(self):
-    if self.platform == 'windows':
-      return [[_windows_build_bat(self.args.compiler),
-               'src/csharp/Grpc.sln',
-               '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
+    if self.args.compiler == 'coreclr':
+      if self.platform == 'windows':
+        return [['tools\\run_tests\\build_csharp_coreclr.bat']]
+      else:
+        return [['tools/run_tests/build_csharp_coreclr.sh']]
     else:
-      return [['tools/run_tests/build_csharp.sh']]
+      if self.platform == 'windows':
+        return [[_windows_build_bat(self.args.compiler),
+                 'src/csharp/Grpc.sln',
+                 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
+      else:
+        return [['tools/run_tests/build_csharp.sh']]
 
   def post_tests_steps(self):
     if self.platform == 'windows':
@@ -587,7 +617,8 @@
     return 'Makefile'
 
   def dockerfile_dir(self):
-    return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(self.args.arch)
+    return 'tools/dockerfile/test/csharp_%s_%s' % (self._docker_distro,
+                                                   _docker_arch_suffix(self.args.arch))
 
   def __str__(self):
     return 'csharp'
@@ -729,7 +760,8 @@
 
 def _windows_build_bat(compiler):
   """Returns name of build.bat for selected compiler."""
-  if compiler == 'default' or compiler == 'vs2013':
+  # For CoreCLR, fall back to the default compiler for C core
+  if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
     return 'vsprojects\\build_vs2013.bat'
   elif compiler == 'vs2015':
     return 'vsprojects\\build_vs2015.bat'
@@ -742,7 +774,8 @@
 
 def _windows_toolset_option(compiler):
   """Returns msbuild PlatformToolset for selected compiler."""
-  if compiler == 'default' or compiler == 'vs2013':
+  # For CoreCLR, fall back to the default compiler for C core
+  if compiler == 'default' or compiler == 'vs2013' or compiler == 'coreclr':
     return '/p:PlatformToolset=v120'
   elif compiler == 'vs2015':
     return '/p:PlatformToolset=v140'
@@ -838,7 +871,8 @@
                            'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
                            'vs2010', 'vs2013', 'vs2015',
                            'python2.7', 'python3.4',
-                           'node0.12', 'node4', 'node5'],
+                           'node0.12', 'node4', 'node5',
+                           'coreclr'],
                   default='default',
                   help='Selects compiler to use. Allowed values depend on the platform and language.')
 argp.add_argument('--build_only',
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 6d7c0a5..03d4b81 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -4624,7 +4624,7 @@
     "language": "c++", 
     "name": "interop_server_main", 
     "src": [
-      "test/cpp/interop/server_main.cc"
+      "test/cpp/interop/interop_server.cc"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -5400,6 +5400,7 @@
       "test/core/end2end/tests/simple_delayed_request.c", 
       "test/core/end2end/tests/simple_metadata.c", 
       "test/core/end2end/tests/simple_request.c", 
+      "test/core/end2end/tests/streaming_error_response.c", 
       "test/core/end2end/tests/trailing_metadata.c"
     ], 
     "third_party": false, 
@@ -5458,6 +5459,7 @@
       "test/core/end2end/tests/simple_delayed_request.c", 
       "test/core/end2end/tests/simple_metadata.c", 
       "test/core/end2end/tests/simple_request.c", 
+      "test/core/end2end/tests/streaming_error_response.c", 
       "test/core/end2end/tests/trailing_metadata.c"
     ], 
     "third_party": false, 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 3ed7a6b..c62058e 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -5188,6 +5188,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -6024,6 +6046,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -6823,6 +6867,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -7484,6 +7549,26 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -8318,6 +8403,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -8932,6 +9039,22 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -9740,6 +9863,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -10576,6 +10721,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_loadreporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -11375,6 +11542,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -12047,6 +12235,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -12740,6 +12949,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -13412,6 +13642,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -14105,6 +14356,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -14940,6 +15212,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -15776,6 +16070,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -16449,6 +16765,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -17190,6 +17527,26 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -18002,6 +18359,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -18816,6 +19195,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -19458,6 +19859,26 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -20270,6 +20691,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -20868,6 +21311,22 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -21654,6 +22113,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -22468,6 +22949,28 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_loadreporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -23120,6 +23623,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -23792,6 +24316,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -24443,6 +24988,27 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -25177,6 +25743,29 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -25900,6 +26489,26 @@
   }, 
   {
     "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "trailing_metadata"
     ], 
     "ci_platforms": [
@@ -54190,6 +54799,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2c452818a10ddef09b90c89a53db14b9b56b21f3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2c6e69067c68c145dc5d3a60b86d8081fdf95d0d"
     ], 
     "ci_platforms": [
@@ -54988,6 +55616,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/42ead79c94eccdf8a8c3d8036be73e14fa260dd5"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/43202ad9b1a689d919ab9ae91c2d0223394867bf"
     ], 
     "ci_platforms": [
@@ -55330,6 +55977,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/4e05d6cf1c3f0c04f6ee92d09a53ee0fe35c085a"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/4e21c4b5c454df51c102f09ea1ba78c42133ee16"
     ], 
     "ci_platforms": [
@@ -57249,6 +57915,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/8f980dd25f1c77e3536131c2c620aa32e8c13180"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/90a9c3390752b94ca19a58cb2fe6267bc818f718"
     ], 
     "ci_platforms": [
@@ -58465,6 +59150,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/aef36c49d7dec0dcf8cdc224d9e9221fa2cb1db0"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/af8b24ffaecdfaf96c0cd7c76f31dc9e1b4d0935"
     ], 
     "ci_platforms": [
@@ -59510,6 +60214,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/crash-14ed70cd9ea7987cdd0c8f6e39398ee7c60ee2ff"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/crash-3bd02c98286bfa7be8e13c5500ddb587bba74fbb"
     ], 
     "ci_platforms": [
@@ -60175,6 +60898,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/dcb06a6e34cbed15515e5b3581ca666f704777bd"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/dccd1fd6d3394f5f68c87950ed7356a2e9ef0f6f"
     ], 
     "ci_platforms": [
@@ -60669,6 +61411,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/ea46b684f1e67a27c231f2d536c41da631189b9c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/eb969b9ab1b0d6b5d197795223ba7a091ebd8460"
     ], 
     "ci_platforms": [
diff --git a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
index 075750a..18971d6 100644
--- a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
+++ b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
@@ -171,7 +171,7 @@
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\test.grpc.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\server_main.cc">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\interop_server.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
index 51a6b9e..4ee8135 100644
--- a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
+++ b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
@@ -10,7 +10,7 @@
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\server_main.cc">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\interop_server.cc">
       <Filter>test\cpp\interop</Filter>
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index 22cd102..923c1d1 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -225,6 +225,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\simple_request.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\streaming_error_response.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index 1bb208b..6533eaa 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -112,6 +112,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\simple_request.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\streaming_error_response.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index bfd437e..0b859e2 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -227,6 +227,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\simple_request.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\streaming_error_response.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index 61c065f..ea1c5e3 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -115,6 +115,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\simple_request.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\streaming_error_response.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>