1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.reftable;
12
13 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
14 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
15 import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertFalse;
18 import static org.junit.Assert.assertTrue;
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
25
26 import org.eclipse.jgit.internal.storage.io.BlockSource;
27 import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats;
28 import org.eclipse.jgit.lib.ObjectId;
29 import org.eclipse.jgit.lib.ObjectIdRef;
30 import org.eclipse.jgit.lib.Ref;
31 import org.junit.Test;
32
33 public class ReftableCompactorTest {
34 private static final String MASTER = "refs/heads/master";
35 private static final String NEXT = "refs/heads/next";
36
37 @Test
38 public void noTables() throws IOException {
39 ReftableCompactor compactor;
40 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
41 compactor = new ReftableCompactor(out);
42 compactor.compact();
43 }
44 Stats stats = compactor.getStats();
45 assertEquals(0, stats.minUpdateIndex());
46 assertEquals(0, stats.maxUpdateIndex());
47 assertEquals(0, stats.refCount());
48 }
49
50 @Test
51 public void oneTable() throws IOException {
52 byte[] inTab;
53 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
54 ReftableWriter writer = new ReftableWriter(inBuf)
55 .setMinUpdateIndex(0)
56 .setMaxUpdateIndex(0)
57 .begin();
58
59 writer.writeRef(ref(MASTER, 1));
60 writer.finish();
61 inTab = inBuf.toByteArray();
62 }
63
64 byte[] outTab;
65 ReftableCompactor compactor;
66 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
67 compactor = new ReftableCompactor(outBuf);
68 List<ReftableReader> readers = new ArrayList<>();
69 readers.add(read(inTab));
70 compactor.addAll(readers);
71 compactor.compact();
72 outTab = outBuf.toByteArray();
73 }
74 Stats stats = compactor.getStats();
75 assertEquals(0, stats.minUpdateIndex());
76 assertEquals(0, stats.maxUpdateIndex());
77 assertEquals(1, stats.refCount());
78
79 ReftableReader rr = read(outTab);
80 try (RefCursor rc = rr.allRefs()) {
81 assertTrue(rc.next());
82 assertEquals(MASTER, rc.getRef().getName());
83 assertEquals(id(1), rc.getRef().getObjectId());
84 assertEquals(0, rc.getRef().getUpdateIndex());
85 }
86 }
87
88 @Test
89 public void twoTablesOneRef() throws IOException {
90 byte[] inTab1;
91 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
92 ReftableWriter writer = new ReftableWriter(inBuf)
93 .setMinUpdateIndex(0)
94 .setMaxUpdateIndex(0)
95 .begin();
96
97 writer.writeRef(ref(MASTER, 1));
98 writer.finish();
99 inTab1 = inBuf.toByteArray();
100 }
101
102 byte[] inTab2;
103 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
104 ReftableWriter writer = new ReftableWriter(inBuf)
105 .setMinUpdateIndex(1)
106 .setMaxUpdateIndex(1)
107 .begin();
108
109 writer.writeRef(ref(MASTER, 2));
110 writer.finish();
111 inTab2 = inBuf.toByteArray();
112 }
113
114 byte[] outTab;
115 ReftableCompactor compactor;
116 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
117 compactor = new ReftableCompactor(outBuf);
118 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
119 compactor.compact();
120 outTab = outBuf.toByteArray();
121 }
122 Stats stats = compactor.getStats();
123 assertEquals(0, stats.minUpdateIndex());
124 assertEquals(1, stats.maxUpdateIndex());
125 assertEquals(1, stats.refCount());
126
127 ReftableReader rr = read(outTab);
128 try (RefCursor rc = rr.allRefs()) {
129 assertTrue(rc.next());
130 assertEquals(MASTER, rc.getRef().getName());
131 assertEquals(id(2), rc.getRef().getObjectId());
132 assertEquals(1, rc.getRef().getUpdateIndex());
133 }
134 }
135
136 @Test
137 public void twoTablesTwoRefs() throws IOException {
138 byte[] inTab1;
139 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
140 ReftableWriter writer = new ReftableWriter(inBuf)
141 .setMinUpdateIndex(0)
142 .setMaxUpdateIndex(0)
143 .begin();
144
145 writer.writeRef(ref(MASTER, 1));
146 writer.writeRef(ref(NEXT, 2));
147 writer.finish();
148 inTab1 = inBuf.toByteArray();
149 }
150
151 byte[] inTab2;
152 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
153 ReftableWriter writer = new ReftableWriter(inBuf)
154 .setMinUpdateIndex(1)
155 .setMaxUpdateIndex(1)
156 .begin();
157
158 writer.writeRef(ref(MASTER, 3));
159 writer.finish();
160 inTab2 = inBuf.toByteArray();
161 }
162
163 byte[] outTab;
164 ReftableCompactor compactor;
165 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
166 compactor = new ReftableCompactor(outBuf);
167 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
168 compactor.compact();
169 outTab = outBuf.toByteArray();
170 }
171 Stats stats = compactor.getStats();
172 assertEquals(0, stats.minUpdateIndex());
173 assertEquals(1, stats.maxUpdateIndex());
174 assertEquals(2, stats.refCount());
175
176 ReftableReader rr = read(outTab);
177 try (RefCursor rc = rr.allRefs()) {
178 assertTrue(rc.next());
179 assertEquals(MASTER, rc.getRef().getName());
180 assertEquals(id(3), rc.getRef().getObjectId());
181 assertEquals(1, rc.getRef().getUpdateIndex());
182
183 assertTrue(rc.next());
184 assertEquals(NEXT, rc.getRef().getName());
185 assertEquals(id(2), rc.getRef().getObjectId());
186 assertEquals(0, rc.getRef().getUpdateIndex());
187 }
188 }
189
190 @Test
191 public void twoTablesIncludeOneDelete() throws IOException {
192 byte[] inTab1;
193 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
194 ReftableWriter writer = new ReftableWriter(inBuf)
195 .setMinUpdateIndex(0)
196 .setMaxUpdateIndex(0)
197 .begin();
198
199 writer.writeRef(ref(MASTER, 1));
200 writer.finish();
201 inTab1 = inBuf.toByteArray();
202 }
203
204 byte[] inTab2;
205 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
206 ReftableWriter writer = new ReftableWriter(inBuf)
207 .setMinUpdateIndex(1)
208 .setMaxUpdateIndex(1)
209 .begin();
210
211 writer.writeRef(tombstone(MASTER));
212 writer.finish();
213 inTab2 = inBuf.toByteArray();
214 }
215
216 byte[] outTab;
217 ReftableCompactor compactor;
218 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
219 compactor = new ReftableCompactor(outBuf);
220 compactor.setIncludeDeletes(true);
221 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
222 compactor.compact();
223 outTab = outBuf.toByteArray();
224 }
225 Stats stats = compactor.getStats();
226 assertEquals(0, stats.minUpdateIndex());
227 assertEquals(1, stats.maxUpdateIndex());
228 assertEquals(1, stats.refCount());
229
230 ReftableReader rr = read(outTab);
231 try (RefCursor rc = rr.allRefs()) {
232 assertFalse(rc.next());
233 }
234 }
235
236 @Test
237 public void twoTablesNotIncludeOneDelete() throws IOException {
238 byte[] inTab1;
239 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
240 ReftableWriter writer = new ReftableWriter(inBuf)
241 .setMinUpdateIndex(0)
242 .setMaxUpdateIndex(0)
243 .begin();
244
245 writer.writeRef(ref(MASTER, 1));
246 writer.finish();
247 inTab1 = inBuf.toByteArray();
248 }
249
250 byte[] inTab2;
251 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
252 ReftableWriter writer = new ReftableWriter(inBuf)
253 .setMinUpdateIndex(1)
254 .setMaxUpdateIndex(1)
255 .begin();
256
257 writer.writeRef(tombstone(MASTER));
258 writer.finish();
259 inTab2 = inBuf.toByteArray();
260 }
261
262 byte[] outTab;
263 ReftableCompactor compactor;
264 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
265 compactor = new ReftableCompactor(outBuf);
266 compactor.setIncludeDeletes(false);
267 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
268 compactor.compact();
269 outTab = outBuf.toByteArray();
270 }
271 Stats stats = compactor.getStats();
272 assertEquals(0, stats.minUpdateIndex());
273 assertEquals(1, stats.maxUpdateIndex());
274 assertEquals(0, stats.refCount());
275
276 ReftableReader rr = read(outTab);
277 try (RefCursor rc = rr.allRefs()) {
278 assertFalse(rc.next());
279 }
280 }
281
282 private static Ref ref(String name, int id) {
283 return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
284 }
285
286 private static Ref tombstone(String name) {
287 return new ObjectIdRef.Unpeeled(NEW, name, null);
288 }
289
290 private static ObjectId id(int i) {
291 byte[] buf = new byte[OBJECT_ID_LENGTH];
292 buf[0] = (byte) (i & 0xff);
293 buf[1] = (byte) ((i >>> 8) & 0xff);
294 buf[2] = (byte) ((i >>> 16) & 0xff);
295 buf[3] = (byte) (i >>> 24);
296 return ObjectId.fromRaw(buf);
297 }
298
299 private static ReftableReader read(byte[] table) {
300 return new ReftableReader(BlockSource.from(table));
301 }
302 }