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.

RacyGitTests.java 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> 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.lib;
  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import static org.junit.Assert.assertEquals;
  13. import static org.junit.Assert.assertFalse;
  14. import static org.junit.Assert.assertTrue;
  15. import java.io.File;
  16. import java.io.FileOutputStream;
  17. import java.io.IOException;
  18. import java.time.Instant;
  19. import org.eclipse.jgit.api.Git;
  20. import org.eclipse.jgit.dircache.DirCache;
  21. import org.eclipse.jgit.junit.RepositoryTestCase;
  22. import org.eclipse.jgit.junit.time.TimeUtil;
  23. import org.eclipse.jgit.treewalk.FileTreeIterator;
  24. import org.eclipse.jgit.treewalk.WorkingTreeOptions;
  25. import org.eclipse.jgit.util.FS;
  26. import org.junit.Test;
  27. public class RacyGitTests extends RepositoryTestCase {
  28. @Test
  29. public void testRacyGitDetection() throws Exception {
  30. // Reset to force creation of index file
  31. try (Git git = new Git(db)) {
  32. git.reset().call();
  33. }
  34. // wait to ensure that modtimes of the file doesn't match last index
  35. // file modtime
  36. fsTick(db.getIndexFile());
  37. // create two files
  38. File a = writeToWorkDir("a", "a");
  39. File b = writeToWorkDir("b", "b");
  40. TimeUtil.setLastModifiedOf(a.toPath(), b.toPath());
  41. TimeUtil.setLastModifiedOf(b.toPath(), b.toPath());
  42. // wait to ensure that file-modTimes and therefore index entry modTime
  43. // doesn't match the modtime of index-file after next persistance
  44. fsTick(b);
  45. // now add both files to the index. No racy git expected
  46. resetIndex(new FileTreeIterator(db));
  47. assertEquals(
  48. "[a, mode:100644, time:t0, length:1, content:a]"
  49. + "[b, mode:100644, time:t0, length:1, content:b]",
  50. indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
  51. // wait to ensure the file 'a' is updated at t1.
  52. fsTick(db.getIndexFile());
  53. // Create a racy git situation. This is a situation that the index is
  54. // updated and then a file is modified within the same tick of the
  55. // filesystem timestamp resolution. By changing the index file
  56. // artificially, we create a fake racy situation.
  57. File updatedA = writeToWorkDir("a", "a2");
  58. Instant newLastModified = TimeUtil
  59. .setLastModifiedWithOffset(updatedA.toPath(), 100L);
  60. resetIndex(new FileTreeIterator(db));
  61. FS.DETECTED.setLastModified(db.getIndexFile().toPath(),
  62. newLastModified);
  63. DirCache dc = db.readDirCache();
  64. // check index state: although racily clean a should not be reported as
  65. // being dirty since we forcefully reset the index to match the working
  66. // tree
  67. assertEquals(
  68. "[a, mode:100644, time:t1, smudged, length:0, content:a2]"
  69. + "[b, mode:100644, time:t0, length:1, content:b]",
  70. indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT));
  71. // compare state of files in working tree with index to check that
  72. // FileTreeIterator.isModified() works as expected
  73. FileTreeIterator f = new FileTreeIterator(db.getWorkTree(), db.getFS(),
  74. db.getConfig().get(WorkingTreeOptions.KEY));
  75. assertTrue(f.findFile("a"));
  76. try (ObjectReader reader = db.newObjectReader()) {
  77. assertFalse(f.isModified(dc.getEntry("a"), false, reader));
  78. }
  79. }
  80. private File writeToWorkDir(String path, String content) throws IOException {
  81. File f = new File(db.getWorkTree(), path);
  82. try (FileOutputStream fos = new FileOutputStream(f)) {
  83. fos.write(content.getBytes(UTF_8));
  84. return f;
  85. }
  86. }
  87. }