1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.reftree;
45
46 import static org.eclipse.jgit.lib.Constants.HEAD;
47 import static org.eclipse.jgit.lib.Constants.R_HEADS;
48 import static org.eclipse.jgit.lib.Constants.R_TAGS;
49 import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
50 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
51 import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
52 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
53 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
54 import static org.junit.Assert.assertEquals;
55 import static org.junit.Assert.assertFalse;
56 import static org.junit.Assert.assertNotNull;
57 import static org.junit.Assert.assertNull;
58 import static org.junit.Assert.assertSame;
59 import static org.junit.Assert.assertTrue;
60
61 import java.io.IOException;
62 import java.util.Arrays;
63 import java.util.Collections;
64
65 import org.eclipse.jgit.errors.MissingObjectException;
66 import org.eclipse.jgit.internal.JGitText;
67 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
68 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
69 import org.eclipse.jgit.junit.TestRepository;
70 import org.eclipse.jgit.lib.ObjectId;
71 import org.eclipse.jgit.lib.ObjectIdRef;
72 import org.eclipse.jgit.lib.ObjectInserter;
73 import org.eclipse.jgit.lib.ObjectReader;
74 import org.eclipse.jgit.lib.Ref;
75 import org.eclipse.jgit.lib.SymbolicRef;
76 import org.eclipse.jgit.revwalk.RevBlob;
77 import org.eclipse.jgit.revwalk.RevTag;
78 import org.eclipse.jgit.revwalk.RevWalk;
79 import org.eclipse.jgit.transport.ReceiveCommand;
80 import org.junit.Before;
81 import org.junit.Test;
82
83 public class RefTreeTest {
84 private static final String R_MASTER = R_HEADS + "master";
85 private InMemoryRepository repo;
86 private TestRepository<InMemoryRepository> git;
87
88 @Before
89 public void setUp() throws IOException {
90 repo = new InMemoryRepository(new DfsRepositoryDescription("RefTree"));
91 git = new TestRepository<>(repo);
92 }
93
94 @Test
95 public void testEmptyTree() throws IOException {
96 RefTree tree = RefTree.newEmptyTree();
97 try (ObjectReader reader = repo.newObjectReader()) {
98 assertNull(HEAD, tree.exactRef(reader, HEAD));
99 assertNull("master", tree.exactRef(reader, R_MASTER));
100 }
101 }
102
103 @Test
104 public void testApplyThenReadMaster() throws Exception {
105 RefTree tree = RefTree.newEmptyTree();
106 RevBlob id = git.blob("A");
107 Command cmd = new Command(null, ref(R_MASTER, id));
108 assertTrue(tree.apply(Collections.singletonList(cmd)));
109 assertSame(NOT_ATTEMPTED, cmd.getResult());
110
111 try (ObjectReader reader = repo.newObjectReader()) {
112 Ref m = tree.exactRef(reader, R_MASTER);
113 assertNotNull(R_MASTER, m);
114 assertEquals(R_MASTER, m.getName());
115 assertEquals(id, m.getObjectId());
116 assertTrue("peeled", m.isPeeled());
117 }
118 }
119
120 @Test
121 public void testUpdateMaster() throws Exception {
122 RefTree tree = RefTree.newEmptyTree();
123 RevBlob id1 = git.blob("A");
124 Command cmd1 = new Command(null, ref(R_MASTER, id1));
125 assertTrue(tree.apply(Collections.singletonList(cmd1)));
126 assertSame(NOT_ATTEMPTED, cmd1.getResult());
127
128 RevBlob id2 = git.blob("B");
129 Command cmd2 = new Command(ref(R_MASTER, id1), ref(R_MASTER, id2));
130 assertTrue(tree.apply(Collections.singletonList(cmd2)));
131 assertSame(NOT_ATTEMPTED, cmd2.getResult());
132
133 try (ObjectReader reader = repo.newObjectReader()) {
134 Ref m = tree.exactRef(reader, R_MASTER);
135 assertNotNull(R_MASTER, m);
136 assertEquals(R_MASTER, m.getName());
137 assertEquals(id2, m.getObjectId());
138 assertTrue("peeled", m.isPeeled());
139 }
140 }
141
142 @Test
143 public void testHeadSymref() throws Exception {
144 RefTree tree = RefTree.newEmptyTree();
145 RevBlob id = git.blob("A");
146 Command cmd1 = new Command(null, ref(R_MASTER, id));
147 Command cmd2 = new Command(null, symref(HEAD, R_MASTER));
148 assertTrue(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
149 assertSame(NOT_ATTEMPTED, cmd1.getResult());
150 assertSame(NOT_ATTEMPTED, cmd2.getResult());
151
152 try (ObjectReader reader = repo.newObjectReader()) {
153 Ref m = tree.exactRef(reader, HEAD);
154 assertNotNull(HEAD, m);
155 assertEquals(HEAD, m.getName());
156 assertTrue("symbolic", m.isSymbolic());
157 assertNotNull(m.getTarget());
158 assertEquals(R_MASTER, m.getTarget().getName());
159 assertEquals(id, m.getTarget().getObjectId());
160 }
161
162
163 ObjectId newId = write(tree);
164 try (ObjectReader reader = repo.newObjectReader();
165 RevWalk rw = new RevWalk(reader)) {
166 tree = RefTree.read(reader, rw.parseTree(newId));
167 Ref m = tree.exactRef(reader, HEAD);
168 assertEquals(R_MASTER, m.getTarget().getName());
169 }
170 }
171
172 @Test
173 public void testTagIsPeeled() throws Exception {
174 String name = "v1.0";
175 RefTree tree = RefTree.newEmptyTree();
176 RevBlob id = git.blob("A");
177 RevTag tag = git.tag(name, id);
178
179 String ref = R_TAGS + name;
180 Command cmd = create(ref, tag);
181 assertTrue(tree.apply(Collections.singletonList(cmd)));
182 assertSame(NOT_ATTEMPTED, cmd.getResult());
183
184 try (ObjectReader reader = repo.newObjectReader()) {
185 Ref m = tree.exactRef(reader, ref);
186 assertNotNull(ref, m);
187 assertEquals(ref, m.getName());
188 assertEquals(tag, m.getObjectId());
189 assertTrue("peeled", m.isPeeled());
190 assertEquals(id, m.getPeeledObjectId());
191 }
192 }
193
194 @Test
195 public void testApplyAlreadyExists() throws Exception {
196 RefTree tree = RefTree.newEmptyTree();
197 RevBlob a = git.blob("A");
198 Command cmd = new Command(null, ref(R_MASTER, a));
199 assertTrue(tree.apply(Collections.singletonList(cmd)));
200 ObjectId treeId = write(tree);
201
202 RevBlob b = git.blob("B");
203 Command cmd1 = create(R_MASTER, b);
204 Command cmd2 = create(R_MASTER, b);
205 assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
206 assertSame(LOCK_FAILURE, cmd1.getResult());
207 assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
208 assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
209 assertEquals(treeId, write(tree));
210 }
211
212 @Test
213 public void testApplyWrongOldId() throws Exception {
214 RefTree tree = RefTree.newEmptyTree();
215 RevBlob a = git.blob("A");
216 Command cmd = new Command(null, ref(R_MASTER, a));
217 assertTrue(tree.apply(Collections.singletonList(cmd)));
218 ObjectId treeId = write(tree);
219
220 RevBlob b = git.blob("B");
221 RevBlob c = git.blob("C");
222 Command cmd1 = update(R_MASTER, b, c);
223 Command cmd2 = create(R_MASTER, b);
224 assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
225 assertSame(LOCK_FAILURE, cmd1.getResult());
226 assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
227 assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
228 assertEquals(treeId, write(tree));
229 }
230
231 @Test
232 public void testApplyWrongOldIdButAlreadyCurrentIsNoOp() throws Exception {
233 RefTree tree = RefTree.newEmptyTree();
234 RevBlob a = git.blob("A");
235 Command cmd = new Command(null, ref(R_MASTER, a));
236 assertTrue(tree.apply(Collections.singletonList(cmd)));
237 ObjectId treeId = write(tree);
238
239 RevBlob b = git.blob("B");
240 cmd = update(R_MASTER, b, a);
241 assertTrue(tree.apply(Collections.singletonList(cmd)));
242 assertEquals(treeId, write(tree));
243 }
244
245 @Test
246 public void testApplyCannotCreateSubdirectory() throws Exception {
247 RefTree tree = RefTree.newEmptyTree();
248 RevBlob a = git.blob("A");
249 Command cmd = new Command(null, ref(R_MASTER, a));
250 assertTrue(tree.apply(Collections.singletonList(cmd)));
251 ObjectId treeId = write(tree);
252
253 RevBlob b = git.blob("B");
254 Command cmd1 = create(R_MASTER + "/fail", b);
255 assertFalse(tree.apply(Collections.singletonList(cmd1)));
256 assertSame(LOCK_FAILURE, cmd1.getResult());
257 assertEquals(treeId, write(tree));
258 }
259
260 @Test
261 public void testApplyCannotCreateParentRef() throws Exception {
262 RefTree tree = RefTree.newEmptyTree();
263 RevBlob a = git.blob("A");
264 Command cmd = new Command(null, ref(R_MASTER, a));
265 assertTrue(tree.apply(Collections.singletonList(cmd)));
266 ObjectId treeId = write(tree);
267
268 RevBlob b = git.blob("B");
269 Command cmd1 = create("refs/heads", b);
270 assertFalse(tree.apply(Collections.singletonList(cmd1)));
271 assertSame(LOCK_FAILURE, cmd1.getResult());
272 assertEquals(treeId, write(tree));
273 }
274
275 private static Ref ref(String name, ObjectId id) {
276 return new ObjectIdRef.PeeledNonTag(LOOSE, name, id);
277 }
278
279 private static Ref symref(String name, String dest) {
280 Ref d = new ObjectIdRef.PeeledNonTag(NEW, dest, null);
281 return new SymbolicRef(name, d);
282 }
283
284 private Command create(String name, ObjectId id)
285 throws MissingObjectException, IOException {
286 return update(name, ObjectId.zeroId(), id);
287 }
288
289 private Command update(String name, ObjectId oldId, ObjectId newId)
290 throws MissingObjectException, IOException {
291 try (RevWalk rw = new RevWalk(repo)) {
292 return new Command(rw, new ReceiveCommand(oldId, newId, name));
293 }
294 }
295
296 private ObjectId write(RefTree tree) throws IOException {
297 try (ObjectInserter ins = repo.newObjectInserter()) {
298 ObjectId id = tree.writeTree(ins);
299 ins.flush();
300 return id;
301 }
302 }
303 }