test: append/append-verify resume coverage

- CLI: --append/--append-verify acceptance (parse + imply --incremental,
  validate) and incompatibility rejection with -s and --whole-file; both
  removed from the unimplemented reject list.
- Config: on-the-wire append/append_verify round-trip.
- Unit: append_resume_eligible / append_tail_length pure resume math.
- Integration (test_append.py): matching-prefix resume is byte-identical and
  tail-only (wire bytes << source size); --append with a wrong prefix keeps
  prefix+tail (rsync parity) while --append-verify detects the mismatch and
  falls back to a byte-exact full transfer; --append with --inplace and -m.
This commit is contained in:
2026-09-07 15:43:33 +02:00
parent 6ad3887aa1
commit ffdbb6568f
4 changed files with 297 additions and 2 deletions
+96 -2
View File
@@ -773,8 +773,6 @@ static void test_parse_args_rejects_unimplemented_options() {
"--xattrs",
"-D",
"--devices",
"--append",
"--append-verify",
"--delete-excluded",
"--max-delete",
"--prune-empty-dirs",
@@ -1855,8 +1853,104 @@ static void test_parse_args_max_delete_inert_without_delete() {
config_delete(cfg);
}
/* --append is accepted and implies the per-file incremental check a tail resume
* needs; it validates cleanly on its own. */
static void test_parse_args_append() {
Config* cfg = config_create();
cfg->send_directory = str_dup("/src");
cfg->receive_root_directory = str_dup("/dst");
char* argv[] = {"fastsync", "--append", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 4, argv, positional_args, &positional_count), 0);
EXPECT_TRUE(cfg->append);
EXPECT_FALSE(cfg->append_verify);
EXPECT_TRUE(cfg->use_incremental);
EXPECT_TRUE(validate_config(cfg));
config_delete(cfg);
}
static void test_parse_args_append_verify() {
Config* cfg = config_create();
cfg->send_directory = str_dup("/src");
cfg->receive_root_directory = str_dup("/dst");
char* argv[] = {"fastsync", "--append-verify", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 4, argv, positional_args, &positional_count), 0);
EXPECT_TRUE(cfg->append_verify);
EXPECT_FALSE(cfg->append);
EXPECT_TRUE(cfg->use_incremental);
EXPECT_TRUE(validate_config(cfg));
config_delete(cfg);
}
/* Both spellings are accepted; the safer --append-verify semantics win on the
* wire (the sender checks append_verify first), so neither flag is silently
* dropped but the run is still valid. */
static void test_parse_args_append_both() {
Config* cfg = config_create();
cfg->send_directory = str_dup("/src");
cfg->receive_root_directory = str_dup("/dst");
char* argv[] = {"fastsync", "--append", "--append-verify", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0);
EXPECT_TRUE(cfg->append);
EXPECT_TRUE(cfg->append_verify);
EXPECT_TRUE(validate_config(cfg));
config_delete(cfg);
}
static void test_validate_config_append_rejects_chunk_serialization() {
Config* cfg = config_create();
char* argv[] = {"fastsync", "--append", "-s", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0);
EXPECT_FALSE(validate_config(cfg));
config_delete(cfg);
}
static void test_validate_config_append_verify_rejects_chunk_serialization() {
Config* cfg = config_create();
char* argv[] = {"fastsync", "--append-verify", "-s", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0);
EXPECT_FALSE(validate_config(cfg));
config_delete(cfg);
}
static void test_validate_config_append_rejects_whole_file() {
Config* cfg = config_create();
char* argv[] = {"fastsync", "--append", "-W", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0);
EXPECT_FALSE(validate_config(cfg));
config_delete(cfg);
}
static void test_validate_config_append_verify_rejects_whole_file() {
Config* cfg = config_create();
char* argv[] = {"fastsync", "--append-verify", "-W", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0);
EXPECT_FALSE(validate_config(cfg));
config_delete(cfg);
}
void test_client_cli() {
test_validate_config_required_paths();
test_parse_args_append();
test_parse_args_append_verify();
test_parse_args_append_both();
test_validate_config_append_rejects_chunk_serialization();
test_validate_config_append_verify_rejects_chunk_serialization();
test_validate_config_append_rejects_whole_file();
test_validate_config_append_verify_rejects_whole_file();
test_validate_config_incompatible_options();
test_validate_config_tls_requirements();
test_validate_config_delta_sendfile_constraints();