aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java280
1 files changed, 280 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
new file mode 100644
index 0000000000..3a7fa2388e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2012-2013, Robin Rosenberg <robin.rosenberg@dewire.com> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.util;
+
+import static java.time.Instant.EPOCH;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFilePermission;
+import java.time.Duration;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.errors.CommandFailedException;
+import org.eclipse.jgit.junit.MockSystemReader;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.RepositoryCache;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FSTest {
+ private File trash;
+
+ @Before
+ public void setUp() throws Exception {
+ SystemReader.setInstance(new MockSystemReader());
+ trash = File.createTempFile("tmp_", "");
+ trash.delete();
+ assertTrue("mkdir " + trash, trash.mkdir());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
+
+ /**
+ * The old File methods traverse symbolic links and look at the targets.
+ * With symbolic links we usually want to modify/look at the link. For some
+ * reason the executable attribute seems to always look at the target, but
+ * for the other attributes like lastModified, hidden and exists we must
+ * differ between the link and the target.
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testSymlinkAttributes() throws IOException, InterruptedException {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ FS fs = FS.DETECTED;
+ File link = new File(trash, "a");
+ File target = new File(trash, "b");
+ fs.createSymLink(link, "b");
+ assertTrue(fs.exists(link));
+ String targetName = fs.readSymLink(link);
+ assertEquals("b", targetName);
+ assertTrue(fs.lastModifiedInstant(link).compareTo(EPOCH) > 0);
+ assertTrue(fs.exists(link));
+ assertFalse(fs.canExecute(link));
+ // The length of a symbolic link is a length of the target file path.
+ assertEquals(1, fs.length(link));
+ assertFalse(fs.exists(target));
+ assertFalse(fs.isFile(target));
+ assertFalse(fs.isDirectory(target));
+ assertFalse(fs.canExecute(target));
+
+ RepositoryTestCase.fsTick(link);
+ // Now create the link target
+ FileUtils.createNewFile(target);
+ assertTrue(fs.exists(link));
+ assertTrue(fs.lastModifiedInstant(link).compareTo(EPOCH) > 0);
+ assertTrue(fs.lastModifiedInstant(target)
+ .compareTo(fs.lastModifiedInstant(link)) > 0);
+ assertFalse(fs.canExecute(link));
+ fs.setExecute(target, true);
+ assertFalse(fs.canExecute(link));
+ assumeTrue(fs.supportsExecute());
+ assertTrue(fs.canExecute(target));
+ }
+
+ @Test
+ public void testUnicodeFilePath() throws IOException {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ FS fs = FS.DETECTED;
+ File link = new File(trash, "ä");
+ File target = new File(trash, "å");
+
+ try {
+ // Check if the runtime can support Unicode file paths.
+ link.toPath();
+ target.toPath();
+ } catch (InvalidPathException e) {
+ // When executing a test with LANG environment variable set to non
+ // UTF-8 encoding, it seems that JRE cannot handle Unicode file
+ // paths. This happens when this test is executed in Bazel as it
+ // unsets LANG
+ // (https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions).
+ // Skip the test if the runtime cannot handle Unicode characters.
+ assumeNoException(e);
+ }
+
+ fs.createSymLink(link, "å");
+ assertTrue(fs.exists(link));
+ assertEquals("å", fs.readSymLink(link));
+ }
+
+ @Test
+ public void testExecutableAttributes() throws Exception {
+ FS fs = FS.DETECTED.newInstance();
+ // If this assumption fails the test is halted and ignored.
+ assumeTrue(fs instanceof FS_POSIX);
+ ((FS_POSIX) fs).setUmask(0022);
+
+ File f = new File(trash, "bla");
+ assertTrue(f.createNewFile());
+ assertFalse(fs.canExecute(f));
+
+ Set<PosixFilePermission> permissions = readPermissions(f);
+ assertTrue(!permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
+ assertTrue(!permissions.contains(PosixFilePermission.GROUP_EXECUTE));
+ assertTrue(!permissions.contains(PosixFilePermission.OWNER_EXECUTE));
+
+ fs.setExecute(f, true);
+
+ permissions = readPermissions(f);
+ assertTrue("'owner' execute permission not set",
+ permissions.contains(PosixFilePermission.OWNER_EXECUTE));
+ assertTrue("'group' execute permission not set",
+ permissions.contains(PosixFilePermission.GROUP_EXECUTE));
+ assertTrue("'others' execute permission not set",
+ permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
+
+ ((FS_POSIX) fs).setUmask(0033);
+ fs.setExecute(f, false);
+ assertFalse(fs.canExecute(f));
+ fs.setExecute(f, true);
+
+ permissions = readPermissions(f);
+ assertTrue("'owner' execute permission not set",
+ permissions.contains(PosixFilePermission.OWNER_EXECUTE));
+ assertFalse("'group' execute permission set",
+ permissions.contains(PosixFilePermission.GROUP_EXECUTE));
+ assertFalse("'others' execute permission set",
+ permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
+ }
+
+ private Set<PosixFilePermission> readPermissions(File f) throws IOException {
+ return Files
+ .getFileAttributeView(f.toPath(), PosixFileAttributeView.class)
+ .readAttributes().permissions();
+ }
+
+ @Test(expected = CommandFailedException.class)
+ public void testReadPipePosixCommandFailure()
+ throws CommandFailedException {
+ FS fs = FS.DETECTED.newInstance();
+ assumeTrue(fs instanceof FS_POSIX);
+
+ FS.readPipe(fs.userHome(),
+ new String[] { "/bin/sh", "-c", "exit 1" },
+ SystemReader.getInstance().getDefaultCharset().name());
+ }
+
+ @Test(expected = CommandFailedException.class)
+ public void testReadPipeCommandStartFailure()
+ throws CommandFailedException {
+ FS fs = FS.DETECTED.newInstance();
+
+ FS.readPipe(fs.userHome(),
+ new String[] { "this-command-does-not-exist" },
+ SystemReader.getInstance().getDefaultCharset().name());
+ }
+
+ @Test
+ @SuppressWarnings("boxing")
+ public void testConcurrentSymlinkSupport()
+ throws ExecutionException, InterruptedException {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ int n = 3;
+ List<CompletableFuture<Boolean>> futures = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ futures.add(CompletableFuture.supplyAsync(
+ () -> FS.DETECTED.newInstance().supportsSymlinks()));
+ }
+
+ for (int i = 0; i < n; i++) {
+ assertTrue(futures.get(i).get());
+ }
+ }
+
+ @Test
+ public void testFsTimestampResolution() throws Exception {
+ DateTimeFormatter formatter = DateTimeFormatter
+ .ofPattern("uuuu-MMM-dd HH:mm:ss.nnnnnnnnn", Locale.ENGLISH)
+ .withZone(ZoneId.systemDefault());
+ Path dir = Files.createTempDirectory("probe-filesystem");
+ Duration resolution = FS.getFileStoreAttributes(dir)
+ .getFsTimestampResolution();
+ long resolutionNs = resolution.toNanos();
+ assertTrue(resolutionNs > 0);
+ for (int i = 0; i < 10; i++) {
+ Path f = null;
+ try {
+ f = dir.resolve("testTimestampResolution" + i);
+ Files.createFile(f);
+ FileUtils.touch(f);
+ FileTime t1 = Files.getLastModifiedTime(f);
+ TimeUnit.NANOSECONDS.sleep(resolutionNs);
+ FileUtils.touch(f);
+ FileTime t2 = Files.getLastModifiedTime(f);
+ assertTrue(String.format(
+ "expected t2=%s to be larger than t1=%s\nsince file timestamp resolution was measured to be %,d ns",
+ formatter.format(t2.toInstant()),
+ formatter.format(t1.toInstant()),
+ Long.valueOf(resolutionNs)), t2.compareTo(t1) > 0);
+ } finally {
+ if (f != null) {
+ Files.delete(f);
+ }
+ }
+ }
+ }
+
+ // bug 548682
+ @Test
+ public void testRepoCacheRelativePathUnbornRepo() {
+ assertFalse(RepositoryCache.FileKey
+ .isGitRepository(new File("repo.git"), FS.DETECTED));
+ }
+
+ @Test
+ public void testSearchPath() throws IOException {
+ File f1 = new File(trash, "file1");
+ FileUtils.createNewFile(f1);
+ f1.setExecutable(true);
+ File f2 = new File(trash, "file2");
+ FileUtils.createNewFile(f2);
+ assertEquals(f1, FS.searchPath(trash.getAbsolutePath(), "file1"));
+ assertNull(FS.searchPath(trash.getAbsolutePath(), "file2"));
+ }
+
+ @Test
+ public void testSearchPathEmptyPath() {
+ assertNull(FS.searchPath("", "file1"));
+ assertNull(FS.searchPath(File.pathSeparator, "file1"));
+ assertNull(FS.searchPath(File.pathSeparator + File.pathSeparator,
+ "file1"));
+ assertNull(FS.searchPath(
+ " " + File.pathSeparator + " " + File.pathSeparator + " \t",
+ "file1"));
+ }
+}