Revert "Revert "Metadata handling rewrite""

This reverts commit 5e01e2ac977655aa074faf7fde0a74298f5e4c55.
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 2ce3f2f..f536012 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -228,12 +228,7 @@
       : disable_blocking(non_block),
         credentials_type(creds_type),
         message_content(content) {}
-  void Log() const {
-    gpr_log(
-        GPR_INFO,
-        "Scenario: disable_blocking %d, credentials %s, message size %" PRIuPTR,
-        disable_blocking, credentials_type.c_str(), message_content.size());
-  }
+  void Log() const;
   bool disable_blocking;
   // Although the below grpc::string's are logically const, we can't declare
   // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
@@ -242,6 +237,20 @@
   grpc::string message_content;
 };
 
+static std::ostream& operator<<(std::ostream& out,
+                                const TestScenario& scenario) {
+  return out << "TestScenario{disable_blocking="
+             << (scenario.disable_blocking ? "true" : "false")
+             << ", credentials='" << scenario.credentials_type
+             << "', message_size=" << scenario.message_content.size() << "}";
+}
+
+void TestScenario::Log() const {
+  std::ostringstream out;
+  out << *this;
+  gpr_log(GPR_DEBUG, "%s", out.str().c_str());
+}
+
 class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
  protected:
   AsyncEnd2endTest() { GetParam().Log(); }
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 1a1a94e..d2c7edc 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -209,10 +209,7 @@
  public:
   TestScenario(bool proxy, const grpc::string& creds_type)
       : use_proxy(proxy), credentials_type(creds_type) {}
-  void Log() const {
-    gpr_log(GPR_INFO, "Scenario: proxy %d, credentials %s", use_proxy,
-            credentials_type.c_str());
-  }
+  void Log() const;
   bool use_proxy;
   // Although the below grpc::string is logically const, we can't declare
   // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
@@ -220,6 +217,19 @@
   grpc::string credentials_type;
 };
 
+static std::ostream& operator<<(std::ostream& out,
+                                const TestScenario& scenario) {
+  return out << "TestScenario{use_proxy="
+             << (scenario.use_proxy ? "true" : "false") << ", credentials='"
+             << scenario.credentials_type << "'}";
+}
+
+void TestScenario::Log() const {
+  std::ostringstream out;
+  out << *this;
+  gpr_log(GPR_DEBUG, "%s", out.str().c_str());
+}
+
 class End2endTest : public ::testing::TestWithParam<TestScenario> {
  protected:
   End2endTest()
@@ -636,7 +646,7 @@
   TestBidiStreamServerCancel(CANCEL_AFTER_PROCESSING, 5);
 }
 
-TEST_P(End2endTest, SimpleRpcWithCustomeUserAgentPrefix) {
+TEST_P(End2endTest, SimpleRpcWithCustomUserAgentPrefix) {
   user_agent_prefix_ = "custom_prefix";
   ResetStub();
   EchoRequest request;
@@ -1293,6 +1303,7 @@
   EXPECT_FALSE(s.ok());
   EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
 }
+
 TEST_P(SecureEnd2endTest, SetPerCallCredentials) {
   ResetStub();
   EchoRequest request;
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
index de304b9..07db474 100644
--- a/test/cpp/grpclb/grpclb_test.cc
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -288,7 +288,8 @@
   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_OK;
-  op->data.send_status_from_server.status_details = "xyz";
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
   op->flags = 0;
   op->reserved = NULL;
   op++;
@@ -433,7 +434,9 @@
     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_OK;
-    op->data.send_status_from_server.status_details = "Backend server out a-ok";
+    grpc_slice status_details =
+        grpc_slice_from_static_string("Backend server out a-ok");
+    op->data.send_status_from_server.status_details = &status_details;
     op->flags = 0;
     op->reserved = NULL;
     op++;
@@ -462,8 +465,7 @@
   grpc_metadata_array trailing_metadata_recv;
   grpc_status_code status;
   grpc_call_error error;
-  char *details = NULL;
-  size_t details_capacity = 0;
+  grpc_slice details;
   grpc_byte_buffer *request_payload;
   grpc_byte_buffer *response_payload_recv;
   int i;
@@ -472,9 +474,11 @@
   grpc_slice request_payload_slice =
       grpc_slice_from_copied_string("hello world");
 
+  grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr:1234");
   c = grpc_channel_create_call(cf->client, NULL, GRPC_PROPAGATE_DEFAULTS,
-                               cf->cq, "/foo", "foo.test.google.fr:1234",
-                               GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL);
+                               cf->cq, grpc_slice_from_static_string("/foo"),
+                               &host, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                               NULL);
   gpr_log(GPR_INFO, "Call 0x%" PRIxPTR " created", (intptr_t)c);
   GPR_ASSERT(c);
   char *peer;
@@ -497,7 +501,6 @@
   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->flags = 0;
   op->reserved = NULL;
   op++;
@@ -553,7 +556,7 @@
 
   grpc_metadata_array_destroy(&initial_metadata_recv);
   grpc_metadata_array_destroy(&trailing_metadata_recv);
-  gpr_free(details);
+  grpc_slice_unref(details);
   gpr_log(GPR_INFO, "Client call (peer %s) DESTROYED.", peer);
   gpr_free(peer);
 }
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 3265554..1df2fc8 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -32,6 +32,7 @@
  */
 
 #include <memory>
