From c59aaa14c433a2afb45fb794e839a8af2561de65 Mon Sep 17 00:00:00 2001 From: Andrew Beltrano Date: Fri, 1 Dec 2023 14:27:22 -0700 Subject: [PATCH] Add server tests. --- src/common/server/NetRemoteServer.cxx | 5 + .../microsoft/net/remote/NetRemoteServer.hxx | 2 + tests/unit/CMakeLists.txt | 3 +- tests/unit/TestNetRemoteCommon.hxx | 16 ++ tests/unit/TestNetRemoteServer.cxx | 148 ++++++++++++++++++ tests/unit/TestNetRemoteServiceClient.cxx | 28 +--- 6 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 tests/unit/TestNetRemoteCommon.hxx create mode 100644 tests/unit/TestNetRemoteServer.cxx diff --git a/src/common/server/NetRemoteServer.cxx b/src/common/server/NetRemoteServer.cxx index 1e8a0a3a..f388ecbe 100644 --- a/src/common/server/NetRemoteServer.cxx +++ b/src/common/server/NetRemoteServer.cxx @@ -12,6 +12,11 @@ NetRemoteServer::NetRemoteServer(std::string_view serverAddress) : m_serverAddress{ serverAddress } {} +NetRemoteServer::~NetRemoteServer() +{ + Stop(); +} + std::unique_ptr& NetRemoteServer::GetGrpcServer() noexcept { return m_server; diff --git a/src/common/server/include/microsoft/net/remote/NetRemoteServer.hxx b/src/common/server/include/microsoft/net/remote/NetRemoteServer.hxx index 5c3694b2..e922ceb9 100644 --- a/src/common/server/include/microsoft/net/remote/NetRemoteServer.hxx +++ b/src/common/server/include/microsoft/net/remote/NetRemoteServer.hxx @@ -16,6 +16,8 @@ namespace Microsoft::Net::Remote */ struct NetRemoteServer { + virtual ~NetRemoteServer(); + /** * @brief Construct a new NetRemoteServer object. * diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 1217bdde..651d4b5f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(netremote-test-unit) target_sources(netremote-test-unit PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/TestNetRemoteServer.cxx ${CMAKE_CURRENT_LIST_DIR}/TestNetRemoteServiceClient.cxx ) @@ -17,7 +18,7 @@ target_link_libraries(netremote-test-unit Catch2::Catch2WithMain gRPC::grpc++ magic_enum::magic_enum - netremote-service + netremote-server ) catch_discover_tests(netremote-test-unit) diff --git a/tests/unit/TestNetRemoteCommon.hxx b/tests/unit/TestNetRemoteCommon.hxx new file mode 100644 index 00000000..5353ac60 --- /dev/null +++ b/tests/unit/TestNetRemoteCommon.hxx @@ -0,0 +1,16 @@ + +#ifndef TEST_NET_REMOTE_COMMON_HXX +#define TEST_NET_REMOTE_COMMON_HXX + +#include +#include + +namespace Microsoft::Net::Remote::Test +{ +using namespace std::chrono_literals; + +constexpr auto RemoteServiceAddressHttp = "localhost:5047"; +constexpr auto RemoteServiceConnectionTimeout = 3s; +} // namespace Micosoft::Net::Remote::Test + +#endif // TEST_NET_REMOTE_COMMON_HXX diff --git a/tests/unit/TestNetRemoteServer.cxx b/tests/unit/TestNetRemoteServer.cxx new file mode 100644 index 00000000..61d9e3da --- /dev/null +++ b/tests/unit/TestNetRemoteServer.cxx @@ -0,0 +1,148 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "TestNetRemoteCommon.hxx" + +TEST_CASE("Create a NetRemoteServer instance", "[basic][rpc][remote]") +{ + using namespace Microsoft::Net::Remote; + + SECTION("Create doesn't cause a crash") + { + REQUIRE_NOTHROW(NetRemoteServer{ Test::RemoteServiceAddressHttp }); + } +} + +TEST_CASE("Destroy a NetRemoteServer instance", "[basic][rpc][remote]") +{ + using namespace Microsoft::Net::Remote; + + SECTION("Destroy doesn't cause a crash") + { + std::optional server{ Test::RemoteServiceAddressHttp }; + REQUIRE_NOTHROW(server.reset()); + } + + SECTION("Destroy doesn't cause a crash with no connected clients") + { + std::optional server{ Test::RemoteServiceAddressHttp }; + REQUIRE_NOTHROW(server.reset()); + } +} + +TEST_CASE("NetRemoteServer can be reached", "[basic][rpc][remote]") +{ + using namespace Microsoft::Net::Remote; + using namespace Microsoft::Net::Remote::Service; + + NetRemoteServer server{ Test::RemoteServiceAddressHttp }; + server.Run(); + + SECTION("Can be reached using insecure channel") + { + auto channel = grpc::CreateChannel(Test::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); + auto client = NetRemote::NewStub(channel); + + REQUIRE(channel->WaitForConnected(std::chrono::system_clock::now() + Test::RemoteServiceConnectionTimeout)); + } +} + +TEST_CASE("NetRemoteServer shuts down correctly", "[basic][rpc][remote]") +{ + using namespace Microsoft::Net::Remote; + using namespace Microsoft::Net::Remote::Service; + + NetRemoteServer server{ Test::RemoteServiceAddressHttp }; + server.Run(); + + SECTION("Stop() doesn't cause a crash with no connected clients") + { + REQUIRE_NOTHROW(server.Stop()); + } + + SECTION("Stop() severs connections for connected clients") + { + // Vary the number of connected clients and validate test section for each. + const auto numClientsToCreate = Catch::Generators::range(1, 3); + + // Establish client connections to the server. + std::vector, std::unique_ptr>> clients(static_cast(numClientsToCreate.get())); + std::ranges::transform(clients, std::begin(clients), [&](auto&&) + { + auto channel = grpc::CreateChannel(Test::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); + auto client = NetRemote::NewStub(channel); + REQUIRE(channel->WaitForConnected(std::chrono::system_clock::now() + Test::RemoteServiceConnectionTimeout)); + + return std::make_tuple(channel, std::move(client)); + }); + + // Stop the server. + REQUIRE_NOTHROW(server.Stop()); + + // Validate each channel is in IDLE state. + for (const auto& [channel, _] : clients) + { + REQUIRE(channel->GetState(false) == GRPC_CHANNEL_IDLE); + } + } + + SECTION("Stop() invalidates gRPC server instance with no connected clients") + { + REQUIRE_NOTHROW(server.Stop()); + REQUIRE(server.GetGrpcServer() == nullptr); + } + + SECTION("Stop() invalidates gRPC server instance with connected clients") + { + // Vary the number of connected clients and validate test section for each. + const auto numClientsToCreate = Catch::Generators::range(1, 3); + + std::vector, std::unique_ptr>> clients(static_cast(numClientsToCreate.get())); + std::ranges::transform(clients, std::begin(clients), [&](auto&&) + { + auto channel = grpc::CreateChannel(Test::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); + auto client = NetRemote::NewStub(channel); + REQUIRE(channel->WaitForConnected(std::chrono::system_clock::now() + Test::RemoteServiceConnectionTimeout)); + + return std::make_tuple(channel, std::move(client)); + }); + + REQUIRE_NOTHROW(server.Stop()); + REQUIRE(server.GetGrpcServer() == nullptr); + } +} + +TEST_CASE("NetRemoteServer can be cycled through run/stop states", "[basic][rpc][remote]") +{ + using namespace Microsoft::Net::Remote; + using namespace Microsoft::Net::Remote::Service; + + NetRemoteServer server{ Test::RemoteServiceAddressHttp }; + REQUIRE_NOTHROW(server.Run()); + + SECTION("Can be cycled multiple times") + { + const auto numCycles = Catch::Generators::range(1, 3); + + for ([[maybe_unused]] auto _ : std::views::iota(0, numCycles.get())) + { + REQUIRE_NOTHROW(server.Stop()); + REQUIRE_NOTHROW(server.Run()); + + auto channel = grpc::CreateChannel(Test::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); + auto client = NetRemote::NewStub(channel); + REQUIRE(channel->WaitForConnected(std::chrono::system_clock::now() + Test::RemoteServiceConnectionTimeout)); + } + } +} diff --git a/tests/unit/TestNetRemoteServiceClient.cxx b/tests/unit/TestNetRemoteServiceClient.cxx index 225c91b4..5da1d677 100644 --- a/tests/unit/TestNetRemoteServiceClient.cxx +++ b/tests/unit/TestNetRemoteServiceClient.cxx @@ -1,41 +1,25 @@ -#include -#include -#include #include #include #include #include #include -#include #include -using namespace std::chrono_literals; +#include -namespace detail -{ -constexpr auto RemoteServiceAddressHttp = "localhost:5047"; -[[maybe_unused]] constexpr auto RemoteServiceAddressHttps = "localhost:7073"; -constexpr auto RemoteServiceConnectionTimeout = 3s; -} // namespace detail - -TEST_CASE("net remote service can be reached", "[basic][rpc][client][remote]") -{ - using namespace Microsoft::Net::Remote::Service; - - auto channel = grpc::CreateChannel(detail::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); - auto client = NetRemote::NewStub(channel); - - REQUIRE(channel->WaitForConnected(std::chrono::system_clock::now() + detail::RemoteServiceConnectionTimeout)); -} +#include "TestNetRemoteCommon.hxx" TEST_CASE("WifiConfigureAccessPoint API can be called", "[basic][rpc][client][remote]") { using namespace Microsoft::Net::Remote; using namespace Microsoft::Net::Remote::Service; - auto channel = grpc::CreateChannel(detail::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); + NetRemoteServer server{ Test::RemoteServiceAddressHttp }; + server.Run(); + + auto channel = grpc::CreateChannel(Test::RemoteServiceAddressHttp, grpc::InsecureChannelCredentials()); auto client = NetRemote::NewStub(channel); SECTION("Can be called")