You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2016/04/15 21:18:20 UTC
mina-sshd git commit: Adding unit tests for RootedFileSystemProvider
implementation of java.nio.file.spi.FileSystemProvider
Repository: mina-sshd
Updated Branches:
refs/heads/master 9fb39d224 -> 876e80b70
Adding unit tests for RootedFileSystemProvider implementation of java.nio.file.spi.FileSystemProvider
Related to SSHD-605 latest fix
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/876e80b7
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/876e80b7
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/876e80b7
Branch: refs/heads/master
Commit: 876e80b7090d8f82a936a784345000463a8f5e79
Parents: 9fb39d2
Author: Al Ho <ah...@linkedin.com>
Authored: Fri Apr 15 22:18:38 2016 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Fri Apr 15 22:18:38 2016 +0300
----------------------------------------------------------------------
.../sshd/common/file/root/AssertableFile.java | 72 +++++
.../file/root/RootedFileSystemProviderTest.java | 304 +++++++++++++++++++
2 files changed, 376 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/876e80b7/sshd-core/src/test/java/org/apache/sshd/common/file/root/AssertableFile.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/file/root/AssertableFile.java b/sshd-core/src/test/java/org/apache/sshd/common/file/root/AssertableFile.java
new file mode 100644
index 0000000..4c7ac31
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/file/root/AssertableFile.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.file.root;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.sshd.common.util.NumberUtils;
+import org.apache.sshd.util.test.BaseTestSupport;
+
+/**
+ * TODO upgrade to default methods in JDK 8
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AssertableFile extends BaseTestSupport {
+ protected AssertableFile() {
+ super();
+ }
+
+ public static boolean notExists(Path p) {
+ boolean cond = !Files.exists(p);
+ assertTrue(p + " does not exist", cond);
+ return cond;
+ }
+
+ public static boolean isFile(Path p) {
+ boolean cond = Files.exists(p);
+ assertTrue(p + " exists", cond);
+ return cond;
+ }
+
+ public static boolean isDir(Path p) {
+ boolean cond = Files.isDirectory(p);
+ assertTrue(p + " is directory", cond);
+ return cond;
+ }
+
+ public static boolean isReadable(Path p) {
+ boolean cond = Files.isReadable(p);
+ assertTrue(p + " is readable by user", cond);
+ return cond;
+ }
+
+ public static boolean isNonEmpty(byte[] bytes) {
+ boolean cond = !NumberUtils.isEmpty(bytes);
+ assertTrue("bytes are non empty", cond);
+ return cond;
+ }
+
+ public static boolean isRootedAt(Path root, Path check) {
+ boolean cond = check.toAbsolutePath().normalize().startsWith(root.toAbsolutePath().normalize());
+ assertTrue(check + " is subpath of parent " + root, cond);
+ return cond;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/876e80b7/sshd-core/src/test/java/org/apache/sshd/common/file/root/RootedFileSystemProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/file/root/RootedFileSystemProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/file/root/RootedFileSystemProviderTest.java
new file mode 100644
index 0000000..44eaf60
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/file/root/RootedFileSystemProviderTest.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.file.root;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Random;
+import java.util.TreeSet;
+
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Tests the RootedFileSystemProvider implementation of
+ * {@link java.nio.file.spi.FileSystemProvider} checking that permissions for
+ * generic FS commands are not permitted outside of the root directory.
+ *
+ * Individual tests are form pairs (e.g. testX, testXInvalid) where testXInvalid
+ * is expected to test a parent path of {@link RootedFileSystem#getRoot()}
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RootedFileSystemProviderTest extends AssertableFile {
+ private static RootedFileSystem fileSystem;
+ private static Path rootSandbox;
+
+ public RootedFileSystemProviderTest() {
+ super();
+ }
+
+ @BeforeClass
+ public static void onlyOnce() throws IOException {
+ rootSandbox = FileHelper.createTestSandbox();
+ fileSystem = (RootedFileSystem) new RootedFileSystemProvider().newFileSystem(rootSandbox,
+ Collections.<String, Object> emptyMap());
+ }
+
+ @Test
+ public void testRoot() {
+ assertTrue(isFile(fileSystem.getRoot()) && isDir(fileSystem.getRoot()) && isReadable(fileSystem.getRoot())
+ && isRootedAt(rootSandbox, fileSystem.getRoot()));
+ }
+
+ /* mkdir */
+ @Test
+ public void testMkdir() throws IOException {
+ Path created = FileHelper.createDirectory(fileSystem.getPath(getCurrentTestName()));
+ assertTrue(isFile(created) && isDir(created) && isReadable(created));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testMkdirInvalid() throws IOException {
+ Path parent = FileHelper.createDirectory(fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in creating directory %s", parent.toString()));
+ }
+
+ /* rmdir */
+ @Test
+ public void testRmdir() throws IOException {
+ Path created = FileHelper.createDirectory(fileSystem.getPath(getCurrentTestName()));
+ Path deleted = FileHelper.deleteDirectory(created);
+ notExists(deleted);
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testRmdirInvalid() throws IOException {
+ Path deleted = FileHelper.deleteDirectory(fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in removing directory %s", deleted.toString()));
+ }
+
+ /* chdir */
+ @Test
+ public void testChdir() throws IOException {
+ Path created = FileHelper.createDirectory(fileSystem.getPath(getCurrentTestName()));
+ Path createdFile = FileHelper.createFile(created.resolve(getCurrentTestName()));
+ boolean hasFile = false;
+ try (DirectoryStream<Path> ds = FileHelper.readDirectory(created)) {
+ for (Path p : ds) {
+ hasFile |= FileHelper.isSameFile(createdFile,
+ fileSystem.getPath(created.getFileName() + "/" + p.getFileName()));
+ }
+ }
+ assertTrue(createdFile + " found in ch directory", hasFile);
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testChdirInvalid() throws IOException {
+ Path chdir = FileHelper.createDirectory(fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in changing directory %s", chdir.toString()));
+ }
+
+ /* write */
+ @Test
+ public void testWriteFile() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ assertTrue(isFile(created) && isReadable(created));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testWriteFileInvalid() throws IOException {
+ Path written = FileHelper.createFile(fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in writing file %s", written.toString()));
+ }
+
+ /* read */
+ @Test
+ public void testReadFile() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ isNonEmpty(FileHelper.readFile(created));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testReadFileInvalid() throws IOException {
+ Path read = fileSystem.getPath("../" + getCurrentTestName());
+ FileHelper.readFile(read);
+ fail(String.format("Unexpected success in reading file %s", read.toString()));
+ }
+
+ /* rm */
+ @Test
+ public void testDeleteFile() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path deleted = FileHelper.deleteFile(created);
+ notExists(deleted);
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testDeleteFileInvalid() throws IOException {
+ Path deleted = FileHelper.deleteFile(fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in deleting file %s", deleted.toString()));
+ }
+
+ /* cp */
+ @Test
+ public void testCopyFile() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path destination = fileSystem.getPath(getCurrentTestName() + "dest");
+ FileHelper.copyFile(created, destination);
+ assertTrue(isFile(destination) && isReadable(destination));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testCopyFileInvalid() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path copy = FileHelper.copyFile(created, fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in copying file to %s", copy.toString()));
+ }
+
+ /* mv */
+ @Test
+ public void testMoveFile() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path destination = fileSystem.getPath(getCurrentTestName() + "dest");
+ FileHelper.moveFile(created, destination);
+ assertTrue(notExists(created) && isFile(destination) && isReadable(destination));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testMoveFileInvalid() throws IOException {
+ Path created = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path moved = FileHelper.moveFile(created, fileSystem.getPath("../" + getCurrentTestName()));
+ fail(String.format("Unexpected success in moving file to %s", moved.toString()));
+ }
+
+ /* link */
+ @Test
+ public void testCreateLink() throws IOException {
+ Path existing = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path link = fileSystem.getPath(getCurrentTestName() + "link");
+ FileHelper.createLink(link, existing);
+ assertTrue(isFile(link) && isReadable(link));
+ }
+
+ @Test(expected = InvalidPathException.class)
+ public void testCreateLinkInvalid() throws IOException {
+ Path existing = FileHelper.createFile(fileSystem.getPath(getCurrentTestName()));
+ Path link = FileHelper.createLink(fileSystem.getPath("../" + getCurrentTestName() + "link"), existing);
+ fail(String.format("Unexpected success in linking file %s", link.toString()));
+ }
+
+ /* Private helper */
+
+ /**
+ * Wrapper around the FileSystemProvider to test generic FS related
+ * commands. All created temp directories and files used for testing are
+ * deleted upon JVM exit.
+ */
+ @SuppressWarnings("synthetic-access")
+ private static final class FileHelper {
+ private FileHelper() {
+ super();
+ }
+
+ /**
+ * Create a randomized test sandbox on each test execution
+ *
+ * @return the created sandbox Path
+ * @throws IOException
+ * on failure to create
+ */
+ public static Path createTestSandbox() throws IOException {
+ Path created = Files.createTempDirectory("testRoot");
+ created.toFile().deleteOnExit();
+ return created;
+ }
+
+ public static Path createFile(Path source) throws InvalidPathException, IOException {
+ try (FileChannel fc = fileSystem.provider().newFileChannel(source,
+ new TreeSet<OpenOption>(Arrays.asList(StandardOpenOption.CREATE, StandardOpenOption.WRITE)))) {
+ byte[] randomBytes = new byte[1000];
+ new Random().nextBytes(randomBytes);
+ fc.write(ByteBuffer.wrap(randomBytes));
+ source.toFile().deleteOnExit();
+ return source;
+ }
+ }
+
+ public static Path createLink(Path link, Path existing) throws IOException {
+ fileSystem.provider().createLink(link, existing);
+ link.toFile().deleteOnExit();
+ return link;
+ }
+
+ public static Path createDirectory(Path dir) throws InvalidPathException, IOException {
+ fileSystem.provider().createDirectory(dir);
+ dir.toFile().deleteOnExit();
+ return dir;
+ }
+
+ public static Path deleteDirectory(Path dir) throws InvalidPathException, IOException {
+ return deleteFile(dir);
+ }
+
+ public static Path deleteFile(Path source) throws InvalidPathException, IOException {
+ fileSystem.provider().delete(source);
+ return source;
+ }
+
+ public static byte[] readFile(Path source) throws IOException {
+ try (FileChannel fc = fileSystem.provider().newFileChannel(source,
+ new TreeSet<OpenOption>(Arrays.asList(StandardOpenOption.READ)))) {
+ byte[] readBytes = new byte[(int) source.toFile().length()];
+ fc.read(ByteBuffer.wrap(readBytes));
+ return readBytes;
+ }
+ }
+
+ public static Path copyFile(Path source, Path destination) throws InvalidPathException, IOException {
+ fileSystem.provider().copy(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
+ destination.toFile().deleteOnExit();
+ return destination;
+ }
+
+ public static Path moveFile(Path source, Path destination) throws InvalidPathException, IOException {
+ fileSystem.provider().move(source, destination, StandardCopyOption.ATOMIC_MOVE);
+ destination.toFile().deleteOnExit();
+ return destination;
+ }
+
+ public static DirectoryStream<Path> readDirectory(Path dir) throws InvalidPathException, IOException {
+ DirectoryStream<Path> dirStream = fileSystem.provider().newDirectoryStream(dir,
+ new DirectoryStream.Filter<Path>() {
+ @Override
+ public boolean accept(Path entry) throws IOException {
+ return true;
+ }
+ });
+ return dirStream;
+ }
+
+ public static boolean isSameFile(Path source, Path destination) throws IOException {
+ return fileSystem.provider().isSameFile(source, destination);
+ }
+ }
+}