]> git.proxmox.com Git - libgit2.git/blame - tests-clar/online/push.c
Merge pull request #1883 from libgit2/ntk/fix/empty_first_commit_line
[libgit2.git] / tests-clar / online / push.c
CommitLineData
613d5eb9
PK
1#include "clar_libgit2.h"
2#include "buffer.h"
3#include "posix.h"
4#include "vector.h"
5#include "../submodule/submodule_helpers.h"
6#include "push_util.h"
1d645aab
JM
7#include "refspec.h"
8#include "remote.h"
613d5eb9 9
613d5eb9
PK
10static git_repository *_repo;
11
5be622fb
CMN
12static char *_remote_ssh_key;
13static char *_remote_ssh_pubkey;
14static char *_remote_ssh_passphrase;
15
613d5eb9
PK
16static char *_remote_url;
17static char *_remote_user;
18static char *_remote_pass;
19
20static git_remote *_remote;
96447d24 21static bool _cred_acquire_called;
613d5eb9
PK
22static record_callbacks_data _record_cbs_data = {{ 0 }};
23static git_remote_callbacks _record_cbs = RECORD_CALLBACKS_INIT(&_record_cbs_data);
24
25static git_oid _oid_b6;
26static git_oid _oid_b5;
27static git_oid _oid_b4;
28static git_oid _oid_b3;
29static git_oid _oid_b2;
30static git_oid _oid_b1;
31
abeefbbe
MS
32static git_oid _tag_commit;
33static git_oid _tag_tree;
34static git_oid _tag_blob;
35static git_oid _tag_lightweight;
1c13b0bf 36static git_oid _tag_tag;
abeefbbe 37
7602cb7c
BS
38static int cred_acquire_cb(
39 git_cred **cred,
40 const char *url,
41 const char *user_from_url,
42 unsigned int allowed_types,
43 void *payload)
613d5eb9
PK
44{
45 GIT_UNUSED(url);
7602cb7c 46 GIT_UNUSED(user_from_url);
613d5eb9 47
59bccf33
BS
48 *((bool*)payload) = true;
49
5be622fb
CMN
50 if (GIT_CREDTYPE_SSH_PUBLICKEY & allowed_types)
51 return git_cred_ssh_keyfile_passphrase_new(cred, _remote_user, _remote_ssh_pubkey, _remote_ssh_key, _remote_ssh_passphrase);
52
613d5eb9
PK
53 if ((GIT_CREDTYPE_USERPASS_PLAINTEXT & allowed_types) == 0 ||
54 git_cred_userpass_plaintext_new(cred, _remote_user, _remote_pass) < 0)
55 return -1;
56
57 return 0;
58}
59
60typedef struct {
61 const char *ref;
62 const char *msg;
63} push_status;
64
65/**
66 * git_push_status_foreach callback that records status entries.
67 * @param data (git_vector *) of push_status instances
68 */
69static int record_push_status_cb(const char *ref, const char *msg, void *data)
70{
71 git_vector *statuses = (git_vector *)data;
72 push_status *s;
73
74 cl_assert(s = git__malloc(sizeof(*s)));
75 s->ref = ref;
76 s->msg = msg;
77
78 git_vector_insert(statuses, s);
79
80 return 0;
81}
82
83static void do_verify_push_status(git_push *push, const push_status expected[], const size_t expected_len)
84{
85 git_vector actual = GIT_VECTOR_INIT;
86 push_status *iter;
87 bool failed = false;
88 size_t i;
89
90 git_push_status_foreach(push, record_push_status_cb, &actual);
91
92 if (expected_len != actual.length)
93 failed = true;
94 else
95 git_vector_foreach(&actual, i, iter)
96 if (strcmp(expected[i].ref, iter->ref) ||
96447d24
CW
97 (expected[i].msg && !iter->msg) ||
98 (!expected[i].msg && iter->msg) ||
99 (expected[i].msg && iter->msg && strcmp(expected[i].msg, iter->msg))) {
613d5eb9
PK
100 failed = true;
101 break;
102 }
103
104 if (failed) {
105 git_buf msg = GIT_BUF_INIT;
106
107 git_buf_puts(&msg, "Expected and actual push statuses differ:\nEXPECTED:\n");
108
109 for(i = 0; i < expected_len; i++) {
110 git_buf_printf(&msg, "%s: %s\n",
111 expected[i].ref,
112 expected[i].msg ? expected[i].msg : "<NULL>");
113 }
114
115 git_buf_puts(&msg, "\nACTUAL:\n");
116
117 git_vector_foreach(&actual, i, iter)
118 git_buf_printf(&msg, "%s: %s\n", iter->ref, iter->msg);
119
120 cl_fail(git_buf_cstr(&msg));
121
122 git_buf_free(&msg);
123 }
124
125 git_vector_foreach(&actual, i, iter)
126 git__free(iter);
127
128 git_vector_free(&actual);
129}
130
131/**
132 * Verifies that after git_push_finish(), refs on a remote have the expected
133 * names, oids, and order.
156cfec0 134 *
613d5eb9
PK
135 * @param remote remote to verify
136 * @param expected_refs expected remote refs after push
137 * @param expected_refs_len length of expected_refs
138 */
139static void verify_refs(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
140{
141 git_vector actual_refs = GIT_VECTOR_INIT;
142
143 git_remote_ls(remote, record_ref_cb, &actual_refs);
144 verify_remote_refs(&actual_refs, expected_refs, expected_refs_len);
145
146 git_vector_free(&actual_refs);
147}
148
1d645aab
JM
149static int tracking_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload)
150{
151 git_vector *tracking = (git_vector *)payload;
152
153 if (branch_type == GIT_BRANCH_REMOTE)
154 git_vector_insert(tracking, git__strdup(branch_name));
155 else
156 GIT_UNUSED(branch_name);
157
158 return 0;
159}
160
161/**
162 * Verifies that after git_push_update_tips(), remote tracking branches have the expected
163 * names and oids.
164 *
165 * @param remote remote to verify
166 * @param expected_refs expected remote refs after push
167 * @param expected_refs_len length of expected_refs
168 */
169static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
170{
4330ab26 171 git_refspec *fetch_spec;
1d645aab
JM
172 size_t i, j;
173 git_buf msg = GIT_BUF_INIT;
174 git_buf ref_name = GIT_BUF_INIT;
175 git_buf canonical_ref_name = GIT_BUF_INIT;
176 git_vector actual_refs = GIT_VECTOR_INIT;
177 char *actual_ref;
178 git_oid oid;
179 int failed = 0;
180
181 /* Get current remote branches */
182 cl_git_pass(git_branch_foreach(remote->repo, GIT_BRANCH_REMOTE, tracking_branch_list_cb, &actual_refs));
183
184 /* Loop through expected refs, make sure they exist */
185 for (i = 0; i < expected_refs_len; i++) {
186
187 /* Convert remote reference name into tracking branch name.
188 * If the spec is not under refs/heads/, then skip.
189 */
4330ab26
CMN
190 fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name);
191 if (!fetch_spec)
1d645aab
JM
192 continue;
193
194 cl_git_pass(git_refspec_transform_r(&ref_name, fetch_spec, expected_refs[i].name));
195
196 /* Find matching remote branch */
197 git_vector_foreach(&actual_refs, j, actual_ref) {
198
199 /* Construct canonical ref name from the actual_ref name */
200 git_buf_clear(&canonical_ref_name);
201 cl_git_pass(git_buf_printf(&canonical_ref_name, "refs/remotes/%s", actual_ref));
202 if (!strcmp(git_buf_cstr(&ref_name), git_buf_cstr(&canonical_ref_name)))
203 break;
204 }
205
206 if (j == actual_refs.length) {
207 git_buf_printf(&msg, "Did not find expected tracking branch '%s'.", git_buf_cstr(&ref_name));
208 failed = 1;
209 goto failed;
210 }
211
212 /* Make sure tracking branch is at expected commit ID */
213 cl_git_pass(git_reference_name_to_id(&oid, remote->repo, git_buf_cstr(&canonical_ref_name)));
214
215 if (git_oid_cmp(expected_refs[i].oid, &oid) != 0) {
216 git_buf_puts(&msg, "Tracking branch commit does not match expected ID.");
217 failed = 1;
218 goto failed;
219 }
220
2ff4469a 221 git__free(actual_ref);
1d645aab
JM
222 cl_git_pass(git_vector_remove(&actual_refs, j));
223 }
224
225 /* Make sure there are no extra branches */
226 if (actual_refs.length > 0) {
227 git_buf_puts(&msg, "Unexpected remote tracking branches exist.");
228 failed = 1;
229 goto failed;
230 }
231
232failed:
233
234 if(failed)
235 cl_fail(git_buf_cstr(&msg));
236
237 git_vector_foreach(&actual_refs, i, actual_ref)
238 git__free(actual_ref);
239
240 git_vector_free(&actual_refs);
241 git_buf_free(&msg);
2ff4469a
PK
242 git_buf_free(&canonical_ref_name);
243 git_buf_free(&ref_name);
1d645aab
JM
244 return;
245}
246
6443eaf2 247void test_online_push__initialize(void)
613d5eb9
PK
248{
249 git_vector delete_specs = GIT_VECTOR_INIT;
250 size_t i;
251 char *curr_del_spec;
96447d24 252 _cred_acquire_called = false;
613d5eb9
PK
253
254 _repo = cl_git_sandbox_init("push_src");
255
256 cl_fixture_sandbox("testrepo.git");
257 cl_rename("push_src/submodule/.gitted", "push_src/submodule/.git");
258
259 rewrite_gitmodules(git_repository_workdir(_repo));
260
261 /* git log --format=oneline --decorate --graph
262 * *-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, b6) merge b3, b4, and b5 to b6
263 * |\ \
264 * | | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git'
265 * | * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt
266 * | |/
267 * * | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt
268 * |/
269 * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt
270 * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt
271 */
272 git_oid_fromstr(&_oid_b6, "951bbbb90e2259a4c8950db78946784fb53fcbce");
273 git_oid_fromstr(&_oid_b5, "fa38b91f199934685819bea316186d8b008c52a2");
274 git_oid_fromstr(&_oid_b4, "27b7ce66243eb1403862d05f958c002312df173d");
275 git_oid_fromstr(&_oid_b3, "d9b63a88223d8367516f50bd131a5f7349b7f3e4");
276 git_oid_fromstr(&_oid_b2, "a78705c3b2725f931d3ee05348d83cc26700f247");
277 git_oid_fromstr(&_oid_b1, "a78705c3b2725f931d3ee05348d83cc26700f247");
278
abeefbbe
MS
279 git_oid_fromstr(&_tag_commit, "805c54522e614f29f70d2413a0470247d8b424ac");
280 git_oid_fromstr(&_tag_tree, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e");
281 git_oid_fromstr(&_tag_blob, "b483ae7ba66decee9aee971f501221dea84b1498");
282 git_oid_fromstr(&_tag_lightweight, "951bbbb90e2259a4c8950db78946784fb53fcbce");
1c13b0bf 283 git_oid_fromstr(&_tag_tag, "eea4f2705eeec2db3813f2430829afce99cd00b5");
abeefbbe 284
613d5eb9
PK
285 /* Remote URL environment variable must be set. User and password are optional. */
286 _remote_url = cl_getenv("GITTEST_REMOTE_URL");
287 _remote_user = cl_getenv("GITTEST_REMOTE_USER");
288 _remote_pass = cl_getenv("GITTEST_REMOTE_PASS");
5be622fb
CMN
289 _remote_ssh_key = cl_getenv("GITTEST_REMOTE_SSH_KEY");
290 _remote_ssh_pubkey = cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
291 _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
613d5eb9
PK
292 _remote = NULL;
293
294 if (_remote_url) {
29f27599 295 cl_git_pass(git_remote_create(&_remote, _repo, "test", _remote_url));
613d5eb9 296
96447d24 297 git_remote_set_cred_acquire_cb(_remote, cred_acquire_cb, &_cred_acquire_called);
613d5eb9
PK
298 record_callbacks_data_clear(&_record_cbs_data);
299 git_remote_set_callbacks(_remote, &_record_cbs);
300
301 cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH));
302
303 /* Clean up previously pushed branches. Fails if receive.denyDeletes is
304 * set on the remote. Also, on Git 1.7.0 and newer, you must run
305 * 'git config receive.denyDeleteCurrent ignore' in the remote repo in
306 * order to delete the remote branch pointed to by HEAD (usually master).
307 * See: https://raw.github.com/git/git/master/Documentation/RelNotes/1.7.0.txt
308 */
309 cl_git_pass(git_remote_ls(_remote, delete_ref_cb, &delete_specs));
310 if (delete_specs.length) {
311 git_push *push;
312
313 cl_git_pass(git_push_new(&push, _remote));
314
315 git_vector_foreach(&delete_specs, i, curr_del_spec) {
316 git_push_add_refspec(push, curr_del_spec);
317 git__free(curr_del_spec);
318 }
319
320 cl_git_pass(git_push_finish(push));
321 git_push_free(push);
322 }
323
324 git_remote_disconnect(_remote);
325 git_vector_free(&delete_specs);
326
327 /* Now that we've deleted everything, fetch from the remote */
328 cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_FETCH));
329 cl_git_pass(git_remote_download(_remote, NULL, NULL));
330 cl_git_pass(git_remote_update_tips(_remote));
331 git_remote_disconnect(_remote);
332 } else
333 printf("GITTEST_REMOTE_URL unset; skipping push test\n");
334}
335
6443eaf2 336void test_online_push__cleanup(void)
613d5eb9
PK
337{
338 if (_remote)
339 git_remote_free(_remote);
c4e3e797
BS
340 _remote = NULL;
341
342 /* Freed by cl_git_sandbox_cleanup */
343 _repo = NULL;
613d5eb9
PK
344
345 record_callbacks_data_clear(&_record_cbs_data);
346
347 cl_fixture_cleanup("testrepo.git");
348 cl_git_sandbox_cleanup();
349}
350
351/**
352 * Calls push and relists refs on remote to verify success.
156cfec0 353 *
613d5eb9
PK
354 * @param refspecs refspecs to push
355 * @param refspecs_len length of refspecs
356 * @param expected_refs expected remote refs after push
357 * @param expected_refs_len length of expected_refs
358 * @param expected_ret expected return value from git_push_finish()
359 */
360static void do_push(const char *refspecs[], size_t refspecs_len,
361 push_status expected_statuses[], size_t expected_statuses_len,
362 expected_ref expected_refs[], size_t expected_refs_len, int expected_ret)
363{
364 git_push *push;
b8b897bb 365 git_push_options opts = GIT_PUSH_OPTIONS_INIT;
613d5eb9
PK
366 size_t i;
367 int ret;
368
369 if (_remote) {
b8b897bb
PK
370 /* Auto-detect the number of threads to use */
371 opts.pb_parallelism = 0;
372
613d5eb9
PK
373 cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH));
374
375 cl_git_pass(git_push_new(&push, _remote));
b8b897bb 376 cl_git_pass(git_push_set_options(push, &opts));
613d5eb9
PK
377
378 for (i = 0; i < refspecs_len; i++)
379 cl_git_pass(git_push_add_refspec(push, refspecs[i]));
380
381 if (expected_ret < 0) {
382 cl_git_fail(ret = git_push_finish(push));
383 cl_assert_equal_i(0, git_push_unpack_ok(push));
384 }
385 else {
386 cl_git_pass(ret = git_push_finish(push));
387 cl_assert_equal_i(1, git_push_unpack_ok(push));
388 }
389
390 do_verify_push_status(push, expected_statuses, expected_statuses_len);
391
392 cl_assert_equal_i(expected_ret, ret);
393
613d5eb9
PK
394 verify_refs(_remote, expected_refs, expected_refs_len);
395
1d645aab
JM
396 cl_git_pass(git_push_update_tips(push));
397 verify_tracking_branches(_remote, expected_refs, expected_refs_len);
398
399 git_push_free(push);
613d5eb9
PK
400
401 git_remote_disconnect(_remote);
402 }
403}
404
405/* Call push_finish() without ever calling git_push_add_refspec() */
6443eaf2 406void test_online_push__noop(void)
613d5eb9
PK
407{
408 do_push(NULL, 0, NULL, 0, NULL, 0, 0);
409}
410
6443eaf2 411void test_online_push__b1(void)
613d5eb9
PK
412{
413 const char *specs[] = { "refs/heads/b1:refs/heads/b1" };
414 push_status exp_stats[] = { { "refs/heads/b1", NULL } };
415 expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } };
416 do_push(specs, ARRAY_SIZE(specs),
417 exp_stats, ARRAY_SIZE(exp_stats),
418 exp_refs, ARRAY_SIZE(exp_refs), 0);
419}
420
6443eaf2 421void test_online_push__b2(void)
613d5eb9
PK
422{
423 const char *specs[] = { "refs/heads/b2:refs/heads/b2" };
424 push_status exp_stats[] = { { "refs/heads/b2", NULL } };
425 expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } };
426 do_push(specs, ARRAY_SIZE(specs),
427 exp_stats, ARRAY_SIZE(exp_stats),
428 exp_refs, ARRAY_SIZE(exp_refs), 0);
429}
430
6443eaf2 431void test_online_push__b3(void)
613d5eb9
PK
432{
433 const char *specs[] = { "refs/heads/b3:refs/heads/b3" };
434 push_status exp_stats[] = { { "refs/heads/b3", NULL } };
435 expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } };
436 do_push(specs, ARRAY_SIZE(specs),
437 exp_stats, ARRAY_SIZE(exp_stats),
438 exp_refs, ARRAY_SIZE(exp_refs), 0);
439}
440
6443eaf2 441void test_online_push__b4(void)
613d5eb9
PK
442{
443 const char *specs[] = { "refs/heads/b4:refs/heads/b4" };
444 push_status exp_stats[] = { { "refs/heads/b4", NULL } };
445 expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } };
446 do_push(specs, ARRAY_SIZE(specs),
447 exp_stats, ARRAY_SIZE(exp_stats),
448 exp_refs, ARRAY_SIZE(exp_refs), 0);
449}
450
6443eaf2 451void test_online_push__b5(void)
613d5eb9
PK
452{
453 const char *specs[] = { "refs/heads/b5:refs/heads/b5" };
454 push_status exp_stats[] = { { "refs/heads/b5", NULL } };
455 expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } };
456 do_push(specs, ARRAY_SIZE(specs),
457 exp_stats, ARRAY_SIZE(exp_stats),
458 exp_refs, ARRAY_SIZE(exp_refs), 0);
459}
460
6443eaf2 461void test_online_push__multi(void)
613d5eb9
PK
462{
463 const char *specs[] = {
464 "refs/heads/b1:refs/heads/b1",
465 "refs/heads/b2:refs/heads/b2",
466 "refs/heads/b3:refs/heads/b3",
467 "refs/heads/b4:refs/heads/b4",
468 "refs/heads/b5:refs/heads/b5"
469 };
470 push_status exp_stats[] = {
471 { "refs/heads/b1", NULL },
472 { "refs/heads/b2", NULL },
473 { "refs/heads/b3", NULL },
474 { "refs/heads/b4", NULL },
475 { "refs/heads/b5", NULL }
476 };
477 expected_ref exp_refs[] = {
478 { "refs/heads/b1", &_oid_b1 },
479 { "refs/heads/b2", &_oid_b2 },
480 { "refs/heads/b3", &_oid_b3 },
481 { "refs/heads/b4", &_oid_b4 },
482 { "refs/heads/b5", &_oid_b5 }
483 };
484 do_push(specs, ARRAY_SIZE(specs),
485 exp_stats, ARRAY_SIZE(exp_stats),
486 exp_refs, ARRAY_SIZE(exp_refs), 0);
487}
488
6443eaf2 489void test_online_push__implicit_tgt(void)
613d5eb9
PK
490{
491 const char *specs1[] = { "refs/heads/b1:" };
492 push_status exp_stats1[] = { { "refs/heads/b1", NULL } };
493 expected_ref exp_refs1[] = { { "refs/heads/b1", &_oid_b1 } };
494
495 const char *specs2[] = { "refs/heads/b2:" };
496 push_status exp_stats2[] = { { "refs/heads/b2", NULL } };
497 expected_ref exp_refs2[] = {
498 { "refs/heads/b1", &_oid_b1 },
499 { "refs/heads/b2", &_oid_b2 }
500 };
501
502 do_push(specs1, ARRAY_SIZE(specs1),
503 exp_stats1, ARRAY_SIZE(exp_stats1),
504 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
505 do_push(specs2, ARRAY_SIZE(specs2),
506 exp_stats2, ARRAY_SIZE(exp_stats2),
507 exp_refs2, ARRAY_SIZE(exp_refs2), 0);
508}
509
6443eaf2 510void test_online_push__fast_fwd(void)
613d5eb9
PK
511{
512 /* Fast forward b1 in tgt from _oid_b1 to _oid_b6. */
513
514 const char *specs_init[] = { "refs/heads/b1:refs/heads/b1" };
515 push_status exp_stats_init[] = { { "refs/heads/b1", NULL } };
516 expected_ref exp_refs_init[] = { { "refs/heads/b1", &_oid_b1 } };
517
518 const char *specs_ff[] = { "refs/heads/b6:refs/heads/b1" };
519 push_status exp_stats_ff[] = { { "refs/heads/b1", NULL } };
520 expected_ref exp_refs_ff[] = { { "refs/heads/b1", &_oid_b6 } };
521
522 /* Do a force push to reset b1 in target back to _oid_b1 */
523 const char *specs_reset[] = { "+refs/heads/b1:refs/heads/b1" };
524 /* Force should have no effect on a fast forward push */
525 const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" };
526
527 do_push(specs_init, ARRAY_SIZE(specs_init),
528 exp_stats_init, ARRAY_SIZE(exp_stats_init),
529 exp_refs_init, ARRAY_SIZE(exp_refs_init), 0);
530
531 do_push(specs_ff, ARRAY_SIZE(specs_ff),
532 exp_stats_ff, ARRAY_SIZE(exp_stats_ff),
533 exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0);
534
535 do_push(specs_reset, ARRAY_SIZE(specs_reset),
536 exp_stats_init, ARRAY_SIZE(exp_stats_init),
537 exp_refs_init, ARRAY_SIZE(exp_refs_init), 0);
538
539 do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force),
540 exp_stats_ff, ARRAY_SIZE(exp_stats_ff),
541 exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0);
542}
543
abeefbbe
MS
544void test_online_push__tag_commit(void)
545{
546 const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" };
547 push_status exp_stats[] = { { "refs/tags/tag-commit", NULL } };
548 expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } };
549 do_push(specs, ARRAY_SIZE(specs),
550 exp_stats, ARRAY_SIZE(exp_stats),
551 exp_refs, ARRAY_SIZE(exp_refs), 0);
552}
553
554void test_online_push__tag_tree(void)
555{
556 const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" };
557 push_status exp_stats[] = { { "refs/tags/tag-tree", NULL } };
558 expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } };
559 do_push(specs, ARRAY_SIZE(specs),
560 exp_stats, ARRAY_SIZE(exp_stats),
561 exp_refs, ARRAY_SIZE(exp_refs), 0);
562}
563
564void test_online_push__tag_blob(void)
565{
566 const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" };
567 push_status exp_stats[] = { { "refs/tags/tag-blob", NULL } };
568 expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } };
569 do_push(specs, ARRAY_SIZE(specs),
570 exp_stats, ARRAY_SIZE(exp_stats),
571 exp_refs, ARRAY_SIZE(exp_refs), 0);
572}
573
574void test_online_push__tag_lightweight(void)
575{
576 const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" };
577 push_status exp_stats[] = { { "refs/tags/tag-lightweight", NULL } };
578 expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } };
579 do_push(specs, ARRAY_SIZE(specs),
580 exp_stats, ARRAY_SIZE(exp_stats),
581 exp_refs, ARRAY_SIZE(exp_refs), 0);
582}
583
1c13b0bf
ET
584void test_online_push__tag_to_tag(void)
585{
586 const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" };
587 push_status exp_stats[] = { { "refs/tags/tag-tag", NULL } };
588 expected_ref exp_refs[] = { { "refs/tags/tag-tag", &_tag_tag } };
589 do_push(specs, ARRAY_SIZE(specs),
590 exp_stats, ARRAY_SIZE(exp_stats),
591 exp_refs, ARRAY_SIZE(exp_refs), 0);
592}
593
6443eaf2 594void test_online_push__force(void)
613d5eb9
PK
595{
596 const char *specs1[] = {"refs/heads/b3:refs/heads/tgt"};
597 push_status exp_stats1[] = { { "refs/heads/tgt", NULL } };
598 expected_ref exp_refs1[] = { { "refs/heads/tgt", &_oid_b3 } };
599
600 const char *specs2[] = {"refs/heads/b4:refs/heads/tgt"};
601
602 const char *specs2_force[] = {"+refs/heads/b4:refs/heads/tgt"};
603 push_status exp_stats2_force[] = { { "refs/heads/tgt", NULL } };
604 expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } };
605
606 do_push(specs1, ARRAY_SIZE(specs1),
607 exp_stats1, ARRAY_SIZE(exp_stats1),
608 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
609
610 do_push(specs2, ARRAY_SIZE(specs2),
611 NULL, 0,
612 exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD);
613
614 /* Non-fast-forward update with force should pass. */
615 do_push(specs2_force, ARRAY_SIZE(specs2_force),
616 exp_stats2_force, ARRAY_SIZE(exp_stats2_force),
617 exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0);
618}
619
6443eaf2 620void test_online_push__delete(void)
613d5eb9
PK
621{
622 const char *specs1[] = {
623 "refs/heads/b1:refs/heads/tgt1",
624 "refs/heads/b1:refs/heads/tgt2"
625 };
626 push_status exp_stats1[] = {
627 { "refs/heads/tgt1", NULL },
628 { "refs/heads/tgt2", NULL }
629 };
630 expected_ref exp_refs1[] = {
631 { "refs/heads/tgt1", &_oid_b1 },
632 { "refs/heads/tgt2", &_oid_b1 }
633 };
634
635 const char *specs_del_fake[] = { ":refs/heads/fake" };
636 /* Force has no effect for delete. */
637 const char *specs_del_fake_force[] = { "+:refs/heads/fake" };
d73d52df 638 push_status exp_stats_fake[] = { { "refs/heads/fake", NULL } };
613d5eb9
PK
639
640 const char *specs_delete[] = { ":refs/heads/tgt1" };
641 push_status exp_stats_delete[] = { { "refs/heads/tgt1", NULL } };
642 expected_ref exp_refs_delete[] = { { "refs/heads/tgt2", &_oid_b1 } };
643 /* Force has no effect for delete. */
644 const char *specs_delete_force[] = { "+:refs/heads/tgt1" };
645
646 do_push(specs1, ARRAY_SIZE(specs1),
647 exp_stats1, ARRAY_SIZE(exp_stats1),
648 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
649
d73d52df
CW
650 /* When deleting a non-existent branch, the git client sends zero for both
651 * the old and new commit id. This should succeed on the server with the
652 * same status report as if the branch were actually deleted. The server
653 * returns a warning on the side-band iff the side-band is supported.
654 * Since libgit2 doesn't support the side-band yet, there are no warnings.
613d5eb9
PK
655 */
656 do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake),
d73d52df
CW
657 exp_stats_fake, 1,
658 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
613d5eb9 659 do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force),
d73d52df
CW
660 exp_stats_fake, 1,
661 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
613d5eb9
PK
662
663 /* Delete one of the pushed branches. */
664 do_push(specs_delete, ARRAY_SIZE(specs_delete),
665 exp_stats_delete, ARRAY_SIZE(exp_stats_delete),
666 exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0);
667
668 /* Re-push branches and retry delete with force. */
669 do_push(specs1, ARRAY_SIZE(specs1),
670 exp_stats1, ARRAY_SIZE(exp_stats1),
671 exp_refs1, ARRAY_SIZE(exp_refs1), 0);
672 do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force),
673 exp_stats_delete, ARRAY_SIZE(exp_stats_delete),
674 exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0);
675}
676
6443eaf2 677void test_online_push__bad_refspecs(void)
613d5eb9
PK
678{
679 /* All classes of refspecs that should be rejected by
680 * git_push_add_refspec() should go in this test.
681 */
682 git_push *push;
683
684 if (_remote) {
b412d563 685// cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH));
613d5eb9
PK
686 cl_git_pass(git_push_new(&push, _remote));
687
688 /* Unexpanded branch names not supported */
689 cl_git_fail(git_push_add_refspec(push, "b6:b6"));
690
691 git_push_free(push);
692 }
693}
694
6443eaf2 695void test_online_push__expressions(void)
613d5eb9
PK
696{
697 /* TODO: Expressions in refspecs doesn't actually work yet */
698 const char *specs_left_expr[] = { "refs/heads/b2~1:refs/heads/b2" };
699
700 const char *specs_right_expr[] = { "refs/heads/b2:refs/heads/b2~1" };
701 push_status exp_stats_right_expr[] = { { "refs/heads/b2~1", "funny refname" } };
702
703 /* TODO: Find a more precise way of checking errors than a exit code of -1. */
704 do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr),
705 NULL, 0,
706 NULL, 0, -1);
707
708 do_push(specs_right_expr, ARRAY_SIZE(specs_right_expr),
709 exp_stats_right_expr, ARRAY_SIZE(exp_stats_right_expr),
710 NULL, 0, 0);
711}
087f64d3 712
abeefbbe 713void test_online_push__notes(void)
087f64d3
JM
714{
715 git_oid note_oid, *target_oid, expected_oid;
716 git_signature *signature;
717 const char *specs[] = { "refs/notes/commits:refs/notes/commits" };
718 push_status exp_stats[] = { { "refs/notes/commits", NULL } };
719 expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } };
720 git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
721
722 target_oid = &_oid_b6;
723
724 /* Create note to push */
725 cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
abeefbbe 726 cl_git_pass(git_note_create(&note_oid, _repo, signature, signature, NULL, target_oid, "hello world\n", 0));
087f64d3
JM
727
728 do_push(specs, ARRAY_SIZE(specs),
729 exp_stats, ARRAY_SIZE(exp_stats),
730 exp_refs, ARRAY_SIZE(exp_refs), 0);
731
732 git_signature_free(signature);
733}