@@ -0,0 +1,235 @@
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user