1 #include "clar_libgit2.h"
5 #include "../submodule/submodule_helpers.h"
10 static git_repository
*_repo
;
12 static char *_remote_url
= NULL
;
14 static char *_remote_user
= NULL
;
15 static char *_remote_pass
= NULL
;
17 static char *_remote_ssh_key
= NULL
;
18 static char *_remote_ssh_pubkey
= NULL
;
19 static char *_remote_ssh_passphrase
= NULL
;
21 static char *_remote_default
= NULL
;
22 static char *_remote_expectcontinue
= NULL
;
24 static int cred_acquire_cb(git_credential
**, const char *, const char *, unsigned int, void *);
26 static git_remote
*_remote
;
27 static record_callbacks_data _record_cbs_data
= {{ 0 }};
28 static git_remote_callbacks _record_cbs
= RECORD_CALLBACKS_INIT(&_record_cbs_data
);
30 static git_oid _oid_b6
;
31 static git_oid _oid_b5
;
32 static git_oid _oid_b4
;
33 static git_oid _oid_b3
;
34 static git_oid _oid_b2
;
35 static git_oid _oid_b1
;
37 static git_oid _tag_commit
;
38 static git_oid _tag_tree
;
39 static git_oid _tag_blob
;
40 static git_oid _tag_lightweight
;
41 static git_oid _tag_tag
;
43 static int cred_acquire_cb(
44 git_credential
**cred
,
46 const char *user_from_url
,
47 unsigned int allowed_types
,
51 GIT_UNUSED(user_from_url
);
54 if (GIT_CREDENTIAL_USERNAME
& allowed_types
) {
56 printf("GITTEST_REMOTE_USER must be set\n");
60 return git_credential_username_new(cred
, _remote_user
);
63 if (GIT_CREDENTIAL_DEFAULT
& allowed_types
) {
64 if (!_remote_default
) {
65 printf("GITTEST_REMOTE_DEFAULT must be set to use NTLM/Negotiate credentials\n");
69 return git_credential_default_new(cred
);
72 if (GIT_CREDENTIAL_SSH_KEY
& allowed_types
) {
73 if (!_remote_user
|| !_remote_ssh_pubkey
|| !_remote_ssh_key
|| !_remote_ssh_passphrase
) {
74 printf("GITTEST_REMOTE_USER, GITTEST_REMOTE_SSH_PUBKEY, GITTEST_REMOTE_SSH_KEY and GITTEST_REMOTE_SSH_PASSPHRASE must be set\n");
78 return git_credential_ssh_key_new(cred
, _remote_user
, _remote_ssh_pubkey
, _remote_ssh_key
, _remote_ssh_passphrase
);
81 if (GIT_CREDENTIAL_USERPASS_PLAINTEXT
& allowed_types
) {
82 if (!_remote_user
|| !_remote_pass
) {
83 printf("GITTEST_REMOTE_USER and GITTEST_REMOTE_PASS must be set\n");
87 return git_credential_userpass_plaintext_new(cred
, _remote_user
, _remote_pass
);
94 * git_push_status_foreach callback that records status entries.
96 static int record_push_status_cb(const char *ref
, const char *msg
, void *payload
)
98 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
101 cl_assert(s
= git__calloc(1, sizeof(*s
)));
103 cl_assert(s
->ref
= git__strdup(ref
));
104 s
->success
= (msg
== NULL
);
106 cl_assert(s
->msg
= git__strdup(msg
));
108 git_vector_insert(&data
->statuses
, s
);
113 static void do_verify_push_status(record_callbacks_data
*data
, const push_status expected
[], const size_t expected_len
)
115 git_vector
*actual
= &data
->statuses
;
120 if (expected_len
!= actual
->length
)
123 git_vector_foreach(actual
, i
, iter
)
124 if (strcmp(expected
[i
].ref
, iter
->ref
) ||
125 (expected
[i
].success
!= iter
->success
) ||
126 (expected
[i
].msg
&& (!iter
->msg
|| strcmp(expected
[i
].msg
, iter
->msg
)))) {
132 git_buf msg
= GIT_BUF_INIT
;
134 git_buf_puts(&msg
, "Expected and actual push statuses differ:\nEXPECTED:\n");
136 for(i
= 0; i
< expected_len
; i
++) {
137 git_buf_printf(&msg
, "%s: %s\n",
139 expected
[i
].success
? "success" : "failed");
142 git_buf_puts(&msg
, "\nACTUAL:\n");
144 git_vector_foreach(actual
, i
, iter
) {
146 git_buf_printf(&msg
, "%s: success\n", iter
->ref
);
148 git_buf_printf(&msg
, "%s: failed with message: %s", iter
->ref
, iter
->msg
);
151 cl_fail(git_buf_cstr(&msg
));
153 git_buf_dispose(&msg
);
156 git_vector_foreach(actual
, i
, iter
) {
157 push_status
*s
= (push_status
*)iter
;
163 git_vector_free(actual
);
167 * Verifies that after git_push_finish(), refs on a remote have the expected
168 * names, oids, and order.
170 * @param remote remote to verify
171 * @param expected_refs expected remote refs after push
172 * @param expected_refs_len length of expected_refs
174 static void verify_refs(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
176 const git_remote_head
**actual_refs
;
177 size_t actual_refs_len
;
179 git_remote_ls(&actual_refs
, &actual_refs_len
, remote
);
180 verify_remote_refs(actual_refs
, actual_refs_len
, expected_refs
, expected_refs_len
);
184 * Verifies that after git_push_update_tips(), remote tracking branches have the expected
187 * @param remote remote to verify
188 * @param expected_refs expected remote refs after push
189 * @param expected_refs_len length of expected_refs
191 static void verify_tracking_branches(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
193 git_refspec
*fetch_spec
;
195 git_buf msg
= GIT_BUF_INIT
;
196 git_buf ref_name
= GIT_BUF_INIT
;
197 git_vector actual_refs
= GIT_VECTOR_INIT
;
198 git_branch_iterator
*iter
;
201 int failed
= 0, error
;
202 git_branch_t branch_type
;
205 /* Get current remote-tracking branches */
206 cl_git_pass(git_branch_iterator_new(&iter
, remote
->repo
, GIT_BRANCH_REMOTE
));
208 while ((error
= git_branch_next(&ref
, &branch_type
, iter
)) == 0) {
209 cl_assert_equal_i(branch_type
, GIT_BRANCH_REMOTE
);
211 cl_git_pass(git_vector_insert(&actual_refs
, git__strdup(git_reference_name(ref
))));
213 git_reference_free(ref
);
216 cl_assert_equal_i(error
, GIT_ITEROVER
);
217 git_branch_iterator_free(iter
);
219 /* Loop through expected refs, make sure they exist */
220 for (i
= 0; i
< expected_refs_len
; i
++) {
222 /* Convert remote reference name into remote-tracking branch name.
223 * If the spec is not under refs/heads/, then skip.
225 fetch_spec
= git_remote__matching_refspec(remote
, expected_refs
[i
].name
);
229 cl_git_pass(git_refspec_transform(&ref_name
, fetch_spec
, expected_refs
[i
].name
));
231 /* Find matching remote branch */
232 git_vector_foreach(&actual_refs
, j
, actual_ref
) {
233 if (!strcmp(git_buf_cstr(&ref_name
), actual_ref
))
237 if (j
== actual_refs
.length
) {
238 git_buf_printf(&msg
, "Did not find expected tracking branch '%s'.", git_buf_cstr(&ref_name
));
243 /* Make sure tracking branch is at expected commit ID */
244 cl_git_pass(git_reference_name_to_id(&oid
, remote
->repo
, actual_ref
));
246 if (git_oid_cmp(expected_refs
[i
].oid
, &oid
) != 0) {
247 git_buf_puts(&msg
, "Tracking branch commit does not match expected ID.");
252 git__free(actual_ref
);
253 cl_git_pass(git_vector_remove(&actual_refs
, j
));
256 /* Make sure there are no extra branches */
257 if (actual_refs
.length
> 0) {
258 git_buf_puts(&msg
, "Unexpected remote tracking branches exist.");
265 cl_fail(git_buf_cstr(&msg
));
267 git_vector_foreach(&actual_refs
, i
, actual_ref
)
268 git__free(actual_ref
);
270 git_vector_free(&actual_refs
);
271 git_buf_dispose(&msg
);
272 git_buf_dispose(&ref_name
);
275 static void verify_update_tips_callback(git_remote
*remote
, expected_ref expected_refs
[], size_t expected_refs_len
)
277 git_refspec
*fetch_spec
;
278 git_buf msg
= GIT_BUF_INIT
;
279 git_buf ref_name
= GIT_BUF_INIT
;
280 updated_tip
*tip
= NULL
;
284 for (i
= 0; i
< expected_refs_len
; ++i
) {
285 /* Convert remote reference name into tracking branch name.
286 * If the spec is not under refs/heads/, then skip.
288 fetch_spec
= git_remote__matching_refspec(remote
, expected_refs
[i
].name
);
292 cl_git_pass(git_refspec_transform(&ref_name
, fetch_spec
, expected_refs
[i
].name
));
294 /* Find matching update_tip entry */
295 git_vector_foreach(&_record_cbs_data
.updated_tips
, j
, tip
) {
296 if (!strcmp(git_buf_cstr(&ref_name
), tip
->name
))
300 if (j
== _record_cbs_data
.updated_tips
.length
) {
301 git_buf_printf(&msg
, "Did not find expected updated tip entry for branch '%s'.", git_buf_cstr(&ref_name
));
306 if (git_oid_cmp(expected_refs
[i
].oid
, &tip
->new_oid
) != 0) {
307 git_buf_printf(&msg
, "Updated tip ID does not match expected ID");
315 cl_fail(git_buf_cstr(&msg
));
317 git_buf_dispose(&ref_name
);
318 git_buf_dispose(&msg
);
321 void test_online_push__initialize(void)
323 git_vector delete_specs
= GIT_VECTOR_INIT
;
324 const git_remote_head
**heads
;
326 git_push_options push_opts
= GIT_PUSH_OPTIONS_INIT
;
327 git_fetch_options fetch_opts
= GIT_FETCH_OPTIONS_INIT
;
329 _repo
= cl_git_sandbox_init("push_src");
331 cl_git_pass(git_repository_set_ident(_repo
, "Random J. Hacker", "foo@example.com"));
332 cl_fixture_sandbox("testrepo.git");
333 cl_rename("push_src/submodule/.gitted", "push_src/submodule/.git");
335 rewrite_gitmodules(git_repository_workdir(_repo
));
337 /* git log --format=oneline --decorate --graph
338 * *-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, b6) merge b3, b4, and b5 to b6
340 * | | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git'
341 * | * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt
343 * * | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt
345 * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt
346 * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt
348 git_oid_fromstr(&_oid_b6
, "951bbbb90e2259a4c8950db78946784fb53fcbce");
349 git_oid_fromstr(&_oid_b5
, "fa38b91f199934685819bea316186d8b008c52a2");
350 git_oid_fromstr(&_oid_b4
, "27b7ce66243eb1403862d05f958c002312df173d");
351 git_oid_fromstr(&_oid_b3
, "d9b63a88223d8367516f50bd131a5f7349b7f3e4");
352 git_oid_fromstr(&_oid_b2
, "a78705c3b2725f931d3ee05348d83cc26700f247");
353 git_oid_fromstr(&_oid_b1
, "a78705c3b2725f931d3ee05348d83cc26700f247");
355 git_oid_fromstr(&_tag_commit
, "805c54522e614f29f70d2413a0470247d8b424ac");
356 git_oid_fromstr(&_tag_tree
, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e");
357 git_oid_fromstr(&_tag_blob
, "b483ae7ba66decee9aee971f501221dea84b1498");
358 git_oid_fromstr(&_tag_lightweight
, "951bbbb90e2259a4c8950db78946784fb53fcbce");
359 git_oid_fromstr(&_tag_tag
, "eea4f2705eeec2db3813f2430829afce99cd00b5");
361 /* Remote URL environment variable must be set. User and password are optional. */
363 _remote_url
= cl_getenv("GITTEST_REMOTE_URL");
364 _remote_user
= cl_getenv("GITTEST_REMOTE_USER");
365 _remote_pass
= cl_getenv("GITTEST_REMOTE_PASS");
366 _remote_ssh_key
= cl_getenv("GITTEST_REMOTE_SSH_KEY");
367 _remote_ssh_pubkey
= cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
368 _remote_ssh_passphrase
= cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
369 _remote_default
= cl_getenv("GITTEST_REMOTE_DEFAULT");
370 _remote_expectcontinue
= cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
373 /* Skip the test if we're missing the remote URL */
377 if (_remote_expectcontinue
)
378 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE
, 1);
380 cl_git_pass(git_remote_create(&_remote
, _repo
, "test", _remote_url
));
382 record_callbacks_data_clear(&_record_cbs_data
);
384 cl_git_pass(git_remote_connect(_remote
, GIT_DIRECTION_PUSH
, &_record_cbs
, NULL
, NULL
));
386 /* Clean up previously pushed branches. Fails if receive.denyDeletes is
387 * set on the remote. Also, on Git 1.7.0 and newer, you must run
388 * 'git config receive.denyDeleteCurrent ignore' in the remote repo in
389 * order to delete the remote branch pointed to by HEAD (usually master).
390 * See: https://raw.github.com/git/git/master/Documentation/RelNotes/1.7.0.txt
392 cl_git_pass(git_remote_ls(&heads
, &heads_len
, _remote
));
393 cl_git_pass(create_deletion_refspecs(&delete_specs
, heads
, heads_len
));
394 if (delete_specs
.length
) {
396 (char **) delete_specs
.contents
,
400 memcpy(&push_opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
401 cl_git_pass(git_remote_upload(_remote
, &arr
, &push_opts
));
404 git_remote_disconnect(_remote
);
405 git_vector_free_deep(&delete_specs
);
407 /* Now that we've deleted everything, fetch from the remote */
408 memcpy(&fetch_opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
409 cl_git_pass(git_remote_fetch(_remote
, NULL
, &fetch_opts
, NULL
));
412 void test_online_push__cleanup(void)
415 git_remote_free(_remote
);
418 git__free(_remote_url
);
419 git__free(_remote_user
);
420 git__free(_remote_pass
);
421 git__free(_remote_ssh_key
);
422 git__free(_remote_ssh_pubkey
);
423 git__free(_remote_ssh_passphrase
);
424 git__free(_remote_default
);
425 git__free(_remote_expectcontinue
);
427 /* Freed by cl_git_sandbox_cleanup */
430 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE
, 0);
432 record_callbacks_data_clear(&_record_cbs_data
);
434 cl_fixture_cleanup("testrepo.git");
435 cl_git_sandbox_cleanup();
438 static int push_pack_progress_cb(
439 int stage
, unsigned int current
, unsigned int total
, void* payload
)
441 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
442 GIT_UNUSED(stage
); GIT_UNUSED(current
); GIT_UNUSED(total
);
443 if (data
->pack_progress_calls
< 0)
444 return data
->pack_progress_calls
;
446 data
->pack_progress_calls
++;
450 static int push_transfer_progress_cb(
451 unsigned int current
, unsigned int total
, size_t bytes
, void* payload
)
453 record_callbacks_data
*data
= (record_callbacks_data
*) payload
;
454 GIT_UNUSED(current
); GIT_UNUSED(total
); GIT_UNUSED(bytes
);
455 if (data
->transfer_progress_calls
< 0)
456 return data
->transfer_progress_calls
;
458 data
->transfer_progress_calls
++;
463 * Calls push and relists refs on remote to verify success.
465 * @param refspecs refspecs to push
466 * @param refspecs_len length of refspecs
467 * @param expected_refs expected remote refs after push
468 * @param expected_refs_len length of expected_refs
469 * @param expected_ret expected return value from git_push_finish()
470 * @param check_progress_cb Check that the push progress callbacks are called
473 const char *refspecs
[], size_t refspecs_len
,
474 push_status expected_statuses
[], size_t expected_statuses_len
,
475 expected_ref expected_refs
[], size_t expected_refs_len
,
476 int expected_ret
, int check_progress_cb
, int check_update_tips_cb
)
478 git_push_options opts
= GIT_PUSH_OPTIONS_INIT
;
481 git_strarray specs
= {0};
482 record_callbacks_data
*data
;
485 /* Auto-detect the number of threads to use */
486 opts
.pb_parallelism
= 0;
488 memcpy(&opts
.callbacks
, &_record_cbs
, sizeof(git_remote_callbacks
));
489 data
= opts
.callbacks
.payload
;
491 opts
.callbacks
.pack_progress
= push_pack_progress_cb
;
492 opts
.callbacks
.push_transfer_progress
= push_transfer_progress_cb
;
493 opts
.callbacks
.push_update_reference
= record_push_status_cb
;
496 specs
.count
= refspecs_len
;
497 specs
.strings
= git__calloc(refspecs_len
, sizeof(char *));
498 cl_assert(specs
.strings
);
501 for (i
= 0; i
< refspecs_len
; i
++)
502 specs
.strings
[i
] = (char *) refspecs
[i
];
504 /* if EUSER, then abort in transfer */
505 if (check_progress_cb
&& expected_ret
== GIT_EUSER
)
506 data
->transfer_progress_calls
= GIT_EUSER
;
508 error
= git_remote_push(_remote
, &specs
, &opts
);
509 git__free(specs
.strings
);
511 if (expected_ret
< 0) {
512 cl_git_fail_with(expected_ret
, error
);
517 if (check_progress_cb
&& expected_ret
== 0) {
518 cl_assert(data
->pack_progress_calls
> 0);
519 cl_assert(data
->transfer_progress_calls
> 0);
522 do_verify_push_status(data
, expected_statuses
, expected_statuses_len
);
524 verify_refs(_remote
, expected_refs
, expected_refs_len
);
525 verify_tracking_branches(_remote
, expected_refs
, expected_refs_len
);
527 if (check_update_tips_cb
)
528 verify_update_tips_callback(_remote
, expected_refs
, expected_refs_len
);
534 /* Call push_finish() without ever calling git_push_add_refspec() */
535 void test_online_push__noop(void)
537 do_push(NULL
, 0, NULL
, 0, NULL
, 0, 0, 0, 1);
540 void test_online_push__b1(void)
542 const char *specs
[] = { "refs/heads/b1:refs/heads/b1" };
543 push_status exp_stats
[] = { { "refs/heads/b1", 1 } };
544 expected_ref exp_refs
[] = { { "refs/heads/b1", &_oid_b1
} };
545 do_push(specs
, ARRAY_SIZE(specs
),
546 exp_stats
, ARRAY_SIZE(exp_stats
),
547 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
550 void test_online_push__b2(void)
552 const char *specs
[] = { "refs/heads/b2:refs/heads/b2" };
553 push_status exp_stats
[] = { { "refs/heads/b2", 1 } };
554 expected_ref exp_refs
[] = { { "refs/heads/b2", &_oid_b2
} };
555 do_push(specs
, ARRAY_SIZE(specs
),
556 exp_stats
, ARRAY_SIZE(exp_stats
),
557 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
560 void test_online_push__b3(void)
562 const char *specs
[] = { "refs/heads/b3:refs/heads/b3" };
563 push_status exp_stats
[] = { { "refs/heads/b3", 1 } };
564 expected_ref exp_refs
[] = { { "refs/heads/b3", &_oid_b3
} };
565 do_push(specs
, ARRAY_SIZE(specs
),
566 exp_stats
, ARRAY_SIZE(exp_stats
),
567 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
570 void test_online_push__b4(void)
572 const char *specs
[] = { "refs/heads/b4:refs/heads/b4" };
573 push_status exp_stats
[] = { { "refs/heads/b4", 1 } };
574 expected_ref exp_refs
[] = { { "refs/heads/b4", &_oid_b4
} };
575 do_push(specs
, ARRAY_SIZE(specs
),
576 exp_stats
, ARRAY_SIZE(exp_stats
),
577 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
580 void test_online_push__b5(void)
582 const char *specs
[] = { "refs/heads/b5:refs/heads/b5" };
583 push_status exp_stats
[] = { { "refs/heads/b5", 1 } };
584 expected_ref exp_refs
[] = { { "refs/heads/b5", &_oid_b5
} };
585 do_push(specs
, ARRAY_SIZE(specs
),
586 exp_stats
, ARRAY_SIZE(exp_stats
),
587 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
590 void test_online_push__b5_cancel(void)
592 const char *specs
[] = { "refs/heads/b5:refs/heads/b5" };
593 do_push(specs
, ARRAY_SIZE(specs
), NULL
, 0, NULL
, 0, GIT_EUSER
, 1, 1);
596 void test_online_push__multi(void)
599 const git_reflog_entry
*entry
;
601 const char *specs
[] = {
602 "refs/heads/b1:refs/heads/b1",
603 "refs/heads/b2:refs/heads/b2",
604 "refs/heads/b3:refs/heads/b3",
605 "refs/heads/b4:refs/heads/b4",
606 "refs/heads/b5:refs/heads/b5"
608 push_status exp_stats
[] = {
609 { "refs/heads/b1", 1 },
610 { "refs/heads/b2", 1 },
611 { "refs/heads/b3", 1 },
612 { "refs/heads/b4", 1 },
613 { "refs/heads/b5", 1 }
615 expected_ref exp_refs
[] = {
616 { "refs/heads/b1", &_oid_b1
},
617 { "refs/heads/b2", &_oid_b2
},
618 { "refs/heads/b3", &_oid_b3
},
619 { "refs/heads/b4", &_oid_b4
},
620 { "refs/heads/b5", &_oid_b5
}
622 do_push(specs
, ARRAY_SIZE(specs
),
623 exp_stats
, ARRAY_SIZE(exp_stats
),
624 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
626 cl_git_pass(git_reflog_read(&log
, _repo
, "refs/remotes/test/b1"));
627 entry
= git_reflog_entry_byindex(log
, 0);
629 cl_assert_equal_s("update by push", git_reflog_entry_message(entry
));
630 cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry
)->email
);
633 git_reflog_free(log
);
636 void test_online_push__implicit_tgt(void)
638 const char *specs1
[] = { "refs/heads/b1" };
639 push_status exp_stats1
[] = { { "refs/heads/b1", 1 } };
640 expected_ref exp_refs1
[] = { { "refs/heads/b1", &_oid_b1
} };
642 const char *specs2
[] = { "refs/heads/b2" };
643 push_status exp_stats2
[] = { { "refs/heads/b2", 1 } };
644 expected_ref exp_refs2
[] = {
645 { "refs/heads/b1", &_oid_b1
},
646 { "refs/heads/b2", &_oid_b2
}
649 do_push(specs1
, ARRAY_SIZE(specs1
),
650 exp_stats1
, ARRAY_SIZE(exp_stats1
),
651 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
652 do_push(specs2
, ARRAY_SIZE(specs2
),
653 exp_stats2
, ARRAY_SIZE(exp_stats2
),
654 exp_refs2
, ARRAY_SIZE(exp_refs2
), 0, 0, 0);
657 void test_online_push__fast_fwd(void)
659 /* Fast forward b1 in tgt from _oid_b1 to _oid_b6. */
661 const char *specs_init
[] = { "refs/heads/b1:refs/heads/b1" };
662 push_status exp_stats_init
[] = { { "refs/heads/b1", 1 } };
663 expected_ref exp_refs_init
[] = { { "refs/heads/b1", &_oid_b1
} };
665 const char *specs_ff
[] = { "refs/heads/b6:refs/heads/b1" };
666 push_status exp_stats_ff
[] = { { "refs/heads/b1", 1 } };
667 expected_ref exp_refs_ff
[] = { { "refs/heads/b1", &_oid_b6
} };
669 /* Do a force push to reset b1 in target back to _oid_b1 */
670 const char *specs_reset
[] = { "+refs/heads/b1:refs/heads/b1" };
671 /* Force should have no effect on a fast forward push */
672 const char *specs_ff_force
[] = { "+refs/heads/b6:refs/heads/b1" };
674 do_push(specs_init
, ARRAY_SIZE(specs_init
),
675 exp_stats_init
, ARRAY_SIZE(exp_stats_init
),
676 exp_refs_init
, ARRAY_SIZE(exp_refs_init
), 0, 1, 1);
678 do_push(specs_ff
, ARRAY_SIZE(specs_ff
),
679 exp_stats_ff
, ARRAY_SIZE(exp_stats_ff
),
680 exp_refs_ff
, ARRAY_SIZE(exp_refs_ff
), 0, 0, 0);
682 do_push(specs_reset
, ARRAY_SIZE(specs_reset
),
683 exp_stats_init
, ARRAY_SIZE(exp_stats_init
),
684 exp_refs_init
, ARRAY_SIZE(exp_refs_init
), 0, 0, 0);
686 do_push(specs_ff_force
, ARRAY_SIZE(specs_ff_force
),
687 exp_stats_ff
, ARRAY_SIZE(exp_stats_ff
),
688 exp_refs_ff
, ARRAY_SIZE(exp_refs_ff
), 0, 0, 0);
691 void test_online_push__tag_commit(void)
693 const char *specs
[] = { "refs/tags/tag-commit:refs/tags/tag-commit" };
694 push_status exp_stats
[] = { { "refs/tags/tag-commit", 1 } };
695 expected_ref exp_refs
[] = { { "refs/tags/tag-commit", &_tag_commit
} };
696 do_push(specs
, ARRAY_SIZE(specs
),
697 exp_stats
, ARRAY_SIZE(exp_stats
),
698 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
701 void test_online_push__tag_tree(void)
703 const char *specs
[] = { "refs/tags/tag-tree:refs/tags/tag-tree" };
704 push_status exp_stats
[] = { { "refs/tags/tag-tree", 1 } };
705 expected_ref exp_refs
[] = { { "refs/tags/tag-tree", &_tag_tree
} };
706 do_push(specs
, ARRAY_SIZE(specs
),
707 exp_stats
, ARRAY_SIZE(exp_stats
),
708 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
711 void test_online_push__tag_blob(void)
713 const char *specs
[] = { "refs/tags/tag-blob:refs/tags/tag-blob" };
714 push_status exp_stats
[] = { { "refs/tags/tag-blob", 1 } };
715 expected_ref exp_refs
[] = { { "refs/tags/tag-blob", &_tag_blob
} };
716 do_push(specs
, ARRAY_SIZE(specs
),
717 exp_stats
, ARRAY_SIZE(exp_stats
),
718 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
721 void test_online_push__tag_lightweight(void)
723 const char *specs
[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" };
724 push_status exp_stats
[] = { { "refs/tags/tag-lightweight", 1 } };
725 expected_ref exp_refs
[] = { { "refs/tags/tag-lightweight", &_tag_lightweight
} };
726 do_push(specs
, ARRAY_SIZE(specs
),
727 exp_stats
, ARRAY_SIZE(exp_stats
),
728 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
731 void test_online_push__tag_to_tag(void)
733 const char *specs
[] = { "refs/tags/tag-tag:refs/tags/tag-tag" };
734 push_status exp_stats
[] = { { "refs/tags/tag-tag", 1 } };
735 expected_ref exp_refs
[] = { { "refs/tags/tag-tag", &_tag_tag
} };
736 do_push(specs
, ARRAY_SIZE(specs
),
737 exp_stats
, ARRAY_SIZE(exp_stats
),
738 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 0, 0);
741 void test_online_push__force(void)
743 const char *specs1
[] = {"refs/heads/b3:refs/heads/tgt"};
744 push_status exp_stats1
[] = { { "refs/heads/tgt", 1 } };
745 expected_ref exp_refs1
[] = { { "refs/heads/tgt", &_oid_b3
} };
747 const char *specs2
[] = {"refs/heads/b4:refs/heads/tgt"};
749 const char *specs2_force
[] = {"+refs/heads/b4:refs/heads/tgt"};
750 push_status exp_stats2_force
[] = { { "refs/heads/tgt", 1 } };
751 expected_ref exp_refs2_force
[] = { { "refs/heads/tgt", &_oid_b4
} };
753 do_push(specs1
, ARRAY_SIZE(specs1
),
754 exp_stats1
, ARRAY_SIZE(exp_stats1
),
755 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
757 do_push(specs2
, ARRAY_SIZE(specs2
),
759 exp_refs1
, ARRAY_SIZE(exp_refs1
), GIT_ENONFASTFORWARD
, 0, 0);
761 /* Non-fast-forward update with force should pass. */
762 record_callbacks_data_clear(&_record_cbs_data
);
763 do_push(specs2_force
, ARRAY_SIZE(specs2_force
),
764 exp_stats2_force
, ARRAY_SIZE(exp_stats2_force
),
765 exp_refs2_force
, ARRAY_SIZE(exp_refs2_force
), 0, 1, 1);
768 void test_online_push__delete(void)
770 const char *specs1
[] = {
771 "refs/heads/b1:refs/heads/tgt1",
772 "refs/heads/b1:refs/heads/tgt2"
774 push_status exp_stats1
[] = {
775 { "refs/heads/tgt1", 1 },
776 { "refs/heads/tgt2", 1 }
778 expected_ref exp_refs1
[] = {
779 { "refs/heads/tgt1", &_oid_b1
},
780 { "refs/heads/tgt2", &_oid_b1
}
783 const char *specs_del_fake
[] = { ":refs/heads/fake" };
784 /* Force has no effect for delete. */
785 const char *specs_del_fake_force
[] = { "+:refs/heads/fake" };
786 push_status exp_stats_fake
[] = { { "refs/heads/fake", 1 } };
788 const char *specs_delete
[] = { ":refs/heads/tgt1" };
789 push_status exp_stats_delete
[] = { { "refs/heads/tgt1", 1 } };
790 expected_ref exp_refs_delete
[] = { { "refs/heads/tgt2", &_oid_b1
} };
791 /* Force has no effect for delete. */
792 const char *specs_delete_force
[] = { "+:refs/heads/tgt1" };
794 do_push(specs1
, ARRAY_SIZE(specs1
),
795 exp_stats1
, ARRAY_SIZE(exp_stats1
),
796 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 1, 1);
798 /* When deleting a non-existent branch, the git client sends zero for both
799 * the old and new commit id. This should succeed on the server with the
800 * same status report as if the branch were actually deleted. The server
801 * returns a warning on the side-band iff the side-band is supported.
802 * Since libgit2 doesn't support the side-band yet, there are no warnings.
804 do_push(specs_del_fake
, ARRAY_SIZE(specs_del_fake
),
806 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
807 do_push(specs_del_fake_force
, ARRAY_SIZE(specs_del_fake_force
),
809 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
811 /* Delete one of the pushed branches. */
812 do_push(specs_delete
, ARRAY_SIZE(specs_delete
),
813 exp_stats_delete
, ARRAY_SIZE(exp_stats_delete
),
814 exp_refs_delete
, ARRAY_SIZE(exp_refs_delete
), 0, 0, 0);
816 /* Re-push branches and retry delete with force. */
817 do_push(specs1
, ARRAY_SIZE(specs1
),
818 exp_stats1
, ARRAY_SIZE(exp_stats1
),
819 exp_refs1
, ARRAY_SIZE(exp_refs1
), 0, 0, 0);
820 do_push(specs_delete_force
, ARRAY_SIZE(specs_delete_force
),
821 exp_stats_delete
, ARRAY_SIZE(exp_stats_delete
),
822 exp_refs_delete
, ARRAY_SIZE(exp_refs_delete
), 0, 0, 0);
825 void test_online_push__bad_refspecs(void)
827 /* All classes of refspecs that should be rejected by
828 * git_push_add_refspec() should go in this test.
839 cl_git_fail(git_remote_upload(_remote
, &arr
, NULL
));
843 void test_online_push__expressions(void)
845 /* TODO: Expressions in refspecs doesn't actually work yet */
846 const char *specs_left_expr
[] = { "refs/heads/b2~1:refs/heads/b2" };
848 /* TODO: Find a more precise way of checking errors than a exit code of -1. */
849 do_push(specs_left_expr
, ARRAY_SIZE(specs_left_expr
),
854 void test_online_push__notes(void)
856 git_oid note_oid
, *target_oid
, expected_oid
;
857 git_signature
*signature
;
858 const char *specs
[] = { "refs/notes/commits:refs/notes/commits" };
859 push_status exp_stats
[] = { { "refs/notes/commits", 1 } };
860 expected_ref exp_refs
[] = { { "refs/notes/commits", &expected_oid
} };
861 const char *specs_del
[] = { ":refs/notes/commits" };
863 git_oid_fromstr(&expected_oid
, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
865 target_oid
= &_oid_b6
;
867 /* Create note to push */
868 cl_git_pass(git_signature_new(&signature
, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
869 cl_git_pass(git_note_create(¬e_oid
, _repo
, NULL
, signature
, signature
, target_oid
, "hello world\n", 0));
871 do_push(specs
, ARRAY_SIZE(specs
),
872 exp_stats
, ARRAY_SIZE(exp_stats
),
873 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
875 /* And make sure to delete the note */
877 do_push(specs_del
, ARRAY_SIZE(specs_del
),
881 git_signature_free(signature
);
884 void test_online_push__configured(void)
886 git_oid note_oid
, *target_oid
, expected_oid
;
887 git_signature
*signature
;
888 git_remote
*old_remote
;
889 const char *specs
[] = { "refs/notes/commits:refs/notes/commits" };
890 push_status exp_stats
[] = { { "refs/notes/commits", 1 } };
891 expected_ref exp_refs
[] = { { "refs/notes/commits", &expected_oid
} };
892 const char *specs_del
[] = { ":refs/notes/commits" };
894 git_oid_fromstr(&expected_oid
, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
896 target_oid
= &_oid_b6
;
898 cl_git_pass(git_remote_add_push(_repo
, git_remote_name(_remote
), specs
[0]));
899 old_remote
= _remote
;
900 cl_git_pass(git_remote_lookup(&_remote
, _repo
, git_remote_name(_remote
)));
901 git_remote_free(old_remote
);
903 /* Create note to push */
904 cl_git_pass(git_signature_new(&signature
, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
905 cl_git_pass(git_note_create(¬e_oid
, _repo
, NULL
, signature
, signature
, target_oid
, "hello world\n", 0));
908 exp_stats
, ARRAY_SIZE(exp_stats
),
909 exp_refs
, ARRAY_SIZE(exp_refs
), 0, 1, 1);
911 /* And make sure to delete the note */
913 do_push(specs_del
, ARRAY_SIZE(specs_del
),
917 git_signature_free(signature
);