Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

RefUpdateTest.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  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.junit.SampleDataRepositoryTestCase;
  61. import org.eclipse.jgit.lib.AnyObjectId;
  62. import org.eclipse.jgit.lib.Constants;
  63. import org.eclipse.jgit.lib.ObjectId;
  64. import org.eclipse.jgit.lib.PersonIdent;
  65. import org.eclipse.jgit.lib.Ref;
  66. import org.eclipse.jgit.lib.RefRename;
  67. import org.eclipse.jgit.lib.RefUpdate;
  68. import org.eclipse.jgit.lib.RefUpdate.Result;
  69. import org.eclipse.jgit.lib.ReflogEntry;
  70. import org.eclipse.jgit.lib.ReflogReader;
  71. import org.eclipse.jgit.lib.Repository;
  72. import org.eclipse.jgit.revwalk.RevCommit;
  73. import org.eclipse.jgit.revwalk.RevWalk;
  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 testRefKeySameAsName() {
  264. Map<String, Ref> allRefs = db.getAllRefs();
  265. for (Entry<String, Ref> e : allRefs.entrySet()) {
  266. assertEquals(e.getKey(), e.getValue().getName());
  267. }
  268. }
  269. /**
  270. * Try modify a ref forward, fast forward
  271. *
  272. * @throws IOException
  273. */
  274. @Test
  275. public void testUpdateRefForward() throws IOException {
  276. ObjectId ppid = db.resolve("refs/heads/master^");
  277. ObjectId pid = db.resolve("refs/heads/master");
  278. RefUpdate updateRef = db.updateRef("refs/heads/master");
  279. updateRef.setNewObjectId(ppid);
  280. updateRef.setForceUpdate(true);
  281. Result update = updateRef.update();
  282. assertEquals(Result.FORCED, update);
  283. assertEquals(ppid, db.resolve("refs/heads/master"));
  284. // real test
  285. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  286. updateRef2.setNewObjectId(pid);
  287. Result update2 = updateRef2.update();
  288. assertEquals(Result.FAST_FORWARD, update2);
  289. assertEquals(pid, db.resolve("refs/heads/master"));
  290. }
  291. /**
  292. * Update the HEAD ref. Only it should be changed, not what it points to.
  293. *
  294. * @throws Exception
  295. */
  296. @Test
  297. public void testUpdateRefDetached() throws Exception {
  298. ObjectId pid = db.resolve("refs/heads/master");
  299. ObjectId ppid = db.resolve("refs/heads/master^");
  300. RefUpdate updateRef = db.updateRef("HEAD", true);
  301. updateRef.setForceUpdate(true);
  302. updateRef.setNewObjectId(ppid);
  303. Result update = updateRef.update();
  304. assertEquals(Result.FORCED, update);
  305. assertEquals(ppid, db.resolve("HEAD"));
  306. Ref ref = db.getRef("HEAD");
  307. assertEquals("HEAD", ref.getName());
  308. assertTrue("is detached", !ref.isSymbolic());
  309. // the branch HEAD referred to is left untouched
  310. assertEquals(pid, db.resolve("refs/heads/master"));
  311. ReflogReader reflogReader = db.getReflogReader("HEAD");
  312. ReflogEntry e = reflogReader.getReverseEntries().get(0);
  313. assertEquals(pid, e.getOldId());
  314. assertEquals(ppid, e.getNewId());
  315. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  316. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  317. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  318. }
  319. /**
  320. * Update the HEAD ref when the referenced branch is unborn
  321. *
  322. * @throws Exception
  323. */
  324. @Test
  325. public void testUpdateRefDetachedUnbornHead() throws Exception {
  326. ObjectId ppid = db.resolve("refs/heads/master^");
  327. writeSymref("HEAD", "refs/heads/unborn");
  328. RefUpdate updateRef = db.updateRef("HEAD", true);
  329. updateRef.setForceUpdate(true);
  330. updateRef.setNewObjectId(ppid);
  331. Result update = updateRef.update();
  332. assertEquals(Result.NEW, update);
  333. assertEquals(ppid, db.resolve("HEAD"));
  334. Ref ref = db.getRef("HEAD");
  335. assertEquals("HEAD", ref.getName());
  336. assertTrue("is detached", !ref.isSymbolic());
  337. // the branch HEAD referred to is left untouched
  338. assertNull(db.resolve("refs/heads/unborn"));
  339. ReflogReader reflogReader = db.getReflogReader("HEAD");
  340. ReflogEntry e = reflogReader.getReverseEntries().get(0);
  341. assertEquals(ObjectId.zeroId(), e.getOldId());
  342. assertEquals(ppid, e.getNewId());
  343. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  344. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  345. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  346. }
  347. /**
  348. * Delete a ref that exists both as packed and loose. Make sure the ref
  349. * cannot be resolved after delete.
  350. *
  351. * @throws IOException
  352. */
  353. @Test
  354. public void testDeleteLoosePacked() throws IOException {
  355. ObjectId pid = db.resolve("refs/heads/c^");
  356. RefUpdate updateRef = db.updateRef("refs/heads/c");
  357. updateRef.setNewObjectId(pid);
  358. updateRef.setForceUpdate(true);
  359. Result update = updateRef.update();
  360. assertEquals(Result.FORCED, update); // internal
  361. // The real test here
  362. RefUpdate updateRef2 = db.updateRef("refs/heads/c");
  363. updateRef2.setForceUpdate(true);
  364. Result delete = updateRef2.delete();
  365. assertEquals(Result.FORCED, delete);
  366. assertNull(db.resolve("refs/heads/c"));
  367. }
  368. /**
  369. * Try modify a ref to same
  370. *
  371. * @throws IOException
  372. */
  373. @Test
  374. public void testUpdateRefNoChange() throws IOException {
  375. ObjectId pid = db.resolve("refs/heads/master");
  376. RefUpdate updateRef = db.updateRef("refs/heads/master");
  377. updateRef.setNewObjectId(pid);
  378. Result update = updateRef.update();
  379. assertEquals(Result.NO_CHANGE, update);
  380. assertEquals(pid, db.resolve("refs/heads/master"));
  381. }
  382. /**
  383. * Test case originating from
  384. * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
  385. *
  386. * Make sure the in memory cache is updated properly after
  387. * update of symref. This one did not fail because the
  388. * ref was packed due to implementation issues.
  389. *
  390. * @throws Exception
  391. */
  392. @Test
  393. public void testRefsCacheAfterUpdate() throws Exception {
  394. // Do not use the defalt repo for this case.
  395. Map<String, Ref> allRefs = db.getAllRefs();
  396. ObjectId oldValue = db.resolve("HEAD");
  397. ObjectId newValue = db.resolve("HEAD^");
  398. // first make HEAD refer to loose ref
  399. RefUpdate updateRef = db.updateRef(Constants.HEAD);
  400. updateRef.setForceUpdate(true);
  401. updateRef.setNewObjectId(newValue);
  402. Result update = updateRef.update();
  403. assertEquals(Result.FORCED, update);
  404. // now update that ref
  405. updateRef = db.updateRef(Constants.HEAD);
  406. updateRef.setForceUpdate(true);
  407. updateRef.setNewObjectId(oldValue);
  408. update = updateRef.update();
  409. assertEquals(Result.FAST_FORWARD, update);
  410. allRefs = db.getAllRefs();
  411. Ref master = allRefs.get("refs/heads/master");
  412. Ref head = allRefs.get("HEAD");
  413. assertEquals("refs/heads/master", master.getName());
  414. assertEquals("HEAD", head.getName());
  415. assertTrue("is symbolic reference", head.isSymbolic());
  416. assertSame(master, head.getTarget());
  417. }
  418. /**
  419. * Test case originating from
  420. * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
  421. *
  422. * Make sure the in memory cache is updated properly after
  423. * update of symref.
  424. *
  425. * @throws Exception
  426. */
  427. @Test
  428. public void testRefsCacheAfterUpdateLooseOnly() throws Exception {
  429. // Do not use the defalt repo for this case.
  430. Map<String, Ref> allRefs = db.getAllRefs();
  431. ObjectId oldValue = db.resolve("HEAD");
  432. writeSymref(Constants.HEAD, "refs/heads/newref");
  433. RefUpdate updateRef = db.updateRef(Constants.HEAD);
  434. updateRef.setForceUpdate(true);
  435. updateRef.setNewObjectId(oldValue);
  436. Result update = updateRef.update();
  437. assertEquals(Result.NEW, update);
  438. allRefs = db.getAllRefs();
  439. Ref head = allRefs.get("HEAD");
  440. Ref newref = allRefs.get("refs/heads/newref");
  441. assertEquals("refs/heads/newref", newref.getName());
  442. assertEquals("HEAD", head.getName());
  443. assertTrue("is symbolic reference", head.isSymbolic());
  444. assertSame(newref, head.getTarget());
  445. }
  446. /**
  447. * Try modify a ref, but get wrong expected old value
  448. *
  449. * @throws IOException
  450. */
  451. @Test
  452. public void testUpdateRefLockFailureWrongOldValue() throws IOException {
  453. ObjectId pid = db.resolve("refs/heads/master");
  454. RefUpdate updateRef = db.updateRef("refs/heads/master");
  455. updateRef.setNewObjectId(pid);
  456. updateRef.setExpectedOldObjectId(db.resolve("refs/heads/master^"));
  457. Result update = updateRef.update();
  458. assertEquals(Result.LOCK_FAILURE, update);
  459. assertEquals(pid, db.resolve("refs/heads/master"));
  460. }
  461. /**
  462. * Try modify a ref forward, fast forward, checking old value first
  463. *
  464. * @throws IOException
  465. */
  466. @Test
  467. public void testUpdateRefForwardWithCheck1() throws IOException {
  468. ObjectId ppid = db.resolve("refs/heads/master^");
  469. ObjectId pid = db.resolve("refs/heads/master");
  470. RefUpdate updateRef = db.updateRef("refs/heads/master");
  471. updateRef.setNewObjectId(ppid);
  472. updateRef.setForceUpdate(true);
  473. Result update = updateRef.update();
  474. assertEquals(Result.FORCED, update);
  475. assertEquals(ppid, db.resolve("refs/heads/master"));
  476. // real test
  477. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  478. updateRef2.setExpectedOldObjectId(ppid);
  479. updateRef2.setNewObjectId(pid);
  480. Result update2 = updateRef2.update();
  481. assertEquals(Result.FAST_FORWARD, update2);
  482. assertEquals(pid, db.resolve("refs/heads/master"));
  483. }
  484. /**
  485. * Try modify a ref forward, fast forward, checking old commit first
  486. *
  487. * @throws IOException
  488. */
  489. @Test
  490. public void testUpdateRefForwardWithCheck2() throws IOException {
  491. ObjectId ppid = db.resolve("refs/heads/master^");
  492. ObjectId pid = db.resolve("refs/heads/master");
  493. RefUpdate updateRef = db.updateRef("refs/heads/master");
  494. updateRef.setNewObjectId(ppid);
  495. updateRef.setForceUpdate(true);
  496. Result update = updateRef.update();
  497. assertEquals(Result.FORCED, update);
  498. assertEquals(ppid, db.resolve("refs/heads/master"));
  499. // real test
  500. RevCommit old = new RevWalk(db).parseCommit(ppid);
  501. RefUpdate updateRef2 = db.updateRef("refs/heads/master");
  502. updateRef2.setExpectedOldObjectId(old);
  503. updateRef2.setNewObjectId(pid);
  504. Result update2 = updateRef2.update();
  505. assertEquals(Result.FAST_FORWARD, update2);
  506. assertEquals(pid, db.resolve("refs/heads/master"));
  507. }
  508. /**
  509. * Try modify a ref that is locked
  510. *
  511. * @throws IOException
  512. */
  513. @Test
  514. public void testUpdateRefLockFailureLocked() throws IOException {
  515. ObjectId opid = db.resolve("refs/heads/master");
  516. ObjectId pid = db.resolve("refs/heads/master^");
  517. RefUpdate updateRef = db.updateRef("refs/heads/master");
  518. updateRef.setNewObjectId(pid);
  519. LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
  520. "refs/heads/master"), db.getFS());
  521. try {
  522. assertTrue(lockFile1.lock()); // precondition to test
  523. Result update = updateRef.update();
  524. assertEquals(Result.LOCK_FAILURE, update);
  525. assertEquals(opid, db.resolve("refs/heads/master"));
  526. LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"),
  527. db.getFS());
  528. assertFalse(lockFile2.lock()); // was locked, still is
  529. } finally {
  530. lockFile1.unlock();
  531. }
  532. }
  533. /**
  534. * Try to delete a ref. Delete requires force.
  535. *
  536. * @throws IOException
  537. */
  538. @Test
  539. public void testDeleteLoosePackedRejected() throws IOException {
  540. ObjectId pid = db.resolve("refs/heads/c^");
  541. ObjectId oldpid = db.resolve("refs/heads/c");
  542. RefUpdate updateRef = db.updateRef("refs/heads/c");
  543. updateRef.setNewObjectId(pid);
  544. Result update = updateRef.update();
  545. assertEquals(Result.REJECTED, update);
  546. assertEquals(oldpid, db.resolve("refs/heads/c"));
  547. }
  548. @Test
  549. public void testRenameBranchNoPreviousLog() throws IOException {
  550. assertFalse("precondition, no log on old branchg", new File(db
  551. .getDirectory(), "logs/refs/heads/b").exists());
  552. ObjectId rb = db.resolve("refs/heads/b");
  553. ObjectId oldHead = db.resolve(Constants.HEAD);
  554. assertFalse(rb.equals(oldHead)); // assumption for this test
  555. RefRename renameRef = db.renameRef("refs/heads/b",
  556. "refs/heads/new/name");
  557. Result result = renameRef.rename();
  558. assertEquals(Result.RENAMED, result);
  559. assertEquals(rb, db.resolve("refs/heads/new/name"));
  560. assertNull(db.resolve("refs/heads/b"));
  561. assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size());
  562. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
  563. .getLastEntry().getComment());
  564. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  565. assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
  566. }
  567. @Test
  568. public void testRenameBranchHasPreviousLog() throws IOException {
  569. ObjectId rb = db.resolve("refs/heads/b");
  570. ObjectId oldHead = db.resolve(Constants.HEAD);
  571. assertFalse("precondition for this test, branch b != HEAD", rb
  572. .equals(oldHead));
  573. writeReflog(db, rb, "Just a message", "refs/heads/b");
  574. assertTrue("log on old branch", new File(db.getDirectory(),
  575. "logs/refs/heads/b").exists());
  576. RefRename renameRef = db.renameRef("refs/heads/b",
  577. "refs/heads/new/name");
  578. Result result = renameRef.rename();
  579. assertEquals(Result.RENAMED, result);
  580. assertEquals(rb, db.resolve("refs/heads/new/name"));
  581. assertNull(db.resolve("refs/heads/b"));
  582. assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
  583. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
  584. .getLastEntry().getComment());
  585. assertEquals("Just a message", db.getReflogReader("new/name")
  586. .getReverseEntries().get(1).getComment());
  587. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  588. assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
  589. }
  590. @Test
  591. public void testRenameCurrentBranch() throws IOException {
  592. ObjectId rb = db.resolve("refs/heads/b");
  593. writeSymref(Constants.HEAD, "refs/heads/b");
  594. ObjectId oldHead = db.resolve(Constants.HEAD);
  595. assertEquals("internal test condition, b == HEAD", oldHead, rb);
  596. writeReflog(db, rb, "Just a message", "refs/heads/b");
  597. assertTrue("log on old branch", new File(db.getDirectory(),
  598. "logs/refs/heads/b").exists());
  599. RefRename renameRef = db.renameRef("refs/heads/b",
  600. "refs/heads/new/name");
  601. Result result = renameRef.rename();
  602. assertEquals(Result.RENAMED, result);
  603. assertEquals(rb, db.resolve("refs/heads/new/name"));
  604. assertNull(db.resolve("refs/heads/b"));
  605. assertEquals("Branch: renamed b to new/name", db.getReflogReader(
  606. "new/name").getLastEntry().getComment());
  607. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  608. assertEquals(rb, db.resolve(Constants.HEAD));
  609. assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
  610. assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment());
  611. assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment());
  612. }
  613. @Test
  614. public void testRenameBranchAlsoInPack() throws IOException {
  615. ObjectId rb = db.resolve("refs/heads/b");
  616. ObjectId rb2 = db.resolve("refs/heads/b~1");
  617. assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage());
  618. RefUpdate updateRef = db.updateRef("refs/heads/b");
  619. updateRef.setNewObjectId(rb2);
  620. updateRef.setForceUpdate(true);
  621. Result update = updateRef.update();
  622. assertEquals("internal check new ref is loose", Result.FORCED, update);
  623. assertEquals(Ref.Storage.LOOSE, db.getRef("refs/heads/b").getStorage());
  624. writeReflog(db, rb, "Just a message", "refs/heads/b");
  625. assertTrue("log on old branch", new File(db.getDirectory(),
  626. "logs/refs/heads/b").exists());
  627. RefRename renameRef = db.renameRef("refs/heads/b",
  628. "refs/heads/new/name");
  629. Result result = renameRef.rename();
  630. assertEquals(Result.RENAMED, result);
  631. assertEquals(rb2, db.resolve("refs/heads/new/name"));
  632. assertNull(db.resolve("refs/heads/b"));
  633. assertEquals("Branch: renamed b to new/name", db.getReflogReader(
  634. "new/name").getLastEntry().getComment());
  635. assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size());
  636. assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment());
  637. assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
  638. // make sure b's log file is gone too.
  639. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
  640. // Create new Repository instance, to reread caches and make sure our
  641. // assumptions are persistent.
  642. Repository ndb = new FileRepository(db.getDirectory());
  643. assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
  644. assertNull(ndb.resolve("refs/heads/b"));
  645. }
  646. public void tryRenameWhenLocked(String toLock, String fromName,
  647. String toName, String headPointsTo) throws IOException {
  648. // setup
  649. writeSymref(Constants.HEAD, headPointsTo);
  650. ObjectId oldfromId = db.resolve(fromName);
  651. ObjectId oldHeadId = db.resolve(Constants.HEAD);
  652. writeReflog(db, oldfromId, "Just a message", fromName);
  653. List<ReflogEntry> oldFromLog = db
  654. .getReflogReader(fromName).getReverseEntries();
  655. List<ReflogEntry> oldHeadLog = oldHeadId != null ? db
  656. .getReflogReader(Constants.HEAD).getReverseEntries() : null;
  657. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  658. "logs/" + fromName).exists());
  659. // "someone" has branch X locked
  660. LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock),
  661. db.getFS());
  662. try {
  663. assertTrue(lockFile.lock());
  664. // Now this is our test
  665. RefRename renameRef = db.renameRef(fromName, toName);
  666. Result result = renameRef.rename();
  667. assertEquals(Result.LOCK_FAILURE, result);
  668. // Check that the involved refs are the same despite the failure
  669. assertExists(false, toName);
  670. if (!toLock.equals(toName))
  671. assertExists(false, toName + ".lock");
  672. assertExists(true, toLock + ".lock");
  673. if (!toLock.equals(fromName))
  674. assertExists(false, "logs/" + fromName + ".lock");
  675. assertExists(false, "logs/" + toName + ".lock");
  676. assertEquals(oldHeadId, db.resolve(Constants.HEAD));
  677. assertEquals(oldfromId, db.resolve(fromName));
  678. assertNull(db.resolve(toName));
  679. assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
  680. .getReverseEntries().toString());
  681. if (oldHeadId != null)
  682. assertEquals(oldHeadLog.toString(), db.getReflogReader(
  683. Constants.HEAD).getReverseEntries().toString());
  684. } finally {
  685. lockFile.unlock();
  686. }
  687. }
  688. private void assertExists(boolean positive, String toName) {
  689. assertEquals(toName + (positive ? " " : " does not ") + "exist",
  690. positive, new File(db.getDirectory(), toName).exists());
  691. }
  692. @Test
  693. public void testRenameBranchCannotLockAFileHEADisFromLockHEAD()
  694. throws IOException {
  695. tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
  696. "refs/heads/b");
  697. }
  698. @Test
  699. public void testRenameBranchCannotLockAFileHEADisFromLockFrom()
  700. throws IOException {
  701. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  702. "refs/heads/new/name", "refs/heads/b");
  703. }
  704. @Test
  705. public void testRenameBranchCannotLockAFileHEADisFromLockTo()
  706. throws IOException {
  707. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  708. "refs/heads/new/name", "refs/heads/b");
  709. }
  710. @Test
  711. public void testRenameBranchCannotLockAFileHEADisToLockFrom()
  712. throws IOException {
  713. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  714. "refs/heads/new/name", "refs/heads/new/name");
  715. }
  716. @Test
  717. public void testRenameBranchCannotLockAFileHEADisToLockTo()
  718. throws IOException {
  719. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  720. "refs/heads/new/name", "refs/heads/new/name");
  721. }
  722. @Test
  723. public void testRenameBranchCannotLockAFileHEADisOtherLockFrom()
  724. throws IOException {
  725. tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
  726. "refs/heads/new/name", "refs/heads/a");
  727. }
  728. @Test
  729. public void testRenameBranchCannotLockAFileHEADisOtherLockTo()
  730. throws IOException {
  731. tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
  732. "refs/heads/new/name", "refs/heads/a");
  733. }
  734. @Test
  735. public void testRenameRefNameColission1avoided() throws IOException {
  736. // setup
  737. ObjectId rb = db.resolve("refs/heads/b");
  738. writeSymref(Constants.HEAD, "refs/heads/a");
  739. RefUpdate updateRef = db.updateRef("refs/heads/a");
  740. updateRef.setNewObjectId(rb);
  741. updateRef.setRefLogMessage("Setup", false);
  742. assertEquals(Result.FAST_FORWARD, updateRef.update());
  743. ObjectId oldHead = db.resolve(Constants.HEAD);
  744. assertEquals(oldHead, rb); // assumption for this test
  745. writeReflog(db, rb, "Just a message", "refs/heads/a");
  746. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  747. "logs/refs/heads/a").exists());
  748. // Now this is our test
  749. RefRename renameRef = db.renameRef("refs/heads/a", "refs/heads/a/b");
  750. Result result = renameRef.rename();
  751. assertEquals(Result.RENAMED, result);
  752. assertNull(db.resolve("refs/heads/a"));
  753. assertEquals(rb, db.resolve("refs/heads/a/b"));
  754. assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size());
  755. assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b")
  756. .getReverseEntries().get(0).getComment());
  757. assertEquals("Just a message", db.getReflogReader("a/b")
  758. .getReverseEntries().get(1).getComment());
  759. assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries()
  760. .get(2).getComment());
  761. // same thing was logged to HEAD
  762. assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD")
  763. .getReverseEntries().get(0).getComment());
  764. }
  765. @Test
  766. public void testRenameRefNameColission2avoided() throws IOException {
  767. // setup
  768. ObjectId rb = db.resolve("refs/heads/b");
  769. writeSymref(Constants.HEAD, "refs/heads/prefix/a");
  770. RefUpdate updateRef = db.updateRef("refs/heads/prefix/a");
  771. updateRef.setNewObjectId(rb);
  772. updateRef.setRefLogMessage("Setup", false);
  773. updateRef.setForceUpdate(true);
  774. assertEquals(Result.FORCED, updateRef.update());
  775. ObjectId oldHead = db.resolve(Constants.HEAD);
  776. assertEquals(oldHead, rb); // assumption for this test
  777. writeReflog(db, rb, "Just a message", "refs/heads/prefix/a");
  778. assertTrue("internal check, we have a log", new File(db.getDirectory(),
  779. "logs/refs/heads/prefix/a").exists());
  780. // Now this is our test
  781. RefRename renameRef = db.renameRef("refs/heads/prefix/a",
  782. "refs/heads/prefix");
  783. Result result = renameRef.rename();
  784. assertEquals(Result.RENAMED, result);
  785. assertNull(db.resolve("refs/heads/prefix/a"));
  786. assertEquals(rb, db.resolve("refs/heads/prefix"));
  787. assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size());
  788. assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
  789. "prefix").getReverseEntries().get(0).getComment());
  790. assertEquals("Just a message", db.getReflogReader("prefix")
  791. .getReverseEntries().get(1).getComment());
  792. assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries()
  793. .get(2).getComment());
  794. assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
  795. "HEAD").getReverseEntries().get(0).getComment());
  796. }
  797. private static void writeReflog(Repository db, ObjectId newId, String msg,
  798. String refName) throws IOException {
  799. RefDirectory refs = (RefDirectory) db.getRefDatabase();
  800. RefDirectoryUpdate update = refs.newUpdate(refName, true);
  801. update.setNewObjectId(newId);
  802. refs.log(update, msg, true);
  803. }
  804. private static class SubclassedId extends ObjectId {
  805. SubclassedId(AnyObjectId src) {
  806. super(src);
  807. }
  808. }
  809. }