View Javadoc
1   /*
2    * Copyright (C) 2009-2010, Google Inc.
3    * Copyright (C) 2009, Robin Rosenberg
4    * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
5    * and other copyright owners as documented in the project's IP log.
6    *
7    * This program and the accompanying materials are made available
8    * under the terms of the Eclipse Distribution License v1.0 which
9    * accompanies this distribution, is reproduced below, and is
10   * available at http://www.eclipse.org/org/documents/edl-v10.php
11   *
12   * All rights reserved.
13   *
14   * Redistribution and use in source and binary forms, with or
15   * without modification, are permitted provided that the following
16   * conditions are met:
17   *
18   * - Redistributions of source code must retain the above copyright
19   *   notice, this list of conditions and the following disclaimer.
20   *
21   * - Redistributions in binary form must reproduce the above
22   *   copyright notice, this list of conditions and the following
23   *   disclaimer in the documentation and/or other materials provided
24   *   with the distribution.
25   *
26   * - Neither the name of the Eclipse Foundation, Inc. nor the
27   *   names of its contributors may be used to endorse or promote
28   *   products derived from this software without specific prior
29   *   written permission.
30   *
31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44   */
45  
46  package org.eclipse.jgit.lib;
47  
48  import static org.eclipse.jgit.junit.Assert.assertEquals;
49  import static org.junit.Assert.assertEquals;
50  import static org.junit.Assert.assertFalse;
51  import static org.junit.Assert.assertNotNull;
52  import static org.junit.Assert.assertNull;
53  import static org.junit.Assert.assertSame;
54  import static org.junit.Assert.assertTrue;
55  import static org.junit.Assert.fail;
56  
57  import java.io.File;
58  import java.io.FileOutputStream;
59  import java.io.IOException;
60  import java.util.Map;
61  import java.util.TreeSet;
62  
63  import org.eclipse.jgit.lib.Ref.Storage;
64  import org.eclipse.jgit.lib.RefUpdate.Result;
65  import org.eclipse.jgit.storage.file.FileBasedConfig;
66  import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
67  import org.junit.Test;
68  
69  /**
70   * Misc tests for refs. A lot of things are tested elsewhere so not having a
71   * test for a ref related method, does not mean it is untested.
72   */
73  public class RefTest extends SampleDataRepositoryTestCase {
74  
75  	private void writeSymref(String src, String dst) throws IOException {
76  		RefUpdate u = db.updateRef(src);
77  		switch (u.link(dst)) {
78  		case NEW:
79  		case FORCED:
80  		case NO_CHANGE:
81  			break;
82  		default:
83  			fail("link " + src + " to " + dst);
84  		}
85  	}
86  
87  	private void writeNewRef(String name, ObjectId value) throws IOException {
88  		RefUpdate updateRef = db.updateRef(name);
89  		updateRef.setNewObjectId(value);
90  		assertEquals(RefUpdate.Result.NEW, updateRef.update());
91  	}
92  
93  	@Test
94  	public void testRemoteNames() throws Exception {
95  		FileBasedConfig config = db.getConfig();
96  		config.setBoolean(ConfigConstants.CONFIG_REMOTE_SECTION,
97  				"origin", "dummy", true);
98  		config.setBoolean(ConfigConstants.CONFIG_REMOTE_SECTION,
99  				"ab/c", "dummy", true);
100 		config.save();
101 		assertEquals("[ab/c, origin]",
102 				new TreeSet<String>(db.getRemoteNames()).toString());
103 
104 		// one-level deep remote branch
105 		assertEquals("master",
106 				db.shortenRemoteBranchName("refs/remotes/origin/master"));
107 		assertEquals("origin", db.getRemoteName("refs/remotes/origin/master"));
108 
109 		// two-level deep remote branch
110 		assertEquals("masta/r",
111 				db.shortenRemoteBranchName("refs/remotes/origin/masta/r"));
112 		assertEquals("origin", db.getRemoteName("refs/remotes/origin/masta/r"));
113 
114 		// Remote with slash and one-level deep branch name
115 		assertEquals("xmaster",
116 				db.shortenRemoteBranchName("refs/remotes/ab/c/xmaster"));
117 		assertEquals("ab/c", db.getRemoteName("refs/remotes/ab/c/xmaster"));
118 
119 		// Remote with slash and two-level deep branch name
120 		assertEquals("xmasta/r",
121 				db.shortenRemoteBranchName("refs/remotes/ab/c/xmasta/r"));
122 		assertEquals("ab/c", db.getRemoteName("refs/remotes/ab/c/xmasta/r"));
123 
124 		// no such remote
125 		assertNull(db.getRemoteName("refs/remotes/nosuchremote/x"));
126 		assertNull(db.shortenRemoteBranchName("refs/remotes/nosuchremote/x"));
127 
128 		// no such remote too, no branch name either
129 		assertNull(db.getRemoteName("refs/remotes/abranch"));
130 		assertNull(db.shortenRemoteBranchName("refs/remotes/abranch"));
131 
132 		// // local branch
133 		assertNull(db.getRemoteName("refs/heads/abranch"));
134 		assertNull(db.shortenRemoteBranchName("refs/heads/abranch"));
135 	}
136 
137 	@Test
138 	public void testReadAllIncludingSymrefs() throws Exception {
139 		ObjectId masterId = db.resolve("refs/heads/master");
140 		RefUpdate updateRef = db.updateRef("refs/remotes/origin/master");
141 		updateRef.setNewObjectId(masterId);
142 		updateRef.setForceUpdate(true);
143 		updateRef.update();
144 		writeSymref("refs/remotes/origin/HEAD",
145 					"refs/remotes/origin/master");
146 
147 		ObjectId r = db.resolve("refs/remotes/origin/HEAD");
148 		assertEquals(masterId, r);
149 
150 		Map<String, Ref> allRefs = db.getAllRefs();
151 		Ref refHEAD = allRefs.get("refs/remotes/origin/HEAD");
152 		assertNotNull(refHEAD);
153 		assertEquals(masterId, refHEAD.getObjectId());
154 		assertFalse(refHEAD.isPeeled());
155 		assertNull(refHEAD.getPeeledObjectId());
156 
157 		Ref refmaster = allRefs.get("refs/remotes/origin/master");
158 		assertEquals(masterId, refmaster.getObjectId());
159 		assertFalse(refmaster.isPeeled());
160 		assertNull(refmaster.getPeeledObjectId());
161 	}
162 
163 	@Test
164 	public void testReadSymRefToPacked() throws IOException {
165 		writeSymref("HEAD", "refs/heads/b");
166 		Ref ref = db.exactRef("HEAD");
167 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
168 		assertTrue("is symref", ref.isSymbolic());
169 		ref = ref.getTarget();
170 		assertEquals("refs/heads/b", ref.getName());
171 		assertEquals(Ref.Storage.PACKED, ref.getStorage());
172 	}
173 
174 	@Test
175 	public void testReadSymRefToLoosePacked() throws IOException {
176 		ObjectId pid = db.resolve("refs/heads/master^");
177 		RefUpdate updateRef = db.updateRef("refs/heads/master");
178 		updateRef.setNewObjectId(pid);
179 		updateRef.setForceUpdate(true);
180 		Result update = updateRef.update();
181 		assertEquals(Result.FORCED, update); // internal
182 
183 		writeSymref("HEAD", "refs/heads/master");
184 		Ref ref = db.exactRef("HEAD");
185 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
186 		ref = ref.getTarget();
187 		assertEquals("refs/heads/master", ref.getName());
188 		assertEquals(Ref.Storage.LOOSE, ref.getStorage());
189 	}
190 
191 	@Test
192 	public void testReadLooseRef() throws IOException {
193 		RefUpdate updateRef = db.updateRef("ref/heads/new");
194 		updateRef.setNewObjectId(db.resolve("refs/heads/master"));
195 		Result update = updateRef.update();
196 		assertEquals(Result.NEW, update);
197 		Ref ref = db.exactRef("ref/heads/new");
198 		assertEquals(Storage.LOOSE, ref.getStorage());
199 	}
200 
201 	@Test
202 	public void testGetShortRef() throws IOException {
203 		Ref ref = db.exactRef("refs/heads/master");
204 		assertEquals("refs/heads/master", ref.getName());
205 		assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
206 	}
207 
208 	@Test
209 	public void testGetShortExactRef() throws IOException {
210 		assertNull(db.getRefDatabase().exactRef("master"));
211 
212 		Ref ref = db.getRefDatabase().exactRef("HEAD");
213 		assertEquals("HEAD", ref.getName());
214 		assertEquals("refs/heads/master", ref.getTarget().getName());
215 		assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
216 	}
217 
218 	@Test
219 	public void testRefsUnderRefs() throws IOException {
220 		ObjectId masterId = db.resolve("refs/heads/master");
221 		writeNewRef("refs/heads/refs/foo/bar", masterId);
222 
223 		assertNull(db.getRefDatabase().exactRef("refs/foo/bar"));
224 
225 		Ref ref = db.findRef("refs/foo/bar");
226 		assertEquals("refs/heads/refs/foo/bar", ref.getName());
227 		assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
228 	}
229 
230 	@Test
231 	public void testAmbiguousRefsUnderRefs() throws IOException {
232 		ObjectId masterId = db.resolve("refs/heads/master");
233 		writeNewRef("refs/foo/bar", masterId);
234 		writeNewRef("refs/heads/refs/foo/bar", masterId);
235 
236 		Ref exactRef = db.getRefDatabase().exactRef("refs/foo/bar");
237 		assertEquals("refs/foo/bar", exactRef.getName());
238 		assertEquals(masterId, exactRef.getObjectId());
239 
240 		Ref ref = db.findRef("refs/foo/bar");
241 		assertEquals("refs/foo/bar", ref.getName());
242 		assertEquals(masterId, ref.getObjectId());
243 	}
244 
245 	/**
246 	 * Let an "outsider" create a loose ref with the same name as a packed one
247 	 *
248 	 * @throws IOException
249 	 * @throws InterruptedException
250 	 */
251 	@Test
252 	public void testReadLoosePackedRef() throws IOException,
253 			InterruptedException {
254 		Ref ref = db.exactRef("refs/heads/master");
255 		assertEquals(Storage.PACKED, ref.getStorage());
256 		FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
257 				"refs/heads/master"));
258 		os.write(ref.getObjectId().name().getBytes());
259 		os.write('\n');
260 		os.close();
261 
262 		ref = db.exactRef("refs/heads/master");
263 		assertEquals(Storage.LOOSE, ref.getStorage());
264 	}
265 
266 	/**
267 	 * Modify a packed ref using the API. This creates a loose ref too, ie.
268 	 * LOOSE_PACKED
269 	 *
270 	 * @throws IOException
271 	 */
272 	@Test
273 	public void testReadSimplePackedRefSameRepo() throws IOException {
274 		Ref ref = db.exactRef("refs/heads/master");
275 		ObjectId pid = db.resolve("refs/heads/master^");
276 		assertEquals(Storage.PACKED, ref.getStorage());
277 		RefUpdate updateRef = db.updateRef("refs/heads/master");
278 		updateRef.setNewObjectId(pid);
279 		updateRef.setForceUpdate(true);
280 		Result update = updateRef.update();
281 		assertEquals(Result.FORCED, update);
282 
283 		ref = db.exactRef("refs/heads/master");
284 		assertEquals(Storage.LOOSE, ref.getStorage());
285 	}
286 
287 	@Test
288 	public void testResolvedNamesBranch() throws IOException {
289 		Ref ref = db.findRef("a");
290 		assertEquals("refs/heads/a", ref.getName());
291 	}
292 
293 	@Test
294 	public void testResolvedSymRef() throws IOException {
295 		Ref ref = db.exactRef(Constants.HEAD);
296 		assertEquals(Constants.HEAD, ref.getName());
297 		assertTrue("is symbolic ref", ref.isSymbolic());
298 		assertSame(Ref.Storage.LOOSE, ref.getStorage());
299 
300 		Ref dst = ref.getTarget();
301 		assertNotNull("has target", dst);
302 		assertEquals("refs/heads/master", dst.getName());
303 
304 		assertSame(dst.getObjectId(), ref.getObjectId());
305 		assertSame(dst.getPeeledObjectId(), ref.getPeeledObjectId());
306 		assertEquals(dst.isPeeled(), ref.isPeeled());
307 	}
308 }