| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/async/cpp/executor.h> |
| #include <lib/gtest/test_loop_fixture.h> |
| #include <lib/sys/cpp/testing/component_context_provider.h> |
| #include <lib/virtualization/testing/fake_manager.h> |
| |
| #include "src/virtualization/lib/grpc/grpc_vsock_server.h" |
| #include "src/virtualization/lib/grpc/grpc_vsock_stub.h" |
| #include "src/virtualization/lib/grpc/test_server.grpc.pb.h" |
| |
| namespace { |
| constexpr uint32_t kTestServicePort = 1234; |
| constexpr const char* kTestMessage = "This is only a test"; |
| |
| class GrpcVsockTest : public gtest::TestLoopFixture { |
| public: |
| void SetUp() override { |
| TestLoopFixture::SetUp(); |
| // Setup a fake guest realm that we can use to connect to a |
| // HostVsockEndpoint. |
| provider_.service_directory_provider()->AddService(fake_guest_manager_.GetHandler()); |
| fuchsia::virtualization::ManagerPtr manager; |
| provider_.context()->svc()->Connect(manager.NewRequest()); |
| manager->Create("test realm", realm_.NewRequest()); |
| RunLoopUntilIdle(); |
| } |
| |
| protected: |
| // Connects to the |HostVsockEnpoint| for the realm. |
| fuchsia::virtualization::HostVsockEndpointPtr GetHostVsockEndpoint() { |
| fuchsia::virtualization::HostVsockEndpointPtr result; |
| realm_->GetHostVsockEndpoint(result.NewRequest()); |
| RunLoopUntilIdle(); |
| return result; |
| } |
| |
| // Access the |FakeGuestVsock|. This can be used to simulate guest |
| // interactions over virtio-vsock. |
| guest::testing::FakeGuestVsock* guest_vsock() { return fake_guest_manager_.GuestVsock(); } |
| |
| async::Executor* executor() { return &executor_; } |
| |
| private: |
| async::Executor executor_{dispatcher()}; |
| fuchsia::virtualization::RealmPtr realm_; |
| guest::testing::FakeManager fake_guest_manager_; |
| sys::testing::ComponentContextProvider provider_; |
| fuchsia::virtualization::HostVsockEndpointPtr socket_endpoint_; |
| }; |
| |
| // Simple gRPC service that echos messages back to the client. |
| class TestEchoServer : public vsock_test::Echo::Service { |
| private: |
| grpc::Status Echo(grpc::ServerContext* context, const vsock_test::EchoMessage* request, |
| vsock_test::EchoMessage* response) override { |
| response->mutable_echo_message()->assign(request->echo_message()); |
| return grpc::Status::OK; |
| } |
| }; |
| |
| // Simulate a gRPC echo server running over virtio-vsock. |
| TEST_F(GrpcVsockTest, Echo) { |
| // Setup gRPC vsock server. |
| GrpcVsockServerBuilder server_builder(GetHostVsockEndpoint()); |
| TestEchoServer server_impl; |
| server_builder.AddListenPort(kTestServicePort); |
| server_builder.RegisterService(&server_impl); |
| fit::result<std::unique_ptr<GrpcVsockServer>, zx_status_t> result; |
| auto p = server_builder.Build().then( |
| [&result](fit::result<std::unique_ptr<GrpcVsockServer>, zx_status_t>& r) mutable { |
| result = std::move(r); |
| }); |
| executor()->schedule_task(std::move(p)); |
| RunLoopUntilIdle(); |
| |
| // Verify the server was started. |
| ASSERT_FALSE(result.is_pending()); |
| ASSERT_FALSE(result.is_error()); |
| ASSERT_TRUE(result.is_ok()); |
| auto server = result.take_value(); |
| ASSERT_TRUE(server != nullptr); |
| |
| // Connect to the service using the guest vsock endpoint. |
| zx::handle guest_handle; |
| guest_vsock()->ConnectToHost(kTestServicePort, |
| [&](auto handle) { guest_handle = std::move(handle); }); |
| RunLoopUntilIdle(); |
| ASSERT_TRUE(guest_handle); |
| // The gRPC server will always use socket as a transport. |
| zx_info_handle_basic_t info; |
| ASSERT_EQ(ZX_OK, |
| guest_handle.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr)); |
| ASSERT_EQ(zx::socket::TYPE, info.type); |
| zx::socket guest_socket(std::move(guest_handle)); |
| |
| // Convert zx::socket into a gRPC stub that can be used to send RPCs. |
| auto stub_result = NewGrpcStub<vsock_test::Echo>(std::move(guest_socket)); |
| ASSERT_TRUE(stub_result.is_ok()); |
| auto stub = stub_result.take_value(); |
| |
| // Test echo |
| grpc::ClientContext context; |
| vsock_test::EchoMessage request; |
| vsock_test::EchoMessage response; |
| request.mutable_echo_message()->assign(kTestMessage); |
| auto grpc_status = stub->Echo(&context, request, &response); |
| ASSERT_TRUE(grpc_status.ok()); |
| ASSERT_EQ(kTestMessage, response.echo_message()); |
| } |
| |
| } // namespace |