Merge dev into human codebase evaluation
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
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
This commit is contained in:
@@ -193,6 +193,26 @@ class TestIncremental:
|
||||
content = f.read()
|
||||
assert b"modified content" in content, f"Modified content not transferred: {content[:50]}"
|
||||
|
||||
def test_checksum_detects_same_size_and_mtime_change(self, shared_server):
|
||||
clean_dir(DEST_DIR)
|
||||
result, _ = run_client(SOURCE_DIR, DEST_DIR, flags=["-M"], port=shared_server.port)
|
||||
assert result.returncode == 0
|
||||
|
||||
received = get_dest_received_dir(DEST_DIR, SOURCE_DIR)
|
||||
source_file = os.path.join(SOURCE_DIR, "small.txt")
|
||||
received_file = os.path.join(received, "small.txt")
|
||||
source_stat = os.stat(source_file)
|
||||
with open(received_file, "wb") as f:
|
||||
f.write(b"different!\n")
|
||||
os.utime(received_file, (source_stat.st_atime, source_stat.st_mtime))
|
||||
|
||||
result, _ = run_client(SOURCE_DIR, DEST_DIR,
|
||||
flags=["-M", "--incremental", "--checksum"],
|
||||
port=shared_server.port)
|
||||
assert result.returncode == 0, f"Checksum sync failed: {result.stderr[:200]}"
|
||||
with open(received_file, "rb") as f:
|
||||
assert f.read() == b"hello world\n"
|
||||
|
||||
|
||||
class TestDelete:
|
||||
def test_delete_removes_extra_files(self, shared_server):
|
||||
@@ -220,8 +240,10 @@ class TestDelete:
|
||||
)
|
||||
|
||||
assert result.returncode == 0, f"Delete sync failed: {(result.stderr or result.stdout)[:200]}"
|
||||
assert not os.path.exists(extra_file), "extra_file.txt should be deleted"
|
||||
assert not os.path.exists(extra_dir), "extra_dir should be deleted"
|
||||
# The default server policy intentionally refuses client-requested
|
||||
# deletion unless it is started with --allow-delete.
|
||||
assert os.path.exists(extra_file), "unauthorized delete removed an extra file"
|
||||
assert os.path.exists(extra_dir), "unauthorized delete removed an extra directory"
|
||||
|
||||
mismatches, missing = verify_transfer(SOURCE_DIR, received)
|
||||
assert not missing, f"Missing: {missing}"
|
||||
@@ -238,7 +260,8 @@ class TestProgress:
|
||||
)
|
||||
assert result.returncode == 0, f"Exit {result.returncode}: {result.stderr[:100]}"
|
||||
output = result.stdout + result.stderr
|
||||
assert output, "--progress produced no output"
|
||||
assert "Sent " in output and "MB" in output, "--progress produced no stable byte marker"
|
||||
assert "Done." in output, "--progress did not report completion"
|
||||
|
||||
|
||||
class TestBandwidthLimit:
|
||||
|
||||
@@ -4,52 +4,51 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import pytest
|
||||
import shlex
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from common import (
|
||||
PROJECT_ROOT, BUILD_DIR, TEST_DATA_DIR,
|
||||
CLIENT_CMD, generate_test_files, verify_transfer, clean_dir, make_result,
|
||||
)
|
||||
from common import (PROJECT_ROOT, BUILD_DIR, TEST_DATA_DIR, CLIENT_CMD,
|
||||
generate_test_files, verify_transfer, clean_dir, make_result,
|
||||
get_dest_received_dir)
|
||||
|
||||
SOURCE_DIR = os.path.join(TEST_DATA_DIR, "ssh_source")
|
||||
DEST_DIR = os.path.join(TEST_DATA_DIR, "ssh_dest")
|
||||
SSH_AVAILABLE = False
|
||||
SSH_SKIP_REASON = "SSH localhost probe was not run"
|
||||
SSH_PROBE_DIR = None
|
||||
|
||||
|
||||
def _check_ssh():
|
||||
global SSH_AVAILABLE
|
||||
global SSH_AVAILABLE, SSH_SKIP_REASON, SSH_PROBE_DIR
|
||||
server_path = os.path.join(BUILD_DIR, "server")
|
||||
if not os.path.isfile(server_path):
|
||||
SSH_SKIP_REASON = f"current server binary is missing: {server_path}"
|
||||
return
|
||||
try:
|
||||
r = subprocess.run(
|
||||
["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=5",
|
||||
"localhost", "which", "fastsync-server"],
|
||||
capture_output=True, timeout=10,
|
||||
)
|
||||
if r.returncode == 0:
|
||||
SSH_PROBE_DIR = tempfile.mkdtemp(prefix="fastsync-ssh-probe-")
|
||||
probe_server = os.path.join(SSH_PROBE_DIR, "fastsync-server")
|
||||
os.symlink(server_path, probe_server)
|
||||
command = f"{shlex.quote(probe_server)} --help"
|
||||
path = subprocess.run(["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=5",
|
||||
"localhost", "sh", "-c", command],
|
||||
capture_output=True, timeout=10, text=True)
|
||||
if path.returncode != 0:
|
||||
SSH_SKIP_REASON = "SSH to localhost is unavailable or current server probe failed"
|
||||
return
|
||||
if "FastSync Server" in path.stdout:
|
||||
SSH_AVAILABLE = True
|
||||
return
|
||||
|
||||
# Try to install server binary into PATH
|
||||
server_path = os.path.join(BUILD_DIR, "server")
|
||||
r = subprocess.run(
|
||||
["ssh", "-o", "BatchMode=yes", "localhost", 'echo "$PATH"'],
|
||||
capture_output=True, timeout=10, text=True,
|
||||
)
|
||||
if r.returncode != 0:
|
||||
return
|
||||
for d in r.stdout.strip().split(":"):
|
||||
d = d.strip()
|
||||
if not d or "wrappers" in d:
|
||||
continue
|
||||
test = subprocess.run(
|
||||
["ssh", "-o", "BatchMode=yes", "localhost",
|
||||
f'test -w "{d}" && ln -sf {server_path} "{d}/fastsync-server" && which fastsync-server'],
|
||||
capture_output=True, timeout=10,
|
||||
)
|
||||
if test.returncode == 0:
|
||||
SSH_AVAILABLE = True
|
||||
return
|
||||
SSH_SKIP_REASON = "SSH probe did not execute the current server binary"
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
SSH_SKIP_REASON = "ssh executable is unavailable"
|
||||
except (OSError, subprocess.TimeoutExpired) as exc:
|
||||
SSH_SKIP_REASON = f"SSH setup failed: {exc}"
|
||||
finally:
|
||||
if SSH_PROBE_DIR:
|
||||
shutil.rmtree(SSH_PROBE_DIR, ignore_errors=True)
|
||||
SSH_PROBE_DIR = None
|
||||
|
||||
|
||||
_check_ssh()
|
||||
@@ -65,18 +64,17 @@ def setup_test_data():
|
||||
|
||||
|
||||
def _run_ssh_test(name, flags, expected_missing=None):
|
||||
"""Run an SSH test case (no server process needed, client spawns SSH)."""
|
||||
ssh_dest = f"localhost:{DEST_DIR}"
|
||||
clean_dir(DEST_DIR)
|
||||
cmd = CLIENT_CMD + [SOURCE_DIR, ssh_dest, "--save-to-disk"] + flags
|
||||
cmd = CLIENT_CMD + [SOURCE_DIR, ssh_dest, "--save-to-disk",
|
||||
"--fastsync-server-path", os.path.join(BUILD_DIR, "server")] + flags
|
||||
start = __import__("time").monotonic()
|
||||
result = subprocess.run(cmd, text=True, capture_output=True)
|
||||
duration = __import__("time").monotonic() - start
|
||||
|
||||
if result.returncode != 0:
|
||||
return make_result(name, False, duration, f"Exit {result.returncode}: {(result.stderr or result.stdout)[:100]}")
|
||||
|
||||
mismatches, missing = verify_transfer(SOURCE_DIR, DEST_DIR)
|
||||
return make_result(name, False, duration,
|
||||
f"Exit {result.returncode}: {(result.stderr or result.stdout)[:100]}")
|
||||
mismatches, missing = verify_transfer(SOURCE_DIR, get_dest_received_dir(DEST_DIR, SOURCE_DIR))
|
||||
if expected_missing:
|
||||
missing = [m for m in missing if m not in expected_missing]
|
||||
if missing:
|
||||
@@ -90,7 +88,7 @@ class TestSSHStandard:
|
||||
@pytest.fixture(autouse=True)
|
||||
def require_ssh(self):
|
||||
if not SSH_AVAILABLE:
|
||||
pytest.skip("SSH to localhost not available")
|
||||
pytest.skip(SSH_SKIP_REASON)
|
||||
|
||||
def test_standard(self):
|
||||
r = _run_ssh_test("SSH (localhost)", [])
|
||||
@@ -129,7 +127,7 @@ class TestSSHFeatures:
|
||||
@pytest.fixture(autouse=True)
|
||||
def require_ssh(self):
|
||||
if not SSH_AVAILABLE:
|
||||
pytest.skip("SSH to localhost not available")
|
||||
pytest.skip(SSH_SKIP_REASON)
|
||||
|
||||
def test_archive(self):
|
||||
r = _run_ssh_test("SSH Archive (-a)", ["-a"])
|
||||
@@ -137,6 +135,5 @@ class TestSSHFeatures:
|
||||
|
||||
def test_exclude(self):
|
||||
r = _run_ssh_test("SSH Exclude (--exclude small.txt)",
|
||||
["--exclude", "small.txt"],
|
||||
expected_missing=["small.txt"])
|
||||
["--exclude", "small.txt"], expected_missing=["small.txt"])
|
||||
assert r["status"] == "Success", r["error"]
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "test_transport_tls.h"
|
||||
#include "test_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
// Define global test state variables
|
||||
int tests_run = 0;
|
||||
@@ -32,6 +33,7 @@ int tests_failed = 0;
|
||||
bool current_test_failed = false;
|
||||
|
||||
int main() {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
printf("\033[1;36m=== RUNNING UNIT TESTS ===\033[0m\n\n");
|
||||
|
||||
RUN_TEST(test_queue);
|
||||
|
||||
@@ -256,9 +256,8 @@ static void test_parse_args_rejects_unimplemented_options() {
|
||||
"--ipv4",
|
||||
"--daemon",
|
||||
"--config",
|
||||
"--server",
|
||||
"--checksum",
|
||||
"--compress-choice"};
|
||||
"--server",
|
||||
"--compress-choice"};
|
||||
|
||||
for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
|
||||
Config* cfg = config_create();
|
||||
|
||||
@@ -35,6 +35,10 @@ static void test_xxhash32_different_data() {
|
||||
EXPECT_TRUE(ha != hb);
|
||||
}
|
||||
|
||||
static void test_xxhash64_different_data() {
|
||||
EXPECT_TRUE(delta_xxhash64("AAAA", 4) != delta_xxhash64("BBBB", 4));
|
||||
}
|
||||
|
||||
static void test_signature_roundtrip() {
|
||||
char old_data[4096];
|
||||
for (int i = 0; i < 4096; i++)
|
||||
@@ -344,6 +348,7 @@ void test_delta() {
|
||||
test_adler32_different_data();
|
||||
test_xxhash32_basic();
|
||||
test_xxhash32_different_data();
|
||||
test_xxhash64_different_data();
|
||||
test_signature_roundtrip();
|
||||
test_delta_identical_files();
|
||||
test_delta_small_edit();
|
||||
|
||||
@@ -126,6 +126,29 @@ static void test_to_disk_creates_dirs() {
|
||||
rmdir("test_nested_tmp");
|
||||
}
|
||||
|
||||
static void test_to_disk_does_not_follow_symlink() {
|
||||
const char* outside = "test_to_disk_outside.txt";
|
||||
const char* link = "test_to_disk_link.txt";
|
||||
const char* content = "confined";
|
||||
unlink(outside);
|
||||
unlink(link);
|
||||
EXPECT_TRUE(to_disk(outside, "outside", 7, false, false));
|
||||
EXPECT_EQ_INT(symlink(outside, link), 0);
|
||||
EXPECT_TRUE(to_disk(link, content, strlen(content), false, false));
|
||||
FILE* fp = fopen(outside, "rb");
|
||||
char buf[16] = {0};
|
||||
EXPECT_NOT_NULL(fp);
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (!fp)
|
||||
return;
|
||||
size_t read_count = fread(buf, 1, sizeof(buf) - 1, fp);
|
||||
EXPECT_TRUE(read_count <= sizeof(buf) - 1);
|
||||
fclose(fp);
|
||||
EXPECT_EQ_STR(buf, "outside");
|
||||
unlink(outside);
|
||||
unlink(link);
|
||||
}
|
||||
|
||||
static void test_file_content_to_buffer() {
|
||||
const char* content = "Buffer content test";
|
||||
EXPECT_TRUE(to_disk("test_buffer_file.txt", content, strlen(content), false, false));
|
||||
@@ -434,6 +457,7 @@ void test_file() {
|
||||
test_file_save_to_disk();
|
||||
test_to_disk_basic();
|
||||
test_to_disk_creates_dirs();
|
||||
test_to_disk_does_not_follow_symlink();
|
||||
test_file_content_to_buffer();
|
||||
test_file_save_to_disk_path_traversal();
|
||||
test_file_save_to_disk_deep_traversal();
|
||||
|
||||
@@ -109,6 +109,19 @@ static void test_metadata_send_null() {
|
||||
close(p[1]);
|
||||
}
|
||||
|
||||
static void test_metadata_rejects_invalid_values() {
|
||||
int p[2];
|
||||
EXPECT_EQ_INT(pipe(p), 0);
|
||||
io_set_fds(p[0], p[1]);
|
||||
int32_t present = 2;
|
||||
EXPECT_TRUE(send_n_data(p[1], &present, sizeof(present)));
|
||||
int ok = 1;
|
||||
EXPECT_NULL(metadata_receive(p[0], &ok));
|
||||
EXPECT_EQ_INT(ok, 0);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
}
|
||||
|
||||
static void test_file_restore_metadata() {
|
||||
const char* path = "temp_meta_restore_test.txt";
|
||||
const char* content = "test content";
|
||||
@@ -137,5 +150,6 @@ void test_metadata() {
|
||||
test_metadata_from_buf_null();
|
||||
test_metadata_send_receive_roundtrip();
|
||||
test_metadata_send_null();
|
||||
test_metadata_rejects_invalid_values();
|
||||
test_file_restore_metadata();
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ static void test_sender_queue_capacities() {
|
||||
pipeline_context_sender_destroy(ctx);
|
||||
}
|
||||
|
||||
/* Test that create handles zero-capacity queues */
|
||||
/* Invalid queue capacities must not create unusable pipeline queues. */
|
||||
static void test_sender_zero_capacity() {
|
||||
Config* cfg = config_create();
|
||||
EXPECT_NOT_NULL(cfg);
|
||||
@@ -91,13 +91,13 @@ static void test_sender_zero_capacity() {
|
||||
cfg->send_directory = str_dup("/src");
|
||||
cfg->receive_root_directory = str_dup("/dst");
|
||||
|
||||
Queue* q1 = queue_create(0, NULL);
|
||||
Queue* q2 = queue_create(0, NULL);
|
||||
PipelineContextSender* ctx = pipeline_context_sender_create(cfg, q1, q2);
|
||||
EXPECT_NOT_NULL(ctx);
|
||||
EXPECT_EQ_INT(ctx->queue_scanner->capacity, 0);
|
||||
EXPECT_EQ_INT(ctx->queue_loader->capacity, 0);
|
||||
pipeline_context_sender_destroy(ctx);
|
||||
// cppcheck-suppress constVariablePointer
|
||||
Queue* const q1 = queue_create(0, NULL);
|
||||
// cppcheck-suppress constVariablePointer
|
||||
Queue* const q2 = queue_create(0, NULL);
|
||||
EXPECT_NULL(q1);
|
||||
EXPECT_NULL(q2);
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
/* Test receiver with zero file_descriptor */
|
||||
@@ -168,6 +168,41 @@ static void test_receive_thread_finished() {
|
||||
}
|
||||
}
|
||||
|
||||
/* A malformed terminal status must wake a writer waiting on an empty queue. */
|
||||
static void test_receive_thread_failure_wakes_writer() {
|
||||
Config* cfg = config_create();
|
||||
EXPECT_NOT_NULL(cfg);
|
||||
free(cfg->version);
|
||||
cfg->version = str_dup(PROTOCOL_VERSION);
|
||||
cfg->send_directory = str_dup("/src");
|
||||
cfg->receive_root_directory = str_dup("/tmp/dst");
|
||||
|
||||
int p[2];
|
||||
EXPECT_EQ_INT(pipe(p), 0);
|
||||
Queue* q = queue_create(1, file_destroy);
|
||||
EXPECT_NOT_NULL(q);
|
||||
PipelineContextReceiver* ctx = pipeline_context_receiver_create(cfg, q, p[0], NULL);
|
||||
EXPECT_NOT_NULL(ctx);
|
||||
|
||||
thrd_t receiver;
|
||||
thrd_t writer;
|
||||
EXPECT_EQ_INT(thrd_create(&writer, write_thread, ctx), thrd_success);
|
||||
EXPECT_EQ_INT(thrd_create(&receiver, receive_thread, ctx), thrd_success);
|
||||
EXPECT_TRUE(send_status(p[1], STATUS_OK));
|
||||
close(p[1]);
|
||||
|
||||
int receiver_result;
|
||||
int writer_result;
|
||||
EXPECT_EQ_INT(thrd_join(receiver, &receiver_result), thrd_success);
|
||||
EXPECT_EQ_INT(thrd_join(writer, &writer_result), thrd_success);
|
||||
EXPECT_EQ_INT(receiver_result, thrd_error);
|
||||
EXPECT_EQ_INT(writer_result, thrd_success);
|
||||
EXPECT_TRUE(ctx->receiver_done);
|
||||
|
||||
close(p[0]);
|
||||
pipeline_context_receiver_destroy(ctx);
|
||||
}
|
||||
|
||||
/* Test that write_thread completes cleanly when queue signals done */
|
||||
static void test_write_thread_done() {
|
||||
Config* cfg = config_create();
|
||||
@@ -223,6 +258,7 @@ void test_multiprocessing() {
|
||||
test_receiver_fd_zero();
|
||||
if (!is_running_under_valgrind()) {
|
||||
test_receive_thread_finished();
|
||||
test_receive_thread_failure_wakes_writer();
|
||||
}
|
||||
test_write_thread_done();
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ static void test_queue_basic() {
|
||||
queue_destroy(q);
|
||||
}
|
||||
|
||||
static void test_queue_rejects_invalid_capacity() {
|
||||
EXPECT_NULL(queue_create(0, NULL));
|
||||
EXPECT_NULL(queue_create(-1, NULL));
|
||||
}
|
||||
|
||||
static void test_queue_resize() {
|
||||
Queue* q = queue_create(3, NULL);
|
||||
EXPECT_NOT_NULL(q);
|
||||
@@ -199,6 +204,7 @@ static void test_queue_multithreaded() {
|
||||
|
||||
void test_queue() {
|
||||
test_queue_basic();
|
||||
test_queue_rejects_invalid_capacity();
|
||||
test_queue_resize();
|
||||
test_queue_destroyer();
|
||||
test_queue_multithreaded();
|
||||
|
||||
+12
-12
@@ -19,7 +19,7 @@ static void test_scanner_single_file() {
|
||||
create_test_file(file1, content1);
|
||||
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
|
||||
0, false, false, false, false);
|
||||
0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -48,7 +48,7 @@ static void test_scanner_multiple_files() {
|
||||
create_test_file(file2, content2);
|
||||
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
|
||||
0, false, false, false, false);
|
||||
0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
const Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -88,7 +88,7 @@ static void test_scanner_subdirectory() {
|
||||
create_test_file(sub_file, content);
|
||||
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0,
|
||||
0, 0, false, false, false, false);
|
||||
0, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
int total_files = 0;
|
||||
@@ -112,7 +112,7 @@ static void test_scanner_empty_directory() {
|
||||
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
||||
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
|
||||
0, false, false, false, false);
|
||||
0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
const Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -136,7 +136,7 @@ static void test_scanner_exclude_pattern() {
|
||||
|
||||
char* exclude[] = {"*.tmp"};
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0,
|
||||
0, 0, false, false, false, false);
|
||||
0, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -169,7 +169,7 @@ static void test_scanner_exclude_subdirectory() {
|
||||
|
||||
char* exclude[] = {"*.tmp"};
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0,
|
||||
0, 0, 0, false, false, false, false);
|
||||
0, 0, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
int total = 0;
|
||||
@@ -207,7 +207,7 @@ static void test_scanner_include_and_exclude() {
|
||||
char* exclude[] = {"*.bak"};
|
||||
char* include[] = {"*.txt", "*.log"};
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2,
|
||||
0, 0, 0, false, false, false, false);
|
||||
0, 0, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -244,7 +244,7 @@ static void test_scanner_max_size() {
|
||||
|
||||
/* max_size = 10 — only files <= 10 bytes */
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10,
|
||||
0, 0, false, false, false, false);
|
||||
0, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -272,7 +272,7 @@ static void test_scanner_min_size() {
|
||||
|
||||
/* min_size = 1 — only files >= 1 byte */
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1,
|
||||
0, false, false, false, false);
|
||||
0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -302,7 +302,7 @@ static void test_scanner_size_range() {
|
||||
|
||||
/* Only files between 3 and 20 bytes */
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20,
|
||||
3, 0, false, false, false, false);
|
||||
3, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -338,7 +338,7 @@ static void test_scanner_mixed_patterns() {
|
||||
char* exclude[] = {"*.bak"};
|
||||
char* include[] = {"*.txt"};
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1,
|
||||
10, 3, 0, false, false, false, false);
|
||||
10, 3, 0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
@@ -369,7 +369,7 @@ static void test_scanner_no_patterns() {
|
||||
create_test_file(f2, "second");
|
||||
|
||||
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
|
||||
0, false, false, false, false);
|
||||
0, false, false, false, false, false);
|
||||
EXPECT_NOT_NULL(scanner);
|
||||
|
||||
Chunk* chunk = directory_scanner_next(scanner);
|
||||
|
||||
@@ -171,10 +171,26 @@ static void test_receive_files_abort() {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_receive_manifest_rejects_traversal() {
|
||||
Config* cfg = config_create();
|
||||
EXPECT_NOT_NULL(cfg);
|
||||
cfg->receive_root_directory = str_dup("/tmp/dst");
|
||||
int p[2];
|
||||
EXPECT_EQ_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, p), 0);
|
||||
io_set_fds(p[0], p[1]);
|
||||
EXPECT_TRUE(send_int(p[1], 1));
|
||||
EXPECT_TRUE(send_str(p[1], "../outside"));
|
||||
EXPECT_EQ_INT(receive_manifest(p[0], cfg, NULL), -1);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
void test_server() {
|
||||
if (!is_running_under_valgrind()) {
|
||||
test_receive_files_finished();
|
||||
test_receive_files_single_file();
|
||||
test_receive_files_abort();
|
||||
test_receive_manifest_rejects_traversal();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user