mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-11-04 03:06:58 +09:00
148 lines
5.4 KiB
C++
148 lines
5.4 KiB
C++
/**
|
|
* @file tests/unit/platform/test_common.cpp
|
|
* @brief Test src/platform/common.*.
|
|
*/
|
|
|
|
// test includes
|
|
#include "../../tests_common.h"
|
|
|
|
// standard includes
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <string_view>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
// lib includes
|
|
#include <boost/asio/buffer.hpp>
|
|
#include <boost/asio/io_context.hpp>
|
|
#include <boost/asio/ip/host_name.hpp>
|
|
#include <boost/asio/ip/udp.hpp>
|
|
|
|
// local includes
|
|
#include <src/platform/common.h>
|
|
|
|
TEST(HostnameTests, TestAsioEquality) {
|
|
// These should be equivalent on all platforms for ASCII hostnames
|
|
ASSERT_EQ(platf::get_host_name(), boost::asio::ip::host_name());
|
|
}
|
|
|
|
TEST(SocketAddressTest, FormatsConstIpv4AndIpv6AddressesAndPreservesNetworkOrderPorts) {
|
|
for (const auto *text : {"192.0.2.17", "2001:db8::17"}) {
|
|
const boost::asio::ip::udp::endpoint endpoint {boost::asio::ip::make_address(text), 4321};
|
|
EXPECT_EQ(platf::from_sockaddr(endpoint.data()), text);
|
|
const auto [port, address] = platf::from_sockaddr_ex(endpoint.data());
|
|
EXPECT_EQ(port, htons(4321));
|
|
EXPECT_EQ(address, text);
|
|
}
|
|
}
|
|
|
|
TEST(SocketAddressTest, UnsupportedAddressFamiliesProduceEmptyAddressesAndZeroPorts) {
|
|
const sockaddr address {};
|
|
EXPECT_TRUE(platf::from_sockaddr(&address).empty());
|
|
EXPECT_EQ(platf::from_sockaddr_ex(&address), (std::pair<std::uint16_t, std::string> {0, {}}));
|
|
}
|
|
|
|
/**
|
|
* @brief Const batch descriptors locate payload boundaries and reject offsets past all buffers.
|
|
*/
|
|
TEST(BatchedSendInfoTest, ConstLookupPreservesBuffersAndFindsEveryBoundary) {
|
|
const std::string_view first = "abc";
|
|
const std::string_view second = "defg";
|
|
std::vector<platf::buffer_descriptor_t> buffers {{nullptr, 0}, {first.data(), first.size()}, {second.data(), second.size()}};
|
|
auto address = boost::asio::ip::address_v4::loopback();
|
|
boost::asio::ip::address endpoint = address;
|
|
const platf::batched_send_info_t batch {nullptr, 0, buffers, 1, 0, 7, 0, endpoint, 0, endpoint};
|
|
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(0).buffer, first.data());
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(0).size, first.size());
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(2).buffer, first.data() + 2);
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(2).size, 1);
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(3).buffer, second.data());
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(3).size, second.size());
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(6).buffer, second.data() + 3);
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(6).size, 1);
|
|
for (const auto offset : {7, 8}) {
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(offset).buffer, nullptr);
|
|
EXPECT_EQ(batch.buffer_for_payload_offset(offset).size, 0);
|
|
}
|
|
EXPECT_EQ(buffers.size(), 3);
|
|
EXPECT_EQ(buffers[1].buffer, first.data());
|
|
EXPECT_EQ(buffers[1].size, first.size());
|
|
}
|
|
|
|
#if defined(_WIN32) || defined(__linux__) || defined(__FreeBSD__)
|
|
/**
|
|
* @brief Exercise source-address control messages on bound UDP sockets with optional headers.
|
|
*/
|
|
class UdpSourceAddressTest: public testing::TestWithParam<std::tuple<bool, bool, bool>> {};
|
|
|
|
TEST_P(UdpSourceAddressTest, SendsTheExpectedDatagramFromTheRequestedAddress) {
|
|
const auto [ipv6, batched, with_header] = GetParam();
|
|
auto address = boost::asio::ip::make_address(ipv6 ? "::1" : "127.0.0.1");
|
|
boost::asio::io_context context;
|
|
boost::asio::ip::udp::socket receiver(context, {address, 0});
|
|
// FreeBSD requires a bound port before accepting IP_SENDSRCADDR.
|
|
boost::asio::ip::udp::socket sender(context, {receiver.local_endpoint().protocol(), 0});
|
|
const auto port = receiver.local_endpoint().port();
|
|
const auto native_socket = static_cast<std::uintptr_t>(sender.native_handle());
|
|
const std::string_view header = "header";
|
|
const std::string_view payload = "payload";
|
|
if (batched) {
|
|
const std::string_view headers = "headerheader";
|
|
const std::string_view payloads = "payloadpayload";
|
|
std::vector<platf::buffer_descriptor_t> buffers {{payloads.data(), payloads.size()}};
|
|
const platf::batched_send_info_t batch_info {
|
|
with_header ? headers.data() : nullptr,
|
|
with_header ? header.size() : 0,
|
|
buffers,
|
|
payload.size(),
|
|
0,
|
|
2,
|
|
native_socket,
|
|
address,
|
|
port,
|
|
address
|
|
};
|
|
ASSERT_TRUE(platf::send_batch(batch_info));
|
|
} else {
|
|
platf::send_info_t packet_info {
|
|
with_header ? header.data() : nullptr,
|
|
with_header ? header.size() : 0,
|
|
payload.data(),
|
|
payload.size(),
|
|
native_socket,
|
|
address,
|
|
port,
|
|
address
|
|
};
|
|
ASSERT_TRUE(platf::send(packet_info));
|
|
}
|
|
|
|
for (auto packet = 0; packet < (batched ? 2 : 1); ++packet) {
|
|
std::array<char, 64> bytes;
|
|
boost::asio::ip::udp::endpoint peer;
|
|
boost::system::error_code receive_error;
|
|
std::size_t received = 0;
|
|
bool completed = false;
|
|
receiver.async_receive_from(boost::asio::buffer(bytes), peer, [&receive_error, &received, &completed](const auto &result, std::size_t size) {
|
|
receive_error = result;
|
|
received = size;
|
|
completed = true;
|
|
});
|
|
context.restart();
|
|
context.run_for(std::chrono::seconds {2});
|
|
ASSERT_TRUE(completed);
|
|
ASSERT_FALSE(receive_error) << receive_error.message();
|
|
EXPECT_EQ(peer.address(), address);
|
|
EXPECT_EQ(std::string_view(bytes.data(), received), with_header ? "headerpayload" : "payload");
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
Loopback,
|
|
UdpSourceAddressTest,
|
|
testing::Combine(testing::Bool(), testing::Bool(), testing::Bool())
|
|
);
|
|
#endif
|