aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2024-06-22 14:15:11 +0200
committerTor Egge <Tor.Egge@online.no>2024-06-22 14:15:11 +0200
commit9f6d388374c99052f65dade552d592efa7477e25 (patch)
treefb5a63b9e18ec7d0c9ab00016693d84815f35b64 /vespalib/src
parentd7c4bf19130d68df0aba20cf1659dc36ae4e33d0 (diff)
Rewrite socket unit test and send fd unit test to gtest.
Diffstat (limited to 'vespalib/src')
-rw-r--r--vespalib/src/tests/net/send_fd/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/net/send_fd/send_fd_test.cpp92
-rw-r--r--vespalib/src/tests/net/socket/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/net/socket/socket_test.cpp382
-rw-r--r--vespalib/src/vespa/vespalib/test/socket_options_verifier.h32
5 files changed, 344 insertions, 164 deletions
diff --git a/vespalib/src/tests/net/send_fd/CMakeLists.txt b/vespalib/src/tests/net/send_fd/CMakeLists.txt
index 4c46a773f5c..b4baaeb5855 100644
--- a/vespalib/src/tests/net/send_fd/CMakeLists.txt
+++ b/vespalib/src/tests/net/send_fd/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(vespalib_send_fd_test_app TEST
send_fd_test.cpp
DEPENDS
vespalib
+ GTest::gtest
)
vespa_add_test(NAME vespalib_send_fd_test_app COMMAND vespalib_send_fd_test_app)
diff --git a/vespalib/src/tests/net/send_fd/send_fd_test.cpp b/vespalib/src/tests/net/send_fd/send_fd_test.cpp
index 59b9aacea07..8dc1235ff76 100644
--- a/vespalib/src/tests/net/send_fd/send_fd_test.cpp
+++ b/vespalib/src/tests/net/send_fd/send_fd_test.cpp
@@ -1,5 +1,5 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/testkit/time_bomb.h>
#include <vespa/vespalib/net/selector.h>
@@ -7,15 +7,19 @@
#include <vespa/vespalib/net/server_socket.h>
#include <vespa/vespalib/net/socket_options.h>
#include <vespa/vespalib/net/socket.h>
+#include <vespa/vespalib/test/nexus.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/test/socket_options_verifier.h>
-#include <thread>
-#include <functional>
#include <chrono>
+#include <functional>
+#include <latch>
+#include <optional>
+#include <thread>
#include <unistd.h>
#include <sys/stat.h>
using namespace vespalib;
+using vespalib::test::Nexus;
vespalib::string read_bytes(SocketHandle &socket, size_t wanted_bytes) {
char tmp[64];
@@ -23,7 +27,9 @@ vespalib::string read_bytes(SocketHandle &socket, size_t wanted_bytes) {
while (result.size() < wanted_bytes) {
size_t read_size = std::min(sizeof(tmp), wanted_bytes - result.size());
ssize_t read_result = socket.read(tmp, read_size);
- ASSERT_GREATER(read_result, 0);
+ if (read_result <= 0) {
+ return result;
+ }
result.append(tmp, read_result);
}
return result;
@@ -34,14 +40,14 @@ void verify_socket_io(bool is_server, SocketHandle &socket) {
vespalib::string client_message = "please pick up, I need to talk to you";
if(is_server) {
ssize_t written = socket.write(server_message.data(), server_message.size());
- EXPECT_EQUAL(written, ssize_t(server_message.size()));
+ EXPECT_EQ(written, ssize_t(server_message.size()));
vespalib::string read = read_bytes(socket, client_message.size());
- EXPECT_EQUAL(client_message, read);
+ EXPECT_EQ(client_message, read);
} else {
ssize_t written = socket.write(client_message.data(), client_message.size());
- EXPECT_EQUAL(written, ssize_t(client_message.size()));
+ EXPECT_EQ(written, ssize_t(client_message.size()));
vespalib::string read = read_bytes(socket, server_message.size());
- EXPECT_EQUAL(server_message, read);
+ EXPECT_EQ(server_message, read);
}
}
@@ -79,10 +85,10 @@ void send_fd(SocketHandle &socket, SocketHandle fd) {
int *fd_dst = (int *) (void *) CMSG_DATA(hdr);
fd_dst[0] = fd.get();
ssize_t res = sendmsg(socket.get(), &msg, 0);
- ASSERT_EQUAL(res, 1);
+ ASSERT_EQ(res, 1);
}
-SocketHandle recv_fd(SocketHandle &socket) {
+void recv_fd(SocketHandle &socket, std::optional<SocketHandle>& result) {
struct msghdr msg = {};
char tag = '*';
struct iovec data;
@@ -94,36 +100,62 @@ SocketHandle recv_fd(SocketHandle &socket) {
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
ssize_t res = recvmsg(socket.get(), &msg, 0);
- ASSERT_EQUAL(res, 1);
+ ASSERT_EQ(res, 1);
struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
bool type_ok = ((hdr->cmsg_level == SOL_SOCKET) &&
(hdr->cmsg_type == SCM_RIGHTS));
ASSERT_TRUE(type_ok);
int *fd_src = (int *) (void *) CMSG_DATA(hdr);
fprintf(stderr, "got fd: %d\n", fd_src[0]);
- return SocketHandle(fd_src[0]);
+ result = SocketHandle(fd_src[0]);
}
//-----------------------------------------------------------------------------
-TEST_MT_FFF("require that an open socket (handle) can be passed over a unix domain socket", 3,
- ServerSocket("tcp/0"), ServerSocket("ipc/file:my_socket"), TimeBomb(60))
-{
- if (thread_id == 0) { // server
- SocketHandle socket = accept(f1);
- TEST_DO(verify_socket_io(true, socket)); // server side
- TEST_BARRIER();
- } else if (thread_id == 1) { // proxy
- SocketHandle server_socket = connect(f1);
- SocketHandle client_socket = accept(f2);
- send_fd(client_socket, std::move(server_socket));
- TEST_BARRIER();
- } else { // client
- SocketHandle proxy_socket = connect(f2);
- SocketHandle socket = recv_fd(proxy_socket);
- TEST_DO(verify_socket_io(false, socket)); // client side
- TEST_BARRIER();
+namespace {
+
+class WaitLatch {
+ std::latch& _latch;
+public:
+ explicit WaitLatch(std::latch& latch) noexcept
+ : _latch(latch)
+ {
}
+ ~WaitLatch() { _latch.arrive_and_wait(); }
+};
+
+}
+
+TEST(SendFdTest, require_that_an_open_socket_handle_can_be_passed_over_a_unix_domain_socket)
+{
+ constexpr size_t num_threads = 3;
+ ServerSocket f1("tcp/0");
+ ServerSocket f2("ipc/file:my_socket");
+ std::latch latch(num_threads);
+ TimeBomb f3(60);
+ auto task = [&f1,&f2,&latch](Nexus& ctx) {
+ auto thread_id = ctx.thread_id();
+ if (thread_id == 0) { // server
+ SocketHandle socket = accept(f1);
+ WaitLatch wait(latch);
+ SCOPED_TRACE("verify socket io server side");
+ verify_socket_io(true, socket); // server side
+ } else if (thread_id == 1) { // proxy
+ SocketHandle server_socket = connect(f1);
+ SocketHandle client_socket = accept(f2);
+ WaitLatch wait(latch);
+ ASSERT_NO_FATAL_FAILURE(send_fd(client_socket, std::move(server_socket)));
+ } else { // client
+ SocketHandle proxy_socket = connect(f2);
+ std::optional<SocketHandle> socket;
+ WaitLatch wait(latch);
+ ASSERT_NO_FATAL_FAILURE(recv_fd(proxy_socket, socket));
+ ASSERT_TRUE(socket.has_value());
+ SCOPED_TRACE("verify socket io client side");
+ verify_socket_io(false, socket.value()); // client side
+ }
+ };
+ Nexus::run(num_threads, task);
}
-TEST_MAIN() { TEST_RUN_ALL(); }
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/vespalib/src/tests/net/socket/CMakeLists.txt b/vespalib/src/tests/net/socket/CMakeLists.txt
index d20720971d2..49c4ca20ba3 100644
--- a/vespalib/src/tests/net/socket/CMakeLists.txt
+++ b/vespalib/src/tests/net/socket/CMakeLists.txt
@@ -4,6 +4,7 @@ vespa_add_executable(vespalib_socket_test_app TEST
socket_test.cpp
DEPENDS
vespalib
+ GTest::gtest
)
vespa_add_test(NAME vespalib_socket_test_app COMMAND vespalib_socket_test_app)
vespa_add_executable(vespalib_socket_server_app
diff --git a/vespalib/src/tests/net/socket/socket_test.cpp b/vespalib/src/tests/net/socket/socket_test.cpp
index b0708388cd6..64f337c03f6 100644
--- a/vespalib/src/tests/net/socket/socket_test.cpp
+++ b/vespalib/src/tests/net/socket/socket_test.cpp
@@ -1,11 +1,12 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/testkit/time_bomb.h>
#include <vespa/vespalib/net/selector.h>
#include <vespa/vespalib/net/socket_spec.h>
#include <vespa/vespalib/net/server_socket.h>
#include <vespa/vespalib/net/socket_options.h>
#include <vespa/vespalib/net/socket.h>
+#include <vespa/vespalib/test/nexus.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/test/socket_options_verifier.h>
#include <thread>
@@ -14,19 +15,55 @@
#include <sys/stat.h>
using namespace vespalib;
+using vespalib::test::Nexus;
-bool ipv4_enabled = false;
-bool ipv6_enabled = false;
+class SocketTest : public ::testing::Test {
+protected:
+ static bool ipv4_enabled;
+ static bool ipv6_enabled;
-int my_inet() {
+ SocketTest();
+ ~SocketTest() override;
+ static void SetUpTestSuite();
+ static void TearDownTestSuite();
+ static int my_inet();
+};
+
+bool SocketTest::ipv4_enabled = false;
+bool SocketTest::ipv6_enabled = false;
+
+SocketTest::SocketTest()
+ : testing::Test()
+{
+}
+
+SocketTest::~SocketTest() = default;
+
+void
+SocketTest::SetUpTestSuite()
+{
+ auto list = SocketAddress::resolve(4080);
+ for (const auto &addr : list) {
+ (void) addr;
+ ipv4_enabled |= addr.is_ipv4();
+ ipv6_enabled |= addr.is_ipv6();
+ }
+ ASSERT_TRUE(ipv4_enabled || ipv6_enabled) << "tcp/ip support not detected";
+}
+
+void
+SocketTest::TearDownTestSuite()
+{
+}
+
+int
+SocketTest::my_inet()
+{
if (ipv6_enabled) {
return AF_INET6;
- }
- if (ipv4_enabled) {
+ } else {
return AF_INET;
}
- TEST_ERROR("tcp/ip support not detected");
- return AF_UNIX;
}
bool is_socket(const vespalib::string &path) {
@@ -52,8 +89,8 @@ void remove_file(const vespalib::string &path) {
void replace_file(const vespalib::string &path, const vespalib::string &data) {
remove_file(path);
int fd = creat(path.c_str(), 0600);
- ASSERT_NOT_EQUAL(fd, -1);
- ASSERT_EQUAL(write(fd, data.data(), data.size()), ssize_t(data.size()));
+ ASSERT_NE(fd, -1);
+ ASSERT_EQ(write(fd, data.data(), data.size()), ssize_t(data.size()));
close(fd);
}
@@ -96,14 +133,14 @@ void verify_socket_io(bool is_server, SocketHandle &socket) {
vespalib::string client_message = "please pick up, I need to talk to you";
if(is_server) {
ssize_t written = socket.write(server_message.data(), server_message.size());
- EXPECT_EQUAL(written, ssize_t(server_message.size()));
+ EXPECT_EQ(written, ssize_t(server_message.size()));
vespalib::string read = read_bytes(socket, client_message.size());
- EXPECT_EQUAL(client_message, read);
+ EXPECT_EQ(client_message, read);
} else {
ssize_t written = socket.write(client_message.data(), client_message.size());
- EXPECT_EQUAL(written, ssize_t(client_message.size()));
+ EXPECT_EQ(written, ssize_t(client_message.size()));
vespalib::string read = read_bytes(socket, server_message.size());
- EXPECT_EQUAL(server_message, read);
+ EXPECT_EQ(server_message, read);
}
}
@@ -122,22 +159,22 @@ SocketHandle connect_sockets(bool is_server, ServerSocket &server_socket) {
//-----------------------------------------------------------------------------
-TEST("my local address") {
+TEST_F(SocketTest, my_local_address)
+{
auto list = SocketAddress::resolve(4080);
fprintf(stderr, "resolve(4080):\n");
for (const auto &addr: list) {
EXPECT_TRUE(addr.is_wildcard());
EXPECT_TRUE(addr.is_ipv4() || addr.is_ipv6());
- ipv4_enabled |= addr.is_ipv4();
- ipv6_enabled |= addr.is_ipv6();
EXPECT_TRUE(!addr.is_ipc());
EXPECT_TRUE(!addr.is_abstract());
- EXPECT_EQUAL(addr.port(), 4080);
+ EXPECT_EQ(addr.port(), 4080);
fprintf(stderr, " %s (%s)\n", addr.spec().c_str(), get_meta(addr).c_str());
}
}
-TEST("yahoo.com address") {
+TEST_F(SocketTest, yahoo_com_address)
+{
auto list = SocketAddress::resolve(80, "yahoo.com");
fprintf(stderr, "resolve(80, 'yahoo.com'):\n");
for (const auto &addr: list) {
@@ -145,80 +182,102 @@ TEST("yahoo.com address") {
EXPECT_TRUE(addr.is_ipv4() || addr.is_ipv6());
EXPECT_TRUE(!addr.is_ipc());
EXPECT_TRUE(!addr.is_abstract());
- EXPECT_EQUAL(addr.port(), 80);
+ EXPECT_EQ(addr.port(), 80);
fprintf(stderr, " %s (%s)\n", addr.spec().c_str(), get_meta(addr).c_str());
}
}
-TEST("ipc address (path)") {
+TEST_F(SocketTest, ipc_address_with_path)
+{
auto addr = SocketAddress::from_path("my_socket");
EXPECT_TRUE(!addr.is_ipv4());
EXPECT_TRUE(!addr.is_ipv6());
EXPECT_TRUE(addr.is_ipc());
EXPECT_TRUE(!addr.is_abstract());
EXPECT_TRUE(!addr.is_wildcard());
- EXPECT_EQUAL(addr.port(), -1);
- EXPECT_EQUAL(vespalib::string("my_socket"), addr.path());
+ EXPECT_EQ(addr.port(), -1);
+ EXPECT_EQ(vespalib::string("my_socket"), addr.path());
EXPECT_TRUE(addr.name().empty());
fprintf(stderr, "from_path(my_socket)\n");
fprintf(stderr, " %s (%s)\n", addr.spec().c_str(), get_meta(addr).c_str());
}
-TEST("ipc address (name)") {
+TEST_F(SocketTest, ipc_address_with_name)
+{
auto addr = SocketAddress::from_name("my_socket");
EXPECT_TRUE(!addr.is_ipv4());
EXPECT_TRUE(!addr.is_ipv6());
EXPECT_TRUE(addr.is_ipc());
EXPECT_TRUE(addr.is_abstract());
EXPECT_TRUE(!addr.is_wildcard());
- EXPECT_EQUAL(addr.port(), -1);
+ EXPECT_EQ(addr.port(), -1);
EXPECT_TRUE(addr.path().empty());
- EXPECT_EQUAL(vespalib::string("my_socket"), addr.name());
+ EXPECT_EQ(vespalib::string("my_socket"), addr.name());
fprintf(stderr, "from_path(my_socket)\n");
fprintf(stderr, " %s (%s)\n", addr.spec().c_str(), get_meta(addr).c_str());
}
-TEST("local client/server addresses") {
+TEST_F(SocketTest, local_client_and_server_addresses) {
auto spec = SocketSpec("tcp/123");
auto client = spec.client_address();
auto server = spec.server_address();
EXPECT_TRUE(!client.is_wildcard());
- EXPECT_EQUAL(client.port(), 123);
+ EXPECT_EQ(client.port(), 123);
EXPECT_TRUE(server.is_wildcard());
- EXPECT_EQUAL(server.port(), 123);
+ EXPECT_EQ(server.port(), 123);
fprintf(stderr, "client(tcp/123): %s (%s)\n", client.spec().c_str(), get_meta(client).c_str());
fprintf(stderr, "server(tcp/123): %s (%s)\n", server.spec().c_str(), get_meta(server).c_str());
}
-TEST_MT_FF("require that basic socket io works", 2, ServerSocket("tcp/0"), TimeBomb(60)) {
- bool is_server = (thread_id == 0);
- SocketHandle socket = connect_sockets(is_server, f1);
- TEST_DO(verify_socket_io(is_server, socket));
-}
-
-TEST_MT_FF("require that basic unix domain socket io works (path)", 2,
- ServerSocket("ipc/file:my_socket"), TimeBomb(60))
+TEST_F(SocketTest, require_that_basic_socket_io_works)
+{
+ constexpr size_t num_threads = 2;
+ ServerSocket f1("tcp/0");
+ TimeBomb f2(60);
+ auto task = [&f1](Nexus& ctx) {
+ bool is_server = (ctx.thread_id() == 0);
+ SocketHandle socket = connect_sockets(is_server, f1);
+ verify_socket_io(is_server, socket);
+ };
+ Nexus::run(num_threads, task);
+}
+
+TEST_F(SocketTest, require_that_basic_unix_domain_socket_io_works_with_path)
+{
+ constexpr size_t num_threads = 2;
+ ServerSocket f1("ipc/file:my_socket");
+ TimeBomb f2(60);
+ auto task = [&f1](Nexus& ctx) {
+ bool is_server = (ctx.thread_id() == 0);
+ SocketHandle socket = connect_sockets(is_server, f1);
+ verify_socket_io(is_server, socket);
+ };
+ Nexus::run(num_threads, task);
+}
+
+TEST_F(SocketTest, require_that_server_accept_can_be_interrupted)
+{
+ constexpr size_t num_threads = 2;
+ ServerSocket f1("tcp/0");
+ TimeBomb f2(60);
+ auto task = [&f1](Nexus& ctx) {
+ bool is_server = (ctx.thread_id() == 0);
+ if (is_server) {
+ fprintf(stderr, "--> calling accept\n");
+ SocketHandle socket = f1.accept();
+ fprintf(stderr, "<-- accept returned\n");
+ EXPECT_TRUE(!socket.valid());
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ fprintf(stderr, "--- closing server socket\n");
+ f1.shutdown();
+ }
+ };
+ Nexus::run(num_threads, task);
+}
+
+TEST_F(SocketTest, require_that_socket_file_is_removed_by_server_socket_when_destructed)
{
- bool is_server = (thread_id == 0);
- SocketHandle socket = connect_sockets(is_server, f1);
- TEST_DO(verify_socket_io(is_server, socket));
-}
-
-TEST_MT_FF("require that server accept can be interrupted", 2, ServerSocket("tcp/0"), TimeBomb(60)) {
- bool is_server = (thread_id == 0);
- if (is_server) {
- fprintf(stderr, "--> calling accept\n");
- SocketHandle socket = f1.accept();
- fprintf(stderr, "<-- accept returned\n");
- EXPECT_TRUE(!socket.valid());
- } else {
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
- fprintf(stderr, "--- closing server socket\n");
- f1.shutdown();
- }
-}
-
-TEST("require that socket file is removed by server socket when destructed") {
remove_file("my_socket");
ServerSocket server("ipc/file:my_socket");
EXPECT_TRUE(server.valid());
@@ -227,7 +286,8 @@ TEST("require that socket file is removed by server socket when destructed") {
EXPECT_TRUE(!is_socket("my_socket"));
}
-TEST("require that socket file is only removed on destruction if it is a socket") {
+TEST_F(SocketTest, require_that_socket_file_is_only_removed_on_destruction_if_it_is_a_socket)
+{
remove_file("my_socket");
ServerSocket server("ipc/file:my_socket");
EXPECT_TRUE(server.valid());
@@ -238,7 +298,8 @@ TEST("require that socket file is only removed on destruction if it is a socket"
remove_file("my_socket");
}
-TEST("require that a server socket will fail to listen to a path that is already a regular file") {
+TEST_F(SocketTest, require_that_a_server_socket_will_fail_to_listen_to_a_path_that_is_already_a_regular_file)
+{
replace_file("my_socket", "hello\n");
ServerSocket server("ipc/file:my_socket");
EXPECT_TRUE(!server.valid());
@@ -247,7 +308,8 @@ TEST("require that a server socket will fail to listen to a path that is already
remove_file("my_socket");
}
-TEST("require that a server socket will fail to listen to a path that is already taken by another server") {
+TEST_F(SocketTest, require_that_a_server_socket_will_fail_to_listen_to_a_path_that_is_already_taken_by_another_server)
+{
remove_file("my_socket");
ServerSocket server1("ipc/file:my_socket");
ServerSocket server2("ipc/file:my_socket");
@@ -258,7 +320,8 @@ TEST("require that a server socket will fail to listen to a path that is already
EXPECT_TRUE(!is_socket("my_socket"));
}
-TEST("require that a server socket will remove an old socket file if it cannot be connected to") {
+TEST_F(SocketTest, require_that_a_server_socket_will_remove_an_old_socket_file_if_it_cannot_be_connected_to)
+{
remove_file("my_socket");
{
SocketHandle server_handle = SocketAddress::from_path("my_socket").listen();
@@ -272,15 +335,21 @@ TEST("require that a server socket will remove an old socket file if it cannot b
}
#ifdef __linux__
-TEST_MT_FF("require that basic unix domain socket io works (name)", 2,
- ServerSocket(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
+TEST_F(SocketTest, require_that_basic_unix_domain_socket_io_works_with_name)
+{
+ constexpr size_t num_threads = 2;
+ ServerSocket f1(make_string("ipc/name:my_socket-%d", int(getpid())));
+ TimeBomb f2(60);
+ auto task = [&f1](Nexus& ctx) {
+ bool is_server = (ctx.thread_id() == 0);
+ SocketHandle socket = connect_sockets(is_server, f1);
+ verify_socket_io(is_server, socket);
+ };
+ Nexus::run(num_threads, task);
+}
+
+TEST_F(SocketTest, require_that_two_server_sockets_cannot_have_the_same_abstract_unix_domain_socket_name)
{
- bool is_server = (thread_id == 0);
- SocketHandle socket = connect_sockets(is_server, f1);
- TEST_DO(verify_socket_io(is_server, socket));
-}
-
-TEST("require that two server sockets cannot have the same abstract unix domain socket name") {
vespalib::string spec = make_string("ipc/name:my_socket-%d", int(getpid()));
ServerSocket server1(spec);
ServerSocket server2(spec);
@@ -288,7 +357,8 @@ TEST("require that two server sockets cannot have the same abstract unix domain
EXPECT_TRUE(!server2.valid());
}
-TEST("require that abstract socket names are freed when the server socket is destructed") {
+TEST_F(SocketTest, require_that_abstract_socket_names_are_freed_when_the_server_socket_is_destructed)
+{
vespalib::string spec = make_string("ipc/name:my_socket-%d", int(getpid()));
ServerSocket server1(spec);
EXPECT_TRUE(server1.valid());
@@ -297,100 +367,162 @@ TEST("require that abstract socket names are freed when the server socket is des
EXPECT_TRUE(server2.valid());
}
-TEST("require that abstract sockets do not have socket files") {
+TEST_F(SocketTest, require_that_abstract_sockets_do_not_have_socket_files)
+{
vespalib::string name = make_string("my_socket-%d", int(getpid()));
ServerSocket server(SocketSpec::from_name(name));
EXPECT_TRUE(server.valid());
EXPECT_TRUE(!is_socket(name));
- EXPECT_TRUE(!is_file(name));
+ EXPECT_TRUE(!is_file(name));
}
-TEST_MT_FFF("require that abstract and file-based unix domain sockets are not in conflict", 4,
- ServerSocket(make_string("ipc/file:my_socket-%d", int(getpid()))),
- ServerSocket(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
+TEST_F(SocketTest, require_that_abstract_and_file_based_unix_domain_sockets_are_not_in_conflict)
{
- bool is_server = ((thread_id % 2) == 0);
- ServerSocket &server_socket = ((thread_id / 2) == 0) ? f1 : f2;
- SocketHandle socket = connect_sockets(is_server, server_socket);
- TEST_DO(verify_socket_io(is_server, socket));
+ constexpr size_t num_threads = 4;
+ ServerSocket f1(make_string("ipc/file:my_socket-%d", int(getpid())));
+ ServerSocket f2(make_string("ipc/name:my_socket-%d", int(getpid())));
+ TimeBomb f3(60);
+ auto task = [&f1,&f2](Nexus& ctx) {
+ auto thread_id = ctx.thread_id();
+ bool is_server = ((thread_id % 2) == 0);
+ ServerSocket &server_socket = ((thread_id / 2) == 0) ? f1 : f2;
+ SocketHandle socket = connect_sockets(is_server, server_socket);
+ verify_socket_io(is_server, socket);
+ };
+ Nexus::run(num_threads, task);
}
#endif
-TEST("require that sockets can be set blocking and non-blocking") {
+TEST_F(SocketTest, require_that_sockets_can_be_set_blocking_and_non_blocking)
+{
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_blocking(-1, true));
EXPECT_TRUE(handle.set_blocking(true));
- TEST_DO(verifier.verify_blocking(true));
+ {
+ SCOPED_TRACE("verify blocking true");
+ verifier.verify_blocking(true);
+ }
EXPECT_TRUE(handle.set_blocking(false));
- TEST_DO(verifier.verify_blocking(false));
+ {
+ SCOPED_TRACE("verify blocking false");
+ verifier.verify_blocking(false);
+ }
}
-TEST("require that server sockets use non-blocking underlying socket") {
+TEST_F(SocketTest, require_that_server_sockets_use_non_blocking_underlying_socket)
+{
ServerSocket tcp_server("tcp/0");
ServerSocket ipc_server("ipc/file:my_socket");
test::SocketOptionsVerifier tcp_verifier(tcp_server.get_fd());
test::SocketOptionsVerifier ipc_verifier(ipc_server.get_fd());
- TEST_DO(tcp_verifier.verify_blocking(false));
- TEST_DO(ipc_verifier.verify_blocking(false));
+ {
+ SCOPED_TRACE("verify tcp nonblocking");
+ tcp_verifier.verify_blocking(false);
+ }
+ {
+ SCOPED_TRACE("verify ipc nonblocking");
+ ipc_verifier.verify_blocking(false);
+ }
}
-TEST("require that tcp nodelay can be enabled and disabled") {
+TEST_F(SocketTest, require_that_tcp_nodelay_can_be_enabled_and_disabled)
+{
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_nodelay(-1, true));
EXPECT_TRUE(handle.set_nodelay(true));
- TEST_DO(verifier.verify_nodelay(true));
+ {
+ SCOPED_TRACE("verify nodelay true");
+ verifier.verify_nodelay(true);
+ }
EXPECT_TRUE(handle.set_nodelay(false));
- TEST_DO(verifier.verify_nodelay(false));
+ {
+ SCOPED_TRACE("verify nodelay false");
+ verifier.verify_nodelay(false);
+ }
}
-TEST("require that reuse addr can be set and cleared") {
+TEST_F(SocketTest, require_that_reuse_addr_can_be_set_and_cleared)
+{
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_reuse_addr(-1, true));
EXPECT_TRUE(handle.set_reuse_addr(true));
- TEST_DO(verifier.verify_reuse_addr(true));
+ {
+ SCOPED_TRACE("verify reuse addr true");
+ verifier.verify_reuse_addr(true);
+ }
EXPECT_TRUE(handle.set_reuse_addr(false));
- TEST_DO(verifier.verify_reuse_addr(false));
+ {
+ SCOPED_TRACE("verify reuse addr false");
+ verifier.verify_reuse_addr(false);
+ }
}
-TEST("require that ipv6_only can be set and cleared") {
+TEST_F(SocketTest, require_that_ipv6_only_can_be_set_and_cleared)
+{
if (ipv6_enabled) {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_ipv6_only(-1, true));
EXPECT_TRUE(handle.set_ipv6_only(true));
- TEST_DO(verifier.verify_ipv6_only(true));
+ {
+ SCOPED_TRACE("verify ipv6 only true");
+ verifier.verify_ipv6_only(true);
+ }
EXPECT_TRUE(handle.set_ipv6_only(false));
- TEST_DO(verifier.verify_ipv6_only(false));
+ {
+ SCOPED_TRACE("verify ipv6 only false");
+ verifier.verify_ipv6_only(false);
+ }
} else {
fprintf(stderr, "WARNING: skipping ipv6_only test since ipv6 is disabled");
}
}
-TEST("require that tcp keepalive can be set and cleared") {
+TEST_F(SocketTest, require_that_tcp_keepalive_can_be_set_and_cleared)
+{
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_keepalive(-1, true));
EXPECT_TRUE(handle.set_keepalive(true));
- TEST_DO(verifier.verify_keepalive(true));
+ {
+ SCOPED_TRACE("verify keepalive true");
+ verifier.verify_keepalive(true);
+ }
EXPECT_TRUE(handle.set_keepalive(false));
- TEST_DO(verifier.verify_keepalive(false));
+ {
+ SCOPED_TRACE("verify keepalive false");
+ verifier.verify_keepalive(false);
+ }
}
-TEST("require that tcp lingering can be adjusted") {
+TEST_F(SocketTest, require_that_tcp_lingering_can_be_adjusted)
+{
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_linger(-1, true, 0));
EXPECT_TRUE(handle.set_linger(true, 0));
- TEST_DO(verifier.verify_linger(true, 0));
+ {
+ SCOPED_TRACE("verify linger true 0");
+ verifier.verify_linger(true, 0);
+ }
EXPECT_TRUE(handle.set_linger(true, 10));
- TEST_DO(verifier.verify_linger(true, 10));
+ {
+ SCOPED_TRACE("verify linger true 10");
+ verifier.verify_linger(true, 10);
+ }
EXPECT_TRUE(handle.set_linger(false, 0));
- TEST_DO(verifier.verify_linger(false, 0));
+ {
+ SCOPED_TRACE("verify linger false 0");
+ verifier.verify_linger(false, 0);
+ }
EXPECT_TRUE(handle.set_linger(false, 10));
- TEST_DO(verifier.verify_linger(false, 0));
+ {
+ SCOPED_TRACE("verify linger false 0 (overridden)");
+ verifier.verify_linger(false, 0);
+ }
}
SocketHandle connect_async(const SocketAddress &addr) {
@@ -411,7 +543,10 @@ SocketHandle connect_async(const SocketAddress &addr) {
ctx.handle = addr.connect_async();
EXPECT_TRUE(ctx.handle.valid());
test::SocketOptionsVerifier verifier(ctx.handle.get());
- TEST_DO(verifier.verify_blocking(false));
+ {
+ SCOPED_TRACE("verify blocking false");
+ verifier.verify_blocking(false);
+ }
if (ctx.handle.valid()) {
selector.add(ctx.handle.get(), ctx, true, true);
while (!ctx.connect_done) {
@@ -420,23 +555,30 @@ SocketHandle connect_async(const SocketAddress &addr) {
}
selector.remove(ctx.handle.get());
}
- EXPECT_EQUAL(ctx.error, 0);
+ EXPECT_EQ(ctx.error, 0);
return std::move(ctx.handle);
}
-TEST_MT_FF("require that async connect pattern works", 2, ServerSocket("tcp/0"), TimeBomb(60)) {
- if (thread_id == 0) {
- SocketHandle socket = f1.accept();
- EXPECT_TRUE(socket.valid());
- TEST_DO(verify_socket_io(true, socket));
- } else {
- SocketAddress addr = SocketSpec::from_port(f1.address().port()).client_address();
- SocketHandle socket = connect_async(addr);
- socket.set_blocking(true);
- TEST_DO(verify_socket_io(false, socket));
- // TEST_DO(connect_async(SocketAddress::select_remote(80, "www.yahoo.com")));
- // TEST_DO(connect_async(SocketAddress::select_remote(85, "myinternalhost")));
- }
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
+TEST_F(SocketTest, require_that_async_connect_pattern_works)
+{
+ constexpr size_t num_threads = 2;
+ ServerSocket f1("tcp/0");
+ TimeBomb f2(60);
+ auto task = [&f1](Nexus& ctx) {
+ if (ctx.thread_id() == 0) {
+ SocketHandle socket = f1.accept();
+ EXPECT_TRUE(socket.valid());
+ SCOPED_TRACE("verify socket io true");
+ verify_socket_io(true, socket);
+ } else {
+ SocketAddress addr = SocketSpec::from_port(f1.address().port()).client_address();
+ SocketHandle socket = connect_async(addr);
+ socket.set_blocking(true);
+ SCOPED_TRACE("verify socket io false");
+ verify_socket_io(false, socket);
+ }
+ };
+ Nexus::run(num_threads, task);
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/vespalib/src/vespa/vespalib/test/socket_options_verifier.h b/vespalib/src/vespa/vespalib/test/socket_options_verifier.h
index 04b4dea414e..3831c03d629 100644
--- a/vespalib/src/vespa/vespalib/test/socket_options_verifier.h
+++ b/vespalib/src/vespa/vespalib/test/socket_options_verifier.h
@@ -2,7 +2,7 @@
#pragma once
-#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/tcp.h>
@@ -16,9 +16,9 @@ namespace {
void verify_bool_opt(int fd, int level, int name, bool expect) {
int data = 0;
socklen_t size = sizeof(data);
- EXPECT_EQUAL(getsockopt(fd, level, name, &data, &size), 0);
- EXPECT_EQUAL(size, sizeof(data));
- EXPECT_EQUAL(data != 0, expect);
+ EXPECT_EQ(getsockopt(fd, level, name, &data, &size), 0);
+ EXPECT_EQ(size, sizeof(data));
+ EXPECT_EQ(data != 0, expect);
}
} // namespace vespalib::test::<unnamed>
@@ -31,31 +31,35 @@ struct SocketOptionsVerifier {
SocketOptionsVerifier(int fd_in) : fd(fd_in) {}
void verify_blocking(bool value) {
int flags = fcntl(fd, F_GETFL, NULL);
- EXPECT_NOT_EQUAL(flags, -1);
- EXPECT_EQUAL(((flags & O_NONBLOCK) == 0), value);
+ EXPECT_NE(flags, -1);
+ EXPECT_EQ(((flags & O_NONBLOCK) == 0), value);
}
void verify_nodelay(bool value) {
- TEST_DO(verify_bool_opt(fd, IPPROTO_TCP, TCP_NODELAY, value));
+ SCOPED_TRACE("verify nodelay");
+ verify_bool_opt(fd, IPPROTO_TCP, TCP_NODELAY, value);
}
void verify_reuse_addr(bool value) {
- TEST_DO(verify_bool_opt(fd, SOL_SOCKET, SO_REUSEADDR, value));
+ SCOPED_TRACE("verify reuse addr");
+ verify_bool_opt(fd, SOL_SOCKET, SO_REUSEADDR, value);
}
void verify_ipv6_only(bool value) {
- TEST_DO(verify_bool_opt(fd, IPPROTO_IPV6, IPV6_V6ONLY, value));
+ SCOPED_TRACE("verify ipv6 only");
+ verify_bool_opt(fd, IPPROTO_IPV6, IPV6_V6ONLY, value);
}
void verify_keepalive(bool value) {
- TEST_DO(verify_bool_opt(fd, SOL_SOCKET, SO_KEEPALIVE, value));
+ SCOPED_TRACE("verify keepalive");
+ verify_bool_opt(fd, SOL_SOCKET, SO_KEEPALIVE, value);
}
void verify_linger(bool enable, int value)
{
struct linger data;
socklen_t size = sizeof(data);
memset(&data, 0, sizeof(data));
- EXPECT_EQUAL(getsockopt(fd, SOL_SOCKET, SO_LINGER, &data, &size), 0);
- EXPECT_EQUAL(size, sizeof(data));
- EXPECT_EQUAL(enable, data.l_onoff);
+ EXPECT_EQ(getsockopt(fd, SOL_SOCKET, SO_LINGER, &data, &size), 0);
+ EXPECT_EQ(size, sizeof(data));
+ EXPECT_EQ(enable, data.l_onoff);
if (enable) {
- EXPECT_EQUAL(value, data.l_linger);
+ EXPECT_EQ(value, data.l_linger);
}
}
};