| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 | /* * * Copyright 2016 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 <memory>#include <mutex>#include <thread>#include <grpc++/channel.h>#include <grpc++/client_context.h>#include <grpc++/create_channel.h>#include <grpc++/server.h>#include <grpc++/server_builder.h>#include <grpc/grpc.h>#include <grpc/support/log.h>#include <grpc/support/time.h>#include "src/proto/grpc/testing/echo.grpc.pb.h"#include "test/core/util/port.h"#include "test/core/util/test_config.h"#include "test/cpp/end2end/test_service_impl.h"#include <gtest/gtest.h>using grpc::testing::EchoRequest;using grpc::testing::EchoResponse;using std::chrono::system_clock;namespace grpc {namespace testing {namespace {// Subclass of TestServiceImpl that increments a request counter for// every call to the Echo RPC.class MyTestServiceImpl : public TestServiceImpl { public:  MyTestServiceImpl() : request_count_(0) {}  Status Echo(ServerContext* context, const EchoRequest* request,              EchoResponse* response) override {    {      std::unique_lock<std::mutex> lock(mu_);      ++request_count_;    }    return TestServiceImpl::Echo(context, request, response);  }  int request_count() {    std::unique_lock<std::mutex> lock(mu_);    return request_count_;  } private:  std::mutex mu_;  int request_count_;};class RoundRobinEnd2endTest : public ::testing::Test { protected:  RoundRobinEnd2endTest() : server_host_("localhost") {}  void StartServers(size_t num_servers,                    std::vector<int> ports = std::vector<int>()) {    for (size_t i = 0; i < num_servers; ++i) {      int port = 0;      if (ports.size() == num_servers) port = ports[i];      servers_.emplace_back(new ServerData(server_host_, port));    }  }  void TearDown() override {    for (size_t i = 0; i < servers_.size(); ++i) {      servers_[i]->Shutdown();    }  }  void ResetStub(bool round_robin) {    ChannelArguments args;    if (round_robin) args.SetLoadBalancingPolicyName("round_robin");    std::ostringstream uri;    uri << "ipv4:///";    for (size_t i = 0; i < servers_.size() - 1; ++i) {      uri << "127.0.0.1:" << servers_[i]->port_ << ",";    }    uri << "127.0.0.1:" << servers_[servers_.size() - 1]->port_;    channel_ =        CreateCustomChannel(uri.str(), InsecureChannelCredentials(), args);    stub_ = grpc::testing::EchoTestService::NewStub(channel_);  }  void SendRpc(int num_rpcs, bool expect_ok = true) {    EchoRequest request;    EchoResponse response;    request.set_message("Live long and prosper.");    for (int i = 0; i < num_rpcs; i++) {      ClientContext context;      Status status = stub_->Echo(&context, request, &response);      if (expect_ok) {        EXPECT_TRUE(status.ok());        EXPECT_EQ(response.message(), request.message());      } else {        EXPECT_FALSE(status.ok());      }    }  }  struct ServerData {    int port_;    std::unique_ptr<Server> server_;    MyTestServiceImpl service_;    explicit ServerData(const grpc::string& server_host, int port = 0) {      port_ = port > 0 ? port : grpc_pick_unused_port_or_die();      gpr_log(GPR_INFO, "starting server on port %d", port_);      std::ostringstream server_address;      server_address << server_host << ":" << port_;      ServerBuilder builder;      builder.AddListeningPort(server_address.str(),                               InsecureServerCredentials());      builder.RegisterService(&service_);      server_ = builder.BuildAndStart();      gpr_log(GPR_INFO, "server startup complete");    }    void Shutdown() { server_->Shutdown(); }  };  const grpc::string server_host_;  std::shared_ptr<Channel> channel_;  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;  std::vector<std::unique_ptr<ServerData>> servers_;};TEST_F(RoundRobinEnd2endTest, PickFirst) {  // Start servers and send one RPC per server.  const int kNumServers = 3;  StartServers(kNumServers);  ResetStub(false /* round_robin */);  SendRpc(kNumServers);  // All requests should have gone to a single server.  bool found = false;  for (size_t i = 0; i < servers_.size(); ++i) {    const int request_count = servers_[i]->service_.request_count();    if (request_count == kNumServers) {      found = true;    } else {      EXPECT_EQ(0, request_count);    }  }  EXPECT_TRUE(found);  // Check LB policy name for the channel.  EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());}TEST_F(RoundRobinEnd2endTest, RoundRobin) {  // Start servers and send one RPC per server.  const int kNumServers = 3;  StartServers(kNumServers);  ResetStub(true /* round_robin */);  // Send one RPC per backend and make sure they are used in order.  // Note: This relies on the fact that the subchannels are reported in  // state READY in the order in which the addresses are specified,  // which is only true because the backends are all local.  for (size_t i = 0; i < servers_.size(); ++i) {    SendRpc(1);    EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i;  }  // Check LB policy name for the channel.  EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());}TEST_F(RoundRobinEnd2endTest, RoundRobinReconnect) {  // Start servers and send one RPC per server.  const int kNumServers = 1;  std::vector<int> ports;  ports.push_back(grpc_pick_unused_port_or_die());  StartServers(kNumServers, ports);  ResetStub(true /* round_robin */);  // Send one RPC per backend and make sure they are used in order.  // Note: This relies on the fact that the subchannels are reported in  // state READY in the order in which the addresses are specified,  // which is only true because the backends are all local.  for (size_t i = 0; i < servers_.size(); ++i) {    SendRpc(1);    EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i;  }  // Check LB policy name for the channel.  EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());  // Kill all servers  for (size_t i = 0; i < servers_.size(); ++i) {    servers_[i]->Shutdown();  }  // Client request should fail.  SendRpc(1, false);  // Bring servers back up on the same port (we aren't recreating the channel).  StartServers(kNumServers, ports);  // Client request should succeed.  SendRpc(1);}}  // namespace}  // namespace testing}  // namespace grpcint main(int argc, char** argv) {  grpc_test_init(argc, argv);  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}
 |