diff options
Diffstat (limited to 'test/cpp/end2end/raw_end2end_test.cc')
-rw-r--r-- | test/cpp/end2end/raw_end2end_test.cc | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/test/cpp/end2end/raw_end2end_test.cc b/test/cpp/end2end/raw_end2end_test.cc new file mode 100644 index 0000000000..a413905ef7 --- /dev/null +++ b/test/cpp/end2end/raw_end2end_test.cc @@ -0,0 +1,370 @@ +/* + * + * Copyright 2015 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 <cinttypes> +#include <memory> +#include <thread> + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/time.h> +#include <grpcpp/channel.h> +#include <grpcpp/client_context.h> +#include <grpcpp/create_channel.h> +#include <grpcpp/server.h> +#include <grpcpp/server_builder.h> +#include <grpcpp/server_context.h> + +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/iomgr/port.h" +#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.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/util/byte_buffer_proto_helper.h" +#include "test/cpp/util/string_ref_helper.h" + +#include <gtest/gtest.h> + +using grpc::testing::EchoRequest; +using grpc::testing::EchoResponse; + +namespace grpc { +namespace testing { + +namespace { + +void* tag(int i) { return (void*)static_cast<intptr_t>(i); } +int detag(void* p) { return static_cast<int>(reinterpret_cast<intptr_t>(p)); } + +class Verifier { + public: + Verifier() {} + + // Expect sets the expected ok value for a specific tag + Verifier& Expect(int i, bool expect_ok) { + expectations_[tag(i)] = expect_ok; + return *this; + } + + // Next waits for 1 async tag to complete, checks its + // expectations, and returns the tag + int Next(CompletionQueue* cq, bool ignore_ok) { + bool ok; + void* got_tag; + EXPECT_TRUE(cq->Next(&got_tag, &ok)); + GotTag(got_tag, ok, ignore_ok); + return detag(got_tag); + } + + // Verify keeps calling Next until all currently set + // expected tags are complete + void Verify(CompletionQueue* cq) { + GPR_ASSERT(!expectations_.empty()); + while (!expectations_.empty()) { + Next(cq, false); + } + } + + private: + void GotTag(void* got_tag, bool ok, bool ignore_ok) { + auto it = expectations_.find(got_tag); + if (it != expectations_.end()) { + if (!ignore_ok) { + EXPECT_EQ(it->second, ok); + } + expectations_.erase(it); + } + } + + std::map<void*, bool> expectations_; +}; + +class RawEnd2EndTest : public ::testing::Test { + protected: + RawEnd2EndTest() {} + + void SetUp() override { + port_ = grpc_pick_unused_port_or_die(); + server_address_ << "localhost:" << port_; + } + + void TearDown() override { + server_->Shutdown(); + void* ignored_tag; + bool ignored_ok; + cq_->Shutdown(); + while (cq_->Next(&ignored_tag, &ignored_ok)) + ; + stub_.reset(); + grpc_recycle_unused_port(port_); + } + + template <typename ServerType> + std::unique_ptr<ServerType> BuildAndStartServer() { + ServerBuilder builder; + builder.AddListeningPort(server_address_.str(), + grpc::InsecureServerCredentials()); + std::unique_ptr<ServerType> service(new ServerType()); + builder.RegisterService(service.get()); + cq_ = builder.AddCompletionQueue(); + server_ = builder.BuildAndStart(); + return service; + } + + void ResetStub() { + ChannelArguments args; + std::shared_ptr<Channel> channel = CreateChannel( + server_address_.str(), grpc::InsecureChannelCredentials()); + stub_ = grpc::testing::EchoTestService::NewStub(channel); + } + + std::unique_ptr<ServerCompletionQueue> cq_; + std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; + std::unique_ptr<Server> server_; + std::ostringstream server_address_; + int port_; + + // For the client application to populate and send to server. + EchoRequest send_request_; + ::grpc::ByteBuffer send_request_buffer_; + + // For the server to give to gRPC to be populated by incoming request + // from client. + EchoRequest recv_request_; + ::grpc::ByteBuffer recv_request_buffer_; + + // For the server application to populate and send back to client. + EchoResponse send_response_; + ::grpc::ByteBuffer send_response_buffer_; + + // For the client to give to gRPC to be populated by incoming response + // from server. + EchoResponse recv_response_; + ::grpc::ByteBuffer recv_response_buffer_; + Status recv_status_; + + // Both sides need contexts + ClientContext cli_ctx_; + ServerContext srv_ctx_; +}; + +// Regular Async, both peers use proto +TEST_F(RawEnd2EndTest, PureAsyncService) { + typedef grpc::testing::EchoTestService::AsyncService SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); + grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx_); + + send_request_.set_message("hello"); + std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( + stub_->AsyncEcho(&cli_ctx_, send_request_, cq_.get())); + service->RequestEcho(&srv_ctx_, &recv_request_, &response_writer, cq_.get(), + cq_.get(), tag(2)); + response_reader->Finish(&recv_response_, &recv_status_, tag(4)); + Verifier().Expect(2, true).Verify(cq_.get()); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + send_response_.set_message(recv_request_.message()); + response_writer.Finish(send_response_, Status::OK, tag(3)); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); + + EXPECT_EQ(send_response_.message(), recv_response_.message()); + EXPECT_TRUE(recv_status_.ok()); +} + +// Client uses proto, server uses generic codegen, unary +TEST_F(RawEnd2EndTest, RawServerUnary) { + typedef grpc::testing::EchoTestService::WithRawMethod_Echo< + grpc::testing::EchoTestService::Service> + SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); + grpc::GenericServerAsyncResponseWriter response_writer(&srv_ctx_); + + send_request_.set_message("hello unary"); + std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( + stub_->AsyncEcho(&cli_ctx_, send_request_, cq_.get())); + service->RequestEcho(&srv_ctx_, &recv_request_buffer_, &response_writer, + cq_.get(), cq_.get(), tag(2)); + response_reader->Finish(&recv_response_, &recv_status_, tag(4)); + Verifier().Expect(2, true).Verify(cq_.get()); + EXPECT_TRUE(ParseFromByteBuffer(&recv_request_buffer_, &recv_request_)); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + send_response_.set_message(recv_request_.message()); + EXPECT_TRUE( + SerializeToByteBufferInPlace(&send_response_, &send_response_buffer_)); + response_writer.Finish(send_response_buffer_, Status::OK, tag(3)); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); + + EXPECT_EQ(send_response_.message(), recv_response_.message()); + EXPECT_TRUE(recv_status_.ok()); +} + +// Client uses proto, server uses generic codegen, client streaming +TEST_F(RawEnd2EndTest, RawServerClientStreaming) { + typedef grpc::testing::EchoTestService::WithRawMethod_RequestStream< + grpc::testing::EchoTestService::Service> + SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); + + grpc::GenericServerAsyncReader srv_stream(&srv_ctx_); + + send_request_.set_message("hello client streaming"); + std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream( + stub_->AsyncRequestStream(&cli_ctx_, &recv_response_, cq_.get(), tag(1))); + + service->RequestRequestStream(&srv_ctx_, &srv_stream, cq_.get(), cq_.get(), + tag(2)); + + Verifier().Expect(2, true).Expect(1, true).Verify(cq_.get()); + + cli_stream->Write(send_request_, tag(3)); + srv_stream.Read(&recv_request_buffer_, tag(4)); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); + ParseFromByteBuffer(&recv_request_buffer_, &recv_request_); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + + cli_stream->Write(send_request_, tag(5)); + srv_stream.Read(&recv_request_buffer_, tag(6)); + Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get()); + + ParseFromByteBuffer(&recv_request_buffer_, &recv_request_); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + cli_stream->WritesDone(tag(7)); + srv_stream.Read(&recv_request_buffer_, tag(8)); + Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get()); + + ParseFromByteBuffer(&recv_request_buffer_, &recv_request_); + send_response_.set_message(recv_request_.message()); + SerializeToByteBufferInPlace(&send_response_, &send_response_buffer_); + srv_stream.Finish(send_response_buffer_, Status::OK, tag(9)); + cli_stream->Finish(&recv_status_, tag(10)); + Verifier().Expect(9, true).Expect(10, true).Verify(cq_.get()); + + EXPECT_EQ(send_response_.message(), recv_response_.message()); + EXPECT_TRUE(recv_status_.ok()); +} + +// Client uses proto, server uses generic codegen, server streaming +TEST_F(RawEnd2EndTest, RawServerServerStreaming) { + typedef grpc::testing::EchoTestService::WithRawMethod_ResponseStream< + grpc::testing::EchoTestService::Service> + SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); + grpc::GenericServerAsyncWriter srv_stream(&srv_ctx_); + + send_request_.set_message("hello server streaming"); + std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream( + stub_->AsyncResponseStream(&cli_ctx_, send_request_, cq_.get(), tag(1))); + + service->RequestResponseStream(&srv_ctx_, &recv_request_buffer_, &srv_stream, + cq_.get(), cq_.get(), tag(2)); + + Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get()); + ParseFromByteBuffer(&recv_request_buffer_, &recv_request_); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + + send_response_.set_message(recv_request_.message()); + SerializeToByteBufferInPlace(&send_response_, &send_response_buffer_); + srv_stream.Write(send_response_buffer_, tag(3)); + cli_stream->Read(&recv_response_, tag(4)); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); + EXPECT_EQ(send_response_.message(), recv_response_.message()); + + srv_stream.Write(send_response_buffer_, tag(5)); + cli_stream->Read(&recv_response_, tag(6)); + Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get()); + EXPECT_EQ(send_response_.message(), recv_response_.message()); + + srv_stream.Finish(Status::OK, tag(7)); + cli_stream->Read(&recv_response_, tag(8)); + Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get()); + + cli_stream->Finish(&recv_status_, tag(9)); + Verifier().Expect(9, true).Verify(cq_.get()); + + EXPECT_TRUE(recv_status_.ok()); +} + +// Client uses proto, server uses generic codegen, bidi streaming +TEST_F(RawEnd2EndTest, RawServerBidiStreaming) { + typedef grpc::testing::EchoTestService::WithRawMethod_BidiStream< + grpc::testing::EchoTestService::Service> + SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); + + grpc::GenericServerAsyncReaderWriter srv_stream(&srv_ctx_); + + send_request_.set_message("hello bidi streaming"); + std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>> + cli_stream(stub_->AsyncBidiStream(&cli_ctx_, cq_.get(), tag(1))); + + service->RequestBidiStream(&srv_ctx_, &srv_stream, cq_.get(), cq_.get(), + tag(2)); + + Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get()); + + cli_stream->Write(send_request_, tag(3)); + srv_stream.Read(&recv_request_buffer_, tag(4)); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); + ParseFromByteBuffer(&recv_request_buffer_, &recv_request_); + EXPECT_EQ(send_request_.message(), recv_request_.message()); + + send_response_.set_message(recv_request_.message()); + SerializeToByteBufferInPlace(&send_response_, &send_response_buffer_); + srv_stream.Write(send_response_buffer_, tag(5)); + cli_stream->Read(&recv_response_, tag(6)); + Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get()); + EXPECT_EQ(send_response_.message(), recv_response_.message()); + + cli_stream->WritesDone(tag(7)); + srv_stream.Read(&recv_request_buffer_, tag(8)); + Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get()); + + srv_stream.Finish(Status::OK, tag(9)); + cli_stream->Finish(&recv_status_, tag(10)); + Verifier().Expect(9, true).Expect(10, true).Verify(cq_.get()); + + EXPECT_TRUE(recv_status_.ok()); +} + +// Testing that this pattern compiles +TEST_F(RawEnd2EndTest, CompileTest) { + typedef grpc::testing::EchoTestService::WithRawMethod_Echo< + grpc::testing::EchoTestService::AsyncService> + SType; + ResetStub(); + auto service = BuildAndStartServer<SType>(); +} + +} // namespace +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + // Change the backup poll interval from 5s to 100ms to speed up the + // ReconnectChannel test + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; +} |