1 #include "clar_libgit2.h"
3 #include "git2/clone.h"
4 #include "git2/cred_helpers.h"
9 #define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository"
10 #define LIVE_EMPTYREPO_URL "http://github.com/libgit2/TestEmptyRepository"
11 #define BB_REPO_URL "https://libgit3@bitbucket.org/libgit2/testgitrepository.git"
12 #define BB_REPO_URL_WITH_PASS "https://libgit3:libgit3@bitbucket.org/libgit2/testgitrepository.git"
13 #define BB_REPO_URL_WITH_WRONG_PASS "https://libgit3:wrong@bitbucket.org/libgit2/testgitrepository.git"
15 #define SSH_REPO_URL "ssh://github.com/libgit2/TestGitRepository"
17 static git_repository
*g_repo
;
18 static git_clone_options g_options
;
20 void test_online_clone__initialize(void)
22 git_checkout_options dummy_opts
= GIT_CHECKOUT_OPTIONS_INIT
;
23 git_remote_callbacks dummy_callbacks
= GIT_REMOTE_CALLBACKS_INIT
;
27 memset(&g_options
, 0, sizeof(git_clone_options
));
28 g_options
.version
= GIT_CLONE_OPTIONS_VERSION
;
29 g_options
.checkout_opts
= dummy_opts
;
30 g_options
.checkout_opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
;
31 g_options
.remote_callbacks
= dummy_callbacks
;
34 void test_online_clone__cleanup(void)
37 git_repository_free(g_repo
);
40 cl_fixture_cleanup("./foo");
43 void test_online_clone__network_full(void)
47 cl_git_pass(git_clone(&g_repo
, LIVE_REPO_URL
, "./foo", &g_options
));
48 cl_assert(!git_repository_is_bare(g_repo
));
49 cl_git_pass(git_remote_load(&origin
, g_repo
, "origin"));
51 cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO
, origin
->download_tags
);
53 git_remote_free(origin
);
56 void test_online_clone__network_bare(void)
60 g_options
.bare
= true;
62 cl_git_pass(git_clone(&g_repo
, LIVE_REPO_URL
, "./foo", &g_options
));
63 cl_assert(git_repository_is_bare(g_repo
));
64 cl_git_pass(git_remote_load(&origin
, g_repo
, "origin"));
66 git_remote_free(origin
);
69 void test_online_clone__empty_repository(void)
73 cl_git_pass(git_clone(&g_repo
, LIVE_EMPTYREPO_URL
, "./foo", &g_options
));
75 cl_assert_equal_i(true, git_repository_is_empty(g_repo
));
76 cl_assert_equal_i(true, git_repository_head_unborn(g_repo
));
78 cl_git_pass(git_reference_lookup(&head
, g_repo
, GIT_HEAD_FILE
));
79 cl_assert_equal_i(GIT_REF_SYMBOLIC
, git_reference_type(head
));
80 cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head
));
82 git_reference_free(head
);
85 static void checkout_progress(const char *path
, size_t cur
, size_t tot
, void *payload
)
87 bool *was_called
= (bool*)payload
;
88 GIT_UNUSED(path
); GIT_UNUSED(cur
); GIT_UNUSED(tot
);
92 static int fetch_progress(const git_transfer_progress
*stats
, void *payload
)
94 bool *was_called
= (bool*)payload
;
100 void test_online_clone__can_checkout_a_cloned_repo(void)
102 git_buf path
= GIT_BUF_INIT
;
104 bool checkout_progress_cb_was_called
= false,
105 fetch_progress_cb_was_called
= false;
107 g_options
.checkout_opts
.checkout_strategy
= GIT_CHECKOUT_SAFE_CREATE
;
108 g_options
.checkout_opts
.progress_cb
= &checkout_progress
;
109 g_options
.checkout_opts
.progress_payload
= &checkout_progress_cb_was_called
;
110 g_options
.remote_callbacks
.transfer_progress
= &fetch_progress
;
111 g_options
.remote_callbacks
.payload
= &fetch_progress_cb_was_called
;
113 cl_git_pass(git_clone(&g_repo
, LIVE_REPO_URL
, "./foo", &g_options
));
115 cl_git_pass(git_buf_joinpath(&path
, git_repository_workdir(g_repo
), "master.txt"));
116 cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path
)));
118 cl_git_pass(git_reference_lookup(&head
, g_repo
, "HEAD"));
119 cl_assert_equal_i(GIT_REF_SYMBOLIC
, git_reference_type(head
));
120 cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head
));
122 cl_assert_equal_i(true, checkout_progress_cb_was_called
);
123 cl_assert_equal_i(true, fetch_progress_cb_was_called
);
125 git_reference_free(head
);
129 static int remote_mirror_cb(git_remote
**out
, git_repository
*repo
,
130 const char *name
, const char *url
, void *payload
)
134 git_remote_callbacks
*callbacks
= (git_remote_callbacks
*) payload
;
137 if ((error
= git_remote_create(&remote
, repo
, name
, url
)) < 0)
140 if ((error
= git_remote_set_callbacks(remote
, callbacks
)) < 0) {
141 git_remote_free(remote
);
145 git_remote_clear_refspecs(remote
);
147 if ((error
= git_remote_add_fetch(remote
, "+refs/*:refs/*")) < 0) {
148 git_remote_free(remote
);
156 void test_online_clone__clone_mirror(void)
158 git_clone_options opts
= GIT_CLONE_OPTIONS_INIT
;
160 git_remote_callbacks callbacks
= GIT_REMOTE_CALLBACKS_INIT
;
162 bool fetch_progress_cb_was_called
= false;
164 callbacks
.transfer_progress
= &fetch_progress
;
165 callbacks
.payload
= &fetch_progress_cb_was_called
;
168 opts
.remote_cb
= remote_mirror_cb
;
169 opts
.remote_cb_payload
= &callbacks
;
171 cl_git_pass(git_clone(&g_repo
, LIVE_REPO_URL
, "./foo.git", &opts
));
173 cl_git_pass(git_reference_lookup(&head
, g_repo
, "HEAD"));
174 cl_assert_equal_i(GIT_REF_SYMBOLIC
, git_reference_type(head
));
175 cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head
));
177 cl_assert_equal_i(true, fetch_progress_cb_was_called
);
179 git_reference_free(head
);
180 git_repository_free(g_repo
);
183 cl_fixture_cleanup("./foo.git");
186 static int update_tips(const char *refname
, const git_oid
*a
, const git_oid
*b
, void *payload
)
188 int *callcount
= (int*)payload
;
189 GIT_UNUSED(refname
); GIT_UNUSED(a
); GIT_UNUSED(b
);
190 *callcount
= *callcount
+ 1;
194 void test_online_clone__custom_remote_callbacks(void)
198 g_options
.remote_callbacks
.update_tips
= update_tips
;
199 g_options
.remote_callbacks
.payload
= &callcount
;
201 cl_git_pass(git_clone(&g_repo
, LIVE_REPO_URL
, "./foo", &g_options
));
202 cl_assert(callcount
> 0);
205 static int cred_failure_cb(
208 const char *username_from_url
,
209 unsigned int allowed_types
,
212 GIT_UNUSED(cred
); GIT_UNUSED(url
); GIT_UNUSED(username_from_url
);
213 GIT_UNUSED(allowed_types
); GIT_UNUSED(data
);
217 void test_online_clone__cred_callback_failure_return_code_is_tunnelled(void)
219 const char *remote_url
= cl_getenv("GITTEST_REMOTE_URL");
220 const char *remote_user
= cl_getenv("GITTEST_REMOTE_USER");
222 if (!remote_url
|| !remote_user
)
225 g_options
.remote_callbacks
.credentials
= cred_failure_cb
;
227 cl_git_fail_with(-172, git_clone(&g_repo
, remote_url
, "./foo", &g_options
));
230 static int cred_count_calls_cb(git_cred
**cred
, const char *url
, const char *user
,
231 unsigned int allowed_types
, void *data
)
233 size_t *counter
= (size_t *) data
;
235 GIT_UNUSED(url
); GIT_UNUSED(user
); GIT_UNUSED(allowed_types
);
237 if (allowed_types
== GIT_CREDTYPE_USERNAME
)
238 return git_cred_username_new(cred
, "foo");
245 return git_cred_userpass_plaintext_new(cred
, "foo", "bar");
248 void test_online_clone__cred_callback_called_again_on_auth_failure(void)
250 const char *remote_url
= cl_getenv("GITTEST_REMOTE_URL");
251 const char *remote_user
= cl_getenv("GITTEST_REMOTE_USER");
254 if (!remote_url
|| !remote_user
)
257 g_options
.remote_callbacks
.credentials
= cred_count_calls_cb
;
258 g_options
.remote_callbacks
.payload
= &counter
;
260 cl_git_fail_with(GIT_EUSER
, git_clone(&g_repo
, remote_url
, "./foo", &g_options
));
261 cl_assert_equal_i(3, counter
);
267 const char *user_from_url
,
268 unsigned int allowed_types
,
272 GIT_UNUSED(user_from_url
);
275 if (!(allowed_types
& GIT_CREDTYPE_DEFAULT
))
278 return git_cred_default_new(cred
);
281 void test_online_clone__credentials(void)
283 /* Remote URL environment variable must be set.
284 * User and password are optional.
286 const char *remote_url
= cl_getenv("GITTEST_REMOTE_URL");
287 git_cred_userpass_payload user_pass
= {
288 cl_getenv("GITTEST_REMOTE_USER"),
289 cl_getenv("GITTEST_REMOTE_PASS")
292 if (!remote_url
) return;
294 if (cl_getenv("GITTEST_REMOTE_DEFAULT")) {
295 g_options
.remote_callbacks
.credentials
= cred_default
;
297 g_options
.remote_callbacks
.credentials
= git_cred_userpass
;
298 g_options
.remote_callbacks
.payload
= &user_pass
;
301 cl_git_pass(git_clone(&g_repo
, remote_url
, "./foo", &g_options
));
302 git_repository_free(g_repo
); g_repo
= NULL
;
303 cl_fixture_cleanup("./foo");
306 void test_online_clone__bitbucket_style(void)
308 git_cred_userpass_payload user_pass
= {
312 g_options
.remote_callbacks
.credentials
= git_cred_userpass
;
313 g_options
.remote_callbacks
.payload
= &user_pass
;
315 cl_git_pass(git_clone(&g_repo
, BB_REPO_URL
, "./foo", &g_options
));
316 git_repository_free(g_repo
); g_repo
= NULL
;
317 cl_fixture_cleanup("./foo");
319 /* User and pass from URL */
320 user_pass
.password
= "wrong";
321 cl_git_pass(git_clone(&g_repo
, BB_REPO_URL_WITH_PASS
, "./foo", &g_options
));
322 git_repository_free(g_repo
); g_repo
= NULL
;
323 cl_fixture_cleanup("./foo");
325 /* Wrong password in URL, fall back to user_pass */
326 user_pass
.password
= "libgit2";
327 cl_git_pass(git_clone(&g_repo
, BB_REPO_URL_WITH_WRONG_PASS
, "./foo", &g_options
));
328 git_repository_free(g_repo
); g_repo
= NULL
;
329 cl_fixture_cleanup("./foo");
332 static int cancel_at_half(const git_transfer_progress
*stats
, void *payload
)
336 if (stats
->received_objects
> (stats
->total_objects
/2))
341 void test_online_clone__can_cancel(void)
343 g_options
.remote_callbacks
.transfer_progress
= cancel_at_half
;
346 git_clone(&g_repo
, LIVE_REPO_URL
, "./foo", &g_options
), 4321);
349 static int cred_cb(git_cred
**cred
, const char *url
, const char *user_from_url
,
350 unsigned int allowed_types
, void *payload
)
352 const char *remote_user
= cl_getenv("GITTEST_REMOTE_USER");
353 const char *pubkey
= cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
354 const char *privkey
= cl_getenv("GITTEST_REMOTE_SSH_KEY");
355 const char *passphrase
= cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
357 GIT_UNUSED(url
); GIT_UNUSED(user_from_url
); GIT_UNUSED(payload
);
359 if (allowed_types
& GIT_CREDTYPE_USERNAME
)
360 return git_cred_username_new(cred
, remote_user
);
362 if (allowed_types
& GIT_CREDTYPE_SSH_KEY
)
363 return git_cred_ssh_key_new(cred
, remote_user
, pubkey
, privkey
, passphrase
);
365 giterr_set(GITERR_NET
, "unexpected cred type");
369 static int check_ssh_auth_methods(git_cred
**cred
, const char *url
, const char *username_from_url
,
370 unsigned int allowed_types
, void *data
)
372 int *with_user
= (int *) data
;
373 GIT_UNUSED(cred
); GIT_UNUSED(url
); GIT_UNUSED(username_from_url
); GIT_UNUSED(data
);
376 cl_assert_equal_i(GIT_CREDTYPE_USERNAME
, allowed_types
);
378 cl_assert(!(allowed_types
& GIT_CREDTYPE_USERNAME
));
383 void test_online_clone__ssh_auth_methods(void)
390 g_options
.remote_callbacks
.credentials
= check_ssh_auth_methods
;
391 g_options
.remote_callbacks
.payload
= &with_user
;
394 cl_git_fail_with(GIT_EUSER
,
395 git_clone(&g_repo
, SSH_REPO_URL
, "./foo", &g_options
));
398 cl_git_fail_with(GIT_EUSER
,
399 git_clone(&g_repo
, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options
));
402 static int custom_remote_ssh_with_paths(
404 git_repository
*repo
,
410 git_remote_callbacks callbacks
= GIT_REMOTE_CALLBACKS_INIT
;
412 if ((error
= git_remote_create(out
, repo
, name
, url
)) < 0)
415 if ((error
= git_remote_set_transport(*out
, git_transport_ssh_with_paths
, payload
)) < 0)
418 callbacks
.credentials
= cred_cb
;
419 git_remote_set_callbacks(*out
, &callbacks
);
424 void test_online_clone__ssh_with_paths(void)
426 char *bad_paths
[] = {
430 char *good_paths
[] = {
431 "/usr/bin/git-upload-pack",
432 "/usr/bin/git-receive-pack",
439 const char *remote_url
= cl_getenv("GITTEST_REMOTE_URL");
440 const char *remote_user
= cl_getenv("GITTEST_REMOTE_USER");
445 if (!remote_url
|| !remote_user
|| strncmp(remote_url
, "ssh://", 5) != 0)
448 g_options
.remote_cb
= custom_remote_ssh_with_paths
;
449 g_options
.remote_cb_payload
= &arr
;
451 cl_git_fail(git_clone(&g_repo
, remote_url
, "./foo", &g_options
));
453 arr
.strings
= good_paths
;
454 cl_git_pass(git_clone(&g_repo
, remote_url
, "./foo", &g_options
));
457 static int cred_foo_bar(git_cred
**cred
, const char *url
, const char *username_from_url
,
458 unsigned int allowed_types
, void *data
)
461 GIT_UNUSED(url
); GIT_UNUSED(username_from_url
); GIT_UNUSED(allowed_types
); GIT_UNUSED(data
);
463 return git_cred_userpass_plaintext_new(cred
, "foo", "bar");
466 void test_online_clone__ssh_cannot_change_username(void)
471 g_options
.remote_callbacks
.credentials
= cred_foo_bar
;
473 cl_git_fail(git_clone(&g_repo
, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options
));
476 int ssh_certificate_check(git_cert
*cert
, int valid
, void *payload
)
478 git_cert_hostkey
*key
;
479 git_oid expected
= {{0}}, actual
= {{0}};
480 const char *expected_str
;
485 expected_str
= cl_getenv("GITTEST_REMOTE_SSH_FINGERPRINT");
489 cl_git_pass(git_oid_fromstrp(&expected
, expected_str
));
490 cl_assert_equal_i(GIT_CERT_HOSTKEY_LIBSSH2
, cert
->cert_type
);
492 key
= (git_cert_hostkey
*) cert
;
493 git_oid_fromraw(&actual
, key
->hash
);
495 cl_assert_equal_i(GIT_CERT_SSH_SHA1
, key
->type
);
497 cl_assert(git_oid_equal(&expected
, &actual
));
502 void test_online_clone__ssh_cert(void)
504 g_options
.remote_callbacks
.certificate_check
= ssh_certificate_check
;
506 cl_git_fail_with(GIT_EUSER
, git_clone(&g_repo
, "ssh://localhost/foo", "./foo", &g_options
));
509 void test_online_clone__url_with_no_path_returns_EINVALIDSPEC(void)
511 cl_git_fail_with(git_clone(&g_repo
, "http://github.com", "./foo", &g_options
),
515 static int fail_certificate_check(git_cert
*cert
, int valid
, void *payload
)
521 return GIT_ECERTIFICATE
;
524 void test_online_clone__certificate_invalid(void)
526 g_options
.remote_callbacks
.certificate_check
= fail_certificate_check
;
528 cl_git_fail_with(git_clone(&g_repo
, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options
),
532 cl_git_fail_with(git_clone(&g_repo
, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options
),
537 static int succeed_certificate_check(git_cert
*cert
, int valid
, void *payload
)
546 void test_online_clone__certificate_valid(void)
548 g_options
.remote_callbacks
.certificate_check
= succeed_certificate_check
;
550 cl_git_pass(git_clone(&g_repo
, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options
));