You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RefUpdateTest.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. /*
  2. * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
  3. * Copyright (C) 2009-2010, Google Inc.
  4. * Copyright (C) 2008-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. package org.eclipse.jgit.internal.storage.file;
  46. import static org.eclipse.jgit.junit.Assert.assertEquals;
  47. import static org.junit.Assert.assertEquals;
  48. import static org.junit.Assert.assertFalse;
  49. import static org.junit.Assert.assertNotNull;
  50. import static org.junit.Assert.assertNotSame;
  51. import static org.junit.Assert.assertNull;
  52. import static org.junit.Assert.assertSame;
  53. import static org.junit.Assert.assertTrue;
  54. import static org.junit.Assert.fail;
  55. import java.io.File;
  56. import java.io.IOException;
  57. import java.util.List;
  58. import java.util.Map;
  59. import java.util.Map.Entry;
  60. import org.eclipse.jgit.internal.storage.file.FileRepository;
  61. import org.eclipse.jgit.internal.storage.file.LockFile;
  62. import org.eclipse.jgit.internal.storage.file.RefDirectory;
  63. import org.eclipse.jgit.internal.storage.file.RefDirectoryUpdate;
  64. import org.eclipse.jgit.internal.storage.file.ReflogReader;
  65. import org.eclipse.jgit.junit.SampleDataRepositoryTestCase;
  66. import org.eclipse.jgit.lib.AnyObjectId;
  67. import org.eclipse.jgit.lib.Constants;
  68. import org.eclipse.jgit.lib.ObjectId;
  69. import org.eclipse.jgit.lib.PersonIdent;
  70. import org.eclipse.jgit.lib.Ref;
  71. import org.eclipse.jgit.lib.RefRename;
  72. import org.eclipse.jgit.lib.RefUpdate;
  73. import org.eclipse.jgit.lib.RefUpdate.Result;
  74. import org.eclipse.jgit.lib.Repository;
  75. import org.eclipse.jgit.revwalk.RevCommit;
  76. import org.eclipse.jgit.revwalk.RevWalk;
  77. import org.junit.Test;
  78. public class RefUpdateTest extends SampleDataRepositoryTestCase {
  79. private void writeSymref(String src, String dst) throws IOException {
  80. RefUpdate u = db.updateRef(src);
  81. switch (u.link(dst)) {
  82. case NEW:
  83. case FORCED:
  84. case NO_CHANGE:
  85. break;
  86. default:
  87. fail("link " + src + " to " + dst);
  88. }
  89. }
  90. private RefUpdate updateRef(final String name) throws IOException {
  91. final RefUpdate ref = db.updateRef(name);
  92. ref.setNewObjectId(db.resolve(Constants.HEAD));
  93. return ref;
  94. }
  95. private void delete(final RefUpdate ref, final Result expected)
  96. throws IOException {
  97. delete(ref, expected, true, true);
  98. }
  99. private void delete(final RefUpdate ref, final Result expected,
  100. final boolean exists, final boolean removed) throws IOException {
  101. assertEquals(exists, db.getAllRefs().containsKey(ref.getName()));
  102. assertEquals(expected, ref.delete());
  103. assertEquals(!removed, db.getAllRefs().containsKey(ref.getName()));
  104. }
  105. @Test
  106. public void testNoCacheObjectIdSubclass() throws IOException {
  107. final String newRef = "refs/heads/abc";
  108. final RefUpdate ru = updateRef(newRef);
  109. final SubclassedId newid = new SubclassedId(ru.getNewObjectId());
  110. ru.setNewObjectId(newid);
  111. Result update = ru.update();
  112. assertEquals(Result.NEW, update);
  113. final Ref r = db.getAllRefs().get(newRef);
  114. assertNotNull(r);
  115. assertEquals(newRef, r.getName());
  116. assertNotNull(r.getObjectId());
  117. assertNotSame(newid, r.getObjectId());
  118. assertSame(ObjectId.class, r.getObjectId().getClass());
  119. assertEquals(newid, r.getObjectId());
  120. List<org.eclipse.jgit.internal.storage.file.ReflogEntry> reverseEntries1 = db.getReflogReader("refs/heads/abc").getReverseEntries();
  121. org.eclipse.jgit.internal.storage.file.ReflogEntry entry1 = reverseEntries1.get(0);
  122. assertEquals(1, reverseEntries1.size());
  123. assertEquals(ObjectId.zeroId(), entry1.getOldId());
  124. assertEquals(r.getObjectId(), entry1.getNewId());
  125. assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString());
  126. assertEquals("", entry1.getComment());
  127. List<org.eclipse.jgit.internal.storage.file.ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD").getReverseEntries();
  128. assertEquals(0, reverseEntries2.size());
  129. }
  130. @Test
  131. public void testNewNamespaceConflictWithLoosePrefixNameExists()
  132. throws IOException {
  133. final String newRef = "refs/heads/z";
  134. final RefUpdate ru = updateRef(newRef);
  135. Result update = ru.update();
  136. assertEquals(Result.NEW, update);
  137. // end setup
  138. final String newRef2 = "refs/heads/z/a";
  139. final RefUpdate ru2 = updateRef(newRef2);
  140. Result update2 = ru2.update();
  141. assertEquals(Result.LOCK_FAILURE, update2);
  142. assertEquals(1, db.getReflogReader("refs/heads/z").getReverseEntries().size());
  143. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  144. }
  145. @Test
  146. public void testNewNamespaceConflictWithPackedPrefixNameExists()
  147. throws IOException {
  148. final String newRef = "refs/heads/master/x";
  149. final RefUpdate ru = updateRef(newRef);
  150. Result update = ru.update();
  151. assertEquals(Result.LOCK_FAILURE, update);
  152. assertNull(db.getReflogReader("refs/heads/master/x"));
  153. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  154. }
  155. @Test
  156. public void testNewNamespaceConflictWithLoosePrefixOfExisting()
  157. throws IOException {
  158. final String newRef = "refs/heads/z/a";
  159. final RefUpdate ru = updateRef(newRef);
  160. Result update = ru.update();
  161. assertEquals(Result.NEW, update);
  162. // end setup
  163. final String newRef2 = "refs/heads/z";
  164. final RefUpdate ru2 = updateRef(newRef2);
  165. Result update2 = ru2.update();
  166. assertEquals(Result.LOCK_FAILURE, update2);
  167. assertEquals(1, db.getReflogReader("refs/heads/z/a").getReverseEntries().size());
  168. assertNull(db.getReflogReader("refs/heads/z"));
  169. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  170. }
  171. @Test
  172. public void testNewNamespaceConflictWithPackedPrefixOfExisting()
  173. throws IOException {
  174. final String newRef = "refs/heads/prefix";
  175. final RefUpdate ru = updateRef(newRef);
  176. Result update = ru.update();
  177. assertEquals(Result.LOCK_FAILURE, update);
  178. assertNull(db.getReflogReader("refs/heads/prefix"));
  179. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  180. }
  181. /**
  182. * Delete a ref that is pointed to by HEAD
  183. *
  184. * @throws IOException
  185. */
  186. @Test
  187. public void testDeleteHEADreferencedRef() throws IOException {
  188. ObjectId pid = db.resolve("refs/heads/master^");
  189. RefUpdate updateRef = db.updateRef("refs/heads/master");
  190. updateRef.setNewObjectId(pid);
  191. updateRef.setForceUpdate(true);
  192. Result update = updateRef.update();
  193. assertEquals(Result.FORCED, update); // internal
  194. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  195. Result delete = updateRef2.delete();
  196. assertEquals(Result.REJECTED_CURRENT_BRANCH, delete);
  197. assertEquals(pid, db.resolve("refs/heads/master"));
  198. assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size());
  199. assertEquals(0,db.getReflogReader("HEAD").getReverseEntries().size());
  200. }
  201. @Test
  202. public void testLooseDelete() throws IOException {
  203. final String newRef = "refs/heads/abc";
  204. RefUpdate ref = updateRef(newRef);
  205. ref.update(); // create loose ref
  206. ref = updateRef(newRef); // refresh
  207. delete(ref, Result.NO_CHANGE);
  208. assertNull(db.getReflogReader("refs/heads/abc"));
  209. }
  210. @Test
  211. public void testDeleteHead() throws IOException {
  212. final RefUpdate ref = updateRef(Constants.HEAD);
  213. delete(ref, Result.REJECTED_CURRENT_BRANCH, true, false);
  214. assertEquals(0, db.getReflogReader("refs/heads/master").getReverseEntries().size());
  215. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  216. }
  217. /**
  218. * Delete a loose ref and make sure the directory in refs is deleted too,
  219. * and the reflog dir too
  220. *
  221. * @throws IOException
  222. */
  223. @Test
  224. public void testDeleteLooseAndItsDirectory() throws IOException {
  225. ObjectId pid = db.resolve("refs/heads/c^");
  226. RefUpdate updateRef = db.updateRef("refs/heads/z/c");
  227. updateRef.setNewObjectId(pid);
  228. updateRef.setForceUpdate(true);
  229. updateRef.setRefLogMessage("new test ref", false);
  230. Result update = updateRef.update();
  231. assertEquals(Result.NEW, update); // internal
  232. assertTrue(new File(db.getDirectory(), Constants.R_HEADS + "z")
  233. .exists());
  234. assertTrue(new File(db.getDirectory(), "logs/refs/heads/z").exists());
  235. // The real test here
  236. RefUpdate updateRef2 = db.updateRef("refs/heads/z/c");
  237. updateRef2.setForceUpdate(true);
  238. Result delete = updateRef2.delete();
  239. assertEquals(Result.FORCED, delete);
  240. assertNull(db.resolve("refs/heads/z/c"));
  241. assertFalse(new File(db.getDirectory(), Constants.R_HEADS + "z")
  242. .exists());
  243. assertFalse(new File(db.getDirectory(), "logs/refs/heads/z").exists());
  244. }
  245. @Test
  246. public void testDeleteNotFound() throws IOException {
  247. final RefUpdate ref = updateRef("refs/heads/xyz");
  248. delete(ref, Result.NEW, false, true);
  249. }
  250. @Test
  251. public void testDeleteFastForward() throws IOException {
  252. final RefUpdate ref = updateRef("refs/heads/a");
  253. delete(ref, Result.FAST_FORWARD);
  254. }
  255. @Test
  256. public void testDeleteForce() throws IOException {
  257. final RefUpdate ref = db.updateRef("refs/heads/b");
  258. ref.setNewObjectId(db.resolve("refs/heads/a"));
  259. delete(ref, Result.REJECTED, true, false);
  260. ref.setForceUpdate(true);
  261. delete(ref, Result.FORCED);
  262. }
  263. @Test
  264. public void testRefKeySameAsName() {
  265. Map<String, Ref> allRefs = db.getAllRefs();
  266. for (Entry<String, Ref> e : allRefs.entrySet()) {
  267. assertEquals(e.getKey(), e.getValue().getName());
  268. }
  269. }
  270. /**
  271. * Try modify a ref forward, fast forward
  272. *
  273. * @throws IOException
  274. */
  275. @Test
  276. public void testUpdateRefForward() throws IOException {
  277. ObjectId ppid = db.resolve("refs/heads/master^");
  278. ObjectId pid = db.resolve("refs/heads/master");
  279. RefUpdate updateRef = db.updateRef("refs/heads/master");
  280. updateRef.setNewObjectId(ppid);
  281. updateRef.setForceUpdate(true);
  282. Result update = updateRef.update();
  283. assertEquals(Result.FORCED, update);
  284. assertEquals(ppid, db.resolve("refs/heads/master"));
  285. // real test
  286. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  287. updateRef2.setNewObjectId(pid);
  288. Result update2 = updateRef2.update();
  289. assertEquals(Result.FAST_FORWARD, update2);
  290. assertEquals(pid, db.resolve("refs/heads/master"));
  291. }
  292. /**
  293. * Update the HEAD ref. Only it should be changed, not what it points to.
  294. *
  295. * @throws Exception
  296. */
  297. @Test
  298. public void testUpdateRefDetached() throws Exception {
  299. ObjectId pid = db.resolve("refs/heads/master");
  300. ObjectId ppid = db.resolve("refs/heads/master^");
  301. RefUpdate updateRef = db.updateRef("HEAD", true);
  302. updateRef.setForceUpdate(true);
  303. updateRef.setNewObjectId(ppid);
  304. Result update = updateRef.update();
  305. assertEquals(Result.FORCED, update);
  306. assertEquals(ppid, db.resolve("HEAD"));
  307. Ref ref = db.getRef("HEAD");
  308. assertEquals("HEAD", ref.getName());
  309. assertTrue("is detached", !ref.isSymbolic());
  310. // the branch HEAD referred to is left untouched
  311. assertEquals(pid, db.resolve("refs/heads/master"));
  312. ReflogReader reflogReader = new ReflogReader(db, "HEAD");
  313. org.eclipse.jgit.internal.storage.file.ReflogEntry e = reflogReader.getReverseEntries().get(0);
  314. assertEquals(pid, e.getOldId());
  315. assertEquals(ppid, e.getNewId());
  316. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  317. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  318. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  319. }
  320. /**
  321. * Update the HEAD ref when the referenced branch is unborn
  322. *
  323. * @throws Exception
  324. */
  325. @Test
  326. public void testUpdateRefDetachedUnbornHead() throws Exception {
  327. ObjectId ppid = db.resolve("refs/heads/master^");
  328. writeSymref("HEAD", "refs/heads/unborn");
  329. RefUpdate updateRef = db.updateRef("HEAD", true);
  330. updateRef.setForceUpdate(true);
  331. updateRef.setNewObjectId(ppid);
  332. Result update = updateRef.update();
  333. assertEquals(Result.NEW, update);
  334. assertEquals(ppid, db.resolve("HEAD"));
  335. Ref ref = db.getRef("HEAD");
  336. assertEquals("HEAD", ref.getName());
  337. assertTrue("is detached", !ref.isSymbolic());
  338. // the branch HEAD referred to is left untouched
  339. assertNull(db.resolve("refs/heads/unborn"));
  340. ReflogReader reflogReader = new ReflogReader(db, "HEAD");
  341. org.eclipse.jgit.internal.storage.file.ReflogEntry e = reflogReader.getReverseEntries().get(0);
  342. assertEquals(ObjectId.zeroId(), e.getOldId());
  343. assertEquals(ppid, e.getNewId());
  344. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  345. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  346. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  347. }
  348. /**
  349. * Delete a ref that exists both as packed and loose. Make sure the ref
  350. * cannot be resolved after delete.
  351. *
  352. * @throws IOException
  353. */
  354. @Test
  355. public void testDeleteLoosePacked() throws IOException {
  356. ObjectId pid = db.resolve("refs/heads/c^");
  357. RefUpdate updateRef = db.updateRef("refs/heads/c");
  358. updateRef.setNewObjectId(pid);
  359. updateRef.setForceUpdate(true);
  360. Result update = updateRef.update();
  361. assertEquals(Result.FORCED, update); // internal
  362. // The real test here
  363. RefUpdate updateRef2 = db.updateRef("refs/heads/c");
  364. updateRef2.setForceUpdate(true);
  365. Result delete = updateRef2.delete();
  366. assertEquals(Result.FORCED, delete);
  367. assertNull(db.resolve("refs/heads/c"));
  368. }
  369. /**
  370. * Try modify a ref to same
  371. *
  372. * @throws IOException
  373. */
  374. @Test
  375. public void testUpdateRefNoChange() throws IOException {
  376. ObjectId pid = db.resolve("refs/heads/master");
  377. RefUpdate updateRef = db.updateRef("refs/heads/master");
  378. updateRef.setNewObjectId(pid);
  379. Result update = updateRef.update();
  380. assertEquals(Result.NO_CHANGE, update);
  381. assertEquals(pid, db.resolve("refs/heads/master"));
  382. }
  383. /**
  384. * Test case originating from
  385. * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
  386. *
  387. * Make sure the in memory cache is updated properly after
  388. * update of symref. This one did not fail because the
  389. * ref was packed due to implementation issues.
  390. *
  391. * @throws Exception
  392. */
  393. @Test
  394. public void testRefsCacheAfterUpdate() throws Exception {
  395. // Do not use the defalt repo for this case.
  396. Map<String, Ref> allRefs = db.getAllRefs();
  397. ObjectId oldValue = db.resolve("HEAD");
  398. ObjectId newValue = db.resolve("HEAD^");
  399. // first make HEAD refer to loose ref
  400. RefUpdate updateRef = db.updateRef(Constants.HEAD);
  401. updateRef.setForceUpdate(true);
  402. updateRef.setNewObjectId(newValue);
  403. Result update = updateRef.update();
  404. assertEquals(Result.FORCED, update);
  405. // now update that ref
  406. updateRef = db.updateRef(Constants.HEAD);
  407. updateRef.setForceUpdate(true);
  408. updateRef.setNewObjectId(oldValue);
  409. update = updateRef.update();
  410. assertEquals(Result.FAST_FORWARD, update);
  411. allRefs = db.getAllRefs();
  412. Ref master = allRefs.get("refs/heads/master");
  413. Ref head = allRefs.get("HEAD");
  414. assertEquals("refs/heads/master", master.getName());
  415. assertEquals("HEAD", head.getName());
  416. assertTrue("is symbolic reference", head.isSymbolic());
  417. assertSame(master, head.getTarget());
  418. }
  419. /**
  420. * Test case originating from
  421. * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
  422. *
  423. * Make sure the in memory cache is updated properly after
  424. * update of symref.
  425. *
  426. * @throws Exception
  427. */
  428. @Test
  429. public void testRefsCacheAfterUpdateLooseOnly() throws Exception {
  430. // Do not use the defalt repo for this case.
  431. Map<String, Ref> allRefs = db.getAllRefs();
  432. ObjectId oldValue = db.resolve("HEAD");
  433. writeSymref(Constants.HEAD, "refs/heads/newref");
  434. RefUpdate updateRef = db.updateRef(Constants.HEAD);
  435. updateRef.setForceUpdate(true);
  436. updateRef.setNewObjectId(oldValue);
  437. Result update = updateRef.update();
  438. assertEquals(Result.NEW, update);
  439. allRefs = db.getAllRefs();
  440. Ref head = allRefs.get("HEAD");
  441. Ref newref = allRefs.get("refs/heads/newref");
  442. assertEquals("refs/heads/newref", newref.getName());
  443. assertEquals("HEAD", head.getName());
  444. assertTrue("is symbolic reference", head.isSymbolic());
  445. assertSame(newref, head.getTarget());
  446. }
  447. /**
  448. * Try modify a ref, but get wrong expected old value
  449. *
  450. * @throws IOException
  451. */
  452. @Test
  453. public void testUpdateRefLockFailureWrongOldValue() throws IOException {
  454. ObjectId pid = db.resolve("refs/heads/master");
  455. RefUpdate updateRef = db.updateRef("refs/heads/master");
  456. updateRef.setNewObjectId(pid);
  457. updateRef.setExpectedOldObjectId(db.resolve("refs/heads/master^"));
  458. Result update = updateRef.update();
  459. assertEquals(Result.LOCK_FAILURE, update);
  460. assertEquals(pid, db.resolve("refs/heads/master"));
  461. }
  462. /**
  463. * Try modify a ref forward, fast forward, checking old value first
  464. *
  465. * @throws IOException
  466. */
  467. @Test
  468. public void testUpdateRefForwardWithCheck1() throws IOException {
  469. ObjectId ppid = db.resolve("refs/heads/master^");
  470. ObjectId pid = db.resolve("refs/heads/master");
  471. RefUpdate updateRef = db.updateRef("refs/heads/master");
  472. updateRef.setNewObjectId(ppid);
  473. updateRef.setForceUpdate(true);
  474. Result update = updateRef.update();
  475. assertEquals(Result.FORCED, update);
  476. assertEquals(ppid, db.resolve("refs/heads/master"));
  477. // real test
  478. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  479. updateRef2.setExpectedOldObjectId(ppid);
  480. updateRef2.setNewObjectId(pid);
  481. Result update2 = updateRef2.update();
  482. assertEquals(Result.FAST_FORWARD, update2);
  483. assertEquals(pid, db.resolve("refs/heads/master"));
  484. }
  485. /**
  486. * Try modify a ref forward, fast forward, checking old commit first
  487. *
  488. * @throws IOException
  489. */
  490. @Test
  491. public void testUpdateRefForwardWithCheck2() throws IOException {
  492. ObjectId ppid = db.resolve("refs/heads/master^");
  493. ObjectId pid = db.resolve("refs/heads/master");
  494. RefUpdate updateRef = db.updateRef("refs/heads/master");
  495. updateRef.setNewObjectId(ppid);
  496. updateRef.setForceUpdate(true);
  497. Result update = updateRef.update();
  498. assertEquals(Result.FORCED, update);
  499. assertEquals(ppid, db.resolve("refs/heads/master"));
  500. // real test
  501. RevCommit old = new RevWalk(db).parseCommit(ppid);
  502. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  503. updateRef2.setExpectedOldObjectId(old);
  504. updateRef2.setNewObjectId(pid);
  505. Result update2 = updateRef2.update();
  506. assertEquals(Result.FAST_FORWARD, update2);
  507. assertEquals(pid, db.resolve("refs/heads/master"));
  508. }
  509. /**
  510. * Try modify a ref that is locked
  511. *
  512. * @throws IOException
  513. */
  514. @Test
  515. public void testUpdateRefLockFailureLocked() throws IOException {
  516. ObjectId opid = db.resolve("refs/heads/master");
  517. ObjectId pid = db.resolve("refs/heads/master^");
  518. RefUpdate updateRef = db.updateRef("refs/heads/master");
  519. updateRef.setNewObjectId(pid);
  520. LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
  521. "refs/heads/master"), db.getFS());
  522. try {
  523. assertTrue(lockFile1.lock()); // precondition to test
  524. Result update = updateRef.update();
  525. assertEquals(Result.LOCK_FAILURE, update);
  526. assertEquals(opid, db.resolve("refs/heads/master"));
  527. LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"),
  528. db.getFS());
  529. assertFalse(lockFile2.lock()); // was locked, still is
  530. } finally {
  531. lockFile1.unlock();
  532. }
  533. }
  534. /**
  535. * Try to delete a ref. Delete requires force.
  536. *
  537. * @throws IOException
  538. */
  539. @Test
  540. public void testDeleteLoosePackedRejected() throws IOException {
  541. ObjectId pid = db.resolve("refs/heads/c^");
  542. ObjectId oldpid = db.resolve("refs/heads/c");
  543. RefUpdate updateRef = db.updateRef("refs/heads/c");
  544. updateRef.setNewObjectId(pid);
  545. Result update = updateRef.update();
  546. assertEquals(Result.REJECTED, update);
  547. assertEquals(oldpid, db.resolve("refs/heads/c"));
  548. }
  549. @Test
  550. public void testRenameBranchNoPreviousLog() throws IOException {
  551. assertFalse("precondition, no log on old branchg", new File(db
  552. .getDirectory(), "logs/refs/heads/b").exists());
  553. ObjectId rb = db.resolve("refs/heads/b");
  554. ObjectId oldHead = db.resolve(Constants.HEAD);
  555. assertFalse(rb.equals(oldHead)); // assumption for this test
  556. RefRename renameRef = db.renameRef("refs/heads/b",
  557. "refs/heads/new/name");
  558. Result result = renameRef.rename();
  559. assertEquals(Result.RENAMED, result);
  560. assertEquals(rb, db.resolve("refs/heads/new/name"));
  561. assertNull(db.resolve("refs/heads/b"));
  562. assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size());
  563. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
  564. .getLastEntry().getComment());
  565. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  566. assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
  567. }
  568. @Test
  569. public void testRenameBranchHasPreviousLog() throws IOException {
  570. ObjectId rb = db.resolve("refs/heads/b");
  571. ObjectId oldHead = db.resolve(Constants.HEAD);
  572. assertFalse("precondition for this test, branch b != HEAD", rb
  573. .equals(oldHead));
  574. writeReflog(db, rb, "Just a message", "refs/heads/b");
  575. assertTrue("log on old branch", new File(db.getDirectory(),
  576. "logs/refs/heads/b").exists());
  577. RefRename renameRef = db.renameRef("refs/heads/b",
  578. "refs/heads/new/name");
  579. Result result = renameRef.rename();
  580. assertEquals(Result.RENAMED, result);
  581. assertEquals(rb, db.resolve("refs/heads/new/name"));
  582. assertNull(db.resolve("refs/heads/b"));
  583. assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
  584. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
  585. .getLastEntry().getComment());
  586. assertEquals("Just a message", db.getReflogReader("new/name")
  587. .getReverseEntries().get(1).getComment());
  588. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  589. assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
  590. }
  591. @Test
  592. public void testRenameCurrentBranch() throws IOException {
  593. ObjectId rb = db.resolve("refs/heads/b");
  594. writeSymref(Constants.HEAD, "refs/heads/b");
  595. ObjectId oldHead = db.resolve(Constants.HEAD);
  596. assertEquals("internal test condition, b == HEAD", oldHead, rb);
  597. writeReflog(db, rb, "Just a message", "refs/heads/b");
  598. assertTrue("log on old branch", new File(db.getDirectory(),
  599. "logs/refs/heads/b").exists());
  600. RefRename renameRef = db.renameRef("refs/heads/b",
  601. "refs/heads/new/name");
  602. Result result = renameRef.rename();
  603. assertEquals(Result.RENAMED, result);
  604. assertEquals(rb, db.resolve("refs/heads/new/name"));
  605. assertNull(db.resolve("refs/heads/b"));
  606. assertEquals("Branch: renamed b to new/name", db.getReflogReader(
  607. "new/name").getLastEntry().getComment());
  608. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  609. assertEquals(rb, db.resolve(Constants.HEAD));
  610. assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
  611. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment());
  612. assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment());
  613. }
  614. @Test
  615. public void testRenameBranchAlsoInPack() throws IOException {
  616. ObjectId rb = db.resolve("refs/heads/b");
  617. ObjectId rb2 = db.resolve("refs/heads/b~1");
  618. assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage());
  619. RefUpdate updateRef = db.updateRef("refs/heads/b");
  620. updateRef.setNewObjectId(rb2);
  621. updateRef.setForceUpdate(true);
  622. Result update = updateRef.update();
  623. assertEquals("internal check new ref is loose", Result.FORCED, update);
  624. assertEquals(Ref.Storage.LOOSE, db.getRef("refs/heads/b").getStorage());
  625. writeReflog(db, rb, "Just a message", "refs/heads/b");
  626. assertTrue("log on old branch", new File(db.getDirectory(),
  627. "logs/refs/heads/b").exists());
  628. RefRename renameRef = db.renameRef("refs/heads/b",
  629. "refs/heads/new/name");
  630. Result result = renameRef.rename();
  631. assertEquals(Result.RENAMED, result);
  632. assertEquals(rb2, db.resolve("refs/heads/new/name"));
  633. assertNull(db.resolve("refs/heads/b"));
  634. assertEquals("Branch: renamed b to new/name", db.getReflogReader(
  635. "new/name").getLastEntry().getComment());
  636. assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size());
  637. assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment());
  638. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  639. // make sure b's log file is gone too.
  640. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  641. // Create new Repository instance, to reread caches and make sure our
  642. // assumptions are persistent.
  643. Repository ndb = new FileRepository(db.getDirectory());
  644. assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
  645. assertNull(ndb.resolve("refs/heads/b"));
  646. }
  647. public void tryRenameWhenLocked(String toLock, String fromName,
  648. String toName, String headPointsTo) throws IOException {
  649. // setup
  650. writeSymref(Constants.HEAD, headPointsTo);
  651. ObjectId oldfromId = db.resolve(fromName);
  652. ObjectId oldHeadId = db.resolve(Constants.HEAD);
  653. writeReflog(db, oldfromId, "Just a message", fromName);
  654. List<org.eclipse.jgit.internal.storage.file.ReflogEntry> oldFromLog = db
  655. .getReflogReader(fromName).getReverseEntries();
  656. List<org.eclipse.jgit.internal.storage.file.ReflogEntry> oldHeadLog = oldHeadId != null ? db
  657. .getReflogReader(Constants.HEAD).getReverseEntries() : null;
  658. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  659. "logs/" + fromName).exists());
  660. // "someone" has branch X locked
  661. LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock),
  662. db.getFS());
  663. try {
  664. assertTrue(lockFile.lock());
  665. // Now this is our test
  666. RefRename renameRef = db.renameRef(fromName, toName);
  667. Result result = renameRef.rename();
  668. assertEquals(Result.LOCK_FAILURE, result);
  669. // Check that the involved refs are the same despite the failure
  670. assertExists(false, toName);
  671. if (!toLock.equals(toName))
  672. assertExists(false, toName + ".lock");
  673. assertExists(true, toLock + ".lock");
  674. if (!toLock.equals(fromName))
  675. assertExists(false, "logs/" + fromName + ".lock");
  676. assertExists(false, "logs/" + toName + ".lock");
  677. assertEquals(oldHeadId, db.resolve(Constants.HEAD));
  678. assertEquals(oldfromId, db.resolve(fromName));
  679. assertNull(db.resolve(toName));
  680. assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
  681. .getReverseEntries().toString());
  682. if (oldHeadId != null)
  683. assertEquals(oldHeadLog.toString(), db.getReflogReader(
  684. Constants.HEAD).getReverseEntries().toString());
  685. } finally {
  686. lockFile.unlock();
  687. }
  688. }
  689. private void assertExists(boolean positive, String toName) {
  690. assertEquals(toName + (positive ? " " : " does not ") + "exist",
  691. positive, new File(db.getDirectory(), toName).exists());
  692. }
  693. @Test
  694. public void testRenameBranchCannotLockAFileHEADisFromLockHEAD()
  695. throws IOException {
  696. tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
  697. "refs/heads/b");
  698. }
  699. @Test
  700. public void testRenameBranchCannotLockAFileHEADisFromLockFrom()
  701. throws IOException {
  702. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  703. "refs/heads/new/name", "refs/heads/b");
  704. }
  705. @Test
  706. public void testRenameBranchCannotLockAFileHEADisFromLockTo()
  707. throws IOException {
  708. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  709. "refs/heads/new/name", "refs/heads/b");
  710. }
  711. @Test
  712. public void testRenameBranchCannotLockAFileHEADisToLockFrom()
  713. throws IOException {
  714. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  715. "refs/heads/new/name", "refs/heads/new/name");
  716. }
  717. @Test
  718. public void testRenameBranchCannotLockAFileHEADisToLockTo()
  719. throws IOException {
  720. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  721. "refs/heads/new/name", "refs/heads/new/name");
  722. }
  723. @Test
  724. public void testRenameBranchCannotLockAFileHEADisOtherLockFrom()
  725. throws IOException {
  726. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  727. "refs/heads/new/name", "refs/heads/a");
  728. }
  729. @Test
  730. public void testRenameBranchCannotLockAFileHEADisOtherLockTo()
  731. throws IOException {
  732. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  733. "refs/heads/new/name", "refs/heads/a");
  734. }
  735. @Test
  736. public void testRenameRefNameColission1avoided() throws IOException {
  737. // setup
  738. ObjectId rb = db.resolve("refs/heads/b");
  739. writeSymref(Constants.HEAD, "refs/heads/a");
  740. RefUpdate updateRef = db.updateRef("refs/heads/a");
  741. updateRef.setNewObjectId(rb);
  742. updateRef.setRefLogMessage("Setup", false);
  743. assertEquals(Result.FAST_FORWARD, updateRef.update());
  744. ObjectId oldHead = db.resolve(Constants.HEAD);
  745. assertEquals(oldHead, rb); // assumption for this test
  746. writeReflog(db, rb, "Just a message", "refs/heads/a");
  747. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  748. "logs/refs/heads/a").exists());
  749. // Now this is our test
  750. RefRename renameRef = db.renameRef("refs/heads/a", "refs/heads/a/b");
  751. Result result = renameRef.rename();
  752. assertEquals(Result.RENAMED, result);
  753. assertNull(db.resolve("refs/heads/a"));
  754. assertEquals(rb, db.resolve("refs/heads/a/b"));
  755. assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size());
  756. assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b")
  757. .getReverseEntries().get(0).getComment());
  758. assertEquals("Just a message", db.getReflogReader("a/b")
  759. .getReverseEntries().get(1).getComment());
  760. assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries()
  761. .get(2).getComment());
  762. // same thing was logged to HEAD
  763. assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD")
  764. .getReverseEntries().get(0).getComment());
  765. }
  766. @Test
  767. public void testRenameRefNameColission2avoided() throws IOException {
  768. // setup
  769. ObjectId rb = db.resolve("refs/heads/b");
  770. writeSymref(Constants.HEAD, "refs/heads/prefix/a");
  771. RefUpdate updateRef = db.updateRef("refs/heads/prefix/a");
  772. updateRef.setNewObjectId(rb);
  773. updateRef.setRefLogMessage("Setup", false);
  774. updateRef.setForceUpdate(true);
  775. assertEquals(Result.FORCED, updateRef.update());
  776. ObjectId oldHead = db.resolve(Constants.HEAD);
  777. assertEquals(oldHead, rb); // assumption for this test
  778. writeReflog(db, rb, "Just a message", "refs/heads/prefix/a");
  779. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  780. "logs/refs/heads/prefix/a").exists());
  781. // Now this is our test
  782. RefRename renameRef = db.renameRef("refs/heads/prefix/a",
  783. "refs/heads/prefix");
  784. Result result = renameRef.rename();
  785. assertEquals(Result.RENAMED, result);
  786. assertNull(db.resolve("refs/heads/prefix/a"));
  787. assertEquals(rb, db.resolve("refs/heads/prefix"));
  788. assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size());
  789. assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
  790. "prefix").getReverseEntries().get(0).getComment());
  791. assertEquals("Just a message", db.getReflogReader("prefix")
  792. .getReverseEntries().get(1).getComment());
  793. assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries()
  794. .get(2).getComment());
  795. assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
  796. "HEAD").getReverseEntries().get(0).getComment());
  797. }
  798. private static void writeReflog(Repository db, ObjectId newId, String msg,
  799. String refName) throws IOException {
  800. RefDirectory refs = (RefDirectory) db.getRefDatabase();
  801. RefDirectoryUpdate update = refs.newUpdate(refName, true);
  802. update.setNewObjectId(newId);
  803. refs.log(update, msg, true);
  804. }
  805. private static class SubclassedId extends ObjectId {
  806. SubclassedId(AnyObjectId src) {
  807. super(src);
  808. }
  809. }
  810. }