grpc/test/cpp/interop/istio_echo_server_lib.cc

185 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "test/cpp/interop/istio_echo_server_lib.h"
#include <thread>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_split.h"
#include "absl/synchronization/blocking_counter.h"
#include <grpcpp/grpcpp.h>
#include "src/core/lib/gprpp/host_port.h"
#include "src/proto/grpc/testing/istio_echo.pb.h"
using proto::EchoRequest;
using proto::EchoResponse;
using proto::EchoTestService;
using proto::ForwardEchoRequest;
using proto::ForwardEchoResponse;
namespace grpc {
namespace testing {
namespace {
const absl::string_view kRequestIdField = "x-request-id";
// const absl::string_view kServiceVersionField = "ServiceVersion";
// const absl::string_view kServicePortField = "ServicePort";
const absl::string_view kStatusCodeField = "StatusCode";
// const absl::string_view kUrlField = "URL";
const absl::string_view kHostField = "Host";
const absl::string_view kHostnameField = "Hostname";
// const absl::string_view kMethodField = "Method";
const absl::string_view kRequestHeader = "RequestHeader";
// const absl::string_view kResponseHeader = "ResponseHeader";
// const absl::string_view kClusterField = "Cluster";
// const absl::string_view kIstioVersionField = "IstioVersion";
const absl::string_view kIpField = "IP"; // The Requesters IP Address.
absl::string_view StringRefToStringView(const string_ref& r) {
return absl::string_view(r.data(), r.size());
}
struct EchoCall {
grpc::ClientContext context;
proto::EchoResponse response;
Status status;
};
} // namespace
Status EchoTestServiceImpl::Echo(ServerContext* context,
const EchoRequest* request,
EchoResponse* response) {
std::string s;
absl::StrAppend(&s, kHostField, "=",
StringRefToStringView(context->ExperimentalGetAuthority()),
"\n");
const std::multimap<string_ref, string_ref> metadata =
context->client_metadata();
for (const auto& kv : metadata) {
// Skip all binary headers.
if (kv.first.ends_with("-bin")) {
continue;
}
absl::StrAppend(&s, kRequestHeader, "=", StringRefToStringView(kv.first),
":", StringRefToStringView(kv.second), "\n");
}
absl::string_view host;
absl::string_view port;
std::string peer = context->peer();
grpc_core::SplitHostPort(peer, &host, &port);
// This is not a complete list, but also not all fields are used. May
// need to add/remove fields later, if required by tests. Only keep the
// fields needed for now.
//
// absl::StrAppend(&s,kServiceVersionField,"=",this->version_,"\n");
// absl::StrAppend(&s,kServicePortField,"=",this->port_,"\n");
// absl::StrAppend(&s,kClusterField,"=",this->cluster_,"\n");
// absl::StrAppend(&s,kIstioVersionField,"=",this->istio_version_,"\n");
absl::StrAppend(&s, kIpField, "=", host, "\n");
absl::StrAppend(&s, kStatusCodeField, "=", std::to_string(200), "\n");
absl::StrAppend(&s, kHostnameField, "=", this->hostname_, "\n");
absl::StrAppend(&s, "Echo=", request->message(), "\n");
gpr_log(GPR_ERROR, "here");
response->set_message(s);
gpr_log(GPR_ERROR, "here");
gpr_log(GPR_INFO, "Echo response:\n%s", s.c_str());
return Status::OK;
}
Status EchoTestServiceImpl::ForwardEcho(ServerContext* /*context*/,
const ForwardEchoRequest* request,
ForwardEchoResponse* response) {
std::string raw_url = request->url();
size_t colon = raw_url.find_first_of(':');
if (colon != std::string::npos) {
std::string scheme = raw_url.substr(0, colon);
if (scheme != "grpc") {
gpr_log(GPR_ERROR, "Protocol %s not supported", scheme.c_str());
return Status(
StatusCode::UNIMPLEMENTED,
absl::StrFormat("Protocol %s not supported", scheme.c_str()));
}
}
// May need to use xds security if urlScheme is "xds"
absl::string_view address = absl::StripPrefix(raw_url, "grpc://");
gpr_log(GPR_INFO, "Creating channel to %s", std::string(address).c_str());
auto channel =
CreateChannel(std::string(address), InsecureChannelCredentials());
auto stub = EchoTestService::NewStub(channel);
auto count = request->count() == 0 ? 1 : request->count();
// Calculate the amount of time to sleep after each call.
std::chrono::duration<double> duration_per_query =
std::chrono::nanoseconds::zero();
if (request->qps() > 0) {
duration_per_query =
std::chrono::nanoseconds(std::chrono::seconds(1)) / request->qps();
}
std::vector<EchoCall> calls(count);
EchoRequest echo_request;
echo_request.set_message(request->message());
absl::BlockingCounter counter(count);
for (int i = 0; i < count; ++i) {
calls[i].context.AddMetadata(std::string(kRequestIdField),
std::to_string(i));
for (const auto& header : request->headers()) {
if (header.key() != kHostField) {
calls[i].context.AddMetadata(header.key(), header.value());
}
}
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() +
std::chrono::microseconds(request->timeout_micros());
calls[i].context.set_deadline(deadline);
stub->async()->Echo(&calls[i].context, &echo_request, &calls[i].response,
[&, index = i](Status s) {
calls[index].status = s;
counter.DecrementCount();
});
std::this_thread::sleep_for(duration_per_query);
}
// Wait for all calls to be done.
counter.Wait();
for (int i = 0; i < count; ++i) {
if (calls[i].status.ok()) {
std::string body;
// The test infrastructure might expect the entire struct instead of
// just the message.
absl::StrAppend(&body, absl::StrFormat("[%d] grpcecho.Echo(%s)\n", i,
request->message()));
auto contents =
absl::StrSplit(calls[i].response.message(), '\n', absl::SkipEmpty());
for (const auto& line : contents) {
absl::StrAppend(&body, absl::StrFormat("[%d body] %s\n", i, line));
}
response->add_output(body);
gpr_log(GPR_INFO, "Forward Echo response:%d\n%s", i, body.c_str());
} else {
gpr_log(GPR_ERROR, "RPC %d failed %d: %s", i,
calls[i].status.error_code(),
calls[i].status.error_message().c_str());
}
}
return Status::OK;
}
} // namespace testing
} // namespace grpc