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 package org.eclipse.jgit.lib;
44
45 import static java.lang.Long.valueOf;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertTrue;
48
49 import java.io.File;
50 import java.io.FileOutputStream;
51 import java.io.IOException;
52 import java.util.TreeSet;
53
54 import org.eclipse.jgit.junit.RepositoryTestCase;
55 import org.eclipse.jgit.treewalk.FileTreeIterator;
56 import org.eclipse.jgit.treewalk.FileTreeIteratorWithTimeControl;
57 import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
58 import org.eclipse.jgit.util.FileUtils;
59
60 public class RacyGitTests extends RepositoryTestCase {
61 public void testIterator() throws IllegalStateException, IOException,
62 InterruptedException {
63 TreeSet<Long> modTimes = new TreeSet<Long>();
64 File lastFile = null;
65 for (int i = 0; i < 10; i++) {
66 lastFile = new File(db.getWorkTree(), "0." + i);
67 FileUtils.createNewFile(lastFile);
68 if (i == 5)
69 fsTick(lastFile);
70 }
71 modTimes.add(valueOf(fsTick(lastFile)));
72 for (int i = 0; i < 10; i++) {
73 lastFile = new File(db.getWorkTree(), "1." + i);
74 FileUtils.createNewFile(lastFile);
75 }
76 modTimes.add(valueOf(fsTick(lastFile)));
77 for (int i = 0; i < 10; i++) {
78 lastFile = new File(db.getWorkTree(), "2." + i);
79 FileUtils.createNewFile(lastFile);
80 if (i % 4 == 0)
81 fsTick(lastFile);
82 }
83 FileTreeIteratorWithTimeControl fileIt = new FileTreeIteratorWithTimeControl(
84 db, modTimes);
85 try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
86 tw.addTree(fileIt);
87 tw.setRecursive(true);
88 FileTreeIterator t;
89 long t0 = 0;
90 for (int i = 0; i < 10; i++) {
91 assertTrue(tw.next());
92 t = tw.getTree(0, FileTreeIterator.class);
93 if (i == 0) {
94 t0 = t.getEntryLastModified();
95 } else {
96 assertEquals(t0, t.getEntryLastModified());
97 }
98 }
99 long t1 = 0;
100 for (int i = 0; i < 10; i++) {
101 assertTrue(tw.next());
102 t = tw.getTree(0, FileTreeIterator.class);
103 if (i == 0) {
104 t1 = t.getEntryLastModified();
105 assertTrue(t1 > t0);
106 } else {
107 assertEquals(t1, t.getEntryLastModified());
108 }
109 }
110 long t2 = 0;
111 for (int i = 0; i < 10; i++) {
112 assertTrue(tw.next());
113 t = tw.getTree(0, FileTreeIterator.class);
114 if (i == 0) {
115 t2 = t.getEntryLastModified();
116 assertTrue(t2 > t1);
117 } else {
118 assertEquals(t2, t.getEntryLastModified());
119 }
120 }
121 }
122 }
123
124 public void testRacyGitDetection() throws IOException,
125 IllegalStateException, InterruptedException {
126 TreeSet<Long> modTimes = new TreeSet<Long>();
127 File lastFile;
128
129
130
131 modTimes.add(valueOf(fsTick(db.getIndexFile())));
132
133
134 addToWorkDir("a", "a");
135 lastFile = addToWorkDir("b", "b");
136
137
138
139 modTimes.add(valueOf(fsTick(lastFile)));
140
141
142 resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
143
144 assertEquals(
145 "[a, mode:100644, time:t0, length:1, content:a]" +
146 "[b, mode:100644, time:t0, length:1, content:b]",
147 indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
148
149
150
151
152 modTimes.add(Long.valueOf(db.getIndexFile().lastModified()));
153
154
155 addToWorkDir("a", "a2");
156
157
158
159 resetIndex(new FileTreeIteratorWithTimeControl(db, modTimes));
160
161 db.readDirCache();
162
163 assertEquals(
164 "[a, mode:100644, time:t1, smudged, length:0, content:a2]" +
165 "[b, mode:100644, time:t0, length:1, content:b]",
166 indexState(SMUDGE|MOD_TIME|LENGTH|CONTENT));
167 }
168
169 private File addToWorkDir(String path, String content) throws IOException {
170 File f = new File(db.getWorkTree(), path);
171 FileOutputStream fos = new FileOutputStream(f);
172 try {
173 fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
174 return f;
175 } finally {
176 fos.close();
177 }
178 }
179 }