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.

FileReftableTest.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Copyright (C) 2019, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.storage.file;
  11. import static org.eclipse.jgit.lib.RefUpdate.Result.FAST_FORWARD;
  12. import static org.eclipse.jgit.lib.RefUpdate.Result.FORCED;
  13. import static org.eclipse.jgit.lib.RefUpdate.Result.IO_FAILURE;
  14. import static org.eclipse.jgit.lib.RefUpdate.Result.LOCK_FAILURE;
  15. import static org.junit.Assert.assertEquals;
  16. import static org.junit.Assert.assertFalse;
  17. import static org.junit.Assert.assertNotEquals;
  18. import static org.junit.Assert.assertNotNull;
  19. import static org.junit.Assert.assertNotSame;
  20. import static org.junit.Assert.assertNull;
  21. import static org.junit.Assert.assertSame;
  22. import static org.junit.Assert.assertTrue;
  23. import static org.junit.Assert.fail;
  24. import java.io.File;
  25. import java.io.IOException;
  26. import java.util.ArrayList;
  27. import java.util.List;
  28. import org.eclipse.jgit.lib.AnyObjectId;
  29. import org.eclipse.jgit.lib.Constants;
  30. import org.eclipse.jgit.lib.NullProgressMonitor;
  31. import org.eclipse.jgit.lib.ObjectId;
  32. import org.eclipse.jgit.lib.PersonIdent;
  33. import org.eclipse.jgit.lib.Ref;
  34. import org.eclipse.jgit.lib.RefRename;
  35. import org.eclipse.jgit.lib.RefUpdate;
  36. import org.eclipse.jgit.lib.RefUpdate.Result;
  37. import org.eclipse.jgit.lib.ReflogEntry;
  38. import org.eclipse.jgit.lib.ReflogReader;
  39. import org.eclipse.jgit.lib.RepositoryCache;
  40. import org.eclipse.jgit.revwalk.RevWalk;
  41. import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
  42. import org.eclipse.jgit.transport.ReceiveCommand;
  43. import org.junit.Test;
  44. public class FileReftableTest extends SampleDataRepositoryTestCase {
  45. String bCommit;
  46. @Override
  47. public void setUp() throws Exception {
  48. super.setUp();
  49. Ref b = db.exactRef("refs/heads/b");
  50. bCommit = b.getObjectId().getName();
  51. db.convertToReftable(false, false);
  52. }
  53. @SuppressWarnings("boxing")
  54. @Test
  55. public void testRacyReload() throws Exception {
  56. ObjectId id = db.resolve("master");
  57. int retry = 0;
  58. try (FileRepository repo1 = new FileRepository(db.getDirectory());
  59. FileRepository repo2 = new FileRepository(db.getDirectory())) {
  60. FileRepository repos[] = { repo1, repo2 };
  61. for (int i = 0; i < 10; i++) {
  62. for (int j = 0; j < 2; j++) {
  63. FileRepository repo = repos[j];
  64. RefUpdate u = repo.getRefDatabase().newUpdate(
  65. String.format("branch%d", i * 10 + j), false);
  66. u.setNewObjectId(id);
  67. RefUpdate.Result r = u.update();
  68. if (!r.equals(Result.NEW)) {
  69. retry++;
  70. u = repo.getRefDatabase().newUpdate(
  71. String.format("branch%d", i * 10 + j), false);
  72. u.setNewObjectId(id);
  73. r = u.update();
  74. assertEquals(r, Result.NEW);
  75. }
  76. }
  77. }
  78. // only the first one succeeds
  79. assertEquals(retry, 19);
  80. }
  81. }
  82. @Test
  83. public void additionalRefsAreRemoved() {
  84. assertFalse(new File(db.getDirectory(), Constants.HEAD).exists());
  85. }
  86. @Test
  87. public void testCompactFully() throws Exception {
  88. ObjectId c1 = db.resolve("master^^");
  89. ObjectId c2 = db.resolve("master^");
  90. for (int i = 0; i < 5; i++) {
  91. RefUpdate u = db.updateRef("refs/heads/master");
  92. u.setForceUpdate(true);
  93. u.setNewObjectId((i%2) == 0 ? c1 : c2);
  94. assertEquals(u.update(), FORCED);
  95. }
  96. File tableDir = new File(db.getDirectory(), Constants.REFTABLE);
  97. assertTrue(tableDir.listFiles().length > 1);
  98. ((FileReftableDatabase)db.getRefDatabase()).compactFully();
  99. assertEquals(tableDir.listFiles().length,1);
  100. }
  101. @Test
  102. public void testConvert() throws Exception {
  103. Ref h = db.exactRef("HEAD");
  104. assertTrue(h.isSymbolic());
  105. assertEquals("refs/heads/master", h.getTarget().getName());
  106. Ref b = db.exactRef("refs/heads/b");
  107. assertFalse(b.isSymbolic());
  108. assertTrue(b.isPeeled());
  109. assertEquals(bCommit, b.getObjectId().name());
  110. assertTrue(db.getRefDatabase().hasFastTipsWithSha1());
  111. }
  112. @Test
  113. public void testConvertToRefdir() throws Exception {
  114. db.convertToPackedRefs(false);
  115. assertTrue(db.getRefDatabase() instanceof RefDirectory);
  116. Ref h = db.exactRef("HEAD");
  117. assertTrue(h.isSymbolic());
  118. assertEquals("refs/heads/master", h.getTarget().getName());
  119. Ref b = db.exactRef("refs/heads/b");
  120. assertFalse(b.isSymbolic());
  121. assertTrue(b.isPeeled());
  122. assertEquals(bCommit, b.getObjectId().name());
  123. assertFalse(db.getRefDatabase().hasFastTipsWithSha1());
  124. }
  125. @Test
  126. public void testBatchrefUpdate() throws Exception {
  127. ObjectId cur = db.resolve("master");
  128. ObjectId prev = db.resolve("master^");
  129. PersonIdent person = new PersonIdent("name", "mail@example.com");
  130. ReceiveCommand rc1 = new ReceiveCommand(ObjectId.zeroId(), cur, "refs/heads/batch1");
  131. ReceiveCommand rc2 = new ReceiveCommand(ObjectId.zeroId(), prev, "refs/heads/batch2");
  132. String msg = "message";
  133. try (RevWalk rw = new RevWalk(db)) {
  134. db.getRefDatabase().newBatchUpdate()
  135. .addCommand(rc1, rc2)
  136. .setAtomic(true)
  137. .setRefLogIdent(person)
  138. .setRefLogMessage(msg, false)
  139. .execute(rw, NullProgressMonitor.INSTANCE);
  140. }
  141. assertEquals(rc1.getResult(), ReceiveCommand.Result.OK);
  142. assertEquals(rc2.getResult(), ReceiveCommand.Result.OK);
  143. ReflogEntry e = db.getReflogReader("refs/heads/batch1").getLastEntry();
  144. assertEquals(msg, e.getComment());
  145. assertEquals(person, e.getWho());
  146. assertEquals(cur, e.getNewId());
  147. e = db.getReflogReader("refs/heads/batch2").getLastEntry();
  148. assertEquals(msg, e.getComment());
  149. assertEquals(person, e.getWho());
  150. assertEquals(prev, e.getNewId());
  151. assertEquals(cur, db.exactRef("refs/heads/batch1").getObjectId());
  152. assertEquals(prev, db.exactRef("refs/heads/batch2").getObjectId());
  153. }
  154. @Test
  155. public void testFastforwardStatus() throws Exception {
  156. ObjectId cur = db.resolve("master");
  157. ObjectId prev = db.resolve("master^");
  158. RefUpdate u = db.updateRef("refs/heads/master");
  159. u.setNewObjectId(prev);
  160. u.setForceUpdate(true);
  161. assertEquals(FORCED, u.update());
  162. RefUpdate u2 = db.updateRef("refs/heads/master");
  163. u2.setNewObjectId(cur);
  164. assertEquals(FAST_FORWARD, u2.update());
  165. }
  166. @Test
  167. public void testUpdateChecksOldValue() throws Exception {
  168. ObjectId cur = db.resolve("master");
  169. ObjectId prev = db.resolve("master^");
  170. RefUpdate u1 = db.updateRef("refs/heads/master");
  171. RefUpdate u2 = db.updateRef("refs/heads/master");
  172. u1.setExpectedOldObjectId(cur);
  173. u1.setNewObjectId(prev);
  174. u1.setForceUpdate(true);
  175. u2.setExpectedOldObjectId(cur);
  176. u2.setNewObjectId(prev);
  177. u2.setForceUpdate(true);
  178. assertEquals(FORCED, u1.update());
  179. assertEquals(LOCK_FAILURE, u2.update());
  180. }
  181. @Test
  182. public void testWritesymref() throws Exception {
  183. writeSymref(Constants.HEAD, "refs/heads/a");
  184. assertNotNull(db.exactRef("refs/heads/b"));
  185. }
  186. @Test
  187. public void testFastforwardStatus2() throws Exception {
  188. writeSymref(Constants.HEAD, "refs/heads/a");
  189. ObjectId bId = db.exactRef("refs/heads/b").getObjectId();
  190. RefUpdate u = db.updateRef("refs/heads/a");
  191. u.setNewObjectId(bId);
  192. u.setRefLogMessage("Setup", false);
  193. assertEquals(FAST_FORWARD, u.update());
  194. }
  195. @Test
  196. public void testDelete() throws Exception {
  197. RefUpdate up = db.getRefDatabase().newUpdate("refs/heads/a", false);
  198. up.setForceUpdate(true);
  199. RefUpdate.Result res = up.delete();
  200. assertEquals(res, FORCED);
  201. assertNull(db.exactRef("refs/heads/a"));
  202. }
  203. @Test
  204. public void testDeleteWithoutHead() throws IOException {
  205. // Prepare repository without HEAD
  206. RefUpdate refUpdate = db.updateRef(Constants.HEAD, true);
  207. refUpdate.setForceUpdate(true);
  208. refUpdate.setNewObjectId(ObjectId.zeroId());
  209. RefUpdate.Result updateResult = refUpdate.update();
  210. assertEquals(FORCED, updateResult);
  211. Ref r = db.exactRef("HEAD");
  212. assertEquals(ObjectId.zeroId(), r.getObjectId());
  213. RefUpdate.Result deleteHeadResult = db.updateRef(Constants.HEAD)
  214. .delete();
  215. // why does doDelete say NEW ?
  216. assertEquals(RefUpdate.Result.NO_CHANGE, deleteHeadResult);
  217. // Any result is ok as long as it's not an NPE
  218. db.updateRef(Constants.R_HEADS + "master").delete();
  219. }
  220. @Test
  221. public void testUpdateRefDetached() throws Exception {
  222. ObjectId pid = db.resolve("refs/heads/master");
  223. ObjectId ppid = db.resolve("refs/heads/master^");
  224. RefUpdate updateRef = db.updateRef("HEAD", true);
  225. updateRef.setForceUpdate(true);
  226. updateRef.setNewObjectId(ppid);
  227. RefUpdate.Result update = updateRef.update();
  228. assertEquals(FORCED, update);
  229. assertEquals(ppid, db.resolve("HEAD"));
  230. Ref ref = db.exactRef("HEAD");
  231. assertEquals("HEAD", ref.getName());
  232. assertTrue("is detached", !ref.isSymbolic());
  233. // the branch HEAD referred to is left untouched
  234. assertEquals(pid, db.resolve("refs/heads/master"));
  235. ReflogReader reflogReader = db.getReflogReader("HEAD");
  236. ReflogEntry e = reflogReader.getReverseEntries().get(0);
  237. assertEquals(ppid, e.getNewId());
  238. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  239. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  240. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  241. assertEquals(pid, e.getOldId());
  242. }
  243. @Test
  244. public void testWriteReflog() throws Exception {
  245. ObjectId pid = db.resolve("refs/heads/master^");
  246. RefUpdate updateRef = db.updateRef("refs/heads/master");
  247. updateRef.setNewObjectId(pid);
  248. String msg = "REFLOG!";
  249. updateRef.setRefLogMessage(msg, true);
  250. PersonIdent person = new PersonIdent("name", "mail@example.com");
  251. updateRef.setRefLogIdent(person);
  252. updateRef.setForceUpdate(true);
  253. RefUpdate.Result update = updateRef.update();
  254. assertEquals(FORCED, update); // internal
  255. ReflogReader r = db.getReflogReader("refs/heads/master");
  256. ReflogEntry e = r.getLastEntry();
  257. assertEquals(e.getNewId(), pid);
  258. assertEquals(e.getComment(), "REFLOG!: FORCED");
  259. assertEquals(e.getWho(), person);
  260. }
  261. @Test
  262. public void testLooseDelete() throws IOException {
  263. final String newRef = "refs/heads/abc";
  264. assertNull(db.exactRef(newRef));
  265. RefUpdate ref = db.updateRef(newRef);
  266. ObjectId nonZero = db.resolve(Constants.HEAD);
  267. assertNotEquals(nonZero, ObjectId.zeroId());
  268. ref.setNewObjectId(nonZero);
  269. assertEquals(RefUpdate.Result.NEW, ref.update());
  270. ref = db.updateRef(newRef);
  271. ref.setNewObjectId(db.resolve(Constants.HEAD));
  272. assertEquals(ref.delete(), RefUpdate.Result.NO_CHANGE);
  273. // Differs from RefupdateTest. Deleting a loose ref leaves reflog trail.
  274. ReflogReader reader = db.getReflogReader("refs/heads/abc");
  275. assertEquals(ObjectId.zeroId(), reader.getReverseEntry(1).getOldId());
  276. assertEquals(nonZero, reader.getReverseEntry(1).getNewId());
  277. assertEquals(nonZero, reader.getReverseEntry(0).getOldId());
  278. assertEquals(ObjectId.zeroId(), reader.getReverseEntry(0).getNewId());
  279. }
  280. private static class SubclassedId extends ObjectId {
  281. SubclassedId(AnyObjectId src) {
  282. super(src);
  283. }
  284. }
  285. @Test
  286. public void testNoCacheObjectIdSubclass() throws IOException {
  287. final String newRef = "refs/heads/abc";
  288. final RefUpdate ru = updateRef(newRef);
  289. final SubclassedId newid = new SubclassedId(ru.getNewObjectId());
  290. ru.setNewObjectId(newid);
  291. RefUpdate.Result update = ru.update();
  292. assertEquals(RefUpdate.Result.NEW, update);
  293. Ref r = db.exactRef(newRef);
  294. assertEquals(newRef, r.getName());
  295. assertNotNull(r.getObjectId());
  296. assertNotSame(newid, r.getObjectId());
  297. assertSame(ObjectId.class, r.getObjectId().getClass());
  298. assertEquals(newid, r.getObjectId());
  299. List<ReflogEntry> reverseEntries1 = db.getReflogReader("refs/heads/abc")
  300. .getReverseEntries();
  301. ReflogEntry entry1 = reverseEntries1.get(0);
  302. assertEquals(1, reverseEntries1.size());
  303. assertEquals(ObjectId.zeroId(), entry1.getOldId());
  304. assertEquals(r.getObjectId(), entry1.getNewId());
  305. assertEquals(new PersonIdent(db).toString(),
  306. entry1.getWho().toString());
  307. assertEquals("", entry1.getComment());
  308. List<ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD")
  309. .getReverseEntries();
  310. assertEquals(0, reverseEntries2.size());
  311. }
  312. @Test
  313. public void testDeleteSymref() throws IOException {
  314. RefUpdate dst = updateRef("refs/heads/abc");
  315. assertEquals(RefUpdate.Result.NEW, dst.update());
  316. ObjectId id = dst.getNewObjectId();
  317. RefUpdate u = db.updateRef("refs/symref");
  318. assertEquals(RefUpdate.Result.NEW, u.link(dst.getName()));
  319. Ref ref = db.exactRef(u.getName());
  320. assertNotNull(ref);
  321. assertTrue(ref.isSymbolic());
  322. assertEquals(dst.getName(), ref.getLeaf().getName());
  323. assertEquals(id, ref.getLeaf().getObjectId());
  324. u = db.updateRef(u.getName());
  325. u.setDetachingSymbolicRef();
  326. u.setForceUpdate(true);
  327. assertEquals(FORCED, u.delete());
  328. assertNull(db.exactRef(u.getName()));
  329. ref = db.exactRef(dst.getName());
  330. assertNotNull(ref);
  331. assertFalse(ref.isSymbolic());
  332. assertEquals(id, ref.getObjectId());
  333. }
  334. @Test
  335. public void writeUnbornHead() throws Exception {
  336. RefUpdate.Result r = db.updateRef("HEAD").link("refs/heads/unborn");
  337. assertEquals(FORCED, r);
  338. Ref head = db.exactRef("HEAD");
  339. assertTrue(head.isSymbolic());
  340. assertEquals(head.getTarget().getName(), "refs/heads/unborn");
  341. }
  342. /**
  343. * Update the HEAD ref when the referenced branch is unborn
  344. *
  345. * @throws Exception
  346. */
  347. @Test
  348. public void testUpdateRefDetachedUnbornHead() throws Exception {
  349. ObjectId ppid = db.resolve("refs/heads/master^");
  350. writeSymref("HEAD", "refs/heads/unborn");
  351. RefUpdate updateRef = db.updateRef("HEAD", true);
  352. updateRef.setForceUpdate(true);
  353. updateRef.setNewObjectId(ppid);
  354. RefUpdate.Result update = updateRef.update();
  355. assertEquals(RefUpdate.Result.NEW, update);
  356. assertEquals(ppid, db.resolve("HEAD"));
  357. Ref ref = db.exactRef("HEAD");
  358. assertEquals("HEAD", ref.getName());
  359. assertTrue("is detached", !ref.isSymbolic());
  360. // the branch HEAD referred to is left untouched
  361. assertNull(db.resolve("refs/heads/unborn"));
  362. ReflogReader reflogReader = db.getReflogReader("HEAD");
  363. ReflogEntry e = reflogReader.getReverseEntries().get(0);
  364. assertEquals(ObjectId.zeroId(), e.getOldId());
  365. assertEquals(ppid, e.getNewId());
  366. assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
  367. assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
  368. assertEquals(1250379778000L, e.getWho().getWhen().getTime());
  369. }
  370. @Test
  371. public void testDeleteNotFound() throws IOException {
  372. RefUpdate ref = updateRef("refs/heads/doesnotexist");
  373. assertNull(db.exactRef(ref.getName()));
  374. assertEquals(RefUpdate.Result.NEW, ref.delete());
  375. assertNull(db.exactRef(ref.getName()));
  376. }
  377. @Test
  378. public void testRenameSymref() throws IOException {
  379. db.resolve("HEAD");
  380. RefRename r = db.renameRef("HEAD", "KOPF");
  381. assertEquals(IO_FAILURE, r.rename());
  382. }
  383. @Test
  384. public void testRenameCurrentBranch() throws IOException {
  385. ObjectId rb = db.resolve("refs/heads/b");
  386. writeSymref(Constants.HEAD, "refs/heads/b");
  387. ObjectId oldHead = db.resolve(Constants.HEAD);
  388. assertEquals("internal test condition, b == HEAD", oldHead, rb);
  389. RefRename renameRef = db.renameRef("refs/heads/b",
  390. "refs/heads/new/name");
  391. RefUpdate.Result result = renameRef.rename();
  392. assertEquals(RefUpdate.Result.RENAMED, result);
  393. assertEquals(rb, db.resolve("refs/heads/new/name"));
  394. assertNull(db.resolve("refs/heads/b"));
  395. assertEquals(rb, db.resolve(Constants.HEAD));
  396. List<String> names = new ArrayList<>();
  397. names.add("HEAD");
  398. names.add("refs/heads/b");
  399. names.add("refs/heads/new/name");
  400. for (String nm : names) {
  401. ReflogReader rd = db.getReflogReader(nm);
  402. assertNotNull(rd);
  403. ReflogEntry last = rd.getLastEntry();
  404. ObjectId id = last.getNewId();
  405. assertTrue(ObjectId.zeroId().equals(id) || rb.equals(id));
  406. id = last.getNewId();
  407. assertTrue(ObjectId.zeroId().equals(id) || rb.equals(id));
  408. String want = "Branch: renamed b to new/name";
  409. assertEquals(want, last.getComment());
  410. }
  411. }
  412. @Test
  413. public void isGitRepository() {
  414. assertTrue(RepositoryCache.FileKey.isGitRepository(db.getDirectory(), db.getFS()));
  415. }
  416. @Test
  417. public void testRenameDestExists() throws IOException {
  418. ObjectId rb = db.resolve("refs/heads/b");
  419. writeSymref(Constants.HEAD, "refs/heads/b");
  420. ObjectId oldHead = db.resolve(Constants.HEAD);
  421. assertEquals("internal test condition, b == HEAD", oldHead, rb);
  422. RefRename renameRef = db.renameRef("refs/heads/b", "refs/heads/a");
  423. RefUpdate.Result result = renameRef.rename();
  424. assertEquals(RefUpdate.Result.LOCK_FAILURE, result);
  425. }
  426. @Test
  427. public void testRenameAtomic() throws IOException {
  428. ObjectId prevId = db.resolve("refs/heads/master^");
  429. RefRename rename = db.renameRef("refs/heads/master",
  430. "refs/heads/newmaster");
  431. RefUpdate updateRef = db.updateRef("refs/heads/master");
  432. updateRef.setNewObjectId(prevId);
  433. updateRef.setForceUpdate(true);
  434. assertEquals(FORCED, updateRef.update());
  435. assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename());
  436. }
  437. @Test
  438. public void reftableRefsStorageClass() throws IOException {
  439. Ref b = db.exactRef("refs/heads/b");
  440. assertEquals(Ref.Storage.PACKED, b.getStorage());
  441. }
  442. private RefUpdate updateRef(String name) throws IOException {
  443. final RefUpdate ref = db.updateRef(name);
  444. ref.setNewObjectId(db.resolve(Constants.HEAD));
  445. return ref;
  446. }
  447. private void writeSymref(String src, String dst) throws IOException {
  448. RefUpdate u = db.updateRef(src);
  449. switch (u.link(dst)) {
  450. case NEW:
  451. case FORCED:
  452. case NO_CHANGE:
  453. break;
  454. default:
  455. fail("link " + src + " to " + dst);
  456. }
  457. }
  458. }