+#include <unordered_map>
 
 #include <unistd.h>
 
@@ -108,119 +109,78 @@
   grpc::testing::InteropClient client(CreateChannelForTestCase(FLAGS_test_case),
                                       true,
                                       FLAGS_do_not_abort_on_transient_failures);
-  if (FLAGS_test_case == "empty_unary") {
-    client.DoEmpty();
-  } else if (FLAGS_test_case == "large_unary") {
-    client.DoLargeUnary();
-  } 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.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") {
-    client.DoHalfDuplex();
-  } else if (FLAGS_test_case == "ping_pong") {
-    client.DoPingPong();
-  } else if (FLAGS_test_case == "cancel_after_begin") {
-    client.DoCancelAfterBegin();
-  } else if (FLAGS_test_case == "cancel_after_first_response") {
-    client.DoCancelAfterFirstResponse();
-  } else if (FLAGS_test_case == "timeout_on_sleeping_server") {
-    client.DoTimeoutOnSleepingServer();
-  } else if (FLAGS_test_case == "empty_stream") {
-    client.DoEmptyStream();
-  } else if (FLAGS_test_case == "compute_engine_creds") {
-    client.DoComputeEngineCreds(FLAGS_default_service_account,
-                                FLAGS_oauth_scope);
-  } else if (FLAGS_test_case == "jwt_token_creds") {
-    grpc::string json_key = GetServiceAccountJsonKey();
-    client.DoJwtTokenCreds(json_key);
-  } else if (FLAGS_test_case == "oauth2_auth_token") {
-    client.DoOauth2AuthToken(FLAGS_default_service_account, FLAGS_oauth_scope);
-  } else if (FLAGS_test_case == "per_rpc_creds") {
-    grpc::string json_key = GetServiceAccountJsonKey();
-    client.DoPerRpcCreds(json_key);
-  } else if (FLAGS_test_case == "status_code_and_message") {
-    client.DoStatusWithMessage();
-  } else if (FLAGS_test_case == "custom_metadata") {
-    client.DoCustomMetadata();
-  } else if (FLAGS_test_case == "unimplemented_method") {
-    client.DoUnimplementedMethod();
-  } else if (FLAGS_test_case == "unimplemented_service") {
-    client.DoUnimplementedService();
-  } else if (FLAGS_test_case == "cacheable_unary") {
-    client.DoCacheableUnary();
-  } else if (FLAGS_test_case == "all") {
-    client.DoEmpty();
-    client.DoLargeUnary();
-    client.DoClientCompressedUnary();
-    client.DoServerCompressedUnary();
-    client.DoRequestStreaming();
-    client.DoResponseStreaming();
-    client.DoClientCompressedStreaming();
-    client.DoServerCompressedStreaming();
-    client.DoHalfDuplex();
-    client.DoPingPong();
-    client.DoCancelAfterBegin();
-    client.DoCancelAfterFirstResponse();
-    client.DoTimeoutOnSleepingServer();
-    client.DoEmptyStream();
-    client.DoStatusWithMessage();
-    client.DoCustomMetadata();
-    client.DoUnimplementedMethod();
-    client.DoUnimplementedService();
-    client.DoCacheableUnary();
-    // service_account_creds and jwt_token_creds can only run with ssl.
-    if (FLAGS_use_tls) {
-      grpc::string json_key = GetServiceAccountJsonKey();
-      client.DoJwtTokenCreds(json_key);
-      client.DoOauth2AuthToken(FLAGS_default_service_account,
-                               FLAGS_oauth_scope);
-      client.DoPerRpcCreds(json_key);
-    }
-    // compute_engine_creds only runs in GCE.
-  } else {
-    const char* testcases[] = {"all",
-                               "cacheable_unary",
-                               "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",
-                               "unimplemented_method",
-                               "unimplemented_service"};
-    char* joined_testcases =
-        gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", NULL);
 
+  std::unordered_map<grpc::string, std::function<bool()>> actions;
+  actions["empty_unary"] =
+      std::bind(&grpc::testing::InteropClient::DoEmpty, &client);
+  actions["large_unary"] =
+      std::bind(&grpc::testing::InteropClient::DoLargeUnary, &client);
+  actions["server_compressed_unary"] = std::bind(
+      &grpc::testing::InteropClient::DoServerCompressedUnary, &client);
+  actions["client_compressed_unary"] = std::bind(
+      &grpc::testing::InteropClient::DoClientCompressedUnary, &client);
+  actions["client_streaming"] =
+      std::bind(&grpc::testing::InteropClient::DoRequestStreaming, &client);
+  actions["server_streaming"] =
+      std::bind(&grpc::testing::InteropClient::DoResponseStreaming, &client);
+  actions["server_compressed_streaming"] = std::bind(
+      &grpc::testing::InteropClient::DoServerCompressedStreaming, &client);
+  actions["client_compressed_streaming"] = std::bind(
+      &grpc::testing::InteropClient::DoClientCompressedStreaming, &client);
+  actions["slow_consumer"] = std::bind(
+      &grpc::testing::InteropClient::DoResponseStreamingWithSlowConsumer,
+      &client);
+  actions["half_duplex"] =
+      std::bind(&grpc::testing::InteropClient::DoHalfDuplex, &client);
+  actions["ping_pong"] =
+      std::bind(&grpc::testing::InteropClient::DoPingPong, &client);
+  actions["cancel_after_begin"] =
+      std::bind(&grpc::testing::InteropClient::DoCancelAfterBegin, &client);
+  actions["cancel_after_first_response"] = std::bind(
+      &grpc::testing::InteropClient::DoCancelAfterFirstResponse, &client);
+  actions["timeout_on_sleeping_server"] = std::bind(
+      &grpc::testing::InteropClient::DoTimeoutOnSleepingServer, &client);
+  actions["empty_stream"] =
+      std::bind(&grpc::testing::InteropClient::DoEmptyStream, &client);
+  if (FLAGS_use_tls) {
+    actions["compute_engine_creds"] =
+        std::bind(&grpc::testing::InteropClient::DoComputeEngineCreds, &client,
+                  FLAGS_default_service_account, FLAGS_oauth_scope);
+    actions["jwt_token_creds"] =
+        std::bind(&grpc::testing::InteropClient::DoJwtTokenCreds, &client,
+                  GetServiceAccountJsonKey());
+    actions["oauth2_auth_token"] =
+        std::bind(&grpc::testing::InteropClient::DoOauth2AuthToken, &client,
+                  FLAGS_default_service_account, FLAGS_oauth_scope);
+    actions["per_rpc_creds"] =
+        std::bind(&grpc::testing::InteropClient::DoPerRpcCreds, &client,
+                  GetServiceAccountJsonKey());
+  }
+  actions["status_code_and_message"] =
+      std::bind(&grpc::testing::InteropClient::DoStatusWithMessage, &client);
+  actions["custom_metadata"] =
+      std::bind(&grpc::testing::InteropClient::DoCustomMetadata, &client);
+  actions["unimplemented_method"] =
+      std::bind(&grpc::testing::InteropClient::DoUnimplementedMethod, &client);
+  actions["unimplemented_service"] =
+      std::bind(&grpc::testing::InteropClient::DoUnimplementedService, &client);
+  // actions["cacheable_unary"] =
+  //    std::bind(&grpc::testing::InteropClient::DoCacheableUnary, &client);
+
+  if (FLAGS_test_case == "all") {
+    for (const auto& action : actions) {
+      action.second();
+    }
+  } else if (actions.find(FLAGS_test_case) != actions.end()) {
+    actions.find(FLAGS_test_case)->second();
+  } else {
+    grpc::string test_cases;
+    for (const auto& action : actions) {
+      if (!test_cases.empty()) test_cases += "\n";
+      test_cases += action.first;
+    }
     gpr_log(GPR_ERROR, "Unsupported test case %s. Valid options are\n%s",
-            FLAGS_test_case.c_str(), joined_testcases);
-    gpr_free(joined_testcases);
+            FLAGS_test_case.c_str(), test_cases.c_str());
     ret = 1;
   }
 
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index d124262..aa34d94 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -109,7 +109,10 @@
 
 UnimplementedService::Stub*
 InteropClient::ServiceStub::GetUnimplementedServiceStub() {
-  return UnimplementedService::NewStub(channel_).get();
+  if (unimplemented_service_stub_ == nullptr) {
+    unimplemented_service_stub_ = UnimplementedService::NewStub(channel_);
+  }
+  return unimplemented_service_stub_.get();
 }
 
 void InteropClient::ServiceStub::Reset(std::shared_ptr<Channel> channel) {
@@ -943,7 +946,7 @@
     const auto& server_initial_metadata = context.GetServerInitialMetadata();
     auto iter = server_initial_metadata.find(kEchoInitialMetadataKey);
     GPR_ASSERT(iter != server_initial_metadata.end());
-    GPR_ASSERT(iter->second.data() == kInitialMetadataValue);
+    GPR_ASSERT(iter->second == kInitialMetadataValue);
     const auto& server_trailing_metadata = context.GetServerTrailingMetadata();
     iter = server_trailing_metadata.find(kEchoTrailingBinMetadataKey);
     GPR_ASSERT(iter != server_trailing_metadata.end());
@@ -994,7 +997,7 @@
     const auto& server_initial_metadata = context.GetServerInitialMetadata();
     auto iter = server_initial_metadata.find(kEchoInitialMetadataKey);
     GPR_ASSERT(iter != server_initial_metadata.end());
-    GPR_ASSERT(iter->second.data() == kInitialMetadataValue);
+    GPR_ASSERT(iter->second == kInitialMetadataValue);
     const auto& server_trailing_metadata = context.GetServerTrailingMetadata();
     iter = server_trailing_metadata.find(kEchoTrailingBinMetadataKey);
     GPR_ASSERT(iter != server_trailing_metadata.end());
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index 7ec7ebe..74f4db6 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -107,6 +107,7 @@
 
    private:
     std::unique_ptr<TestService::Stub> stub_;
+    std::unique_ptr<UnimplementedService::Stub> unimplemented_service_stub_;
     std::shared_ptr<Channel> channel_;
     bool new_stub_every_call_;  // If true, a new stub is returned by every
                                 // Get() call
diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc
index 956840b..1810cd0 100644
--- a/test/cpp/interop/interop_server.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -91,7 +91,9 @@
 
   auto iter = client_metadata.find(kEchoInitialMetadataKey);
   if (iter != client_metadata.end()) {
-    context->AddInitialMetadata(kEchoInitialMetadataKey, iter->second.data());
+    context->AddInitialMetadata(
+        kEchoInitialMetadataKey,
+        grpc::string(iter->second.begin(), iter->second.end()));
   }
   iter = client_metadata.find(kEchoTrailingBinMetadataKey);
   if (iter != client_metadata.end()) {
diff --git a/test/cpp/microbenchmarks/bm_fullstack.cc b/test/cpp/microbenchmarks/bm_fullstack.cc
index 6c0bf80..bd158db 100644
--- a/test/cpp/microbenchmarks/bm_fullstack.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack.cc
@@ -443,6 +443,8 @@
                    Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>);
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
                    Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/test/server_context_test_spouse_test.cc b/test/cpp/test/server_context_test_spouse_test.cc
index e0d6a2f..eb279e2 100644
--- a/test/cpp/test/server_context_test_spouse_test.cc
+++ b/test/cpp/test/server_context_test_spouse_test.cc
@@ -36,11 +36,14 @@
 #include <cstring>
 #include <vector>
 
+#include <grpc++/impl/grpc_library.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
 namespace testing {
 
+static internal::GrpcLibraryInitializer g_initializer;
+
 const char key1[] = "metadata-key1";
 const char key2[] = "metadata-key2";
 const char val1[] = "metadata-val1";