1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.dfs;
12
13 import static org.eclipse.jgit.junit.JGitTestUtil.concat;
14 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
15 import static org.eclipse.jgit.lib.Constants.encodeASCII;
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertNull;
18 import static org.junit.Assert.assertTrue;
19 import static org.junit.Assert.fail;
20
21 import java.io.IOException;
22
23 import org.eclipse.jgit.internal.fsck.FsckError;
24 import org.eclipse.jgit.internal.fsck.FsckError.CorruptObject;
25 import org.eclipse.jgit.junit.TestRepository;
26 import org.eclipse.jgit.lib.Constants;
27 import org.eclipse.jgit.lib.ObjectChecker.ErrorType;
28 import org.eclipse.jgit.lib.ObjectId;
29 import org.eclipse.jgit.lib.ObjectInserter;
30 import org.eclipse.jgit.revwalk.RevCommit;
31 import org.junit.Before;
32 import org.junit.Test;
33
34 public class DfsFsckTest {
35 private TestRepository<InMemoryRepository> git;
36
37 private InMemoryRepository repo;
38
39 private ObjectInserter ins;
40
41 @Before
42 public void setUp() throws IOException {
43 DfsRepositoryDescription desc = new DfsRepositoryDescription("test");
44 git = new TestRepository<>(new InMemoryRepository(desc));
45 repo = git.getRepository();
46 ins = repo.newObjectInserter();
47 }
48
49 @Test
50 public void testHealthyRepo() throws Exception {
51 RevCommit commit0 = git.commit().message("0").create();
52 RevCommit commit1 = git.commit().message("1").parent(commit0).create();
53 git.update("master", commit1);
54
55 DfsFsck fsck = new DfsFsck(repo);
56 FsckError errors = fsck.check(null);
57
58 assertEquals(errors.getCorruptObjects().size(), 0);
59 assertEquals(errors.getMissingObjects().size(), 0);
60 assertEquals(errors.getCorruptIndices().size(), 0);
61 }
62
63 @Test
64 public void testCommitWithCorruptAuthor() throws Exception {
65 StringBuilder b = new StringBuilder();
66 b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
67 b.append("author b <b@c> <b@c> 0 +0000\n");
68 b.append("committer <> 0 +0000\n");
69 byte[] data = encodeASCII(b.toString());
70 ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
71 ins.flush();
72
73 DfsFsck fsck = new DfsFsck(repo);
74 FsckError errors = fsck.check(null);
75
76 assertEquals(errors.getCorruptObjects().size(), 1);
77 CorruptObject o = errors.getCorruptObjects().iterator().next();
78 assertTrue(o.getId().equals(id));
79 assertEquals(o.getErrorType(), ErrorType.BAD_DATE);
80 }
81
82 @Test
83 public void testCommitWithoutTree() throws Exception {
84 StringBuilder b = new StringBuilder();
85 b.append("parent ");
86 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
87 b.append('\n');
88 byte[] data = encodeASCII(b.toString());
89 ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
90 ins.flush();
91
92 DfsFsck fsck = new DfsFsck(repo);
93 FsckError errors = fsck.check(null);
94
95 assertEquals(errors.getCorruptObjects().size(), 1);
96 CorruptObject o = errors.getCorruptObjects().iterator().next();
97 assertTrue(o.getId().equals(id));
98 assertEquals(o.getErrorType(), ErrorType.MISSING_TREE);
99 }
100
101 @Test
102 public void testTagWithoutObject() throws Exception {
103 StringBuilder b = new StringBuilder();
104 b.append("type commit\n");
105 b.append("tag test-tag\n");
106 b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
107 byte[] data = encodeASCII(b.toString());
108 ObjectId id = ins.insert(Constants.OBJ_TAG, data);
109 ins.flush();
110
111 DfsFsck fsck = new DfsFsck(repo);
112 FsckError errors = fsck.check(null);
113
114 assertEquals(errors.getCorruptObjects().size(), 1);
115 CorruptObject o = errors.getCorruptObjects().iterator().next();
116 assertTrue(o.getId().equals(id));
117 assertEquals(o.getErrorType(), ErrorType.MISSING_OBJECT);
118 }
119
120 @Test
121 public void testTreeWithNullSha() throws Exception {
122 byte[] data = concat(encodeASCII("100644 A"), new byte[] { '\0' },
123 new byte[OBJECT_ID_LENGTH]);
124 ObjectId id = ins.insert(Constants.OBJ_TREE, data);
125 ins.flush();
126
127 DfsFsck fsck = new DfsFsck(repo);
128 FsckError errors = fsck.check(null);
129
130 assertEquals(errors.getCorruptObjects().size(), 1);
131 CorruptObject o = errors.getCorruptObjects().iterator().next();
132 assertTrue(o.getId().equals(id));
133 assertEquals(o.getErrorType(), ErrorType.NULL_SHA1);
134 }
135
136 @Test
137 public void testMultipleInvalidObjects() throws Exception {
138 StringBuilder b = new StringBuilder();
139 b.append("tree ");
140 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
141 b.append('\n');
142 b.append("parent ");
143 b.append("\n");
144 byte[] data = encodeASCII(b.toString());
145 ObjectId id1 = ins.insert(Constants.OBJ_COMMIT, data);
146
147 b = new StringBuilder();
148 b.append("100644");
149 data = encodeASCII(b.toString());
150 ObjectId id2 = ins.insert(Constants.OBJ_TREE, data);
151
152 ins.flush();
153
154 DfsFsck fsck = new DfsFsck(repo);
155 FsckError errors = fsck.check(null);
156
157 assertEquals(errors.getCorruptObjects().size(), 2);
158 for (CorruptObject o : errors.getCorruptObjects()) {
159 if (o.getId().equals(id1)) {
160 assertEquals(o.getErrorType(), ErrorType.BAD_PARENT_SHA1);
161 } else if (o.getId().equals(id2)) {
162 assertNull(o.getErrorType());
163 } else {
164 fail();
165 }
166 }
167 }
168
169 @Test
170 public void testValidConnectivity() throws Exception {
171 ObjectId blobId = ins
172 .insert(Constants.OBJ_BLOB, Constants.encode("foo"));
173
174 byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
175 blobId.copyRawTo(blobIdBytes, 0);
176 byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
177 ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
178 ins.flush();
179
180 RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
181 .create();
182
183 git.update("master", commit);
184
185 DfsFsck fsck = new DfsFsck(repo);
186 FsckError errors = fsck.check(null);
187 assertEquals(errors.getMissingObjects().size(), 0);
188 }
189
190 @Test
191 public void testMissingObject() throws Exception {
192 ObjectId blobId = ObjectId
193 .fromString("19102815663d23f8b75a47e7a01965dcdc96468c");
194 byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
195 blobId.copyRawTo(blobIdBytes, 0);
196 byte[] data = concat(encodeASCII("100644 regular-file\0"), blobIdBytes);
197 ObjectId treeId = ins.insert(Constants.OBJ_TREE, data);
198 ins.flush();
199
200 RevCommit commit = git.commit().message("0").setTopLevelTree(treeId)
201 .create();
202
203 git.update("master", commit);
204
205 DfsFsck fsck = new DfsFsck(repo);
206 FsckError errors = fsck.check(null);
207 assertEquals(errors.getMissingObjects().size(), 1);
208 assertEquals(errors.getMissingObjects().iterator().next(), blobId);
209 }
210
211 @Test
212 public void testNonCommitHead() throws Exception {
213 RevCommit commit0 = git.commit().message("0").create();
214 StringBuilder b = new StringBuilder();
215 b.append("object ");
216 b.append(commit0.getName());
217 b.append('\n');
218 b.append("type commit\n");
219 b.append("tag test-tag\n");
220 b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
221
222 byte[] data = encodeASCII(b.toString());
223 ObjectId tagId = ins.insert(Constants.OBJ_TAG, data);
224 ins.flush();
225
226 git.update("master", tagId);
227
228 DfsFsck fsck = new DfsFsck(repo);
229 FsckError errors = fsck.check(null);
230 assertEquals(errors.getCorruptObjects().size(), 0);
231 assertEquals(errors.getNonCommitHeads().size(), 1);
232 assertEquals(errors.getNonCommitHeads().iterator().next(),
233 "refs/heads/master");
234 }
235
236 private ObjectId insertGitModules(String contents) throws IOException {
237 ObjectId blobId = ins.insert(Constants.OBJ_BLOB,
238 Constants.encode(contents));
239
240 byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH];
241 blobId.copyRawTo(blobIdBytes, 0);
242 byte[] data = concat(encodeASCII("100644 .gitmodules\0"), blobIdBytes);
243 ins.insert(Constants.OBJ_TREE, data);
244 ins.flush();
245
246 return blobId;
247 }
248
249 @Test
250 public void testInvalidGitModules() throws Exception {
251 String fakeGitmodules = new StringBuilder()
252 .append("[submodule \"test\"]\n")
253 .append(" path = xlib\n")
254 .append(" url = https://example.com/repo/xlib.git\n\n")
255 .append("[submodule \"test2\"]\n")
256 .append(" path = zlib\n")
257 .append(" url = -upayload.sh\n")
258 .toString();
259
260 ObjectId blobId = insertGitModules(fakeGitmodules);
261
262 DfsFsck fsck = new DfsFsck(repo);
263 FsckError errors = fsck.check(null);
264 assertEquals(errors.getCorruptObjects().size(), 1);
265
266 CorruptObject error = errors.getCorruptObjects().iterator().next();
267 assertEquals(error.getId(), blobId);
268 assertEquals(error.getType(), Constants.OBJ_BLOB);
269 assertEquals(error.getErrorType(), ErrorType.GITMODULES_URL);
270 }
271
272
273 @Test
274 public void testValidGitModules() throws Exception {
275 String fakeGitmodules = new StringBuilder()
276 .append("[submodule \"test\"]\n")
277 .append(" path = xlib\n")
278 .append(" url = https://example.com/repo/xlib.git\n\n")
279 .append("[submodule \"test2\"]\n")
280 .append(" path = zlib\n")
281 .append(" url = ok/path\n")
282 .toString();
283
284 insertGitModules(fakeGitmodules);
285
286 DfsFsck fsck = new DfsFsck(repo);
287 FsckError errors = fsck.check(null);
288 assertEquals(errors.getCorruptObjects().size(), 0);
289 }
290
291 }