]> git.proxmox.com Git - libgit2.git/blame - tests/online/push.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / online / push.c
CommitLineData
613d5eb9 1#include "clar_libgit2.h"
613d5eb9
PK
2#include "posix.h"
3#include "vector.h"
4#include "../submodule/submodule_helpers.h"
5#include "push_util.h"
1d645aab
JM
6#include "refspec.h"
7#include "remote.h"
613d5eb9 8
613d5eb9
PK
9static git_repository *_repo;
10
e069c621 11static char *_remote_url = NULL;
84efffc3 12
e069c621
ET
13static char *_remote_user = NULL;
14static char *_remote_pass = NULL;
5be622fb 15
e069c621
ET
16static char *_remote_ssh_key = NULL;
17static char *_remote_ssh_pubkey = NULL;
18static char *_remote_ssh_passphrase = NULL;
613d5eb9 19
e069c621 20static char *_remote_default = NULL;
22a2d3d5 21static char *_remote_expectcontinue = NULL;
84efffc3 22
22a2d3d5 23static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *);
e3c131c5 24
613d5eb9
PK
25static git_remote *_remote;
26static record_callbacks_data _record_cbs_data = {{ 0 }};
27static git_remote_callbacks _record_cbs = RECORD_CALLBACKS_INIT(&_record_cbs_data);
28
29static git_oid _oid_b6;
30static git_oid _oid_b5;
31static git_oid _oid_b4;
32static git_oid _oid_b3;
33static git_oid _oid_b2;
34static git_oid _oid_b1;
35
abeefbbe
MS
36static git_oid _tag_commit;
37static git_oid _tag_tree;
38static git_oid _tag_blob;
39static git_oid _tag_lightweight;
1c13b0bf 40static git_oid _tag_tag;
abeefbbe 41
7602cb7c 42static int cred_acquire_cb(
22a2d3d5 43 git_credential **cred,
2648dc1a
ET
44 const char *url,
45 const char *user_from_url,
46 unsigned int allowed_types,
47 void *payload)
613d5eb9
PK
48{
49 GIT_UNUSED(url);
7602cb7c 50 GIT_UNUSED(user_from_url);
2648dc1a 51 GIT_UNUSED(payload);
613d5eb9 52
22a2d3d5 53 if (GIT_CREDENTIAL_USERNAME & allowed_types) {
e26b08d3
CMN
54 if (!_remote_user) {
55 printf("GITTEST_REMOTE_USER must be set\n");
56 return -1;
57 }
58
22a2d3d5 59 return git_credential_username_new(cred, _remote_user);
e26b08d3
CMN
60 }
61
22a2d3d5 62 if (GIT_CREDENTIAL_DEFAULT & allowed_types) {
84efffc3
ET
63 if (!_remote_default) {
64 printf("GITTEST_REMOTE_DEFAULT must be set to use NTLM/Negotiate credentials\n");
65 return -1;
66 }
67
22a2d3d5 68 return git_credential_default_new(cred);
84efffc3
ET
69 }
70
22a2d3d5 71 if (GIT_CREDENTIAL_SSH_KEY & allowed_types) {
2648dc1a
ET
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");
74 return -1;
75 }
84efffc3 76
22a2d3d5 77 return git_credential_ssh_key_new(cred, _remote_user, _remote_ssh_pubkey, _remote_ssh_key, _remote_ssh_passphrase);
2648dc1a 78 }
5be622fb 79
22a2d3d5 80 if (GIT_CREDENTIAL_USERPASS_PLAINTEXT & allowed_types) {
2648dc1a
ET
81 if (!_remote_user || !_remote_pass) {
82 printf("GITTEST_REMOTE_USER and GITTEST_REMOTE_PASS must be set\n");
83 return -1;
84 }
613d5eb9 85
22a2d3d5 86 return git_credential_userpass_plaintext_new(cred, _remote_user, _remote_pass);
2648dc1a
ET
87 }
88
89 return -1;
613d5eb9
PK
90}
91
613d5eb9
PK
92/**
93 * git_push_status_foreach callback that records status entries.
613d5eb9 94 */
6eb9e39c 95static int record_push_status_cb(const char *ref, const char *msg, void *payload)
613d5eb9 96{
6eb9e39c 97 record_callbacks_data *data = (record_callbacks_data *) payload;
613d5eb9
PK
98 push_status *s;
99
6eb9e39c
CMN
100 cl_assert(s = git__calloc(1, sizeof(*s)));
101 if (ref)
102 cl_assert(s->ref = git__strdup(ref));
9d41984c 103 s->success = (msg == NULL);
6eb9e39c
CMN
104 if (msg)
105 cl_assert(s->msg = git__strdup(msg));
613d5eb9 106
6eb9e39c 107 git_vector_insert(&data->statuses, s);
613d5eb9
PK
108
109 return 0;
110}
111
6eb9e39c 112static void do_verify_push_status(record_callbacks_data *data, const push_status expected[], const size_t expected_len)
613d5eb9 113{
6eb9e39c 114 git_vector *actual = &data->statuses;
613d5eb9
PK
115 push_status *iter;
116 bool failed = false;
117 size_t i;
118
6eb9e39c 119 if (expected_len != actual->length)
613d5eb9
PK
120 failed = true;
121 else
6eb9e39c 122 git_vector_foreach(actual, i, iter)
613d5eb9 123 if (strcmp(expected[i].ref, iter->ref) ||
9d41984c
ET
124 (expected[i].success != iter->success) ||
125 (expected[i].msg && (!iter->msg || strcmp(expected[i].msg, iter->msg)))) {
613d5eb9
PK
126 failed = true;
127 break;
128 }
129
130 if (failed) {
e579e0f7 131 git_str msg = GIT_STR_INIT;
613d5eb9 132
e579e0f7 133 git_str_puts(&msg, "Expected and actual push statuses differ:\nEXPECTED:\n");
613d5eb9
PK
134
135 for(i = 0; i < expected_len; i++) {
e579e0f7 136 git_str_printf(&msg, "%s: %s\n",
613d5eb9 137 expected[i].ref,
9d41984c 138 expected[i].success ? "success" : "failed");
613d5eb9
PK
139 }
140
e579e0f7 141 git_str_puts(&msg, "\nACTUAL:\n");
613d5eb9 142
6eb9e39c 143 git_vector_foreach(actual, i, iter) {
9d41984c 144 if (iter->success)
e579e0f7 145 git_str_printf(&msg, "%s: success\n", iter->ref);
9d41984c 146 else
e579e0f7 147 git_str_printf(&msg, "%s: failed with message: %s", iter->ref, iter->msg);
9d41984c 148 }
613d5eb9 149
e579e0f7 150 cl_fail(git_str_cstr(&msg));
613d5eb9 151
e579e0f7 152 git_str_dispose(&msg);
613d5eb9
PK
153 }
154
6c7cee42
RD
155 git_vector_foreach(actual, i, iter) {
156 push_status *s = (push_status *)iter;
157 git__free(s->ref);
158 git__free(s->msg);
159 git__free(s);
160 }
613d5eb9 161
6eb9e39c 162 git_vector_free(actual);
613d5eb9
PK
163}
164
165/**
166 * Verifies that after git_push_finish(), refs on a remote have the expected
167 * names, oids, and order.
156cfec0 168 *
613d5eb9
PK
169 * @param remote remote to verify
170 * @param expected_refs expected remote refs after push
171 * @param expected_refs_len length of expected_refs
172 */
173static void verify_refs(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
174{
359dce72
CMN
175 const git_remote_head **actual_refs;
176 size_t actual_refs_len;
613d5eb9 177
359dce72
CMN
178 git_remote_ls(&actual_refs, &actual_refs_len, remote);
179 verify_remote_refs(actual_refs, actual_refs_len, expected_refs, expected_refs_len);
613d5eb9
PK
180}
181
1d645aab
JM
182/**
183 * Verifies that after git_push_update_tips(), remote tracking branches have the expected
184 * names and oids.
185 *
186 * @param remote remote to verify
187 * @param expected_refs expected remote refs after push
188 * @param expected_refs_len length of expected_refs
189 */
190static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
191{
4330ab26 192 git_refspec *fetch_spec;
1d645aab 193 size_t i, j;
e579e0f7 194 git_str msg = GIT_STR_INIT;
1d645aab 195 git_buf ref_name = GIT_BUF_INIT;
1d645aab 196 git_vector actual_refs = GIT_VECTOR_INIT;
8ec889a4 197 git_branch_iterator *iter;
1d645aab
JM
198 char *actual_ref;
199 git_oid oid;
8ec889a4 200 int failed = 0, error;
a667ca82 201 git_branch_t branch_type;
8ec889a4 202 git_reference *ref;
1d645aab 203
fe794b2e 204 /* Get current remote-tracking branches */
8ec889a4
CMN
205 cl_git_pass(git_branch_iterator_new(&iter, remote->repo, GIT_BRANCH_REMOTE));
206
207 while ((error = git_branch_next(&ref, &branch_type, iter)) == 0) {
208 cl_assert_equal_i(branch_type, GIT_BRANCH_REMOTE);
209
210 cl_git_pass(git_vector_insert(&actual_refs, git__strdup(git_reference_name(ref))));
f96e7e6c
ET
211
212 git_reference_free(ref);
8ec889a4
CMN
213 }
214
215 cl_assert_equal_i(error, GIT_ITEROVER);
11bd7a03 216 git_branch_iterator_free(iter);
1d645aab
JM
217
218 /* Loop through expected refs, make sure they exist */
219 for (i = 0; i < expected_refs_len; i++) {
220
fe794b2e 221 /* Convert remote reference name into remote-tracking branch name.
1d645aab
JM
222 * If the spec is not under refs/heads/, then skip.
223 */
4330ab26
CMN
224 fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name);
225 if (!fetch_spec)
1d645aab
JM
226 continue;
227
bf522e08 228 cl_git_pass(git_refspec_transform(&ref_name, fetch_spec, expected_refs[i].name));
1d645aab
JM
229
230 /* Find matching remote branch */
231 git_vector_foreach(&actual_refs, j, actual_ref) {
e579e0f7 232 if (!strcmp(ref_name.ptr, actual_ref))
1d645aab
JM
233 break;
234 }
235
236 if (j == actual_refs.length) {
e579e0f7 237 git_str_printf(&msg, "Did not find expected tracking branch '%s'.", ref_name.ptr);
1d645aab
JM
238 failed = 1;
239 goto failed;
240 }
241
242 /* Make sure tracking branch is at expected commit ID */
8ec889a4 243 cl_git_pass(git_reference_name_to_id(&oid, remote->repo, actual_ref));
1d645aab
JM
244
245 if (git_oid_cmp(expected_refs[i].oid, &oid) != 0) {
e579e0f7 246 git_str_puts(&msg, "Tracking branch commit does not match expected ID.");
1d645aab
JM
247 failed = 1;
248 goto failed;
249 }
250
2ff4469a 251 git__free(actual_ref);
1d645aab
JM
252 cl_git_pass(git_vector_remove(&actual_refs, j));
253 }
254
255 /* Make sure there are no extra branches */
256 if (actual_refs.length > 0) {
e579e0f7 257 git_str_puts(&msg, "Unexpected remote tracking branches exist.");
1d645aab
JM
258 failed = 1;
259 goto failed;
260 }
261
262failed:
f70cfd34 263 if (failed)
e579e0f7 264 cl_fail(git_str_cstr(&msg));
1d645aab
JM
265
266 git_vector_foreach(&actual_refs, i, actual_ref)
267 git__free(actual_ref);
268
269 git_vector_free(&actual_refs);
e579e0f7 270 git_str_dispose(&msg);
ac3d33df 271 git_buf_dispose(&ref_name);
f70cfd34
JG
272}
273
274static void verify_update_tips_callback(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len)
275{
276 git_refspec *fetch_spec;
e579e0f7 277 git_str msg = GIT_STR_INIT;
f70cfd34
JG
278 git_buf ref_name = GIT_BUF_INIT;
279 updated_tip *tip = NULL;
280 size_t i, j;
281 int failed = 0;
282
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.
286 */
287 fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name);
288 if (!fetch_spec)
289 continue;
290
291 cl_git_pass(git_refspec_transform(&ref_name, fetch_spec, expected_refs[i].name));
292
293 /* Find matching update_tip entry */
294 git_vector_foreach(&_record_cbs_data.updated_tips, j, tip) {
e579e0f7 295 if (!strcmp(ref_name.ptr, tip->name))
f70cfd34
JG
296 break;
297 }
298
299 if (j == _record_cbs_data.updated_tips.length) {
e579e0f7 300 git_str_printf(&msg, "Did not find expected updated tip entry for branch '%s'.", ref_name.ptr);
f70cfd34
JG
301 failed = 1;
302 goto failed;
303 }
304
1af5aecb 305 if (git_oid_cmp(expected_refs[i].oid, &tip->new_oid) != 0) {
e579e0f7 306 git_str_printf(&msg, "Updated tip ID does not match expected ID");
f70cfd34
JG
307 failed = 1;
308 goto failed;
309 }
310 }
311
312failed:
313 if (failed)
e579e0f7 314 cl_fail(git_str_cstr(&msg));
f70cfd34 315
ac3d33df 316 git_buf_dispose(&ref_name);
e579e0f7 317 git_str_dispose(&msg);
1d645aab
JM
318}
319
6443eaf2 320void test_online_push__initialize(void)
613d5eb9
PK
321{
322 git_vector delete_specs = GIT_VECTOR_INIT;
ae297212 323 const git_remote_head **heads;
fe794b2e 324 size_t heads_len;
0f69b41d
CMN
325 git_push_options push_opts = GIT_PUSH_OPTIONS_INIT;
326 git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
613d5eb9
PK
327
328 _repo = cl_git_sandbox_init("push_src");
329
659cf202 330 cl_git_pass(git_repository_set_ident(_repo, "Random J. Hacker", "foo@example.com"));
613d5eb9
PK
331 cl_fixture_sandbox("testrepo.git");
332 cl_rename("push_src/submodule/.gitted", "push_src/submodule/.git");
333
334 rewrite_gitmodules(git_repository_workdir(_repo));
335
336 /* git log --format=oneline --decorate --graph
337 * *-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, b6) merge b3, b4, and b5 to b6
338 * |\ \
339 * | | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git'
340 * | * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt
341 * | |/
342 * * | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt
343 * |/
344 * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt
345 * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt
346 */
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");
353
abeefbbe
MS
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");
1c13b0bf 358 git_oid_fromstr(&_tag_tag, "eea4f2705eeec2db3813f2430829afce99cd00b5");
abeefbbe 359
613d5eb9 360 /* Remote URL environment variable must be set. User and password are optional. */
e069c621 361
613d5eb9
PK
362 _remote_url = cl_getenv("GITTEST_REMOTE_URL");
363 _remote_user = cl_getenv("GITTEST_REMOTE_USER");
364 _remote_pass = cl_getenv("GITTEST_REMOTE_PASS");
5be622fb
CMN
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");
84efffc3 368 _remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT");
22a2d3d5 369 _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
613d5eb9
PK
370 _remote = NULL;
371
0f65733b
VM
372 /* Skip the test if we're missing the remote URL */
373 if (!_remote_url)
374 cl_skip();
613d5eb9 375
22a2d3d5
UG
376 if (_remote_expectcontinue)
377 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
378
0f65733b 379 cl_git_pass(git_remote_create(&_remote, _repo, "test", _remote_url));
613d5eb9 380
0f65733b 381 record_callbacks_data_clear(&_record_cbs_data);
613d5eb9 382
07bd3e57 383 cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs, NULL, NULL));
613d5eb9 384
0f65733b
VM
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
390 */
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) {
fe794b2e
CMN
394 git_strarray arr = {
395 (char **) delete_specs.contents,
396 delete_specs.length,
397 };
613d5eb9 398
0f69b41d
CMN
399 memcpy(&push_opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks));
400 cl_git_pass(git_remote_upload(_remote, &arr, &push_opts));
0f65733b
VM
401 }
402
403 git_remote_disconnect(_remote);
6c7cee42 404 git_vector_free_deep(&delete_specs);
613d5eb9 405
0f65733b 406 /* Now that we've deleted everything, fetch from the remote */
0f69b41d
CMN
407 memcpy(&fetch_opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks));
408 cl_git_pass(git_remote_fetch(_remote, NULL, &fetch_opts, NULL));
613d5eb9
PK
409}
410
6443eaf2 411void test_online_push__cleanup(void)
613d5eb9
PK
412{
413 if (_remote)
414 git_remote_free(_remote);
c4e3e797
BS
415 _remote = NULL;
416
e069c621
ET
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);
22a2d3d5 424 git__free(_remote_expectcontinue);
e069c621 425
c4e3e797
BS
426 /* Freed by cl_git_sandbox_cleanup */
427 _repo = NULL;
613d5eb9 428
22a2d3d5
UG
429 git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 0);
430
613d5eb9
PK
431 record_callbacks_data_clear(&_record_cbs_data);
432
433 cl_fixture_cleanup("testrepo.git");
434 cl_git_sandbox_cleanup();
435}
436
11bd7a03
RB
437static int push_pack_progress_cb(
438 int stage, unsigned int current, unsigned int total, void* payload)
b176eded 439{
6eb9e39c 440 record_callbacks_data *data = (record_callbacks_data *) payload;
7baa7631 441 GIT_UNUSED(stage); GIT_UNUSED(current); GIT_UNUSED(total);
6eb9e39c
CMN
442 if (data->pack_progress_calls < 0)
443 return data->pack_progress_calls;
444
445 data->pack_progress_calls++;
5b188225 446 return 0;
b176eded
JM
447}
448
11bd7a03
RB
449static int push_transfer_progress_cb(
450 unsigned int current, unsigned int total, size_t bytes, void* payload)
b176eded 451{
6eb9e39c 452 record_callbacks_data *data = (record_callbacks_data *) payload;
af302aca 453 GIT_UNUSED(current); GIT_UNUSED(total); GIT_UNUSED(bytes);
6eb9e39c
CMN
454 if (data->transfer_progress_calls < 0)
455 return data->transfer_progress_calls;
456
457 data->transfer_progress_calls++;
5b188225 458 return 0;
b176eded
JM
459}
460
613d5eb9
PK
461/**
462 * Calls push and relists refs on remote to verify success.
156cfec0 463 *
613d5eb9
PK
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()
b176eded 469 * @param check_progress_cb Check that the push progress callbacks are called
613d5eb9 470 */
11bd7a03
RB
471static void do_push(
472 const char *refspecs[], size_t refspecs_len,
613d5eb9 473 push_status expected_statuses[], size_t expected_statuses_len,
11bd7a03 474 expected_ref expected_refs[], size_t expected_refs_len,
f70cfd34 475 int expected_ret, int check_progress_cb, int check_update_tips_cb)
613d5eb9 476{
b8b897bb 477 git_push_options opts = GIT_PUSH_OPTIONS_INIT;
613d5eb9 478 size_t i;
6eb9e39c 479 int error;
64e3e6d4 480 git_strarray specs = {0};
6eb9e39c 481 record_callbacks_data *data;
613d5eb9
PK
482
483 if (_remote) {
b8b897bb
PK
484 /* Auto-detect the number of threads to use */
485 opts.pb_parallelism = 0;
486
8f0104ec
CMN
487 memcpy(&opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks));
488 data = opts.callbacks.payload;
613d5eb9 489
8f0104ec
CMN
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;
11bd7a03 493
64e3e6d4
CMN
494 if (refspecs_len) {
495 specs.count = refspecs_len;
496 specs.strings = git__calloc(refspecs_len, sizeof(char *));
497 cl_assert(specs.strings);
11bd7a03 498 }
b176eded 499
613d5eb9 500 for (i = 0; i < refspecs_len; i++)
6eb9e39c
CMN
501 specs.strings[i] = (char *) refspecs[i];
502
503 /* if EUSER, then abort in transfer */
504 if (check_progress_cb && expected_ret == GIT_EUSER)
505 data->transfer_progress_calls = GIT_EUSER;
506
412a3808 507 error = git_remote_push(_remote, &specs, &opts);
6eb9e39c 508 git__free(specs.strings);
613d5eb9
PK
509
510 if (expected_ret < 0) {
6eb9e39c 511 cl_git_fail_with(expected_ret, error);
11bd7a03 512 } else {
6eb9e39c 513 cl_git_pass(error);
613d5eb9
PK
514 }
515
6eb9e39c
CMN
516 if (check_progress_cb && expected_ret == 0) {
517 cl_assert(data->pack_progress_calls > 0);
518 cl_assert(data->transfer_progress_calls > 0);
b176eded
JM
519 }
520
6eb9e39c 521 do_verify_push_status(data, expected_statuses, expected_statuses_len);
613d5eb9 522
613d5eb9 523 verify_refs(_remote, expected_refs, expected_refs_len);
1d645aab
JM
524 verify_tracking_branches(_remote, expected_refs, expected_refs_len);
525
f70cfd34
JG
526 if (check_update_tips_cb)
527 verify_update_tips_callback(_remote, expected_refs, expected_refs_len);
528
613d5eb9 529 }
491cecfe 530
613d5eb9
PK
531}
532
533/* Call push_finish() without ever calling git_push_add_refspec() */
6443eaf2 534void test_online_push__noop(void)
613d5eb9 535{
f70cfd34 536 do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1);
613d5eb9
PK
537}
538
6443eaf2 539void test_online_push__b1(void)
613d5eb9
PK
540{
541 const char *specs[] = { "refs/heads/b1:refs/heads/b1" };
9d41984c 542 push_status exp_stats[] = { { "refs/heads/b1", 1 } };
613d5eb9
PK
543 expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } };
544 do_push(specs, ARRAY_SIZE(specs),
545 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 546 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
613d5eb9
PK
547}
548
6443eaf2 549void test_online_push__b2(void)
613d5eb9
PK
550{
551 const char *specs[] = { "refs/heads/b2:refs/heads/b2" };
9d41984c 552 push_status exp_stats[] = { { "refs/heads/b2", 1 } };
613d5eb9
PK
553 expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } };
554 do_push(specs, ARRAY_SIZE(specs),
555 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 556 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
613d5eb9
PK
557}
558
6443eaf2 559void test_online_push__b3(void)
613d5eb9
PK
560{
561 const char *specs[] = { "refs/heads/b3:refs/heads/b3" };
9d41984c 562 push_status exp_stats[] = { { "refs/heads/b3", 1 } };
613d5eb9
PK
563 expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } };
564 do_push(specs, ARRAY_SIZE(specs),
565 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 566 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
613d5eb9
PK
567}
568
6443eaf2 569void test_online_push__b4(void)
613d5eb9
PK
570{
571 const char *specs[] = { "refs/heads/b4:refs/heads/b4" };
9d41984c 572 push_status exp_stats[] = { { "refs/heads/b4", 1 } };
613d5eb9
PK
573 expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } };
574 do_push(specs, ARRAY_SIZE(specs),
575 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 576 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
613d5eb9
PK
577}
578
6443eaf2 579void test_online_push__b5(void)
613d5eb9
PK
580{
581 const char *specs[] = { "refs/heads/b5:refs/heads/b5" };
9d41984c 582 push_status exp_stats[] = { { "refs/heads/b5", 1 } };
613d5eb9
PK
583 expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } };
584 do_push(specs, ARRAY_SIZE(specs),
585 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 586 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
613d5eb9
PK
587}
588
11bd7a03
RB
589void test_online_push__b5_cancel(void)
590{
591 const char *specs[] = { "refs/heads/b5:refs/heads/b5" };
f70cfd34 592 do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1);
11bd7a03
RB
593}
594
6443eaf2 595void test_online_push__multi(void)
613d5eb9 596{
491cecfe
BS
597 git_reflog *log;
598 const git_reflog_entry *entry;
599
613d5eb9
PK
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"
606 };
607 push_status exp_stats[] = {
9d41984c
ET
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 }
613d5eb9
PK
613 };
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 }
620 };
621 do_push(specs, ARRAY_SIZE(specs),
622 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 623 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
491cecfe
BS
624
625 cl_git_pass(git_reflog_read(&log, _repo, "refs/remotes/test/b1"));
626 entry = git_reflog_entry_byindex(log, 0);
3094102f 627 if (entry) {
412a3808 628 cl_assert_equal_s("update by push", git_reflog_entry_message(entry));
3094102f
BS
629 cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry)->email);
630 }
491cecfe
BS
631
632 git_reflog_free(log);
613d5eb9
PK
633}
634
6443eaf2 635void test_online_push__implicit_tgt(void)
613d5eb9 636{
aad638f3 637 const char *specs1[] = { "refs/heads/b1" };
9d41984c 638 push_status exp_stats1[] = { { "refs/heads/b1", 1 } };
613d5eb9
PK
639 expected_ref exp_refs1[] = { { "refs/heads/b1", &_oid_b1 } };
640
aad638f3 641 const char *specs2[] = { "refs/heads/b2" };
9d41984c 642 push_status exp_stats2[] = { { "refs/heads/b2", 1 } };
613d5eb9
PK
643 expected_ref exp_refs2[] = {
644 { "refs/heads/b1", &_oid_b1 },
645 { "refs/heads/b2", &_oid_b2 }
646 };
647
648 do_push(specs1, ARRAY_SIZE(specs1),
649 exp_stats1, ARRAY_SIZE(exp_stats1),
f70cfd34 650 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1);
613d5eb9
PK
651 do_push(specs2, ARRAY_SIZE(specs2),
652 exp_stats2, ARRAY_SIZE(exp_stats2),
f70cfd34 653 exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0);
613d5eb9
PK
654}
655
6443eaf2 656void test_online_push__fast_fwd(void)
613d5eb9
PK
657{
658 /* Fast forward b1 in tgt from _oid_b1 to _oid_b6. */
659
660 const char *specs_init[] = { "refs/heads/b1:refs/heads/b1" };
9d41984c 661 push_status exp_stats_init[] = { { "refs/heads/b1", 1 } };
613d5eb9
PK
662 expected_ref exp_refs_init[] = { { "refs/heads/b1", &_oid_b1 } };
663
664 const char *specs_ff[] = { "refs/heads/b6:refs/heads/b1" };
9d41984c 665 push_status exp_stats_ff[] = { { "refs/heads/b1", 1 } };
613d5eb9
PK
666 expected_ref exp_refs_ff[] = { { "refs/heads/b1", &_oid_b6 } };
667
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" };
672
673 do_push(specs_init, ARRAY_SIZE(specs_init),
674 exp_stats_init, ARRAY_SIZE(exp_stats_init),
f70cfd34 675 exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1);
613d5eb9
PK
676
677 do_push(specs_ff, ARRAY_SIZE(specs_ff),
678 exp_stats_ff, ARRAY_SIZE(exp_stats_ff),
f70cfd34 679 exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0);
613d5eb9
PK
680
681 do_push(specs_reset, ARRAY_SIZE(specs_reset),
682 exp_stats_init, ARRAY_SIZE(exp_stats_init),
f70cfd34 683 exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0);
613d5eb9
PK
684
685 do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force),
686 exp_stats_ff, ARRAY_SIZE(exp_stats_ff),
f70cfd34 687 exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0);
613d5eb9
PK
688}
689
abeefbbe
MS
690void test_online_push__tag_commit(void)
691{
692 const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" };
9d41984c 693 push_status exp_stats[] = { { "refs/tags/tag-commit", 1 } };
abeefbbe
MS
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),
f70cfd34 697 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
abeefbbe
MS
698}
699
700void test_online_push__tag_tree(void)
701{
702 const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" };
9d41984c 703 push_status exp_stats[] = { { "refs/tags/tag-tree", 1 } };
abeefbbe
MS
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),
f70cfd34 707 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
abeefbbe
MS
708}
709
710void test_online_push__tag_blob(void)
711{
712 const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" };
9d41984c 713 push_status exp_stats[] = { { "refs/tags/tag-blob", 1 } };
abeefbbe
MS
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),
f70cfd34 717 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
abeefbbe
MS
718}
719
720void test_online_push__tag_lightweight(void)
721{
722 const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" };
9d41984c 723 push_status exp_stats[] = { { "refs/tags/tag-lightweight", 1 } };
abeefbbe
MS
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),
f70cfd34 727 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
abeefbbe
MS
728}
729
1c13b0bf
ET
730void test_online_push__tag_to_tag(void)
731{
732 const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" };
9d41984c 733 push_status exp_stats[] = { { "refs/tags/tag-tag", 1 } };
1c13b0bf
ET
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),
f70cfd34 737 exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0);
1c13b0bf
ET
738}
739
6443eaf2 740void test_online_push__force(void)
613d5eb9
PK
741{
742 const char *specs1[] = {"refs/heads/b3:refs/heads/tgt"};
9d41984c 743 push_status exp_stats1[] = { { "refs/heads/tgt", 1 } };
613d5eb9
PK
744 expected_ref exp_refs1[] = { { "refs/heads/tgt", &_oid_b3 } };
745
746 const char *specs2[] = {"refs/heads/b4:refs/heads/tgt"};
747
748 const char *specs2_force[] = {"+refs/heads/b4:refs/heads/tgt"};
9d41984c 749 push_status exp_stats2_force[] = { { "refs/heads/tgt", 1 } };
613d5eb9
PK
750 expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } };
751
752 do_push(specs1, ARRAY_SIZE(specs1),
753 exp_stats1, ARRAY_SIZE(exp_stats1),
f70cfd34 754 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1);
613d5eb9
PK
755
756 do_push(specs2, ARRAY_SIZE(specs2),
757 NULL, 0,
f70cfd34 758 exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0);
613d5eb9
PK
759
760 /* Non-fast-forward update with force should pass. */
f70cfd34 761 record_callbacks_data_clear(&_record_cbs_data);
613d5eb9
PK
762 do_push(specs2_force, ARRAY_SIZE(specs2_force),
763 exp_stats2_force, ARRAY_SIZE(exp_stats2_force),
f70cfd34 764 exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1);
613d5eb9
PK
765}
766
6443eaf2 767void test_online_push__delete(void)
613d5eb9
PK
768{
769 const char *specs1[] = {
770 "refs/heads/b1:refs/heads/tgt1",
771 "refs/heads/b1:refs/heads/tgt2"
772 };
773 push_status exp_stats1[] = {
9d41984c
ET
774 { "refs/heads/tgt1", 1 },
775 { "refs/heads/tgt2", 1 }
613d5eb9
PK
776 };
777 expected_ref exp_refs1[] = {
778 { "refs/heads/tgt1", &_oid_b1 },
779 { "refs/heads/tgt2", &_oid_b1 }
780 };
781
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" };
9d41984c 785 push_status exp_stats_fake[] = { { "refs/heads/fake", 1 } };
613d5eb9
PK
786
787 const char *specs_delete[] = { ":refs/heads/tgt1" };
9d41984c 788 push_status exp_stats_delete[] = { { "refs/heads/tgt1", 1 } };
613d5eb9
PK
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" };
792
793 do_push(specs1, ARRAY_SIZE(specs1),
794 exp_stats1, ARRAY_SIZE(exp_stats1),
f70cfd34 795 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1);
613d5eb9 796
d73d52df
CW
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.
613d5eb9
PK
802 */
803 do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake),
d73d52df 804 exp_stats_fake, 1,
f70cfd34 805 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0);
613d5eb9 806 do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force),
d73d52df 807 exp_stats_fake, 1,
f70cfd34 808 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0);
613d5eb9
PK
809
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),
f70cfd34 813 exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0);
613d5eb9
PK
814
815 /* Re-push branches and retry delete with force. */
816 do_push(specs1, ARRAY_SIZE(specs1),
817 exp_stats1, ARRAY_SIZE(exp_stats1),
f70cfd34 818 exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0);
613d5eb9
PK
819 do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force),
820 exp_stats_delete, ARRAY_SIZE(exp_stats_delete),
f70cfd34 821 exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0);
613d5eb9
PK
822}
823
6443eaf2 824void test_online_push__bad_refspecs(void)
613d5eb9
PK
825{
826 /* All classes of refspecs that should be rejected by
827 * git_push_add_refspec() should go in this test.
828 */
fe794b2e
CMN
829 char *specs = {
830 "b6:b6",
831 };
832 git_strarray arr = {
833 &specs,
834 1,
835 };
613d5eb9
PK
836
837 if (_remote) {
fe794b2e 838 cl_git_fail(git_remote_upload(_remote, &arr, NULL));
613d5eb9
PK
839 }
840}
841
6443eaf2 842void test_online_push__expressions(void)
613d5eb9
PK
843{
844 /* TODO: Expressions in refspecs doesn't actually work yet */
845 const char *specs_left_expr[] = { "refs/heads/b2~1:refs/heads/b2" };
846
613d5eb9
PK
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),
849 NULL, 0,
f70cfd34 850 NULL, 0, -1, 0, 0);
613d5eb9 851}
087f64d3 852
abeefbbe 853void test_online_push__notes(void)
087f64d3
JM
854{
855 git_oid note_oid, *target_oid, expected_oid;
856 git_signature *signature;
857 const char *specs[] = { "refs/notes/commits:refs/notes/commits" };
9d41984c 858 push_status exp_stats[] = { { "refs/notes/commits", 1 } };
087f64d3 859 expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } };
0f29e967 860 const char *specs_del[] = { ":refs/notes/commits" };
0f29e967 861
087f64d3
JM
862 git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
863
864 target_oid = &_oid_b6;
865
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 */
21083a71 868 cl_git_pass(git_note_create(&note_oid, _repo, NULL, signature, signature, target_oid, "hello world\n", 0));
087f64d3
JM
869
870 do_push(specs, ARRAY_SIZE(specs),
871 exp_stats, ARRAY_SIZE(exp_stats),
f70cfd34 872 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
087f64d3 873
0f29e967
ET
874 /* And make sure to delete the note */
875
876 do_push(specs_del, ARRAY_SIZE(specs_del),
877 exp_stats, 1,
aff70018 878 NULL, 0, 0, 0, 0);
0f29e967 879
087f64d3
JM
880 git_signature_free(signature);
881}
64e3e6d4
CMN
882
883void test_online_push__configured(void)
884{
885 git_oid note_oid, *target_oid, expected_oid;
886 git_signature *signature;
77254990 887 git_remote *old_remote;
64e3e6d4
CMN
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" };
892
893 git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb");
894
895 target_oid = &_oid_b6;
896
77254990
CMN
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);
64e3e6d4
CMN
901
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 */
21083a71 904 cl_git_pass(git_note_create(&note_oid, _repo, NULL, signature, signature, target_oid, "hello world\n", 0));
64e3e6d4
CMN
905
906 do_push(NULL, 0,
907 exp_stats, ARRAY_SIZE(exp_stats),
908 exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1);
909
910 /* And make sure to delete the note */
911
912 do_push(specs_del, ARRAY_SIZE(specs_del),
913 exp_stats, 1,
914 NULL, 0, 0, 0, 0);
915
916 git_signature_free(signature);
917}