]>
Commit | Line | Data |
---|---|---|
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 |
10 | static git_repository *_repo; |
11 | ||
5be622fb CMN |
12 | static char *_remote_ssh_key; |
13 | static char *_remote_ssh_pubkey; | |
14 | static char *_remote_ssh_passphrase; | |
15 | ||
613d5eb9 PK |
16 | static char *_remote_url; |
17 | static char *_remote_user; | |
18 | static char *_remote_pass; | |
19 | ||
e3c131c5 CMN |
20 | static int cred_acquire_cb(git_cred **, const char *, const char *, unsigned int, void *); |
21 | ||
613d5eb9 PK |
22 | static git_remote *_remote; |
23 | static record_callbacks_data _record_cbs_data = {{ 0 }}; | |
24 | static git_remote_callbacks _record_cbs = RECORD_CALLBACKS_INIT(&_record_cbs_data); | |
25 | ||
26 | static git_oid _oid_b6; | |
27 | static git_oid _oid_b5; | |
28 | static git_oid _oid_b4; | |
29 | static git_oid _oid_b3; | |
30 | static git_oid _oid_b2; | |
31 | static git_oid _oid_b1; | |
32 | ||
abeefbbe MS |
33 | static git_oid _tag_commit; |
34 | static git_oid _tag_tree; | |
35 | static git_oid _tag_blob; | |
36 | static git_oid _tag_lightweight; | |
1c13b0bf | 37 | static git_oid _tag_tag; |
abeefbbe | 38 | |
7602cb7c | 39 | static 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 |
72 | typedef 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 | */ | |
82 | static 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 | ||
97 | static 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 | */ | |
156 | static 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 |
166 | static 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 | */ | |
186 | static 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 | ||
249 | failed: | |
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 | 264 | void 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 | 351 | void 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 | 366 | static 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 | 374 | static 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 | */ |
392 | static 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 | 447 | void test_online_push__noop(void) |
613d5eb9 | 448 | { |
b176eded | 449 | do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0); |
613d5eb9 PK |
450 | } |
451 | ||
6443eaf2 | 452 | void 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 | 462 | void 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 | 472 | void 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 | 482 | void 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 | 492 | void 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 | 502 | void 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 | 530 | void 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 | 551 | void 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 |
585 | void 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 | ||
595 | void 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 | ||
605 | void 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 | ||
615 | void 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 |
625 | void 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 | 635 | void 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 | 661 | void 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 | 718 | void 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 | 736 | void 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 | 756 | void 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(¬e_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 | } |