Files
FastSync/tests/test_file_sendfile.c
T
TapTap c1e1db8f5e
CI / lint (pull_request) Failing after 2s
CI / build-and-test (pull_request) Has been skipped
CI / sanitizers (address) (pull_request) Has been skipped
CI / sanitizers (undefined) (pull_request) Has been skipped
CI / fuzz-build (pull_request) Has been skipped
CI / coverage (pull_request) Has been skipped
CI / valgrind (pull_request) Has been skipped
fix: refactoring and portability — issues #61, #51, #52
2026-07-20 18:01:36 +02:00

236 lines
6.1 KiB
C

#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 <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
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();
}