]> git.proxmox.com Git - libgit2.git/blob - tests/remote/fetch.c
7e825ca16ca2d35d0cbed7c90cff55a71e63cb04
[libgit2.git] / tests / remote / fetch.c
1 #include "../clar_libgit2.h"
2
3 #include "remote.h"
4 #include "repository.h"
5
6 static git_repository *repo1;
7 static git_repository *repo2;
8 static char* repo1_path;
9 static char* repo2_path;
10
11 static const char *REPO1_REFNAME = "refs/heads/main";
12 static const char *REPO2_REFNAME = "refs/remotes/repo1/main";
13 static char *FORCE_FETCHSPEC = "+refs/heads/main:refs/remotes/repo1/main";
14 static char *NON_FORCE_FETCHSPEC = "refs/heads/main:refs/remotes/repo1/main";
15
16 void test_remote_fetch__initialize(void) {
17 git_config *c;
18 git_buf repo1_path_buf = GIT_BUF_INIT;
19 git_buf repo2_path_buf = GIT_BUF_INIT;
20 const char *sandbox = clar_sandbox_path();
21
22 cl_git_pass(git_buf_joinpath(&repo1_path_buf, sandbox, "fetchtest_repo1"));
23 repo1_path = git_buf_detach(&repo1_path_buf);
24 cl_git_pass(git_repository_init(&repo1, repo1_path, true));
25
26 cl_git_pass(git_buf_joinpath(&repo2_path_buf, sandbox, "fetchtest_repo2"));
27 repo2_path = git_buf_detach(&repo2_path_buf);
28 cl_git_pass(git_repository_init(&repo2, repo2_path, true));
29
30 cl_git_pass(git_repository_config(&c, repo1));
31 cl_git_pass(git_config_set_string(c, "user.email", "some@email"));
32 cl_git_pass(git_config_set_string(c, "user.name", "some@name"));
33 git_config_free(c);
34 git_buf_dispose(&repo1_path_buf);
35 git_buf_dispose(&repo2_path_buf);
36 }
37
38 void test_remote_fetch__cleanup(void) {
39 git_repository_free(repo1);
40 git_repository_free(repo2);
41
42 cl_git_pass(git_futils_rmdir_r(repo1_path, NULL, GIT_RMDIR_REMOVE_FILES));
43 free(repo1_path);
44
45 cl_git_pass(git_futils_rmdir_r(repo2_path, NULL, GIT_RMDIR_REMOVE_FILES));
46 free(repo2_path);
47 }
48
49
50 /**
51 * This checks that the '+' flag on fetchspecs is respected. We create a
52 * repository that has a reference to two commits, one a child of the other.
53 * We fetch this repository into a second repository. Then we reset the
54 * reference in the first repository and run the fetch again. If the '+' flag
55 * is used then the reference in the second repository will change, but if it
56 * is not then it should stay the same.
57 *
58 * @param commit1id A pointer to an OID which will be populated with the first
59 * commit.
60 * @param commit2id A pointer to an OID which will be populated with the second
61 * commit, which is a descendant of the first.
62 * @param force Whether to use a spec with '+' prefixed to force the refs
63 * to update
64 */
65 void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
66 bool force) {
67 char *refspec_strs = {
68 force ? FORCE_FETCHSPEC : NON_FORCE_FETCHSPEC,
69 };
70 git_strarray refspecs = {
71 .count = 1,
72 .strings = &refspec_strs,
73 };
74
75 /* create two commits in repo 1 and a reference to them */
76 {
77 git_oid empty_tree_id;
78 git_tree *empty_tree;
79 git_signature *sig;
80 git_treebuilder *tb;
81 cl_git_pass(git_treebuilder_new(&tb, repo1, NULL));
82 cl_git_pass(git_treebuilder_write(&empty_tree_id, tb));
83 cl_git_pass(git_tree_lookup(&empty_tree, repo1, &empty_tree_id));
84 cl_git_pass(git_signature_default(&sig, repo1));
85 cl_git_pass(git_commit_create(commit1id, repo1, REPO1_REFNAME, sig,
86 sig, NULL, "one", empty_tree, 0, NULL));
87 cl_git_pass(git_commit_create_v(commit2id, repo1, REPO1_REFNAME, sig,
88 sig, NULL, "two", empty_tree, 1, commit1id));
89
90 git_tree_free(empty_tree);
91 git_signature_free(sig);
92 git_treebuilder_free(tb);
93 }
94
95 /* fetch the reference via the remote */
96 {
97 git_remote *remote;
98
99 cl_git_pass(git_remote_create_anonymous(&remote, repo2,
100 git_repository_path(repo1)));
101 cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, "some message"));
102
103 git_remote_free(remote);
104 }
105
106 /* assert that repo2 references the second commit */
107 {
108 const git_oid *target;
109 git_reference *ref;
110 cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
111 target = git_reference_target(ref);
112 cl_assert_equal_b(git_oid_cmp(target, commit2id), 0);
113 git_reference_free(ref);
114 }
115
116 /* set the reference in repo1 to point to the older commit */
117 {
118 git_reference *ref;
119 git_reference *ref2;
120 cl_git_pass(git_reference_lookup(&ref, repo1, REPO1_REFNAME));
121 cl_git_pass(git_reference_set_target(&ref2, ref, commit1id,
122 "rollback"));
123 git_reference_free(ref);
124 git_reference_free(ref2);
125 }
126
127 /* fetch the reference again */
128 {
129 git_remote *remote;
130
131 cl_git_pass(git_remote_create_anonymous(&remote, repo2,
132 git_repository_path(repo1)));
133 cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, "some message"));
134
135 git_remote_free(remote);
136 }
137 }
138
139 void test_remote_fetch__dont_update_refs_if_not_descendant_and_not_force(void) {
140 const git_oid *target;
141 git_oid commit1id;
142 git_oid commit2id;
143 git_reference *ref;
144
145 do_time_travelling_fetch(&commit1id, &commit2id, false);
146
147 /* assert that the reference in repo2 has not changed */
148 cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
149 target = git_reference_target(ref);
150 cl_assert_equal_b(git_oid_cmp(target, &commit2id), 0);
151
152 git_reference_free(ref);
153 }
154
155 void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) {
156 const git_oid *target;
157 git_oid commit1id;
158 git_oid commit2id;
159 git_reference *ref;
160
161 do_time_travelling_fetch(&commit1id, &commit2id, true);
162
163 /* assert that the reference in repo2 has changed */
164 cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
165 target = git_reference_target(ref);
166 cl_assert_equal_b(git_oid_cmp(target, &commit1id), 0);
167
168 git_reference_free(ref);
169 }