Skip to content

Commit

Permalink
Add server tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
abeltrano committed Dec 1, 2023
1 parent fa2915c commit c59aaa1
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/common/server/NetRemoteServer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ NetRemoteServer::NetRemoteServer(std::string_view serverAddress) :
m_serverAddress{ serverAddress }
{}

NetRemoteServer::~NetRemoteServer()
{
Stop();
}

std::unique_ptr<grpc::Server>& NetRemoteServer::GetGrpcServer() noexcept
{
return m_server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Microsoft::Net::Remote
*/
struct NetRemoteServer
{
virtual ~NetRemoteServer();

/**
* @brief Construct a new NetRemoteServer object.
*
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand All @@ -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)
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/TestNetRemoteCommon.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

#ifndef TEST_NET_REMOTE_COMMON_HXX
#define TEST_NET_REMOTE_COMMON_HXX

#include <chrono>
#include <string_view>

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
148 changes: 148 additions & 0 deletions tests/unit/TestNetRemoteServer.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@

#include <algorithm>
#include <optional>
#include <ranges>
#include <tuple>
#include <vector>

#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <grpcpp/create_channel.h>
#include <magic_enum.hpp>
#include <microsoft/net/remote/NetRemoteServer.hxx>
#include <NetRemoteService.grpc.pb.h>

#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<NetRemoteServer> server{ Test::RemoteServiceAddressHttp };
REQUIRE_NOTHROW(server.reset());
}

SECTION("Destroy doesn't cause a crash with no connected clients")
{
std::optional<NetRemoteServer> 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::tuple<std::shared_ptr<grpc::Channel>, std::unique_ptr<NetRemote::Stub>>> clients(static_cast<std::size_t>(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::tuple<std::shared_ptr<grpc::Channel>, std::unique_ptr<NetRemote::Stub>>> clients(static_cast<std::size_t>(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));
}
}
}
28 changes: 6 additions & 22 deletions tests/unit/TestNetRemoteServiceClient.cxx
Original file line number Diff line number Diff line change
@@ -1,41 +1,25 @@

#include <array>
#include <chrono>
#include <cstdint>
#include <format>
#include <iostream>

#include <catch2/catch_test_macros.hpp>
#include <grpcpp/create_channel.h>
#include <magic_enum.hpp>
#include <microsoft/net/remote/NetRemoteService.hxx>
#include <NetRemoteService.grpc.pb.h>

using namespace std::chrono_literals;
#include <microsoft/net/remote/NetRemoteServer.hxx>

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")
Expand Down

0 comments on commit c59aaa1

Please sign in to comment.