1 #include "clar_libgit2.h"
4 #include "../submodule/submodule_helpers.h"
9 static git_repository
*_repo
;
11 static char *_remote_url
= NULL
;
13 static char *_remote_user
= NULL
;
14 static char *_remote_pass
= NULL
;
16 static char *_remote_ssh_key
= NULL
;
17 static char *_remote_ssh_pubkey
= NULL
;
18 static char *_remote_ssh_passphrase
= NULL
;
20 static char *_remote_default
= NULL
;
21 static char *_remote_expectcontinue
= NULL
;
23 static int cred_acquire_cb(git_credential
**, const char *, const char *, unsigned int, void *);
25 static git_remote
*_remote
;
26 static record_callbacks_data _record_cbs_data
= {{ 0 }};
27 static git_remote_callbacks _record_cbs
= RECORD_CALLBACKS_INIT(&_record_cbs_data
);
29 static git_oid _oid_b6
;
30 static git_oid _oid_b5
;
31 static git_oid _oid_b4
;
32 static git_oid _oid_b3
;
33 static git_oid _oid_b2
;
34 static git_oid _oid_b1
;
36 static git_oid _tag_commit
;
37 static git_oid _tag_tree
;
38 static git_oid _tag_blob
;
39 static git_oid _tag_lightweight
;
40 static git_oid _tag_tag
;
42 static int cred_acquire_cb(
43 git_credential
**cred
,
45 const char *user_from_url
,
46 unsigned int allowed_types
,
50 GIT_UNUSED(user_from_url
);
53 if (GIT_CREDENTIAL_USERNAME
& allowed_types
) {
55 printf("GITTEST_REMOTE_USER must be set\n");
59 return git_credential_username_new(cred
, _remote_user
);
62 if (GIT_CREDENTIAL_DEFAULT
& allowed_types
) {
63 if (!_remote_default
) {
64 printf("GITTEST_REMOTE_DEFAULT must be set to use NTLM/Negotiate credentials\n");
68 return git_credential_default_new(cred
);
71 if (GIT_CREDENTIAL_SSH_KEY
& allowed_types
) {
72 if (!_remote_user
|| !_remote_ssh_pubkey
|| !_remote_ssh_key
|| !_remote_ssh_passphrase
) {
73 printf("GITTEST_REMOTE_USER, GITTEST_REMOTE_SSH_PUBKEY, GITTEST_REMOTE_SSH_KEY and GITTEST_REMOTE_SSH_PASSPHRASE must be set\n");
77 return git_credential_ssh_key_new(cred
, _remote_user
, _remote_ssh_pubkey
, _remote_ssh_key
, _remote_ssh_passphrase
);
80 if (GIT_CREDENTIAL_USERPASS_PLAINTEXT
& allowed_types
) {
81 if (!_remote_user
|| !_remote_pass
) {
82 printf("GITTEST_REMOTE_USER and GITTEST_REMOTE_PASS must be set\n");
86 return git_credential_userpass_plaintext_new(cred
, _remote_user
, _remote_pass
);
93 * git_push_status_foreach callback that records status entries.
95 static int record_push_status_cb(const char *ref
, const char *msg
, void *payload
)
97 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
100 cl_assert(s
= git__calloc(1, sizeof(*s
)));
102 cl_assert(s
->ref
= git__strdup(ref
));
103 s
->success
= (msg
== NULL
);
105 cl_assert(s
->msg
= git__strdup(msg
));
107 git_vector_insert(&data
->statuses
, s
);
112 static void do_verify_push_status(record_callbacks_data
*data
, const push_status expected
[], const size_t expected_len
)
114 git_vector
*actual
= &data
->statuses
;
119 if (expected_len
!= actual
->length
)
122 git_vector_foreach(actual
, i
, iter
)
123 if (strcmp(expected
[i
].ref
, iter
->ref
) ||
124 (expected
[i
].success
!= iter
->success
) ||
125 (expected
[i
].msg
&& (!iter
->msg
|| strcmp(expected
[i
].msg
, iter
->msg
)))) {
131 git_str msg
= GIT_STR_INIT
;
133 git_str_puts(&msg
, "Expected and actual push statuses differ:\nEXPECTED:\n");
135 for(i
= 0; i
< expected_len
; i
++) {
136 git_str_printf(&msg
, "%s: %s\n",
138 expected
[i
].success
? "success" : "failed");
141 git_str_puts(&msg
, "\nACTUAL:\n");
143 git_vector_foreach(actual
, i
, iter
) {
145 git_str_printf(&msg
, "%s: success\n", iter
->ref
);
147 git_str_printf(&msg
, "%s: failed with message: %s", iter
->ref
, iter
->msg
);
150 cl_fail(git_str_cstr(&msg
));
152 git_str_dispose(&msg
);
155 git_vector_foreach(actual
, i
, iter
) {
156 push_status
*s
= (push_status
*)iter
;
162 git_vector_free(actual
);
166 * Verifies that after git_push_finish(), refs on a remote have the expected
167 * names, oids, and order.
169 * @param remote remote to verify
170 * @param expected_refs expected remote refs after push
171 * @param expected_refs_len length of expected_refs
173 static void verify_refs(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
175 const git_remote_head
**actual_refs
;
176 size_t actual_refs_len
;
178 git_remote_ls(&actual_refs
, &actual_refs_len
, remote
);
179 verify_remote_refs(actual_refs
, actual_refs_len
, expected_refs
, expected_refs_len
);
183 * Verifies that after git_push_update_tips(), remote tracking branches have the expected
186 * @param remote remote to verify
187 * @param expected_refs expected remote refs after push
188 * @param expected_refs_len length of expected_refs
190 static void verify_tracking_branches(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
192 git_refspec
*fetch_spec
;
194 git_str msg
= GIT_STR_INIT
;
195 git_buf ref_name
= GIT_BUF_INIT
;
196 git_vector actual_refs
= GIT_VECTOR_INIT
;
197 git_branch_iterator
*iter
;
200 int failed
= 0, error
;
201 git_branch_t branch_type
;
204 /* Get current remote-tracking branches */
205 cl_git_pass(git_branch_iterator_new(&iter
, remote
->repo
, GIT_BRANCH_REMOTE
));
207 while ((error
= git_branch_next(&ref
, &branch_type
, iter
)) == 0) {
208 cl_assert_equal_i(branch_type
, GIT_BRANCH_REMOTE
);
210 cl_git_pass(git_vector_insert(&actual_refs
, git__strdup(git_reference_name(ref
))));
212 git_reference_free(ref
);
215 cl_assert_equal_i(error
, GIT_ITEROVER
);
216 git_branch_iterator_free(iter
);
218 /* Loop through expected refs, make sure they exist */
219 for (i
= 0; i
< expected_refs_len
; i
++) {
221 /* Convert remote reference name into remote-tracking branch name.
222 * If the spec is not under refs/heads/, then skip.
224 fetch_spec
= git_remote__matching_refspec(remote
, expected_refs
[i
].name
);
228 cl_git_pass(git_refspec_transform(&ref_name
, fetch_spec
, expected_refs
[i
].name
));
230 /* Find matching remote branch */
231 git_vector_foreach(&actual_refs
, j
, actual_ref
) {
232 if (!strcmp(ref_name
.ptr
, actual_ref
))
236 if (j
== actual_refs
.length
) {
237 git_str_printf(&msg
, "Did not find expected tracking branch '%s'.", ref_name
.ptr
);
242 /* Make sure tracking branch is at expected commit ID */
243 cl_git_pass(git_reference_name_to_id(&oid
, remote
->repo
, actual_ref
));
245 if (git_oid_cmp(expected_refs
[i
].oid
, &oid
) != 0) {
246 git_str_puts(&msg
, "Tracking branch commit does not match expected ID.");
251 git__free(actual_ref
);
252 cl_git_pass(git_vector_remove(&actual_refs
, j
));
255 /* Make sure there are no extra branches */
256 if (actual_refs
.length
> 0) {
257 git_str_puts(&msg
, "Unexpected remote tracking branches exist.");
264 cl_fail(git_str_cstr(&msg
));
266 git_vector_foreach(&actual_refs
, i
, actual_ref
)
267 git__free(actual_ref
);
269 git_vector_free(&actual_refs
);
270 git_str_dispose(&msg
);
271 git_buf_dispose(&ref_name
);
274 static void verify_update_tips_callback(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
276 git_refspec
*fetch_spec
;
277 git_str msg
= GIT_STR_INIT
;
278 git_buf ref_name
= GIT_BUF_INIT
;
279 updated_tip
*tip
= NULL
;
283 for (i
= 0; i
< expected_refs_len
; ++i
) {
284 /* Convert remote reference name into tracking branch name.
285 * If the spec is not under refs/heads/, then skip.
287 fetch_spec
= git_remote__matching_refspec(remote
, expected_refs
[i
].name
);
291 cl_git_pass(git_refspec_transform(&ref_name
, fetch_spec
, expected_refs
[i
].name
));
293 /* Find matching update_tip entry */
294 git_vector_foreach(&_record_cbs_data
.updated_tips
, j
, tip
) {
295 if (!strcmp(ref_name
.ptr
, tip
->name
))
299 if (j
== _record_cbs_data
.updated_tips
.length
) {
300 git_str_printf(&msg
, "Did not find expected updated tip entry for branch '%s'.", ref_name
.ptr
);
305 if (git_oid_cmp(expected_refs
[i
].oid
, &tip
->new_oid
) != 0) {
306 git_str_printf(&msg
, "Updated tip ID does not match expected ID");
314 cl_fail(git_str_cstr(&msg
));
316 git_buf_dispose(&ref_name
);
317 git_str_dispose(&msg
);
320 void test_online_push__initialize(void)
322 git_vector delete_specs
= GIT_VECTOR_INIT
;
323 const git_remote_head
**heads
;
325 git_push_options push_opts
= GIT_PUSH_OPTIONS_INIT
;
326 git_fetch_options fetch_opts
= GIT_FETCH_OPTIONS_INIT
;
328 _repo
= cl_git_sandbox_init("push_src");
330 cl_git_pass(git_repository_set_ident(_repo
, "Random J. Hacker", "foo@example.com"));
331 cl_fixture_sandbox("testrepo.git");
332 cl_rename("push_src/submodule/.gitted", "push_src/submodule/.git");
334 rewrite_gitmodules(git_repository_workdir(_repo
));
336 /* git log --format=oneline --decorate --graph
337 * *-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, b6) merge b3, b4, and b5 to b6
339 * | | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git'
340 * | * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt
342 * * | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt
344 * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt
345 * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt
347 git_oid_fromstr(&_oid_b6
, "951bbbb90e2259a4c8950db78946784fb53fcbce");
348 git_oid_fromstr(&_oid_b5
, "fa38b91f199934685819bea316186d8b008c52a2");
349 git_oid_fromstr(&_oid_b4
, "27b7ce66243eb1403862d05f958c002312df173d");
350 git_oid_fromstr(&_oid_b3
, "d9b63a88223d8367516f50bd131a5f7349b7f3e4");
351 git_oid_fromstr(&_oid_b2
, "a78705c3b2725f931d3ee05348d83cc26700f247");
352 git_oid_fromstr(&_oid_b1
, "a78705c3b2725f931d3ee05348d83cc26700f247");
354 git_oid_fromstr(&_tag_commit
, "805c54522e614f29f70d2413a0470247d8b424ac");
355 git_oid_fromstr(&_tag_tree
, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e");
356 git_oid_fromstr(&_tag_blob
, "b483ae7ba66decee9aee971f501221dea84b1498");
357 git_oid_fromstr(&_tag_lightweight
, "951bbbb90e2259a4c8950db78946784fb53fcbce");
358 git_oid_fromstr(&_tag_tag
, "eea4f2705eeec2db3813f2430829afce99cd00b5");
360 /* Remote URL environment variable must be set. User and password are optional. */
362 _remote_url
= cl_getenv("GITTEST_REMOTE_URL");
363 _remote_user
= cl_getenv("GITTEST_REMOTE_USER");
364 _remote_pass
= cl_getenv("GITTEST_REMOTE_PASS");
365 _remote_ssh_key
= cl_getenv("GITTEST_REMOTE_SSH_KEY");
366 _remote_ssh_pubkey
= cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
367 _remote_ssh_passphrase
= cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
368 _remote_default
= cl_getenv("GITTEST_REMOTE_DEFAULT");
369 _remote_expectcontinue
= cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
372 /* Skip the test if we're missing the remote URL */
376 if (_remote_expectcontinue
)
377 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE
, 1);
379 cl_git_pass(git_remote_create(&_remote
, _repo
, "test", _remote_url
));
381 record_callbacks_data_clear(&_record_cbs_data
);
383 cl_git_pass(git_remote_connect(_remote
, GIT_DIRECTION_PUSH
, &_record_cbs
, NULL
, NULL
));
385 /* Clean up previously pushed branches. Fails if receive.denyDeletes is
386 * set on the remote. Also, on Git 1.7.0 and newer, you must run
387 * 'git config receive.denyDeleteCurrent ignore' in the remote repo in
388 * order to delete the remote branch pointed to by HEAD (usually master).
389 * See: https://raw.github.com/git/git/master/Documentation/RelNotes/1.7.0.txt
391 cl_git_pass(git_remote_ls(&heads
, &heads_len
, _remote
));
392 cl_git_pass(create_deletion_refspecs(&delete_specs
, heads
, heads_len
));
393 if (delete_specs
.length
) {
395 (char **) delete_specs
.contents
,
399 memcpy(&push_opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
400 cl_git_pass(git_remote_upload(_remote
, &arr
, &push_opts
));
403 git_remote_disconnect(_remote
);
404 git_vector_free_deep(&delete_specs
);
406 /* Now that we've deleted everything, fetch from the remote */
407 memcpy(&fetch_opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
408 cl_git_pass(git_remote_fetch(_remote
, NULL
, &fetch_opts
, NULL
));
411 void test_online_push__cleanup(void)
414 git_remote_free(_remote
);
417 git__free(_remote_url
);
418 git__free(_remote_user
);
419 git__free(_remote_pass
);
420 git__free(_remote_ssh_key
);
421 git__free(_remote_ssh_pubkey
);
422 git__free(_remote_ssh_passphrase
);
423 git__free(_remote_default
);
424 git__free(_remote_expectcontinue
);
426 /* Freed by cl_git_sandbox_cleanup */
429 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE
, 0);
431 record_callbacks_data_clear(&_record_cbs_data
);
433 cl_fixture_cleanup("testrepo.git");
434 cl_git_sandbox_cleanup();
437 static int push_pack_progress_cb(
438 int stage
, unsigned int current
, unsigned int total
, void* payload
)
440 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
441 GIT_UNUSED(stage
); GIT_UNUSED(current
); GIT_UNUSED(total
);
442 if (data
->pack_progress_calls
< 0)
443 return data
->pack_progress_calls
;
445 data
->pack_progress_calls
++;
449 static int push_transfer_progress_cb(
450 unsigned int current
, unsigned int total
, size_t bytes
, void* payload
)
452 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
453 GIT_UNUSED(current
); GIT_UNUSED(total
); GIT_UNUSED(bytes
);
454 if (data
->transfer_progress_calls
< 0)
455 return data
->transfer_progress_calls
;
457 data
->transfer_progress_calls
++;
462 * Calls push and relists refs on remote to verify success.
464 * @param refspecs refspecs to push
465 * @param refspecs_len length of refspecs
466 * @param expected_refs expected remote refs after push
467 * @param expected_refs_len length of expected_refs
468 * @param expected_ret expected return value from git_push_finish()
469 * @param check_progress_cb Check that the push progress callbacks are called
472 const char *refspecs
[], size_t refspecs_len
,
473 push_status expected_statuses
[], size_t expected_statuses_len
,
474 expected_ref expected_refs
[], size_t expected_refs_len
,
475 int expected_ret
, int check_progress_cb
, int check_update_tips_cb
)
477 git_push_options opts
= GIT_PUSH_OPTIONS_INIT
;
480 git_strarray specs
= {0};
481 record_callbacks_data
*data
;
484 /* Auto-detect the number of threads to use */
485 opts
.pb_parallelism
= 0;
487 memcpy(&opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
488 data
= opts
.callbacks
.payload
;
490 opts
.callbacks
.pack_progress
= push_pack_progress_cb
;
491 opts
.callbacks
.push_transfer_progress
= push_transfer_progress_cb
;
492 opts
.callbacks
.push_update_reference
= record_push_status_cb
;
495 specs
.count
= refspecs_len
;
496 specs
.strings
= git__calloc(refspecs_len
, sizeof(char *));
497 cl_assert(specs
.strings
);
500 for (i
= 0; i
< refspecs_len
; i
++)
501 specs
.strings
[i
] = (char *) refspecs
[i
];
503 /* if EUSER, then abort in transfer */
504 if (check_progress_cb
&& expected_ret
== GIT_EUSER
)
505 data
->transfer_progress_calls
= GIT_EUSER
;
507 error
= git_remote_push(_remote
, &specs
, &opts
);
508 git__free(specs
.strings
);
510 if (expected_ret
< 0) {
511 cl_git_fail_with(expected_ret
, error
);
516 if (check_progress_cb
&& expected_ret
== 0) {
517 cl_assert(data
->pack_progress_calls
> 0);
518 cl_assert(data
->transfer_progress_calls
> 0);
521 do_verify_push_status(data
, expected_statuses
, expected_statuses_len
);
523 verify_refs(_remote
, expected_refs
, expected_refs_len
);
524 verify_tracking_branches(_remote
, expected_refs
, expected_refs_len
);
526 if (check_update_tips_cb
)
527 verify_update_tips_callback(_remote
, expected_refs
, expected_refs_len
);
533 /* Call push_finish() without ever calling git_push_add_refspec() */
534 void test_online_push__noop(void)
536 do_push(NULL
, 0, NULL
, 0, NULL
, 0, 0, 0, 1);
539 void test_online_push__b1(void)
541 const char *specs
[] = { "refs/heads/b1:refs/heads/b1" };
542 push_status exp_stats
[] = { { "refs/heads/b1", 1 } };
543 expected_ref exp_refs
[] = { { "refs/heads/b1", &_oid_b1
} };
544 do_push(specs
, ARRAY_SIZE(specs
),
545 exp_stats
, ARRAY_SIZE(exp_stats
),
546 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
549 void test_online_push__b2(void)
551 const char *specs
[] = { "refs/heads/b2:refs/heads/b2" };
552 push_status exp_stats
[] = { { "refs/heads/b2", 1 } };
553 expected_ref exp_refs
[] = { { "refs/heads/b2", &_oid_b2
} };
554 do_push(specs
, ARRAY_SIZE(specs
),
555 exp_stats
, ARRAY_SIZE(exp_stats
),
556 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
559 void test_online_push__b3(void)
561 const char *specs
[] = { "refs/heads/b3:refs/heads/b3" };
562 push_status exp_stats
[] = { { "refs/heads/b3", 1 } };
563 expected_ref exp_refs
[] = { { "refs/heads/b3", &_oid_b3
} };
564 do_push(specs
, ARRAY_SIZE(specs
),
565 exp_stats
, ARRAY_SIZE(exp_stats
),
566 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
569 void test_online_push__b4(void)
571 const char *specs
[] = { "refs/heads/b4:refs/heads/b4" };
572 push_status exp_stats
[] = { { "refs/heads/b4", 1 } };
573 expected_ref exp_refs
[] = { { "refs/heads/b4", &_oid_b4
} };
574 do_push(specs
, ARRAY_SIZE(specs
),
575 exp_stats
, ARRAY_SIZE(exp_stats
),
576 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
579 void test_online_push__b5(void)
581 const char *specs
[] = { "refs/heads/b5:refs/heads/b5" };
582 push_status exp_stats
[] = { { "refs/heads/b5", 1 } };
583 expected_ref exp_refs
[] = { { "refs/heads/b5", &_oid_b5
} };
584 do_push(specs
, ARRAY_SIZE(specs
),
585 exp_stats
, ARRAY_SIZE(exp_stats
),
586 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
589 void test_online_push__b5_cancel(void)
591 const char *specs
[] = { "refs/heads/b5:refs/heads/b5" };
592 do_push(specs
, ARRAY_SIZE(specs
), NULL
, 0, NULL
, 0, GIT_EUSER
, 1, 1);
595 void test_online_push__multi(void)
598 const git_reflog_entry
*entry
;
600 const char *specs
[] = {
601 "refs/heads/b1:refs/heads/b1",
602 "refs/heads/b2:refs/heads/b2",
603 "refs/heads/b3:refs/heads/b3",
604 "refs/heads/b4:refs/heads/b4",
605 "refs/heads/b5:refs/heads/b5"
607 push_status exp_stats
[] = {
608 { "refs/heads/b1", 1 },
609 { "refs/heads/b2", 1 },
610 { "refs/heads/b3", 1 },
611 { "refs/heads/b4", 1 },
612 { "refs/heads/b5", 1 }
614 expected_ref exp_refs
[] = {
615 { "refs/heads/b1", &_oid_b1
},
616 { "refs/heads/b2", &_oid_b2
},
617 { "refs/heads/b3", &_oid_b3
},
618 { "refs/heads/b4", &_oid_b4
},
619 { "refs/heads/b5", &_oid_b5
}
621 do_push(specs
, ARRAY_SIZE(specs
),
622 exp_stats
, ARRAY_SIZE(exp_stats
),
623 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
625 cl_git_pass(git_reflog_read(&log
, _repo
, "refs/remotes/test/b1"));
626 entry
= git_reflog_entry_byindex(log
, 0);
628 cl_assert_equal_s("update by push", git_reflog_entry_message(entry
));
629 cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry
)->email
);
632 git_reflog_free(log
);
635 void test_online_push__implicit_tgt(void)
637 const char *specs1
[] = { "refs/heads/b1" };
638 push_status exp_stats1
[] = { { "refs/heads/b1", 1 } };
639 expected_ref exp_refs1
[] = { { "refs/heads/b1", &_oid_b1
} };
641 const char *specs2
[] = { "refs/heads/b2" };
642 push_status exp_stats2
[] = { { "refs/heads/b2", 1 } };
643 expected_ref exp_refs2
[] = {
644 { "refs/heads/b1", &_oid_b1
},
645 { "refs/heads/b2", &_oid_b2
}
648 do_push(specs1
, ARRAY_SIZE(specs1
),
649 exp_stats1
, ARRAY_SIZE(exp_stats1
),
650 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
651 do_push(specs2
, ARRAY_SIZE(specs2
),
652 exp_stats2
, ARRAY_SIZE(exp_stats2
),
653 exp_refs2
, ARRAY_SIZE(exp_refs2
), 0, 0, 0);
656 void test_online_push__fast_fwd(void)
658 /* Fast forward b1 in tgt from _oid_b1 to _oid_b6. */
660 const char *specs_init
[] = { "refs/heads/b1:refs/heads/b1" };
661 push_status exp_stats_init
[] = { { "refs/heads/b1", 1 } };
662 expected_ref exp_refs_init
[] = { { "refs/heads/b1", &_oid_b1
} };
664 const char *specs_ff
[] = { "refs/heads/b6:refs/heads/b1" };
665 push_status exp_stats_ff
[] = { { "refs/heads/b1", 1 } };
666 expected_ref exp_refs_ff
[] = { { "refs/heads/b1", &_oid_b6
} };
668 /* Do a force push to reset b1 in target back to _oid_b1 */
669 const char *specs_reset
[] = { "+refs/heads/b1:refs/heads/b1" };
670 /* Force should have no effect on a fast forward push */
671 const char *specs_ff_force
[] = { "+refs/heads/b6:refs/heads/b1" };
673 do_push(specs_init
, ARRAY_SIZE(specs_init
),
674 exp_stats_init
, ARRAY_SIZE(exp_stats_init
),
675 exp_refs_init
, ARRAY_SIZE(exp_refs_init
), 0, 1, 1);
677 do_push(specs_ff
, ARRAY_SIZE(specs_ff
),
678 exp_stats_ff
, ARRAY_SIZE(exp_stats_ff
),
679 exp_refs_ff
, ARRAY_SIZE(exp_refs_ff
), 0, 0, 0);
681 do_push(specs_reset
, ARRAY_SIZE(specs_reset
),
682 exp_stats_init
, ARRAY_SIZE(exp_stats_init
),
683 exp_refs_init
, ARRAY_SIZE(exp_refs_init
), 0, 0, 0);
685 do_push(specs_ff_force
, ARRAY_SIZE(specs_ff_force
),
686 exp_stats_ff
, ARRAY_SIZE(exp_stats_ff
),
687 exp_refs_ff
, ARRAY_SIZE(exp_refs_ff
), 0, 0, 0);
690 void test_online_push__tag_commit(void)
692 const char *specs
[] = { "refs/tags/tag-commit:refs/tags/tag-commit" };
693 push_status exp_stats
[] = { { "refs/tags/tag-commit", 1 } };
694 expected_ref exp_refs
[] = { { "refs/tags/tag-commit", &_tag_commit
} };
695 do_push(specs
, ARRAY_SIZE(specs
),
696 exp_stats
, ARRAY_SIZE(exp_stats
),
697 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
700 void test_online_push__tag_tree(void)
702 const char *specs
[] = { "refs/tags/tag-tree:refs/tags/tag-tree" };
703 push_status exp_stats
[] = { { "refs/tags/tag-tree", 1 } };
704 expected_ref exp_refs
[] = { { "refs/tags/tag-tree", &_tag_tree
} };
705 do_push(specs
, ARRAY_SIZE(specs
),
706 exp_stats
, ARRAY_SIZE(exp_stats
),
707 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
710 void test_online_push__tag_blob(void)
712 const char *specs
[] = { "refs/tags/tag-blob:refs/tags/tag-blob" };
713 push_status exp_stats
[] = { { "refs/tags/tag-blob", 1 } };
714 expected_ref exp_refs
[] = { { "refs/tags/tag-blob", &_tag_blob
} };
715 do_push(specs
, ARRAY_SIZE(specs
),
716 exp_stats
, ARRAY_SIZE(exp_stats
),
717 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
720 void test_online_push__tag_lightweight(void)
722 const char *specs
[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" };
723 push_status exp_stats
[] = { { "refs/tags/tag-lightweight", 1 } };
724 expected_ref exp_refs
[] = { { "refs/tags/tag-lightweight", &_tag_lightweight
} };
725 do_push(specs
, ARRAY_SIZE(specs
),
726 exp_stats
, ARRAY_SIZE(exp_stats
),
727 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
730 void test_online_push__tag_to_tag(void)
732 const char *specs
[] = { "refs/tags/tag-tag:refs/tags/tag-tag" };
733 push_status exp_stats
[] = { { "refs/tags/tag-tag", 1 } };
734 expected_ref exp_refs
[] = { { "refs/tags/tag-tag", &_tag_tag
} };
735 do_push(specs
, ARRAY_SIZE(specs
),
736 exp_stats
, ARRAY_SIZE(exp_stats
),
737 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 0, 0);
740 void test_online_push__force(void)
742 const char *specs1
[] = {"refs/heads/b3:refs/heads/tgt"};
743 push_status exp_stats1
[] = { { "refs/heads/tgt", 1 } };
744 expected_ref exp_refs1
[] = { { "refs/heads/tgt", &_oid_b3
} };
746 const char *specs2
[] = {"refs/heads/b4:refs/heads/tgt"};
748 const char *specs2_force
[] = {"+refs/heads/b4:refs/heads/tgt"};
749 push_status exp_stats2_force
[] = { { "refs/heads/tgt", 1 } };
750 expected_ref exp_refs2_force
[] = { { "refs/heads/tgt", &_oid_b4
} };
752 do_push(specs1
, ARRAY_SIZE(specs1
),
753 exp_stats1
, ARRAY_SIZE(exp_stats1
),
754 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
756 do_push(specs2
, ARRAY_SIZE(specs2
),
758 exp_refs1
, ARRAY_SIZE(exp_refs1
), GIT_ENONFASTFORWARD
, 0, 0);
760 /* Non-fast-forward update with force should pass. */
761 record_callbacks_data_clear(&_record_cbs_data
);
762 do_push(specs2_force
, ARRAY_SIZE(specs2_force
),
763 exp_stats2_force
, ARRAY_SIZE(exp_stats2_force
),
764 exp_refs2_force
, ARRAY_SIZE(exp_refs2_force
), 0, 1, 1);
767 void test_online_push__delete(void)
769 const char *specs1
[] = {
770 "refs/heads/b1:refs/heads/tgt1",
771 "refs/heads/b1:refs/heads/tgt2"
773 push_status exp_stats1
[] = {
774 { "refs/heads/tgt1", 1 },
775 { "refs/heads/tgt2", 1 }
777 expected_ref exp_refs1
[] = {
778 { "refs/heads/tgt1", &_oid_b1
},
779 { "refs/heads/tgt2", &_oid_b1
}
782 const char *specs_del_fake
[] = { ":refs/heads/fake" };
783 /* Force has no effect for delete. */
784 const char *specs_del_fake_force
[] = { "+:refs/heads/fake" };
785 push_status exp_stats_fake
[] = { { "refs/heads/fake", 1 } };
787 const char *specs_delete
[] = { ":refs/heads/tgt1" };
788 push_status exp_stats_delete
[] = { { "refs/heads/tgt1", 1 } };
789 expected_ref exp_refs_delete
[] = { { "refs/heads/tgt2", &_oid_b1
} };
790 /* Force has no effect for delete. */
791 const char *specs_delete_force
[] = { "+:refs/heads/tgt1" };
793 do_push(specs1
, ARRAY_SIZE(specs1
),
794 exp_stats1
, ARRAY_SIZE(exp_stats1
),
795 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
797 /* When deleting a non-existent branch, the git client sends zero for both
798 * the old and new commit id. This should succeed on the server with the
799 * same status report as if the branch were actually deleted. The server
800 * returns a warning on the side-band iff the side-band is supported.
801 * Since libgit2 doesn't support the side-band yet, there are no warnings.
803 do_push(specs_del_fake
, ARRAY_SIZE(specs_del_fake
),
805 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
806 do_push(specs_del_fake_force
, ARRAY_SIZE(specs_del_fake_force
),
808 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
810 /* Delete one of the pushed branches. */
811 do_push(specs_delete
, ARRAY_SIZE(specs_delete
),
812 exp_stats_delete
, ARRAY_SIZE(exp_stats_delete
),
813 exp_refs_delete
, ARRAY_SIZE(exp_refs_delete
), 0, 0, 0);
815 /* Re-push branches and retry delete with force. */
816 do_push(specs1
, ARRAY_SIZE(specs1
),
817 exp_stats1
, ARRAY_SIZE(exp_stats1
),
818 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
819 do_push(specs_delete_force
, ARRAY_SIZE(specs_delete_force
),
820 exp_stats_delete
, ARRAY_SIZE(exp_stats_delete
),
821 exp_refs_delete
, ARRAY_SIZE(exp_refs_delete
), 0, 0, 0);
824 void test_online_push__bad_refspecs(void)
826 /* All classes of refspecs that should be rejected by
827 * git_push_add_refspec() should go in this test.
838 cl_git_fail(git_remote_upload(_remote
, &arr
, NULL
));
842 void test_online_push__expressions(void)
844 /* TODO: Expressions in refspecs doesn't actually work yet */
845 const char *specs_left_expr
[] = { "refs/heads/b2~1:refs/heads/b2" };
847 /* TODO: Find a more precise way of checking errors than a exit code of -1. */
848 do_push(specs_left_expr
, ARRAY_SIZE(specs_left_expr
),
853 void test_online_push__notes(void)
855 git_oid note_oid
, *target_oid
, expected_oid
;
856 git_signature
*signature
;
857 const char *specs
[] = { "refs/notes/commits:refs/notes/commits" };
858 push_status exp_stats
[] = { { "refs/notes/commits", 1 } };
859 expected_ref exp_refs
[] = { { "refs/notes/commits", &expected_oid
} };
860 const char *specs_del
[] = { ":refs/notes/commits" };
862 git_oid_fromstr(&expected_oid
, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
864 target_oid
= &_oid_b6
;
866 /* Create note to push */
867 cl_git_pass(git_signature_new(&signature
, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
868 cl_git_pass(git_note_create(¬e_oid
, _repo
, NULL
, signature
, signature
, target_oid
, "hello world\n", 0));
870 do_push(specs
, ARRAY_SIZE(specs
),
871 exp_stats
, ARRAY_SIZE(exp_stats
),
872 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
874 /* And make sure to delete the note */
876 do_push(specs_del
, ARRAY_SIZE(specs_del
),
880 git_signature_free(signature
);
883 void test_online_push__configured(void)
885 git_oid note_oid
, *target_oid
, expected_oid
;
886 git_signature
*signature
;
887 git_remote
*old_remote
;
888 const char *specs
[] = { "refs/notes/commits:refs/notes/commits" };
889 push_status exp_stats
[] = { { "refs/notes/commits", 1 } };
890 expected_ref exp_refs
[] = { { "refs/notes/commits", &expected_oid
} };
891 const char *specs_del
[] = { ":refs/notes/commits" };
893 git_oid_fromstr(&expected_oid
, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
895 target_oid
= &_oid_b6
;
897 cl_git_pass(git_remote_add_push(_repo
, git_remote_name(_remote
), specs
[0]));
898 old_remote
= _remote
;
899 cl_git_pass(git_remote_lookup(&_remote
, _repo
, git_remote_name(_remote
)));
900 git_remote_free(old_remote
);
902 /* Create note to push */
903 cl_git_pass(git_signature_new(&signature
, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
904 cl_git_pass(git_note_create(¬e_oid
, _repo
, NULL
, signature
, signature
, target_oid
, "hello world\n", 0));
907 exp_stats
, ARRAY_SIZE(exp_stats
),
908 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
910 /* And make sure to delete the note */
912 do_push(specs_del
, ARRAY_SIZE(specs_del
),
916 git_signature_free(signature
);