Reactor/tests/test_socket.cpp
2025-06-27 18:16:01 -05:00

287 lines
7.3 KiB
C++

#include "../lib/Socket.hpp"
#include <cassert>
#include <iostream>
#include <thread>
#include <chrono>
#include <cstring>
void test_socket_creation()
{
std::cout << "Testing socket creation...\n";
auto tcp_socket = reactor::Socket::createTcp();
assert(tcp_socket.fd() >= 0);
auto tcp6_socket = reactor::Socket::createTcp(true);
assert(tcp6_socket.fd() >= 0);
auto udp_socket = reactor::Socket::createUdp();
assert(udp_socket.fd() >= 0);
auto udp6_socket = reactor::Socket::createUdp(true);
assert(udp6_socket.fd() >= 0);
std::cout << "✓ Socket creation passed\n";
}
void test_socket_move()
{
std::cout << "Testing socket move semantics...\n";
auto socket1 = reactor::Socket::createTcp();
int fd = socket1.fd();
assert(fd >= 0);
auto socket2 = std::move(socket1);
assert(socket2.fd() == fd);
assert(socket1.fd() == -1);
reactor::Socket socket3 = reactor::Socket::createTcp();
int fd3 = socket3.fd();
socket3 = std::move(socket2);
assert(socket3.fd() == fd);
std::cout << "✓ Socket move semantics passed\n";
}
void test_socket_bind_listen()
{
std::cout << "Testing socket bind and listen...\n";
auto socket = reactor::Socket::createTcp();
reactor::InetAddress addr(0);
socket.setReuseAddr(true);
socket.bind(addr);
socket.listen();
auto local_addr = reactor::Socket::getLocalAddr(socket.fd());
assert(local_addr.port() > 0);
std::cout << "✓ Socket bind and listen passed\n";
}
void test_socket_options()
{
std::cout << "Testing socket options...\n";
auto socket = reactor::Socket::createTcp();
socket.setReuseAddr(true);
socket.setReusePort(true);
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
socket.setTcpKeepAlive(7200, 30, 9);
socket.setRecvBuffer(65536);
socket.setSendBuffer(65536);
std::cout << "✓ Socket options passed\n";
}
void test_socket_connection()
{
std::cout << "Testing socket connection...\n";
auto server_socket = reactor::Socket::createTcp();
reactor::InetAddress server_addr(0);
server_socket.setReuseAddr(true);
server_socket.bind(server_addr);
server_socket.listen();
auto actual_addr = reactor::Socket::getLocalAddr(server_socket.fd());
std::cout << "Server listening on: " << actual_addr.toIpPort() << "\n";
std::thread server_thread([&server_socket]() {
reactor::InetAddress peer_addr;
int client_fd = server_socket.accept(peer_addr);
if (client_fd >= 0) {
std::cout << "Server accepted connection from: " << peer_addr.toIpPort() << "\n";
char buffer[1024];
ssize_t n = read(client_fd, buffer, sizeof(buffer));
if (n > 0) {
write(client_fd, buffer, n);
}
close(client_fd);
}
});
std::this_thread::sleep_for(std::chrono::milliseconds(10));
auto client_socket = reactor::Socket::createTcp();
reactor::InetAddress connect_addr("127.0.0.1", actual_addr.port());
int result = client_socket.connect(connect_addr);
if (result == 0 || errno == EINPROGRESS) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
const char* message = "Hello Server";
ssize_t sent = client_socket.write(message, strlen(message));
assert(sent > 0);
char response[1024];
ssize_t received = client_socket.read(response, sizeof(response));
assert(received > 0);
assert(strncmp(message, response, sent) == 0);
}
server_thread.join();
std::cout << "✓ Socket connection passed\n";
}
void test_udp_socket()
{
std::cout << "Testing UDP socket operations...\n";
auto server_socket = reactor::Socket::createUdp();
reactor::InetAddress server_addr(0);
server_socket.setReuseAddr(true);
server_socket.bind(server_addr);
auto actual_addr = reactor::Socket::getLocalAddr(server_socket.fd());
std::cout << "UDP server bound to: " << actual_addr.toIpPort() << "\n";
std::thread server_thread([&server_socket]() {
char buffer[1024];
reactor::InetAddress client_addr;
ssize_t n = server_socket.recvFrom(buffer, sizeof(buffer), client_addr);
if (n > 0) {
server_socket.sendTo(buffer, n, client_addr);
}
});
std::this_thread::sleep_for(std::chrono::milliseconds(10));
auto client_socket = reactor::Socket::createUdp();
reactor::InetAddress target_addr("127.0.0.1", actual_addr.port());
const char* message = "UDP Hello";
ssize_t sent = client_socket.sendTo(message, strlen(message), target_addr);
assert(sent > 0);
char response[1024];
reactor::InetAddress from_addr;
ssize_t received = client_socket.recvFrom(response, sizeof(response), from_addr);
assert(received > 0);
assert(strncmp(message, response, sent) == 0);
server_thread.join();
std::cout << "✓ UDP socket operations passed\n";
}
void test_socket_shutdown()
{
std::cout << "Testing socket shutdown...\n";
auto server_socket = reactor::Socket::createTcp();
reactor::InetAddress server_addr(0);
server_socket.setReuseAddr(true);
server_socket.bind(server_addr);
server_socket.listen();
auto actual_addr = reactor::Socket::getLocalAddr(server_socket.fd());
std::thread server_thread([&server_socket]() {
reactor::InetAddress peer_addr;
int client_fd = server_socket.accept(peer_addr);
if (client_fd >= 0) {
reactor::Socket client_sock(client_fd);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
client_sock.shutdownWrite();
close(client_fd);
}
});
std::this_thread::sleep_for(std::chrono::milliseconds(10));
auto client_socket = reactor::Socket::createTcp();
reactor::InetAddress connect_addr("127.0.0.1", actual_addr.port());
int result = client_socket.connect(connect_addr);
if (result == 0 || errno == EINPROGRESS) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
char buffer[1024];
ssize_t n = client_socket.read(buffer, sizeof(buffer));
assert(n == 0);
}
server_thread.join();
std::cout << "✓ Socket shutdown passed\n";
}
void test_socket_error_handling()
{
std::cout << "Testing socket error handling...\n";
auto socket = reactor::Socket::createTcp();
int error = socket.getSocketError();
assert(error == 0);
reactor::InetAddress invalid_addr("192.0.2.1", 12345);
int result = socket.connect(invalid_addr);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "✓ Socket error handling passed\n";
}
void test_address_retrieval()
{
std::cout << "Testing address retrieval...\n";
auto server_socket = reactor::Socket::createTcp();
reactor::InetAddress server_addr("127.0.0.1", 0);
server_socket.setReuseAddr(true);
server_socket.bind(server_addr);
server_socket.listen();
auto local_addr = reactor::Socket::getLocalAddr(server_socket.fd());
assert(local_addr.toIp() == "127.0.0.1");
assert(local_addr.port() > 0);
std::cout << "✓ Address retrieval passed\n";
}
void test_self_connection_detection()
{
std::cout << "Testing self connection detection...\n";
auto socket = reactor::Socket::createTcp();
reactor::InetAddress addr("127.0.0.1", 0);
socket.setReuseAddr(true);
socket.bind(addr);
auto bound_addr = reactor::Socket::getLocalAddr(socket.fd());
bool is_self = socket.isSelfConnected();
std::cout << "Self connected: " << is_self << "\n";
std::cout << "✓ Self connection detection passed\n";
}
int main()
{
std::cout << "=== Socket Tests ===\n";
test_socket_creation();
test_socket_move();
test_socket_bind_listen();
test_socket_options();
test_socket_connection();
test_udp_socket();
test_socket_shutdown();
test_socket_error_handling();
test_address_retrieval();
test_self_connection_detection();
std::cout << "All socket tests passed! ✓\n";
return 0;
}