diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 10a08a1..25c9a91 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -36,6 +36,9 @@ jobs: - name: Build run: | cmake --build build + - name: Test + run: | + ctest --verbose --output-on-failure --test-dir ${{ github.workspace }}/build/test windows-build-cmake: name: Windows @@ -55,3 +58,6 @@ jobs: - name: Build run: | cmake --build build + - name: Test + run: | + ctest --verbose --output-on-failure --test-dir ${{ github.workspace }}/build/test diff --git a/CMakeLists.txt b/CMakeLists.txt index b6c06cc..c5e9790 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,10 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") project(libtestrig LANGUAGES C) +include(CTest) include(target_copy_dll) include(target_output_to_bin) +include(target_compile_warn_all) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib") @@ -29,13 +31,6 @@ set(EPOS_SOURCES set(LIBTESTRIG_SOURCES ${IPC_SOURCES} ${EPOS_SOURCES}) -if (MSVC) - add_compile_options("/W4") -else() - add_compile_options("-Wall") -endif() - - if (WIN32) add_library(EposCmd SHARED IMPORTED) set_target_properties(EposCmd PROPERTIES @@ -52,10 +47,17 @@ else() set(EposCmd-FOUND TRUE) endif() +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + message("-- Creating coverage reports in Debug mode.") + add_compile_options(-coverage) + add_link_options(-coverage) +endif() + add_library(libtestrig SHARED ${LIBTESTRIG_SOURCES}) target_compile_definitions(libtestrig PRIVATE COMPILING_TESTRIG_DLL) target_include_directories(libtestrig PUBLIC ${LIB_DIR}) target_link_libraries(libtestrig PUBLIC EposCmd) +target_compile_warn_all(libtestrig) target_output_to_bin(libtestrig) if (WIN32) @@ -63,3 +65,4 @@ if (WIN32) endif() add_subdirectory("${CMAKE_SOURCE_DIR}/src") +add_subdirectory("${CMAKE_SOURCE_DIR}/test") diff --git a/CMakePresets.json b/CMakePresets.json index f8acb73..91b68b2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -15,6 +15,7 @@ "CMAKE_COLOR_DIAGNOSTICS": "ON" } }, + { "name": "windows-only", "hidden": true, diff --git a/cmake/target_compile_warn_all.cmake b/cmake/target_compile_warn_all.cmake new file mode 100644 index 0000000..99a7d4c --- /dev/null +++ b/cmake/target_compile_warn_all.cmake @@ -0,0 +1,7 @@ +function(target_compile_warn_all IN_TARGET_NAME) + if (MSVC) + target_compile_options(${IN_TARGET_NAME} PRIVATE "/W4") + else() + target_compile_options(${IN_TARGET_NAME} PRIVATE "-Wall") + endif() +endfunction(target_compile_warn_all IN_TARGET_NAME) \ No newline at end of file diff --git a/lib/epos2/connect.c b/lib/epos2/connect.c index 9859e62..d91103b 100644 --- a/lib/epos2/connect.c +++ b/lib/epos2/connect.c @@ -7,7 +7,7 @@ #include "identify.h" static void vscl_failed_open_device(uint32_t error_code) { - vscl_print_error(error_code); + vscl_rig_perror(error_code); printf("Failed to open device with with following characteristics:\n"); } @@ -53,7 +53,7 @@ uint32_t vscl_initialize_devices(struct controller controllers_out[], void* hand error_code = vscl_clean_enable_device(&controllers_out[0], handles_out[0]); if (error_code != 0) { printf("While attempting to open gateway:\n\t"); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } @@ -77,7 +77,7 @@ uint32_t vscl_initialize_devices(struct controller controllers_out[], void* hand error_code = vscl_clean_enable_device(&controllers_out[i], handles_out[i]); if (error_code != 0) { printf("While attempting to open gateway:\n\t"); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } } @@ -100,7 +100,7 @@ uint32_t vscl_clean_enable_device(struct controller* controller, void* device_ha ret = VCS_ClearFault(device_handle, controller->node_id, &error_code); if (ret == 0) { printf("While clearing fault from %s at %s:\n\t", controller->name, controller->port); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } @@ -125,7 +125,7 @@ uint32_t vscl_close_device(struct controller* controller, void* device_handle) { if (ret == 0) { printf("While attempting to close device %s at node %ihh\n\t", controller->name, controller->node_id); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } @@ -156,7 +156,7 @@ uint32_t vscl_close_devices(struct controller controllers[], void* device_handle if (ret == 0) { printf("While closing subdevice %s at node %ihh:\n\t", controllers[i].name, controllers[i].node_id); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } @@ -169,7 +169,7 @@ uint32_t vscl_close_devices(struct controller controllers[], void* device_handle if (ret == 0) { printf("While closing gateway device %s at node %ihh:\n\t", controllers[0].name, controllers[0].node_id); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } diff --git a/lib/epos2/epos2.c b/lib/epos2/epos2.c index e16b80e..f286311 100644 --- a/lib/epos2/epos2.c +++ b/lib/epos2/epos2.c @@ -11,7 +11,7 @@ int vscl_decode_error(const uint32_t error_code, char* error_msg, vscl_byte_t ma return ret; } -int vscl_print_error(const uint32_t error_code) { +int vscl_rig_perror(const uint32_t error_code) { char msg[64] = { 0 }; int ret = vscl_decode_error(error_code, msg, 64); printf("ERROR 0x%X: %s\n", error_code, msg); @@ -24,7 +24,7 @@ uint32_t vscl_reset_device(void *device_handle, struct controller* controller_in uint32_t error_code = 0; int ret = VCS_ResetDevice(device_handle, controller_in->node_id, &error_code); if (ret == 0) { - vscl_print_error(error_code); + vscl_rig_perror(error_code); printf("Device failed to be reset: %s\n", controller_in->name); } @@ -47,7 +47,7 @@ uint32_t vscl_setup_can_gateway(struct controller controllers[3], void* handles[ error_code = vscl_initialize_devices(controllers, handles, 3); if (error_code != 0) { printf("When initializing multiple devices: "); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } @@ -60,7 +60,7 @@ uint32_t vscl_cleanup_testrig(struct controller controllers[3], void* handles[3] error_code = vscl_close_devices(controllers, handles, 3); if (error_code != 0) { printf("When cleaning up multiple devices: "); - vscl_print_error(error_code); + vscl_rig_perror(error_code); return error_code; } diff --git a/lib/epos2/epos2.h b/lib/epos2/epos2.h index 633d3cd..af56701 100644 --- a/lib/epos2/epos2.h +++ b/lib/epos2/epos2.h @@ -22,7 +22,7 @@ int TESTRIG_API vscl_decode_error(const uint32_t error_code, char* error_msg, vs /* * @brief Decode and print an error code's corresponding message. */ -int TESTRIG_API vscl_print_error(const uint32_t error_code); +int TESTRIG_API vscl_rig_perror(const uint32_t error_code); /* * @brief Reset a device. diff --git a/lib/epos2/identify.c b/lib/epos2/identify.c index fc6e54c..8b0935a 100644 --- a/lib/epos2/identify.c +++ b/lib/epos2/identify.c @@ -7,23 +7,23 @@ static void vscl_print_naming_error(vscl_byte_t error_code) { printf("While identifying device names:\n\t"); - vscl_print_error(error_code); + vscl_rig_perror(error_code); } static void vscl_print_protocol_ident_error(vscl_byte_t error_code, const char* name) { printf("While identifying device protocol stacks for device %s:\n\t", name); - vscl_print_error(error_code); + vscl_rig_perror(error_code); } static void vscl_print_interface_ident_error(vscl_byte_t error_code, const char* name, const char* protocol) { printf("While identifying device interface for device %s on protocol %s:\n\t", name, protocol); - vscl_print_error(error_code); + vscl_rig_perror(error_code); } static void vscl_print_port_ident_error(vscl_byte_t error_code, const char* name, const char* protocol, const char* iface) { printf("While identifying device interface for device %s on protocol %s and interface %s:\n\t", name, protocol, iface); - vscl_print_error(error_code); + vscl_rig_perror(error_code); } uint32_t vscl_ident_names(void) { diff --git a/lib/epos2/manage.c b/lib/epos2/manage.c index b86d5af..510f399 100644 --- a/lib/epos2/manage.c +++ b/lib/epos2/manage.c @@ -16,7 +16,7 @@ uint32_t vscl_abort(const struct controller* controller_in, void* device_handle) int ret = VCS_SetQuickStopState(device_handle, controller_in->node_id, &error_code); if (ret == 0) { - vscl_print_error(error_code); + vscl_rig_perror(error_code); printf("DANGER: Failed to abort rig operations!\n"); } else { diff --git a/lib/ipc/os.c b/lib/ipc/os.c index f25e9f9..1d39440 100644 --- a/lib/ipc/os.c +++ b/lib/ipc/os.c @@ -22,7 +22,7 @@ int vscl_get_sock_destination(char *dest) { errno_t retstat; retstat = getenv_s(&retvalue, usrtemp, 76, "TEMP"); - if (retvalue == 0 || retstat != 0) { perror("Failed to get TEMP"); return retstat; } + if (retvalue == 0 || retstat != 0) { vscl_os_perror("Failed to get TEMP"); return retstat; } strncpy(dest, usrtemp, retvalue); strncat(dest, "\\", 2); @@ -36,8 +36,8 @@ int vscl_get_sock_destination(char *dest) { int vscl_make_new_proc(const char* prog, const char* args) { #if _WIN32 - PROCESS_INFORMATION pi; - STARTUPINFO si; + PROCESS_INFORMATION pi = { 0 }; + STARTUPINFO si = { 0 }; char cmd[1024] = { 0 }; sprintf(cmd, "%s %s", prog, args); @@ -55,7 +55,7 @@ int vscl_make_new_proc(const char* prog, const char* args) { &pi ); - if (mkdetach == FALSE) { vscl_winprint_error("failed to detach"); return -1; } + if (mkdetach == FALSE) { vscl_os_perror("failed to detach"); return -1; } CloseHandle(&si); CloseHandle(&pi); @@ -67,12 +67,12 @@ int vscl_make_new_proc(const char* prog, const char* args) { switch (pid) { case -1: - perror("failed to fork off"); + vscl_os_perror("failed to fork off"); return -1; break; case 0: if (setsid() == -1) { - perror("failed to detach"); + vscl_os_perror("failed to detach"); return -1; } else { @@ -84,7 +84,7 @@ int vscl_make_new_proc(const char* prog, const char* args) { strncpy(argv[0], prog, strlen(prog) + 1); argv[1] = (char*)calloc(64, 1); - char* arg1 = strstr(args, " "); + const char* arg1 = strstr(args, " "); if (arg1 == NULL) { strncpy(argv[1], args, strlen(args) + 1); } @@ -95,8 +95,8 @@ int vscl_make_new_proc(const char* prog, const char* args) { strncpy(interstr, args, interlen); strncpy(argv[1], interstr, strlen(interstr) + 1); - char* argn = strstr(arg1, " "); - char* argn1 = arg1; + char* argn = (char*)strstr(arg1, " "); + char* argn1 = (char*)arg1; while (argn != NULL) { num_args++; if (num_args > sizeof_argv) { @@ -110,7 +110,7 @@ int vscl_make_new_proc(const char* prog, const char* args) { size_t argnlen = vscl_strinterlen(argn, argn1); argnlen = (argnlen == 0) ? 64 : argnlen; - strncpy(argnstr, argn1, argnlen); + strncpy(argnstr, argn1 + 1, argnlen); strncpy(argv[n], argnstr, strlen(argnstr) + 1); argn1 = argn; @@ -135,8 +135,16 @@ int vscl_make_new_proc(const char* prog, const char* args) { #endif } +void vscl_sleep(uint32_t s) { +#ifdef _WIN32 + Sleep(s * 1000); +#else + sleep(s); +#endif +} + +void vscl_os_perror(const char* preamble) { #ifdef _WIN32 -void vscl_winprint_error(const TCHAR* msg) { DWORD errcode = GetLastError(); TCHAR errmsg[256] = { 0 }; @@ -151,6 +159,8 @@ void vscl_winprint_error(const TCHAR* msg) { if (wides == 0) { printf("error while processing error\n"); } - wprintf(L"%s: %s", msg, errmsg); -} + printf("%s: %s", preamble, errmsg); +#else + perror(preamble); #endif +} diff --git a/lib/ipc/os.h b/lib/ipc/os.h index 555192b..67f8477 100644 --- a/lib/ipc/os.h +++ b/lib/ipc/os.h @@ -9,17 +9,17 @@ extern "C" { #endif #include "libtestrig_api.h" +#include -#ifndef _WIN32 +#ifdef _WIN32 +#else #define INVALID_SOCKET -1 #endif TESTRIG_API int vscl_get_sock_destination(char* dest); TESTRIG_API int vscl_make_new_proc(const char* prog, const char* args); - -#ifdef _WIN32 -TESTRIG_API void vscl_winprint_error(const TCHAR* msg); -#endif +TESTRIG_API void vscl_sleep(uint32_t s); +TESTRIG_API void vscl_os_perror(const char* msg); #ifdef __cplusplus } // extern "C" diff --git a/lib/ipc/pipe.c b/lib/ipc/pipe.c index fecd5f3..193c8da 100644 --- a/lib/ipc/pipe.c +++ b/lib/ipc/pipe.c @@ -13,14 +13,14 @@ vscl_pipe_t vscl_create_pipes() { sattrs.lpSecurityDescriptor = NULL; if (!CreatePipe(&piper.child_read, &piper.child_write, &sattrs, 0)) - vscl_winprint_error("While creating child read pipe"); + vscl_os_perror("While creating child read pipe"); if (!SetHandleInformation(piper.child_read, HANDLE_FLAG_INHERIT, 0)) - vscl_winprint_error("While preventing child from taking parent pipe attributes"); + vscl_os_perror("While preventing child from taking parent pipe attributes"); #else int pipestat = pipe(piper.linux_fds); - if (pipestat == -1) { perror("While creating pipes"); } + if (pipestat == -1) { vscl_os_perror("While creating pipes"); } #endif diff --git a/lib/ipc/sock.c b/lib/ipc/sock.c index f776489..be8a658 100644 --- a/lib/ipc/sock.c +++ b/lib/ipc/sock.c @@ -6,11 +6,6 @@ #include "sock.h" #include "os.h" -#ifdef _WIN32 -// TODO: Evaluate if this is sufficient (it is honestly kind of smelly) -typedef int socklen_t; -#endif - int vscl_sock_genpath(char* sockpath) { int retstat; int baselen; @@ -42,11 +37,11 @@ int vscl_sock_setup(struct sockaddr_un* sockaddr_mut) { int wsa_result; wsa_result = WSAStartup(MAKEWORD(2, 2), &wsa_data); - if (wsa_result != 0) { perror("failed WSAStartup"); return -1; } + if (wsa_result != 0) { vscl_os_perror("failed WSAStartup"); return -1; } #endif // _WIN32 fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == INVALID_SOCKET) { perror("failed to create socket"); return -1; } + if (fd == INVALID_SOCKET) { vscl_os_perror("failed to create socket"); return -1; } path_set = (strncmp( sockaddr_mut->sun_path, blank, @@ -68,7 +63,7 @@ int vscl_sock_bind(const int fd, const struct sockaddr_un* sockaddr) { socklen = sizeof(*sockaddr); bindstat = bind(fd, (struct sockaddr*)sockaddr, socklen); - if (bindstat == -1) { perror("failed to bind socket"); } + if (bindstat == -1) { vscl_os_perror("failed to bind socket"); } return bindstat; } @@ -77,7 +72,7 @@ int vscl_sock_listen(const int fd, int max_backlog) { int listenstat; listenstat = listen(fd, max_backlog); - if (listenstat == -1) { perror("failed to set socket to listen"); } + if (listenstat == -1) { vscl_os_perror("failed to set socket to listen"); } return listenstat; } @@ -88,7 +83,7 @@ int vscl_sock_connect(const int fd, const struct sockaddr_un* sockaddr) { socklen = sizeof(*sockaddr); connstat = connect(fd, (struct sockaddr*)sockaddr, socklen); - if (connstat == -1) { perror("failed to connect to socket"); } + if (connstat == -1) { vscl_os_perror("failed to connect to socket"); } return connstat; } @@ -123,7 +118,7 @@ int vscl_sock_send(const int fd, struct rig_message* msg) { #else nbytes = write(fd, buf, 12); #endif - if (nbytes == -1) { perror("Clientside socket send error"); } + if (nbytes == -1) { vscl_os_perror("Clientside socket send error"); } return nbytes; } diff --git a/lib/ipc/win_headers.h b/lib/ipc/win_headers.h index 070e898..1580cab 100644 --- a/lib/ipc/win_headers.h +++ b/lib/ipc/win_headers.h @@ -1,5 +1,6 @@ #ifdef _WIN32 #include #include +#include #include -#endif \ No newline at end of file +#endif diff --git a/lib/libtestrig_api.h b/lib/libtestrig_api.h index 23aa96d..812e0e2 100644 --- a/lib/libtestrig_api.h +++ b/lib/libtestrig_api.h @@ -17,4 +17,4 @@ typedef char vscl_byte_t; enum VSCL_PLATFORM { VSCL_PLATFORM_WINDOWS, VSCL_PLATFORM_LINUX, -}; +}; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14dd2f0..d78669a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,4 +8,5 @@ set(TESTRIG_SOURCES add_executable(testrig ${TESTRIG_SOURCES}) target_link_libraries(testrig PRIVATE libtestrig) target_include_directories(testrig PRIVATE ${LIB_DIR}) +target_compile_warn_all(testrig) target_output_to_bin(testrig) \ No newline at end of file diff --git a/src/actions.c b/src/actions.c index 8fd6505..d7d2417 100644 --- a/src/actions.c +++ b/src/actions.c @@ -44,18 +44,15 @@ int delegate_to_daemon(enum CLI_ACTION act) { if (!found) { printf("testrigd not running; creating new testrig process at "); - int pid = vscl_make_new_proc(PROG_NAME, "--detach --daemon"); + int pid = vscl_make_new_proc(PROG_NAME, "--detach daemon"); printf("%i\n", pid); } int conn = vscl_sock_connect(sock, &sockaddr); int try = 1; while (conn == -1 && try < NUM_MAX_RETRIES) { -#ifdef _WIN32 - Sleep(1000); -#else - sleep(1); -#endif + vscl_sleep(1); + try++; conn = vscl_sock_connect(sock, &sockaddr); } diff --git a/src/args.c b/src/args.c index 2f64631..172cfa5 100644 --- a/src/args.c +++ b/src/args.c @@ -44,13 +44,16 @@ int parse_flag(const char* flag, struct parsed_args* parsed) { int parse_act(const char* act, struct parsed_args* parsed) { int ret = 0; - if (!strncmp("daemon", act, 7)) { parsed->action = ACTION_DAEMON; ret = 1; } - else if (!strncmp("ident", act, 6)) { parsed->action = ACTION_IDENT; ret = 1; } - else if (!strncmp("status", act, 7)) { parsed->action = ACTION_STAT; ret = 1; } - else if (!strncmp("open", act, 5)) { parsed->action = ACTION_OPEN; ret = 1; } - else if (!strncmp("peek", act, 7)) { parsed->action = ACTION_REQUEST; ret = 1; } - else if (!strncmp("close", act, 6)) { parsed->action = ACTION_CLOSE; ret = 1; } - else if (!strncmp("help", act, 5)) { parsed->action = ACTION_HELP; ret = 1; } + char* lead_stripped = strstr(act, " "); + const char* actual = (lead_stripped == NULL) ? act : lead_stripped + 1; + + if (!strncmp("daemon", actual, 7)) { parsed->action = ACTION_DAEMON; ret = 1; } + else if (!strncmp("ident", actual, 6)) { parsed->action = ACTION_IDENT; ret = 1; } + else if (!strncmp("status", actual, 7)) { parsed->action = ACTION_STAT; ret = 1; } + else if (!strncmp("open", actual, 5)) { parsed->action = ACTION_OPEN; ret = 1; } + else if (!strncmp("peek", actual, 7)) { parsed->action = ACTION_REQUEST; ret = 1; } + else if (!strncmp("close", actual, 6)) { parsed->action = ACTION_CLOSE; ret = 1; } + else if (!strncmp("help", actual, 5)) { parsed->action = ACTION_HELP; ret = 1; } return ret; } diff --git a/src/daemon.c b/src/daemon.c index efcfd72..5ba6c32 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -9,9 +9,7 @@ #include "ipc/ipc.h" #ifdef _WIN32 -#include -#include // holy cow there is some include order stuff with windows.h -typedef int socklen_t; +#include "ipc/win_headers.h" #else #include #include @@ -46,7 +44,7 @@ static void interrupt_catcher(int sig, siginfo_t* info, [[ maybe_unused ]] void* static int deploy_interrupt_cleanup([[maybe_unused]] int sock, [[maybe_unused]] struct sockaddr_un* sockaddr) { #ifdef _WIN32 BOOL setted = SetConsoleCtrlHandler(interrupt_catcher, TRUE); - if (!setted) { vscl_winprint_error("daemon ctrl handler"); return 0; } + if (!setted) { vscl_os_perror("daemon ctrl handler"); return 0; } daemon_sockaddr = sockaddr; daemon_sock = sock; @@ -57,7 +55,7 @@ static int deploy_interrupt_cleanup([[maybe_unused]] int sock, [[maybe_unused]] act.sa_sigaction = &interrupt_catcher; int sigint_bound = sigaction(SIGINT, &act, NULL); - if (sigint_bound == -1) { perror("daemon signal capture"); return 0; } + if (sigint_bound == -1) { vscl_os_perror("daemon signal capture"); return 0; } return 1; #endif // _WIN32: Setup signal handler } // interrupt intercept maker @@ -140,7 +138,7 @@ int testrig_daemon(other_args* others) { DAEMON_CURRENT_STATUS = TESTRIG_DAEMON_LISTENING; while (DAEMON_CURRENT_STATUS == TESTRIG_DAEMON_LISTENING) { int accepted = accept(sock, (struct sockaddr*)&sockaddr, &socksize); - if (accepted == -1) { perror("daemon accept failure"); continue; } + if (accepted == -1) { vscl_os_perror("daemon accept failure"); continue; } vscl_byte_t buf[12] = { 0 }; @@ -149,17 +147,17 @@ int testrig_daemon(other_args* others) { #else int recvd = read(accepted, buf, 12); #endif - if (recvd != 12) { perror("did not read full msg"); continue; } + if (recvd != 12) { vscl_os_perror("did not read full msg"); continue; } vscl_byte_t body[8] = { 0 }; for (uint8_t i = 4; i < 12; i++) { body[i - 4] = buf[i]; } - if (!strncmp("STATUS", body, 7)) { testrig_stat(NULL); } + if (!strncmp("STATUS", body, 7)) { testrig_stat(NULL); } else if (!strncmp("OPEN", body, 5)) { testrig_open(NULL); } else if (!strncmp("REQUEST", body, 7)) { testrig_peek(NULL); } - else if (!strncmp("CLOSE", body, 6)) { testrig_close(NULL); } + else if (!strncmp("CLOSE", body, 6)) { testrig_close(NULL); } else if (!strncmp("DOWN", body, 5)) { DAEMON_CURRENT_STATUS = TESTRIG_DAEMON_CLEANING; } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..6a0f0b8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,18 @@ +enable_testing() + +function(make_unit_test OUT_TGT_NAME IN_SOURCES) + if (${ARGC} GREATER 2) + set(_other_args ${ARGV2}) + else() + set(_other_args) + endif() + + add_executable(${OUT_TGT_NAME} ${IN_SOURCES}) + target_link_libraries(${OUT_TGT_NAME} PRIVATE libtestrig) + target_copy_dll(${OUT_TGT_NAME}) + target_compile_warn_all(${OUT_TGT_NAME}) + add_test(NAME "${OUT_TGT_NAME}_test" COMMAND $ ${_other_args}) +endfunction(make_unit_test OUT_TGT_NAME IN_SOURCES) + +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ipc") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/cli") \ No newline at end of file diff --git a/test/cli/CMakeLists.txt b/test/cli/CMakeLists.txt new file mode 100644 index 0000000..4d8b940 --- /dev/null +++ b/test/cli/CMakeLists.txt @@ -0,0 +1 @@ +make_unit_test(daemon_interrupting "${CMAKE_CURRENT_LIST_DIR}/daemon_interrupting.c" $) \ No newline at end of file diff --git a/test/cli/daemon_interrupting.c b/test/cli/daemon_interrupting.c new file mode 100644 index 0000000..326b8d2 --- /dev/null +++ b/test/cli/daemon_interrupting.c @@ -0,0 +1,38 @@ +#include +#include + +#include "ipc/os.h" + +int main(int argc, char** argv) { + if (argc < 2) { fprintf(stderr, "This test requires arguments.\n"); return -1; } + + printf("Starting the daemon...\n"); + int made = vscl_make_new_proc(argv[1], "daemon"); + + if (made != 0 && made != -1) { + printf("Yielding for init...\n"); + vscl_sleep(5); + + printf("Killing the daemon...\n"); + int made2 = vscl_make_new_proc(argv[1], "daemon down"); + vscl_sleep(2); + + char sockpath[108] = { 0 }; + int making_path = vscl_get_sock_destination(sockpath); + if (making_path) { fprintf(stderr, + "Failed to get sock destination for your platform. Did an upstream test fail?\n"); return -1; } + + strncat(sockpath, "testrigd.sock", 15); + + FILE* potential_sock = fopen(sockpath, "r"); + int not_there = potential_sock == NULL; + + return (made != -1 && made2 != -1 && not_there) ? 0 : -1; + } + else if (made == -1) { + vscl_os_perror("Could not make the process.\n"); + return -1; + } + + return 0; +} diff --git a/test/ipc/CMakeLists.txt b/test/ipc/CMakeLists.txt new file mode 100644 index 0000000..0dd74dc --- /dev/null +++ b/test/ipc/CMakeLists.txt @@ -0,0 +1,3 @@ +make_unit_test(sock_naming "${CMAKE_CURRENT_LIST_DIR}/sock_naming.c") +make_unit_test(sock_communicating "${CMAKE_CURRENT_LIST_DIR}/sock_communicating.c" "parent") +make_unit_test(sock_quickopening "${CMAKE_CURRENT_LIST_DIR}/sock_quickopening.c") \ No newline at end of file diff --git a/test/ipc/sock_communicating.c b/test/ipc/sock_communicating.c new file mode 100644 index 0000000..f5cc441 --- /dev/null +++ b/test/ipc/sock_communicating.c @@ -0,0 +1,112 @@ +#include "ipc/sock.h" +#include "ipc/os.h" +#include + +static const char* TESTER_SOCK_NAME = "TEST_SOCK.rigsock"; // NOLINT + +int main(int argc, char** argv) { + if (argc < 2) { fprintf(stderr, "You must pass arguments to this test.\n"); return -1; } + + printf("This was invoked with the following command line:\n"); + printf("\t%s %s\n", argv[0], argv[1]); + fclose(stdin); + + char sockpath[108] = { 0 }; + int retstat = vscl_get_sock_destination(sockpath); + if (retstat != 0) { + fprintf(stderr, + "While preparing the sockets, socket destination grabbing failed.\n"); + return retstat; + } + + strncat(sockpath, TESTER_SOCK_NAME, 19); + struct sockaddr_un sockaddr = { .sun_family = AF_UNIX, }; + strncpy(sockaddr.sun_path, sockpath, 108); + + if (strncmp(argv[1], "parent", 7) == 0) { + int forkstat = vscl_make_new_proc(argv[0], "child"); + if (forkstat == -1) { fprintf(stderr, "Failure to launch\n"); return forkstat; } + else { printf("New process was spawned with PID %i\n", forkstat); } + + int parented = vscl_sock_setup(&sockaddr); + if (parented == INVALID_SOCKET) { + fprintf(stderr, "Parent sock maker fail\n"); + return -1; + } + + int parentstat = vscl_sock_bind(parented, &sockaddr); + if (parentstat == -1) { + fprintf(stderr, "Sock binder fail\n"); + int closestat = vscl_sock_close(parented, &sockaddr); + return (!closestat) ? closestat : parentstat; + } + + parentstat = vscl_sock_listen(parented, 1); + if (parentstat == -1) { + fprintf(stderr, "Sock listener fail at sockpath %s\n", sockaddr.sun_path); + int closestat = vscl_sock_close(parented, &sockaddr); + return (!closestat) ? closestat : parentstat; + } + + int exitplz = 0; + socklen_t socklen = (socklen_t)sizeof(struct sockaddr); + while (!exitplz) { + int acceptor = accept(parented, (struct sockaddr*)&sockaddr, &socklen); + if (acceptor == -1) { fprintf(stderr, "Accept epic fail\n"); continue; } + + vscl_byte_t buf[12] = { 0 }; + +#ifdef _WIN32 + int recvd = recv(acceptor, buf, 12, MSG_PEEK); +#else + int recvd = read(acceptor, buf, 12); +#endif + if (recvd != 12) { + fprintf(stderr, "Failure to read full msg: %i out of 12\n", recvd); + vscl_sock_close(parented, &sockaddr); + return (recvd == 0) ? -1 : recvd; + } + + printf("Success: The message I got was %s\n", buf); + assert(strncmp(buf, "HOWDY WORLD", 12) == 0); + + exitplz = 1; + } + + return vscl_sock_close(parented, &sockaddr); + } + else if (strncmp(argv[1], "child", 6) == 0) { + vscl_sleep(5); // arbitrary + + struct sockaddr_un childsock = { 0 }; + int childed = vscl_sock_setup(&childsock); + if (childed == INVALID_SOCKET) { fprintf(stderr, "Child sock maker fail\n"); return -1; } + else { printf("Child socket created at %s\n", childsock.sun_path); } + + int connection = vscl_sock_connect(childed, &sockaddr); + if (connection == -1) { + fprintf(stderr, "Child connection fail\n"); + vscl_sock_close(childed, &childsock); + int closestat = vscl_sock_close(childed, &sockaddr); + return (!closestat) ? closestat : connection; + } + + struct rig_message msg = { {'H', 'O', 'W', 'D'}, {'Y', ' ', 'W', 'O', 'R', 'L', 'D', 0} }; + int sent = vscl_sock_send(childed, &msg); + if (sent != 12) { + fprintf(stderr, "Failure to send all bytes: %i out of 12\n", sent); + vscl_sock_close(childed, &childsock); + int closestat = vscl_sock_close(childed, &sockaddr); + return (!closestat) ? closestat : -1; + } + else { + printf("Sent all bytes.\n"); + } + + return vscl_sock_close(childed, &childsock); + } + else { + fprintf(stderr, "Invalid token: %s\n", argv[1]); + return -1; + } +} diff --git a/test/ipc/sock_naming.c b/test/ipc/sock_naming.c new file mode 100644 index 0000000..c712a1b --- /dev/null +++ b/test/ipc/sock_naming.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include "ipc/sock.h" +#include "ipc/os.h" + +int main(void) { + printf("Begin socket naming tests.\n"); + int retstat = 0; + + char sockdest[108] = { 0 }; + retstat = vscl_get_sock_destination(sockdest); + if (retstat != 0) { fprintf(stderr, "Failed to find socket path: sockpath became %s\n", sockdest); return retstat; } + + printf("Sockets will go to %s\n", sockdest); + memset(sockdest, 0, 1); + retstat = vscl_sock_genpath(sockdest); + if (retstat != 0) { fprintf(stderr, "Could not generate a proper path for the socket.\n"); return retstat; } + + char new_sockdest[108] = { 0 }; + retstat = vscl_sock_genpath(new_sockdest); + if (retstat != 0) { fprintf(stderr, "Could not generate a proper path for the fresh socket.\n"); return retstat; } + + printf("The socket path was randomly: %s\n", sockdest); + printf("The fresh socket path was randomly: %s\n", new_sockdest); + + // Ensure no early truncation + assert(strstr(sockdest, ".rigsock") != NULL); + assert(strstr(new_sockdest, ".rigsock") != NULL); + printf("Success: The socket path was not truncated.\n"); + + return 0; +} diff --git a/test/ipc/sock_quickopening.c b/test/ipc/sock_quickopening.c new file mode 100644 index 0000000..8af7cdf --- /dev/null +++ b/test/ipc/sock_quickopening.c @@ -0,0 +1,17 @@ +#include "ipc/sock.h" +#include "ipc/os.h" +#include + + +int main(int argc, char** argv) { + struct sockaddr_un sockaddr = { 0 }; + int sock = vscl_sock_setup(&sockaddr); + if (sock == INVALID_SOCKET) { vscl_os_perror("Socket quickopen fail: setup"); return -1; } + else { printf("Sock created for quickopen at %s\n", sockaddr.sun_path); } + + int bound = vscl_sock_bind(sock, &sockaddr); + if (bound == -1) { vscl_os_perror("Socket quickopen fail: bind"); return -1; } + + printf("Goodbye!\n"); + return vscl_sock_close(sock, &sockaddr); +} \ No newline at end of file