]>
Commit | Line | Data |
---|---|---|
65415ea2 BS |
1 | #include "clar_libgit2.h" |
2 | ||
3 | #include "git2/clone.h" | |
520dcc1c | 4 | #include "git2/cred_helpers.h" |
6f748f38 | 5 | #include "remote.h" |
114f5a6c RB |
6 | #include "fileops.h" |
7 | #include "refs.h" | |
65415ea2 | 8 | |
44f36f6e BS |
9 | #define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository" |
10 | #define LIVE_EMPTYREPO_URL "http://github.com/libgit2/TestEmptyRepository" | |
5f10853e | 11 | #define BB_REPO_URL "https://libgit2@bitbucket.org/libgit2/testgitrepository.git" |
cf7038a6 | 12 | #define BB_REPO_URL_WITH_PASS "https://libgit2:libgit2@bitbucket.org/libgit2/testgitrepository.git" |
54ffc1f7 | 13 | #define BB_REPO_URL_WITH_WRONG_PASS "https://libgit2:wrong@bitbucket.org/libgit2/testgitrepository.git" |
1fd21b03 | 14 | #define ASSEMBLA_REPO_URL "https://libgit2:_Libgit2@git.assembla.com/libgit2-test-repos.git" |
65415ea2 | 15 | |
22618906 CMN |
16 | #define SSH_REPO_URL "ssh://github.com/libgit2/TestGitRepository" |
17 | ||
65415ea2 | 18 | static git_repository *g_repo; |
18b2d560 | 19 | static git_clone_options g_options; |
65415ea2 | 20 | |
6443eaf2 | 21 | void test_online_clone__initialize(void) |
65415ea2 | 22 | { |
6affd71f | 23 | git_checkout_options dummy_opts = GIT_CHECKOUT_OPTIONS_INIT; |
0e0cf787 | 24 | git_remote_callbacks dummy_callbacks = GIT_REMOTE_CALLBACKS_INIT; |
730df6d0 | 25 | |
65415ea2 | 26 | g_repo = NULL; |
18b2d560 BS |
27 | |
28 | memset(&g_options, 0, sizeof(git_clone_options)); | |
29 | g_options.version = GIT_CLONE_OPTIONS_VERSION; | |
730df6d0 BS |
30 | g_options.checkout_opts = dummy_opts; |
31 | g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; | |
0e0cf787 | 32 | g_options.remote_callbacks = dummy_callbacks; |
65415ea2 BS |
33 | } |
34 | ||
6443eaf2 | 35 | void test_online_clone__cleanup(void) |
65415ea2 | 36 | { |
9094d30b | 37 | if (g_repo) { |
65415ea2 | 38 | git_repository_free(g_repo); |
9094d30b SC |
39 | g_repo = NULL; |
40 | } | |
7761ce21 | 41 | cl_fixture_cleanup("./foo"); |
65415ea2 BS |
42 | } |
43 | ||
6443eaf2 | 44 | void test_online_clone__network_full(void) |
65415ea2 BS |
45 | { |
46 | git_remote *origin; | |
47 | ||
b412d563 | 48 | cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); |
65415ea2 BS |
49 | cl_assert(!git_repository_is_bare(g_repo)); |
50 | cl_git_pass(git_remote_load(&origin, g_repo, "origin")); | |
add5efe7 | 51 | |
6f748f38 JM |
52 | cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, origin->download_tags); |
53 | ||
add5efe7 | 54 | git_remote_free(origin); |
65415ea2 BS |
55 | } |
56 | ||
6443eaf2 | 57 | void test_online_clone__network_bare(void) |
65415ea2 BS |
58 | { |
59 | git_remote *origin; | |
60 | ||
18b2d560 | 61 | g_options.bare = true; |
65415ea2 | 62 | |
b412d563 | 63 | cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); |
65415ea2 BS |
64 | cl_assert(git_repository_is_bare(g_repo)); |
65 | cl_git_pass(git_remote_load(&origin, g_repo, "origin")); | |
add5efe7 | 66 | |
67 | git_remote_free(origin); | |
65415ea2 BS |
68 | } |
69 | ||
6443eaf2 | 70 | void test_online_clone__empty_repository(void) |
65415ea2 BS |
71 | { |
72 | git_reference *head; | |
73 | ||
b412d563 | 74 | cl_git_pass(git_clone(&g_repo, LIVE_EMPTYREPO_URL, "./foo", &g_options)); |
65415ea2 BS |
75 | |
76 | cl_assert_equal_i(true, git_repository_is_empty(g_repo)); | |
605da51a | 77 | cl_assert_equal_i(true, git_repository_head_unborn(g_repo)); |
65415ea2 BS |
78 | |
79 | cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); | |
80 | cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); | |
2508cc66 | 81 | cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); |
65415ea2 BS |
82 | |
83 | git_reference_free(head); | |
84 | } | |
4d968f13 | 85 | |
9c05c17b | 86 | static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload) |
183d8bdd | 87 | { |
183d8bdd | 88 | bool *was_called = (bool*)payload; |
1fc375e6 | 89 | GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot); |
183d8bdd BS |
90 | (*was_called) = true; |
91 | } | |
92 | ||
fe95ac1b | 93 | static int fetch_progress(const git_transfer_progress *stats, void *payload) |
aa1e8674 | 94 | { |
aa1e8674 | 95 | bool *was_called = (bool*)payload; |
1fc375e6 | 96 | GIT_UNUSED(stats); |
aa1e8674 | 97 | (*was_called) = true; |
fe95ac1b | 98 | return 0; |
aa1e8674 BS |
99 | } |
100 | ||
6443eaf2 | 101 | void test_online_clone__can_checkout_a_cloned_repo(void) |
4d968f13 | 102 | { |
4d968f13 | 103 | git_buf path = GIT_BUF_INIT; |
c4f68b32 | 104 | git_reference *head; |
aa1e8674 BS |
105 | bool checkout_progress_cb_was_called = false, |
106 | fetch_progress_cb_was_called = false; | |
4d968f13 | 107 | |
b3fb9237 | 108 | g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; |
730df6d0 BS |
109 | g_options.checkout_opts.progress_cb = &checkout_progress; |
110 | g_options.checkout_opts.progress_payload = &checkout_progress_cb_was_called; | |
0e0cf787 CMN |
111 | g_options.remote_callbacks.transfer_progress = &fetch_progress; |
112 | g_options.remote_callbacks.payload = &fetch_progress_cb_was_called; | |
4d968f13 | 113 | |
b412d563 | 114 | cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); |
4d968f13 | 115 | |
116 | cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt")); | |
117 | cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path))); | |
c4f68b32 | 118 | |
119 | cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); | |
120 | cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); | |
2508cc66 | 121 | cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); |
add5efe7 | 122 | |
aa1e8674 BS |
123 | cl_assert_equal_i(true, checkout_progress_cb_was_called); |
124 | cl_assert_equal_i(true, fetch_progress_cb_was_called); | |
183d8bdd | 125 | |
add5efe7 | 126 | git_reference_free(head); |
127 | git_buf_free(&path); | |
4d968f13 | 128 | } |
621b50e4 | 129 | |
d19870d9 CMN |
130 | void test_online_clone__clone_into(void) |
131 | { | |
132 | git_buf path = GIT_BUF_INIT; | |
133 | git_remote *remote; | |
134 | git_reference *head; | |
6affd71f | 135 | git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; |
d19870d9 CMN |
136 | git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; |
137 | ||
138 | bool checkout_progress_cb_was_called = false, | |
139 | fetch_progress_cb_was_called = false; | |
140 | ||
141 | checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; | |
142 | checkout_opts.progress_cb = &checkout_progress; | |
143 | checkout_opts.progress_payload = &checkout_progress_cb_was_called; | |
144 | ||
145 | cl_git_pass(git_repository_init(&g_repo, "./foo", false)); | |
146 | cl_git_pass(git_remote_create(&remote, g_repo, "origin", LIVE_REPO_URL)); | |
147 | ||
148 | callbacks.transfer_progress = &fetch_progress; | |
149 | callbacks.payload = &fetch_progress_cb_was_called; | |
150 | git_remote_set_callbacks(remote, &callbacks); | |
151 | ||
1cc974ab | 152 | cl_git_pass(git_clone_into(g_repo, remote, &checkout_opts, NULL, NULL)); |
d19870d9 CMN |
153 | |
154 | cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt")); | |
155 | cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path))); | |
156 | ||
157 | cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); | |
158 | cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); | |
159 | cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); | |
160 | ||
161 | cl_assert_equal_i(true, checkout_progress_cb_was_called); | |
162 | cl_assert_equal_i(true, fetch_progress_cb_was_called); | |
163 | ||
164 | git_remote_free(remote); | |
165 | git_reference_free(head); | |
166 | git_buf_free(&path); | |
167 | } | |
168 | ||
b2067248 CMN |
169 | void test_online_clone__clone_mirror(void) |
170 | { | |
171 | git_buf path = GIT_BUF_INIT; | |
172 | git_remote *remote; | |
173 | git_reference *head; | |
174 | git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; | |
175 | ||
176 | bool fetch_progress_cb_was_called = false; | |
177 | ||
178 | cl_git_pass(git_repository_init(&g_repo, "./foo.git", true)); | |
179 | cl_git_pass(git_remote_create(&remote, g_repo, "origin", LIVE_REPO_URL)); | |
180 | ||
181 | callbacks.transfer_progress = &fetch_progress; | |
182 | callbacks.payload = &fetch_progress_cb_was_called; | |
183 | git_remote_set_callbacks(remote, &callbacks); | |
184 | ||
185 | git_remote_clear_refspecs(remote); | |
186 | cl_git_pass(git_remote_add_fetch(remote, "+refs/*:refs/*")); | |
187 | ||
188 | cl_git_pass(git_clone_into(g_repo, remote, NULL, NULL, NULL)); | |
189 | ||
190 | cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); | |
191 | cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); | |
192 | cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); | |
193 | ||
194 | cl_assert_equal_i(true, fetch_progress_cb_was_called); | |
195 | ||
196 | git_remote_free(remote); | |
197 | git_reference_free(head); | |
198 | git_buf_free(&path); | |
6d1b0438 PK |
199 | git_repository_free(g_repo); |
200 | g_repo = NULL; | |
201 | ||
b2067248 CMN |
202 | cl_fixture_cleanup("./foo.git"); |
203 | } | |
204 | ||
621b50e4 BS |
205 | static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *payload) |
206 | { | |
207 | int *callcount = (int*)payload; | |
208 | GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); | |
209 | *callcount = *callcount + 1; | |
210 | return 0; | |
211 | } | |
212 | ||
ffb02b16 | 213 | void test_online_clone__custom_remote_callbacks(void) |
621b50e4 | 214 | { |
621b50e4 BS |
215 | int callcount = 0; |
216 | ||
0e0cf787 CMN |
217 | g_options.remote_callbacks.update_tips = update_tips; |
218 | g_options.remote_callbacks.payload = &callcount; | |
621b50e4 BS |
219 | |
220 | cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); | |
221 | cl_assert(callcount > 0); | |
222 | } | |
223 | ||
80fc7d6b ET |
224 | static int cred_failure_cb( |
225 | git_cred **cred, | |
226 | const char *url, | |
227 | const char *username_from_url, | |
228 | unsigned int allowed_types, | |
229 | void *data) | |
230 | { | |
8f2a3d62 RB |
231 | GIT_UNUSED(cred); GIT_UNUSED(url); GIT_UNUSED(username_from_url); |
232 | GIT_UNUSED(allowed_types); GIT_UNUSED(data); | |
fe45922d | 233 | return -172; |
80fc7d6b ET |
234 | } |
235 | ||
fe45922d | 236 | void test_online_clone__cred_callback_failure_return_code_is_tunnelled(void) |
80fc7d6b ET |
237 | { |
238 | const char *remote_url = cl_getenv("GITTEST_REMOTE_URL"); | |
5dae3ffe | 239 | const char *remote_user = cl_getenv("GITTEST_REMOTE_USER"); |
80fc7d6b | 240 | |
0f65733b VM |
241 | if (!remote_url || !remote_user) |
242 | clar__skip(); | |
5dae3ffe | 243 | |
80fc7d6b ET |
244 | g_options.remote_callbacks.credentials = cred_failure_cb; |
245 | ||
b529c5f9 | 246 | cl_git_fail_with(-172, git_clone(&g_repo, remote_url, "./foo", &g_options)); |
80fc7d6b ET |
247 | } |
248 | ||
d7f962f4 CMN |
249 | static int cred_count_calls_cb(git_cred **cred, const char *url, const char *user, |
250 | unsigned int allowed_types, void *data) | |
251 | { | |
252 | size_t *counter = (size_t *) data; | |
253 | ||
254 | GIT_UNUSED(url); GIT_UNUSED(user); GIT_UNUSED(allowed_types); | |
255 | ||
ccb85c8f CMN |
256 | if (allowed_types == GIT_CREDTYPE_USERNAME) |
257 | return git_cred_username_new(cred, "foo"); | |
258 | ||
d7f962f4 CMN |
259 | (*counter)++; |
260 | ||
261 | if (*counter == 3) | |
262 | return GIT_EUSER; | |
263 | ||
264 | return git_cred_userpass_plaintext_new(cred, "foo", "bar"); | |
265 | } | |
266 | ||
267 | void test_online_clone__cred_callback_called_again_on_auth_failure(void) | |
268 | { | |
269 | const char *remote_url = cl_getenv("GITTEST_REMOTE_URL"); | |
270 | const char *remote_user = cl_getenv("GITTEST_REMOTE_USER"); | |
271 | size_t counter = 0; | |
272 | ||
273 | if (!remote_url || !remote_user) | |
274 | clar__skip(); | |
275 | ||
276 | g_options.remote_callbacks.credentials = cred_count_calls_cb; | |
277 | g_options.remote_callbacks.payload = &counter; | |
278 | ||
279 | cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, remote_url, "./foo", &g_options)); | |
280 | cl_assert_equal_i(3, counter); | |
281 | } | |
282 | ||
ffb02b16 | 283 | void test_online_clone__credentials(void) |
621b50e4 BS |
284 | { |
285 | /* Remote URL environment variable must be set. User and password are optional. */ | |
286 | const char *remote_url = cl_getenv("GITTEST_REMOTE_URL"); | |
520dcc1c | 287 | git_cred_userpass_payload user_pass = { |
621b50e4 BS |
288 | cl_getenv("GITTEST_REMOTE_USER"), |
289 | cl_getenv("GITTEST_REMOTE_PASS") | |
290 | }; | |
291 | ||
292 | if (!remote_url) return; | |
293 | ||
0e0cf787 CMN |
294 | g_options.remote_callbacks.credentials = git_cred_userpass; |
295 | g_options.remote_callbacks.payload = &user_pass; | |
621b50e4 BS |
296 | |
297 | cl_git_pass(git_clone(&g_repo, remote_url, "./foo", &g_options)); | |
5f10853e BS |
298 | git_repository_free(g_repo); g_repo = NULL; |
299 | cl_fixture_cleanup("./foo"); | |
300 | } | |
301 | ||
302 | void test_online_clone__bitbucket_style(void) | |
303 | { | |
304 | git_cred_userpass_payload user_pass = { | |
305 | "libgit2", "libgit2" | |
306 | }; | |
307 | ||
0e0cf787 CMN |
308 | g_options.remote_callbacks.credentials = git_cred_userpass; |
309 | g_options.remote_callbacks.payload = &user_pass; | |
5f10853e BS |
310 | |
311 | cl_git_pass(git_clone(&g_repo, BB_REPO_URL, "./foo", &g_options)); | |
312 | git_repository_free(g_repo); g_repo = NULL; | |
313 | cl_fixture_cleanup("./foo"); | |
cf7038a6 | 314 | |
54ffc1f7 BS |
315 | /* User and pass from URL */ |
316 | user_pass.password = "wrong"; | |
cf7038a6 BS |
317 | cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_PASS, "./foo", &g_options)); |
318 | git_repository_free(g_repo); g_repo = NULL; | |
319 | cl_fixture_cleanup("./foo"); | |
54ffc1f7 BS |
320 | |
321 | /* Wrong password in URL, fall back to user_pass */ | |
322 | user_pass.password = "libgit2"; | |
323 | cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_WRONG_PASS, "./foo", &g_options)); | |
324 | git_repository_free(g_repo); g_repo = NULL; | |
325 | cl_fixture_cleanup("./foo"); | |
621b50e4 | 326 | } |
fe95ac1b | 327 | |
1fd21b03 BS |
328 | void test_online_clone__assembla_style(void) |
329 | { | |
330 | cl_git_pass(git_clone(&g_repo, ASSEMBLA_REPO_URL, "./foo", NULL)); | |
331 | } | |
332 | ||
fe95ac1b BS |
333 | static int cancel_at_half(const git_transfer_progress *stats, void *payload) |
334 | { | |
335 | GIT_UNUSED(payload); | |
336 | ||
337 | if (stats->received_objects > (stats->total_objects/2)) | |
25e0b157 | 338 | return 4321; |
fe95ac1b BS |
339 | return 0; |
340 | } | |
341 | ||
342 | void test_online_clone__can_cancel(void) | |
343 | { | |
0e0cf787 | 344 | g_options.remote_callbacks.transfer_progress = cancel_at_half; |
d31402a3 | 345 | |
25e0b157 RB |
346 | cl_git_fail_with( |
347 | git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), 4321); | |
fe95ac1b | 348 | } |
d31402a3 CMN |
349 | |
350 | ||
22618906 CMN |
351 | static int check_ssh_auth_methods(git_cred **cred, const char *url, const char *username_from_url, |
352 | unsigned int allowed_types, void *data) | |
353 | { | |
354 | GIT_UNUSED(cred); GIT_UNUSED(url); GIT_UNUSED(username_from_url); GIT_UNUSED(data); | |
d31402a3 | 355 | |
22618906 | 356 | cl_assert_equal_i(GIT_CREDTYPE_SSH_KEY | GIT_CREDTYPE_SSH_CUSTOM, allowed_types); |
d31402a3 | 357 | |
22618906 CMN |
358 | return GIT_EUSER; |
359 | } | |
d31402a3 | 360 | |
22618906 CMN |
361 | void test_online_clone__ssh_auth_methods(void) |
362 | { | |
363 | g_options.remote_callbacks.credentials = check_ssh_auth_methods; | |
d31402a3 | 364 | |
22618906 CMN |
365 | cl_git_fail_with(GIT_EUSER, |
366 | git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options)); | |
367 | } |