View Javadoc
1   /*
2    * Copyright (C) 2020, Lee Worrall and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.transport;
11  
12  import static org.hamcrest.MatcherAssert.assertThat;
13  import static org.hamcrest.Matchers.hasKey;
14  import static org.hamcrest.Matchers.instanceOf;
15  import static org.hamcrest.Matchers.not;
16  import static org.junit.Assert.assertEquals;
17  import static org.junit.Assert.assertSame;
18  import static org.junit.Assert.assertThrows;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.EOFException;
22  import java.util.HashMap;
23  import java.util.LinkedHashMap;
24  import java.util.Map;
25  
26  import org.eclipse.jgit.errors.NoRemoteRepositoryException;
27  import org.eclipse.jgit.lib.Constants;
28  import org.eclipse.jgit.lib.ObjectId;
29  import org.eclipse.jgit.lib.ObjectIdRef;
30  import org.eclipse.jgit.lib.Ref;
31  import org.eclipse.jgit.lib.SymbolicRef;
32  import org.junit.Test;
33  
34  public class BasePackConnectionTest {
35  
36  	@Test
37  	public void testReadAdvertisedRefsShouldThrowExceptionWithOriginalCause() {
38  		try (FailingBasePackConnection basePackConnection =
39  				new FailingBasePackConnection()) {
40  			Exception result = assertThrows(NoRemoteRepositoryException.class,
41  					basePackConnection::readAdvertisedRefs);
42  			assertEquals(EOFException.class, result.getCause().getClass());
43  		}
44  	}
45  
46  	@Test
47  	public void testUpdateWithSymRefsAdds() {
48  		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
49  				"refs/heads/main", ObjectId.fromString(
50  						"0000000000000000000000000000000000000001"));
51  
52  		final Map<String, Ref> refMap = new HashMap<>();
53  		refMap.put(mainRef.getName(), mainRef);
54  		refMap.put("refs/heads/other",
55  				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
56  						ObjectId.fromString(
57  								"0000000000000000000000000000000000000002")));
58  
59  		final Map<String, String> symRefs = new HashMap<>();
60  		symRefs.put("HEAD", "refs/heads/main");
61  
62  		BasePackConnection.updateWithSymRefs(refMap, symRefs);
63  
64  		assertThat(refMap, hasKey("HEAD"));
65  		final Ref headRef = refMap.get("HEAD");
66  		assertThat(headRef, instanceOf(SymbolicRef.class));
67  		final SymbolicRef headSymRef = (SymbolicRef) headRef;
68  		assertEquals("HEAD", headSymRef.getName());
69  		assertSame(mainRef, headSymRef.getTarget());
70  	}
71  
72  	@Test
73  	public void testUpdateWithSymRefsReplaces() {
74  		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
75  				"refs/heads/main", ObjectId.fromString(
76  						"0000000000000000000000000000000000000001"));
77  
78  		final Map<String, Ref> refMap = new HashMap<>();
79  		refMap.put(mainRef.getName(), mainRef);
80  		refMap.put("HEAD", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "HEAD",
81  				mainRef.getObjectId()));
82  		refMap.put("refs/heads/other",
83  				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
84  						ObjectId.fromString(
85  								"0000000000000000000000000000000000000002")));
86  
87  		final Map<String, String> symRefs = new HashMap<>();
88  		symRefs.put("HEAD", "refs/heads/main");
89  
90  		BasePackConnection.updateWithSymRefs(refMap, symRefs);
91  
92  		assertThat(refMap, hasKey("HEAD"));
93  		final Ref headRef = refMap.get("HEAD");
94  		assertThat(headRef, instanceOf(SymbolicRef.class));
95  		final SymbolicRef headSymRef = (SymbolicRef) headRef;
96  		assertEquals("HEAD", headSymRef.getName());
97  		assertSame(mainRef, headSymRef.getTarget());
98  	}
99  
100 	@Test
101 	public void testUpdateWithSymRefsWithIndirectsAdds() {
102 		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
103 				"refs/heads/main", ObjectId.fromString(
104 						"0000000000000000000000000000000000000001"));
105 
106 		final Map<String, Ref> refMap = new HashMap<>();
107 		refMap.put(mainRef.getName(), mainRef);
108 		refMap.put("refs/heads/other",
109 				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
110 						ObjectId.fromString(
111 								"0000000000000000000000000000000000000002")));
112 
113 		final Map<String, String> symRefs = new LinkedHashMap<>(); // Ordered
114 		symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference
115 		symRefs.put("refs/heads/sym1", "refs/heads/main");
116 		symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference
117 
118 		BasePackConnection.updateWithSymRefs(refMap, symRefs);
119 
120 		assertThat(refMap, hasKey("refs/heads/sym1"));
121 		final Ref sym1Ref = refMap.get("refs/heads/sym1");
122 		assertThat(sym1Ref, instanceOf(SymbolicRef.class));
123 		final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref;
124 		assertEquals("refs/heads/sym1", sym1SymRef.getName());
125 		assertSame(mainRef, sym1SymRef.getTarget());
126 
127 		assertThat(refMap, hasKey("refs/heads/sym2"));
128 		final Ref sym2Ref = refMap.get("refs/heads/sym2");
129 		assertThat(sym2Ref, instanceOf(SymbolicRef.class));
130 		final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref;
131 		assertEquals("refs/heads/sym2", sym2SymRef.getName());
132 		assertSame(sym1SymRef, sym2SymRef.getTarget());
133 
134 		assertThat(refMap, hasKey("refs/heads/sym3"));
135 		final Ref sym3Ref = refMap.get("refs/heads/sym3");
136 		assertThat(sym3Ref, instanceOf(SymbolicRef.class));
137 		final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref;
138 		assertEquals("refs/heads/sym3", sym3SymRef.getName());
139 		assertSame(sym2SymRef, sym3SymRef.getTarget());
140 	}
141 
142 	@Test
143 	public void testUpdateWithSymRefsWithIndirectsReplaces() {
144 		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
145 				"refs/heads/main", ObjectId.fromString(
146 						"0000000000000000000000000000000000000001"));
147 
148 		final Map<String, Ref> refMap = new HashMap<>();
149 		refMap.put(mainRef.getName(), mainRef);
150 		refMap.put("refs/heads/sym1", new ObjectIdRef.Unpeeled(
151 				Ref.Storage.LOOSE, "refs/heads/sym1", mainRef.getObjectId()));
152 		refMap.put("refs/heads/sym2", new ObjectIdRef.Unpeeled(
153 				Ref.Storage.LOOSE, "refs/heads/sym2", mainRef.getObjectId()));
154 		refMap.put("refs/heads/sym3", new ObjectIdRef.Unpeeled(
155 				Ref.Storage.LOOSE, "refs/heads/sym3", mainRef.getObjectId()));
156 		refMap.put("refs/heads/other",
157 				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
158 						ObjectId.fromString(
159 								"0000000000000000000000000000000000000002")));
160 
161 		final Map<String, String> symRefs = new LinkedHashMap<>(); // Ordered
162 		symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference
163 		symRefs.put("refs/heads/sym1", "refs/heads/main");
164 		symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference
165 
166 		BasePackConnection.updateWithSymRefs(refMap, symRefs);
167 
168 		assertThat(refMap, hasKey("refs/heads/sym1"));
169 		final Ref sym1Ref = refMap.get("refs/heads/sym1");
170 		assertThat(sym1Ref, instanceOf(SymbolicRef.class));
171 		final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref;
172 		assertEquals("refs/heads/sym1", sym1SymRef.getName());
173 		assertSame(mainRef, sym1SymRef.getTarget());
174 
175 		assertThat(refMap, hasKey("refs/heads/sym2"));
176 		final Ref sym2Ref = refMap.get("refs/heads/sym2");
177 		assertThat(sym2Ref, instanceOf(SymbolicRef.class));
178 		final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref;
179 		assertEquals("refs/heads/sym2", sym2SymRef.getName());
180 		assertSame(sym1SymRef, sym2SymRef.getTarget());
181 
182 		assertThat(refMap, hasKey("refs/heads/sym3"));
183 		final Ref sym3Ref = refMap.get("refs/heads/sym3");
184 		assertThat(sym3Ref, instanceOf(SymbolicRef.class));
185 		final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref;
186 		assertEquals("refs/heads/sym3", sym3SymRef.getName());
187 		assertSame(sym2SymRef, sym3SymRef.getTarget());
188 	}
189 
190 	@Test
191 	public void testUpdateWithSymRefsIgnoresSelfReference() {
192 		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
193 				"refs/heads/main", ObjectId.fromString(
194 						"0000000000000000000000000000000000000001"));
195 
196 		final Map<String, Ref> refMap = new HashMap<>();
197 		refMap.put(mainRef.getName(), mainRef);
198 		refMap.put("refs/heads/other",
199 				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
200 						ObjectId.fromString(
201 								"0000000000000000000000000000000000000002")));
202 
203 		final Map<String, String> symRefs = new LinkedHashMap<>();
204 		symRefs.put("refs/heads/sym1", "refs/heads/sym1");
205 
206 		BasePackConnection.updateWithSymRefs(refMap, symRefs);
207 
208 		assertEquals(2, refMap.size());
209 		assertThat(refMap, not(hasKey("refs/heads/sym1")));
210 	}
211 
212 	@Test
213 	public void testUpdateWithSymRefsIgnoreCircularReference() {
214 		final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
215 				"refs/heads/main", ObjectId.fromString(
216 						"0000000000000000000000000000000000000001"));
217 
218 		final Map<String, Ref> refMap = new HashMap<>();
219 		refMap.put(mainRef.getName(), mainRef);
220 		refMap.put("refs/heads/other",
221 				new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
222 						ObjectId.fromString(
223 								"0000000000000000000000000000000000000002")));
224 
225 		final Map<String, String> symRefs = new LinkedHashMap<>();
226 		symRefs.put("refs/heads/sym2", "refs/heads/sym1");
227 		symRefs.put("refs/heads/sym1", "refs/heads/sym2");
228 
229 		BasePackConnection.updateWithSymRefs(refMap, symRefs);
230 
231 		assertEquals(2, refMap.size());
232 		assertThat(refMap, not(hasKey("refs/heads/sym1")));
233 		assertThat(refMap, not(hasKey("refs/heads/sym2")));
234 	}
235 
236 	@Test
237 	public void testUpdateWithSymRefsFillInHead() {
238 		final String oidName = "0000000000000000000000000000000000000001";
239 		final Ref advertised = new ObjectIdRef.PeeledNonTag(Ref.Storage.NETWORK,
240 				Constants.HEAD, ObjectId.fromString(oidName));
241 
242 		final Map<String, Ref> refMap = new HashMap<>();
243 		refMap.put(advertised.getName(), advertised);
244 
245 		final Map<String, String> symRefs = new HashMap<>();
246 		symRefs.put("HEAD", "refs/heads/main");
247 
248 		BasePackConnection.updateWithSymRefs(refMap, symRefs);
249 
250 		assertThat(refMap, hasKey("HEAD"));
251 		assertThat(refMap, hasKey("refs/heads/main"));
252 		final Ref headRef = refMap.get("HEAD");
253 		final Ref mainRef = refMap.get("refs/heads/main");
254 		assertThat(headRef, instanceOf(SymbolicRef.class));
255 		final SymbolicRef headSymRef = (SymbolicRef) headRef;
256 		assertEquals(Constants.HEAD, headSymRef.getName());
257 		assertSame(mainRef, headSymRef.getTarget());
258 		assertEquals(oidName, headRef.getObjectId().name());
259 		assertEquals(oidName, mainRef.getObjectId().name());
260 	}
261 
262 	private static class FailingBasePackConnection extends BasePackConnection {
263 		FailingBasePackConnection() {
264 			super(new TransportLocal(new URIish(),
265 					new java.io.File("")));
266 			pckIn = new PacketLineIn(new ByteArrayInputStream(new byte[0]));
267 		}
268 	}
269 }