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

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