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