diff --git a/.github/workflows/gtest.yml b/.github/workflows/gtest.yml new file mode 100644 index 00000000..343647bd --- /dev/null +++ b/.github/workflows/gtest.yml @@ -0,0 +1,42 @@ +name: UNIT_TEST +on: [push] +jobs: + Linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: build + run: | + cmake -S . -B build + cmake --build build + + - name: run all tests on Linux + run: ./build/unit_test + + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + title: "UNIT_TEST_ON_LINUX" + webhook: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} + + macOS: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + - name: build + run: | + cmake -S . -B build + cmake --build build + + - name: run all tests on macOS + run: ./build/unit_test + + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + title: "UNIT_TEST_ON_MACOS" + webhook: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index f4163fb3..92add2e2 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -1,4 +1,4 @@ -name: UNIT_TEST +name: UNIT_TEST_SH on: [push] jobs: run-unit-test: diff --git a/.gitignore b/.gitignore index 3cb87c1e..52a48286 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,11 @@ !config !srcs -!srcs/** +!srcs/Socket !www !includes !test +!playground !*.cpp !*.hpp @@ -22,8 +23,9 @@ !Makefile !CPPLINT.cfg !webserv.drawio +!CMakeLists.txt .idea .vscode .DS_Store -CMakeLists.txt \ No newline at end of file +CMakeCache.txt \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..01e4b0b5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.23) +project(webserv) + +set(CMAKE_CXX_STANDARD 98) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "-std=c++98 -Wall -Wextra -Werror -pedantic") + +# google test ------------------------------------------------------------------ +include(FetchContent) +include(GoogleTest) + +FetchContent_Declare( + googletest + DOWNLOAD_EXTRACT_TIMESTAMP true + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +enable_testing() + + +# when you .cpp or .hpp is added, add the following +# include, webserv srcs, unit_test_srcs +# includes --------------------------------------------------------------------- +include_directories( + includes + srcs/Socket +) + +# webserv_srcs ----------------------------------------------------------------- +set(webserv_srcs + srcs/get_valid_config_file_path.cpp + srcs/Socket/Socket.cpp +) + +add_executable(webserv + srcs/main.cpp + ${webserv_srcs} +) + +# unit_test_srcs --------------------------------------------------------------- +set (unit_test_srcs + test/unit_test/is_valid_file_path/test_get_valid_config_file_path.cpp + test/unit_test/TestSocket.cpp +) + +add_executable(unit_test + ${webserv_srcs} + ${unit_test_srcs} + ) + +# test ------------------------------------------------------------------------- +target_link_libraries( + unit_test + GTest::gtest_main +) + +gtest_discover_tests(unit_test) \ No newline at end of file diff --git a/Makefile b/Makefile index 2afe1a7c..e821fb29 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,10 @@ SRCS_DIR = srcs SRCS = main.cpp \ get_valid_config_file_path.cpp +#socket +SOCKET_DIR = Socket +SRCS += $(SOCKET_DIR)/Socket.cpp + # OBJS ------------------------------------------------------------------------- OBJS_DIR = objs @@ -22,21 +26,20 @@ DEPS = $(OBJS:%.o=%.d) # INCLUDES --------------------------------------------------------------------- -INCLUDES_DIR = includes srcs/includes +INCLUDES_DIR = includes \ + $(SRCS_DIR)/$(SOCKET_DIR) INCLUDES = $(addprefix -I, $(INCLUDES_DIR)) # RULES ------------------------------------------------------------------------ .PHONY : all -all : $(OBJS_DIR) $(NAME) +all : $(NAME) $(NAME) : $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ -$(OBJS_DIR) : - @mkdir -p $@ - $(OBJS_DIR)/%.o : $(SRCS_DIR)/%.cpp + @mkdir -p $$(dirname $@) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< .PHONY : clean @@ -54,9 +57,17 @@ re : fclean all lint : cpplint --recursive srcs +#.PHONY : unit +#unit : +# ./test/unit_test/run_unit_test.sh + .PHONY : unit unit : - ./test/unit_test/run_unit_test.sh - + #rm -rf build + cmake -S . -B build + cmake --build build + #./build/unit_test 2>/dev/null + ./build/unit_test + #cd build && ctest -include $(DEPS) \ No newline at end of file diff --git a/includes/webserv.hpp b/includes/webserv.hpp index 2b32404f..f3f5fdd8 100644 --- a/includes/webserv.hpp +++ b/includes/webserv.hpp @@ -1,6 +1,7 @@ #pragma once -# define EXECUTABLE_FILE_ONLY_ARGC 1 +#include + # define CONFIG_FILE_GIVEN_ARGC 2 # define CONFIG_FILE_INDEX 1 @@ -10,10 +11,12 @@ # define PATH_DELIM '/' # define EXTENSION_DELIM '.' -# define STAT_ERROR (-1) +# define STAT_ERROR (-1) +# define ERROR (-1) +# define OK 0 # define INVALID_ARGUMENT_ERROR_MSG "[Error] invalid argument" # define INVALID_PATH_ERROR_MSG "[Error] invalid file path" -std::string get_valid_config_file_path(int argc, char **argv); +std::string get_valid_config_file_path(const char *path); bool is_valid_config_file_path(const char *path); // todo: static diff --git a/playground/.gitignore b/playground/.gitignore new file mode 100644 index 00000000..0da64b3b --- /dev/null +++ b/playground/.gitignore @@ -0,0 +1,5 @@ +* + +!.gitignore +!*.cpp +!*.hpp \ No newline at end of file diff --git a/playground/playground_socket.cpp b/playground/playground_socket.cpp new file mode 100644 index 00000000..8852f9f3 --- /dev/null +++ b/playground/playground_socket.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int test_socket(const char *server_ip, const char *server_port) { + int errcode; + int socket_fd; + int ai_family, ai_socktype, ai_protocol; + struct addrinfo *addr_info; + struct addrinfo hints = {}; +// const char *server_ip = "127.0.0.1"; +// const char *server_port = "65536"; + + printf("ip:%s, port:%s\n", server_ip, server_port); + + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; // allows IPv4 and IPv6 + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV; // socket, IP, PORT + hints.ai_protocol = IPPROTO_TCP; + + errcode = getaddrinfo(server_ip, server_port, &hints, &addr_info); + if (errcode != 0) { + std::cerr << "[Error] getaddrinfo:" << gai_strerror(errcode) << std::endl; + return 1; + } +// std::cout << "errcode:" << errcode << ", " << + + ai_family = addr_info->ai_family; + ai_socktype = addr_info->ai_socktype; + ai_protocol = addr_info->ai_protocol; + errno = 0; + std::cout << "socket" << std::endl; + socket_fd = socket(ai_family, ai_socktype, ai_protocol); + if (socket_fd == -1) { + std::cerr << "[Error] socket:" << strerror(errno) << std::endl; + return 1; + } + + std::cout << "bind" << std::endl; + errno = 0; + if (bind(socket_fd, addr_info->ai_addr, addr_info->ai_addrlen) == -1) { + std::cerr << "[Error] bind:" << strerror(errno) << std::endl; + return 1; + } + + std::cout << "listen" << std::endl; + if (listen(socket_fd, SOMAXCONN) == -1) { + std::cerr << "[Error] listen:" << strerror(errno) << std::endl; + return 1; + } + + std::cout << "OK" << std::endl; + return 0; +} + +// port 0, 0はエラーにならない +int main() { + int ret1 = test_socket("255.255.255.254", "8080"); + int ret2 = test_socket("255.255.255.254", "8080"); + + std::cout << "ret1:" << ret1 << std::endl; + std::cout << "ret2:" << ret2 << std::endl; +} diff --git a/srcs/Socket/Socket.cpp b/srcs/Socket/Socket.cpp new file mode 100644 index 00000000..b0458302 --- /dev/null +++ b/srcs/Socket/Socket.cpp @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include +#include +#include +#include "webserv.hpp" +#include "Socket.hpp" + +Socket::Socket() : _status(ERROR), + _socket_fd(ERROR), + _addr_info(NULL), + _server_ip(SERVER_IP), + _server_port(SERVER_PORT) { + if (create_socket() == ERROR) { + return; + } + if (bind_socket() == ERROR) { + return; + } + if (listen_socket() == ERROR) { + return; + } + if (set_fd_to_nonblock() == ERROR) { + return; + } + this->_status = OK; +} + +Socket::Socket(const char *server_ip, const char *server_port) : _status(ERROR), + _socket_fd(ERROR), + _addr_info(NULL), + _server_ip(server_ip), + _server_port(server_port) { + if (create_socket() == ERROR) { + return; + } + if (bind_socket() == ERROR) { + return; + } + if (listen_socket() == ERROR) { + return; + } + if (set_fd_to_nonblock() == ERROR) { + return; + } + this->_status = OK; +} + +// Socket::Socket(const Socket ©) { +// *this = copy; +// } +// +// Socket &Socket::operator=(const Socket &rhs) { +// if (this != &rhs) { +// _status = rhs._status; +// _socket_fd = rhs._socket_fd; +// _server_ip = rhs._server_ip; +// _server_port = rhs._server_port; +// // _addr_info = rhs._addr_info; +// set_addr_info(this->_server_ip, this->_server_port, &this->_addr_info); +// } +// return *this; +// } + +Socket::~Socket() { + if (this->_addr_info != NULL) { + freeaddrinfo(this->_addr_info); + this->_addr_info = NULL; + } + if (this->_socket_fd != ERROR) { + close_socket_fd(this->_socket_fd); + this->_socket_fd = ERROR; + } + // std::cout << "destructor" << std::endl; +} + +int Socket::create_socket() { + int errcode; + int ai_family, ai_socktype, ai_protocol; + + errcode = set_addr_info(this->_server_ip, this->_server_port, &this->_addr_info); + if (errcode != OK) { + std::cerr << gai_strerror(errcode) << std::endl; + return ERROR; + } + + ai_family = this->_addr_info->ai_family; + ai_socktype = this->_addr_info->ai_socktype; + ai_protocol = this->_addr_info->ai_protocol; + errno = 0; + this->_socket_fd = socket(ai_family, ai_socktype, ai_protocol); + if (this->_socket_fd == ERROR) { + std::cerr << strerror(errno) << std::endl; + return ERROR; + } + return OK; +} + +/* + listen 192.168.1.2:80; + listen 80; + */ +int Socket::set_addr_info(const char *ip, const char *port, struct addrinfo **result) { + struct addrinfo hints = {}; + int errcode; + + set_addr_hints(&hints); + errcode = getaddrinfo(ip, port, &hints, result); + return errcode; +} + +void Socket::set_addr_hints(struct addrinfo *hints) { + hints->ai_socktype = SOCK_STREAM; + hints->ai_family = AF_UNSPEC; // allows IPv4 and IPv6 + hints->ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV; // socket, IP, PORT + hints->ai_protocol = IPPROTO_TCP; +} + +int Socket::bind_socket() const { + const struct sockaddr *ai_addr; + socklen_t ai_addrlen; + + if (set_socket_opt(this->_socket_fd) == ERROR) { + return ERROR; + } + ai_addr = this->_addr_info->ai_addr; + ai_addrlen = this->_addr_info->ai_addrlen; + errno = 0; + if (bind(this->_socket_fd, ai_addr, ai_addrlen) == ERROR) { + std::cerr << strerror(errno) << std::endl; + return ERROR; + } + return OK; +} + +int Socket::set_socket_opt(int socket_fd) { + int opt_val = 1; + socklen_t opt_len = sizeof(opt_val); + + errno = 0; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt_val, opt_len) == ERROR) { + std::cout << strerror(errno) << std::endl; + return ERROR; + } + return OK; +} + +int Socket::listen_socket() const { + errno = 0; + if (listen(this->_socket_fd, SOMAXCONN) == ERROR) { + std::cerr << strerror(errno) << std::endl; + return ERROR; + } + return OK; +} + +int Socket::set_fd_to_nonblock() const { + errno = 0; + if (fcntl(this->_socket_fd, F_SETFL, O_NONBLOCK | FD_CLOEXEC) == ERROR) { + std::cerr << strerror(errno) << std::endl; + return ERROR; + } + return OK; +} + +void Socket::close_socket_fd(int socket_fd) { + errno = 0; + if (close(socket_fd) == ERROR) { + std::cerr << strerror(errno) << std::endl; + } +} + +int Socket::get_socket_fd() const { return this->_socket_fd; } +int Socket::get_status() const { return this->_status; } +// std::string Socket::get_server_port() const { return this->_server_port; } +// std::string Socket::get_server_ip() const { return this->_server_ip; } diff --git a/srcs/Socket/Socket.hpp b/srcs/Socket/Socket.hpp new file mode 100644 index 00000000..eb4c1527 --- /dev/null +++ b/srcs/Socket/Socket.hpp @@ -0,0 +1,37 @@ +#pragma once + +# define SERVER_IP "127.0.0.1" +# define SERVER_PORT "8080" + +// todo: config -> port, protocol +// todo: signal +class Socket { + public: + Socket(); + Socket(const char *server_ip, const char *server_port); + ~Socket(); + // Socket(const Socket ©); // for debug + // Socket &operator=(const Socket &rhs); // for debug + + int get_socket_fd() const; + int get_status() const; + // std::string get_server_ip() const; // for debug + // std::string get_server_port() const; // for debug + + private: + int _status; + int _socket_fd; + struct addrinfo *_addr_info; + const char *_server_ip; // Nullable + const char *_server_port; + + int create_socket(); + int bind_socket() const; + int listen_socket() const; + int set_fd_to_nonblock() const; + + static int set_addr_info(const char *ip, const char *port, struct addrinfo **result); + static void set_addr_hints(struct addrinfo *hints); + static int set_socket_opt(int socket_fd); + static void close_socket_fd(int socket_fd); +}; diff --git a/srcs/get_valid_config_file_path.cpp b/srcs/get_valid_config_file_path.cpp index 9a9e249c..12dfdd78 100644 --- a/srcs/get_valid_config_file_path.cpp +++ b/srcs/get_valid_config_file_path.cpp @@ -61,13 +61,7 @@ bool is_valid_config_file_path(const char *path) { return true; } -// if config file is not given, path is 'default' todo: empty string ? -std::string get_valid_config_file_path(int argc, char **argv) { - const char *path = argv[CONFIG_FILE_INDEX]; - - if (argc == EXECUTABLE_FILE_ONLY_ARGC) { - return std::string(DEFAULT_CONFIG); - } +std::string get_valid_config_file_path(const char *path) { if (!is_valid_config_file_path(path)) { throw std::invalid_argument(INVALID_PATH_ERROR_MSG); } diff --git a/srcs/main.cpp b/srcs/main.cpp index 0ab280c9..cf9e174b 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -3,9 +3,6 @@ #include "webserv.hpp" static void validate_argc(int argc) { - if (argc == EXECUTABLE_FILE_ONLY_ARGC) { - return; - } if (argc == CONFIG_FILE_GIVEN_ARGC) { return; } @@ -19,7 +16,7 @@ int main(int argc, char **argv) { try { validate_argc(argc); - config_file_path = get_valid_config_file_path(argc, argv); + config_file_path = get_valid_config_file_path(argv[CONFIG_FILE_INDEX]); std::cout << "config_file_path=[" << config_file_path << "]" << std::endl; // if path is 'default', config set to default diff --git a/test/unit_test/TestSocket.cpp b/test/unit_test/TestSocket.cpp new file mode 100644 index 00000000..75992957 --- /dev/null +++ b/test/unit_test/TestSocket.cpp @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "webserv.hpp" +#include "Socket.hpp" +#include "Color.hpp" + +static struct sockaddr_in create_addr(); +static int create_nonblock_client_fd(); + +/* *********************** */ +/* Socket Unit Test */ +/* *********************** */ +TEST(SocketUnitTest, DefaultConstructor) { + Socket socket = Socket(); + + EXPECT_EQ(OK, socket.get_status()); +} + +TEST(SocketUnitTest, ConstructorWithArgument) { + Socket socket = Socket(SERVER_IP, SERVER_PORT); + + EXPECT_EQ(OK, socket.get_status()); + +} + +// TEST(SocketUnitTest, CopyConstructor) { +// Socket socket_src = Socket(SERVER_IP, SERVER_PORT); +// Socket socket_new = Socket(socket_src); +// +// EXPECT_EQ(socket_src.get_status(), socket_new.get_status()); +// EXPECT_EQ(socket_src.get_socket_fd(), socket_new.get_socket_fd()); +// EXPECT_EQ(socket_src.get_server_port(), socket_new.get_server_port()); +// EXPECT_EQ(socket_src.get_server_ip(), socket_new.get_server_ip()); +// } +// +// TEST(SocketUnitTest, CopyAssignmentConstructor) { +// Socket socket_src = Socket(SERVER_IP, SERVER_PORT); +// Socket socket_new = socket_src; +// +// EXPECT_EQ(socket_src.get_status(), socket_new.get_status()); +// EXPECT_EQ(socket_src.get_socket_fd(), socket_new.get_socket_fd()); +// EXPECT_EQ(socket_src.get_server_port(), socket_new.get_server_port()); +// EXPECT_EQ(socket_src.get_server_ip(), socket_new.get_server_ip()); +// } + +TEST(SocketUnitTest, ConstructorWithValidServerIP) { + int port = 49152; + Socket socket1 = Socket("127.0.0.1", std::to_string(port++).c_str()); + Socket socket2 = Socket("0.0.0.0", std::to_string(port++).c_str()); + Socket socket3 = Socket("000.0000.00000.000000", std::to_string(port++).c_str()); + + EXPECT_EQ(OK, socket1.get_status()); + EXPECT_EQ(OK, socket2.get_status()); + EXPECT_EQ(OK, socket3.get_status()); + +} + +TEST(SocketUnitTest, ConstructorWithInvalidServerIP) { + int port = 49152; + Socket socket1 = Socket("127.0.0.0.1", std::to_string(port++).c_str()); + Socket socket2 = Socket("256.0.0.0", std::to_string(port++).c_str()); + Socket socket3 = Socket("-1", std::to_string(port++).c_str()); + Socket socket4 = Socket("a.0.0.0", std::to_string(port++).c_str()); + Socket socket5 = Socket("127:0.0.1", std::to_string(port++).c_str()); + Socket socket6 = Socket("127,0.0.1", std::to_string(port++).c_str()); + Socket socket7 = Socket("127.0.0.-1", std::to_string(port++).c_str()); + Socket socket8 = Socket("2147483647.2147483647.2147483647.2147483647", std::to_string(port++).c_str()); + // Socket socket9 = Socket("", std::to_string(port++).c_str()); todo: ok? + Socket socket10 = Socket("hoge", std::to_string(port++).c_str()); + Socket socket11 = Socket("0001.0001.0001.0001", std::to_string(port++).c_str()); + Socket socket12 = Socket("255.255.255.254", std::to_string(port++).c_str()); + // Socket socket13 = Socket("255.255.255.255", std::to_string(port++).c_str()); // Linux OK, todo:error? + + EXPECT_EQ(ERROR, socket1.get_status()); + EXPECT_EQ(ERROR, socket2.get_status()); + EXPECT_EQ(ERROR, socket3.get_status()); + EXPECT_EQ(ERROR, socket4.get_status()); + EXPECT_EQ(ERROR, socket5.get_status()); + EXPECT_EQ(ERROR, socket6.get_status()); + EXPECT_EQ(ERROR, socket7.get_status()); + EXPECT_EQ(ERROR, socket8.get_status()); + // EXPECT_EQ(ERROR, socket9.get_status()); + EXPECT_EQ(ERROR, socket10.get_status()); + EXPECT_EQ(ERROR, socket11.get_status()); + EXPECT_EQ(ERROR, socket12.get_status()); + // EXPECT_EQ(ERROR, socket13.get_status()); +} + +TEST(SocketUnitTest, ConstructorWithValidServerPort) { + Socket socket1 = Socket(SERVER_IP, "0"); // ephemeral port + Socket socket2 = Socket(SERVER_IP, "0000"); + Socket socket3 = Socket(SERVER_IP, "8080"); + Socket socket4 = Socket(SERVER_IP, "65535"); + + EXPECT_EQ(OK, socket1.get_status()); + EXPECT_EQ(OK, socket2.get_status()); + EXPECT_EQ(OK, socket3.get_status()); + EXPECT_EQ(OK, socket4.get_status()); +} + +TEST(SocketUnitTest, ConstructorWithInvalidServerPort) { + Socket socket1 = Socket(SERVER_IP, "-1"); +// Socket socket2 = Socket(SERVER_IP, "65536"); // uisingned short 65536->0(ephemeral port) + // Socket socket3 = Socket(SERVER_IP, ""); // strtol->0 (tmp) + Socket socket4 = Socket(SERVER_IP, "hoge"); + Socket socket5 = Socket(SERVER_IP, "--123123"); + Socket socket6 = Socket(SERVER_IP, "127.1"); + + EXPECT_EQ(ERROR, socket1.get_status()); +// EXPECT_EQ(ERROR, socket2.get_status()); + // EXPECT_EQ(ERROR, socket3.get_status()); + EXPECT_EQ(ERROR, socket4.get_status()); + EXPECT_EQ(ERROR, socket5.get_status()); + EXPECT_EQ(ERROR, socket6.get_status()); +} + +TEST(SocketUnitTest, Getter) { + Socket socket = Socket(); + + EXPECT_EQ(OK, socket.get_status()); + EXPECT_NE(ERROR, socket.get_socket_fd()); +} + +// TEST(SocketUnitTest, ExceedMaxFd) { +// int limit = 20; +// +// struct rlimit old_limits; +// if (getrlimit(RLIMIT_NOFILE, &old_limits) != 0) { +// std::cerr << "getrlimit failed\n"; +// return; +// } +// printf("old_limit.cur:%llu,\n", old_limits.rlim_cur); +// +// struct rlimit new_limits; +// new_limits.rlim_cur = limit; +// new_limits.rlim_max = old_limits.rlim_max; +// +// printf("new_limit.cur:%llu\n", new_limits.rlim_cur); +// +// if (setrlimit(RLIMIT_NOFILE, &new_limits) != 0) { +// std::cerr << "setrlimit failed\n"; +// return; +// } +// +// int min_fd = 3; +// std::vector sockets; +// for (int i = 0; i < limit + 10; ++i) { +// // Socket socket = Socket(SERVER_IP, std::to_string(49152 + i).c_str()); +// // sockets.push_back(socket); +// // sockets[i] = Socket(SERVER_IP, std::to_string(49152 + i).c_str()); +// sockets.push_back(Socket(SERVER_IP, std::to_string(49152 + i).c_str())); +// printf("%si:%d, fd:%d, status:%d%s\n", YELLOW, i, sockets[i].get_socket_fd(), sockets[i].get_status(), RESET); +// +// if (i + min_fd <= limit) { +// EXPECT_EQ(OK, sockets[i].get_status()); +// EXPECT_NE(ERROR, sockets[i].get_socket_fd()); +// } else { +// EXPECT_EQ(ERROR, sockets[i].get_status()); +// EXPECT_EQ(ERROR, sockets[i].get_socket_fd()); +// } +// } +// +// if (setrlimit(RLIMIT_NOFILE, &old_limits) != 0) { +// std::cerr << "Restoring setrlimit failed\n"; +// return; +// } +// +// printf("old_limit.cur:%llu\n", old_limits.rlim_cur); +// } + +/* *********************** */ +/* Socket Integration Test */ +/* *********************** */ +TEST(SocketIntegrationTest, ConnectToClient) { + Socket server; + + EXPECT_EQ(server.get_status(), OK); + EXPECT_NE(server.get_socket_fd(), ERROR); + + int client_fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(std::strtol(SERVER_PORT, NULL, 10)); + addr.sin_addr.s_addr = inet_addr(SERVER_IP); + + EXPECT_EQ(connect(client_fd, (struct sockaddr *)&addr, sizeof(addr)), OK); + + close(client_fd); +} + +TEST(SocketIntegrationTest, ConnectTooManyClient) { + Socket server; + int client_fd; + + EXPECT_EQ(OK, server.get_status()); + EXPECT_NE(ERROR, server.get_socket_fd()); + + // connect under SOMAXCONN + std::vector client_fds; + for (int i = 0; i < SOMAXCONN; ++i) { + client_fd = socket(AF_INET, SOCK_STREAM, 0); + // printf("cnt:%d, client_fd:%d\n", i+1, client_fd); + + EXPECT_NE(ERROR, client_fd); + + if (client_fd != ERROR) { + client_fds.push_back(client_fd); + struct sockaddr_in addr = create_addr(); + + EXPECT_EQ(OK, connect(client_fd, (struct sockaddr *)&addr, sizeof(addr))); + } + } + + // connect over SOMAXCONN -> fd set to nonblock + client_fd = create_nonblock_client_fd(); + // printf("cnt:%d, client_fd:%d\n", SOMAXCONN, client_fd); + + EXPECT_NE(ERROR, client_fd); + + if (client_fd != ERROR) { + client_fds.push_back(client_fd); + struct sockaddr_in addr = create_addr(); + + EXPECT_EQ(ERROR, connect(client_fd, (struct sockaddr *)&addr, sizeof(addr))); + } + + // destruct + for (std::vector::iterator itr = client_fds.begin(); itr != client_fds.end(); ++itr) { + close(*itr); + } + client_fds.clear(); +} + +/* helper funcs */ +static struct sockaddr_in create_addr() { + struct sockaddr_in addr = {}; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(SERVER_IP); + addr.sin_port = htons(std::strtol(SERVER_PORT, NULL, 10)); + return addr; +} + +static int create_nonblock_client_fd() { + int client_fd; + int result_fcntl; + + client_fd = socket(AF_INET, SOCK_STREAM, 0); + if (client_fd == ERROR) { + return ERROR; + } + result_fcntl = fcntl(client_fd, F_SETFL, O_NONBLOCK); + if (result_fcntl == ERROR) { + close(client_fd); + return ERROR; + } + return client_fd; +} diff --git a/test/unit_test/is_valid_file_path/.gitignore b/test/unit_test/is_valid_file_path/.gitignore index 702061f4..c33dd865 100644 --- a/test/unit_test/is_valid_file_path/.gitignore +++ b/test/unit_test/is_valid_file_path/.gitignore @@ -9,4 +9,13 @@ !*.hpp !*.sh -!Makefile \ No newline at end of file +!Makefile +/files/dir/file_--- +/files/dir/file_---.conf +/files/dir/file_--r +/files/dir/file_--r.conf +/files/dir/file_-r-.conf +/files/dir/file_-rr.conf +/files/dir/file_r-- +/files/dir/file_r-r +/files/no_x_dir \ No newline at end of file diff --git a/test/unit_test/is_valid_file_path/test_get_valid_config_file_path.cpp b/test/unit_test/is_valid_file_path/test_get_valid_config_file_path.cpp new file mode 100644 index 00000000..36b7bd14 --- /dev/null +++ b/test/unit_test/is_valid_file_path/test_get_valid_config_file_path.cpp @@ -0,0 +1,87 @@ +#include "gtest/gtest.h" +#include "webserv.hpp" + +// TEST(Test, Test) { +// EXPECT_EQ("OK", "OK"); +// EXPECT_EQ("NG", "OK"); +// EXPECT_EQ(1, func(1)); +// EXPECT_EQ(2, func(2)); +// EXPECT_EQ(3, func(3)); +// } + +TEST(TestGetValidConfigFilePath, SimpleTest) { + EXPECT_EQ("test/unit_test/is_valid_file_path/files/file.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/file.conf")); + // EXPECT_EQ("test/unit_test/is_valid_file_path/files/file.CONF", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/file.CONF")); // not supported in Linux...? + // EXPECT_EQ("test/unit_test/is_valid_file_path/files/file.Conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/file.Conf")); // not supported in Linux...? + // EXPECT_EQ("test/unit_test/is_valid_file_path/files/file.conF", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/file.conF")); // not supported in Linux...? + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/file")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/nothing.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/nothing")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/conf")); + + EXPECT_EQ("test/unit_test/is_valid_file_path/files/a.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/a.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/ a.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/a.conf ")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/ a.conf ")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/X.conf")); + + EXPECT_EQ("test/unit_test/is_valid_file_path/files/a.b.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/a.b.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/a.conf.b")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/conf.a")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/conf.a.")); + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)".")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"..")); + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir.conf")); +} + +TEST(TestGetValidConfigFilePath, TestDirPermissionRWX) { + EXPECT_EQ("test/unit_test/is_valid_file_path/files/dir/file_rrr.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_rrr.conf")); + EXPECT_EQ("test/unit_test/is_valid_file_path/files/dir/file_rr-.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_rr-.conf")); + EXPECT_EQ("test/unit_test/is_valid_file_path/files/dir/file_r-r.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_r-r.conf")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_-rr")); // git add permission denied + EXPECT_EQ("test/unit_test/is_valid_file_path/files/dir/file_r--.conf", get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_r--.conf")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_-r-")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_--r")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_---")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/this_is_dir.conf")); + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_rrr")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_rrr")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_rr-")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_-rr")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_r-r")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_-r-")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_--r")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_---")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/file_r--")); + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/dir/this_is_dir")); + +} + +TEST(TestGetValidConfigFilePath, TestDirPermissionRW) { + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_rrr.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_rr-.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_r-r.conf")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_-rr.conf")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_r--.conf")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_-r-.conf")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_--r.conf")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_---.conf")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/thid_is_dir.conf")); + + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_rrr")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_rr-")); + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_r-r")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_-rr")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_r--")); + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_-r-")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_--r")); // git add permission denied + // EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/file_---")); // git add permission denied + EXPECT_ANY_THROW(get_valid_config_file_path((char *)"test/unit_test/is_valid_file_path/files/no_x_dir/thid_is_dir")); +}