#include "test_file_sendfile.h" #include "file.h" #include "data.h" #include "config.h" #include "protocol.h" #include "utils.h" #include "test_utils.h" #include #include #include #include #include static void test_sendfile_basic() { const char* content = "Hello sendfile test content!"; size_t len = strlen(content); EXPECT_TRUE(to_disk("test_sendfile_basic.txt", content, len)); File* file = file_create("test_sendfile_basic.txt"); EXPECT_NOT_NULL(file); file->data->size = len; file->data->data = malloc(len); EXPECT_NOT_NULL(file->data->data); memcpy(file->data->data, content, len); int p[2]; EXPECT_EQ_INT(pipe(p), 0); io_set_fds(p[0], p[1]); io_set_bwlimit(0); pid_t pid = fork(); if (pid == 0) { close(p[1]); // Receive path: read size then data unsigned long long recv_size; EXPECT_TRUE(receive_n_data(p[0], &recv_size, sizeof(recv_size))); EXPECT_EQ_INT((int)recv_size, (int)len); char* buf = malloc(recv_size + 1); EXPECT_NOT_NULL(buf); EXPECT_TRUE(receive_n_data(p[0], buf, recv_size)); buf[recv_size] = '\0'; EXPECT_EQ_INT(memcmp(buf, content, len), 0); free(buf); close(p[0]); _exit(0); } else { close(p[0]); bool sent = file_send_sendfile(file, p[1], false, 0, false); close(p[1]); int status; waitpid(pid, &status, 0); file_destroy(file); unlink("test_sendfile_basic.txt"); EXPECT_TRUE(sent); EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); } } static void test_sendfile_with_path() { const char* content = "Sendfile with path test"; size_t len = strlen(content); EXPECT_TRUE(to_disk("test_sendfile_path.txt", content, len)); File* file = file_create("test_sendfile_path.txt"); EXPECT_NOT_NULL(file); file->data->size = len; file->data->data = malloc(len); EXPECT_NOT_NULL(file->data->data); memcpy(file->data->data, content, len); int p[2]; EXPECT_EQ_INT(pipe(p), 0); io_set_fds(p[0], p[1]); io_set_bwlimit(0); pid_t pid = fork(); if (pid == 0) { close(p[1]); char* recv_path = receive_str(p[0]); EXPECT_NOT_NULL(recv_path); EXPECT_EQ_STR(recv_path, "test_sendfile_path.txt"); free(recv_path); unsigned long long recv_size; EXPECT_TRUE(receive_n_data(p[0], &recv_size, sizeof(recv_size))); char* buf = malloc(recv_size + 1); EXPECT_NOT_NULL(buf); EXPECT_TRUE(receive_n_data(p[0], buf, recv_size)); buf[recv_size] = '\0'; EXPECT_EQ_INT(memcmp(buf, content, len), 0); free(buf); close(p[0]); _exit(0); } else { close(p[0]); bool sent = file_send_sendfile(file, p[1], false, 0, true); close(p[1]); int status; waitpid(pid, &status, 0); file_destroy(file); unlink("test_sendfile_path.txt"); EXPECT_TRUE(sent); EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); } } static void test_sendfile_empty_file() { const char* content = ""; size_t len = 0; EXPECT_TRUE(to_disk("test_sendfile_empty.txt", content, len)); File* file = file_create("test_sendfile_empty.txt"); EXPECT_NOT_NULL(file); file->data->size = len; file->data->data = NULL; int p[2]; EXPECT_EQ_INT(pipe(p), 0); io_set_fds(p[0], p[1]); io_set_bwlimit(0); pid_t pid = fork(); if (pid == 0) { close(p[1]); unsigned long long recv_size; EXPECT_TRUE(receive_n_data(p[0], &recv_size, sizeof(recv_size))); EXPECT_EQ_INT((int)recv_size, 0); close(p[0]); _exit(0); } else { close(p[0]); bool sent = file_send_sendfile(file, p[1], false, 0, false); close(p[1]); int status; waitpid(pid, &status, 0); file_destroy(file); unlink("test_sendfile_empty.txt"); EXPECT_TRUE(sent); EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); } } static void test_sendfile_with_compression_fallback() { // When compression_level > 0, sendfile falls back to file_send_single_calls const char* content = "Sendfile compression fallback test data here."; size_t len = strlen(content); EXPECT_TRUE(to_disk("test_sendfile_comp.txt", content, len)); File* file = file_create("test_sendfile_comp.txt"); EXPECT_NOT_NULL(file); file->data->size = len; file->data->data = malloc(len); EXPECT_NOT_NULL(file->data->data); memcpy(file->data->data, content, len); Config* cfg = config_create(str_dup(PROTOCOL_VERSION), str_dup("/tmp"), str_dup("/tmp"), false, false, false, false, false, 0, false, 0); int p[2]; EXPECT_EQ_INT(pipe(p), 0); io_set_fds(p[0], p[1]); io_set_bwlimit(0); pid_t pid = fork(); if (pid == 0) { close(p[1]); File* received = file_receive(cfg, p[0]); close(p[0]); bool ok = true; if (!received) ok = false; else { if (!received->data || received->data->size != len) ok = false; else if (memcmp(received->data->data, content, len) != 0) ok = false; } file_destroy(received); config_delete(cfg); _exit(ok ? 0 : 1); } else { close(p[0]); // Send with compression_level=1, should fall back to file_send_single_calls bool sent = file_send_sendfile(file, p[1], false, 1, true); close(p[1]); int status; waitpid(pid, &status, 0); file_destroy(file); config_delete(cfg); unlink("test_sendfile_comp.txt"); EXPECT_TRUE(sent); EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); } } static void test_sendfile_nonexistent_file() { File* file = file_create("nonexistent_file_xyz_sendfile_test.txt"); EXPECT_NOT_NULL(file); file->data->size = 100; file->data->data = malloc(100); EXPECT_NOT_NULL(file->data->data); memset(file->data->data, 0, 100); int p[2]; EXPECT_EQ_INT(pipe(p), 0); io_set_fds(p[0], p[1]); io_set_bwlimit(0); close(p[0]); bool sent = file_send_sendfile(file, p[1], false, 0, false); close(p[1]); file_destroy(file); // File doesn't exist on disk, sendfile should fail EXPECT_FALSE(sent); } void test_file_sendfile() { test_sendfile_basic(); test_sendfile_with_path(); test_sendfile_empty_file(); test_sendfile_with_compression_fallback(); test_sendfile_nonexistent_file(); }