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 2015/05/25 15:06:24 UTC
[2/3] mina-sshd git commit: [SSHD-471] Auto-detect 'target' folder
location and use it in the tests
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b6166cc8/sshd-core/src/test/java/org/apache/sshd/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SftpFileSystemTest.java b/sshd-core/src/test/java/org/apache/sshd/SftpFileSystemTest.java
deleted file mode 100644
index 609d5fb..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/SftpFileSystemTest.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.GroupPrincipal;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.nio.file.attribute.UserPrincipalLookupService;
-import java.nio.file.attribute.UserPrincipalNotFoundException;
-import java.util.Arrays;
-import java.util.Map;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.command.ScpCommandFactory;
-import org.apache.sshd.server.sftp.SftpSubsystemFactory;
-import org.apache.sshd.util.BaseTestSupport;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class SftpFileSystemTest extends BaseTestSupport {
-
- private SshServer sshd;
- private int port;
-
- @Before
- public void setUp() throws Exception {
- sshd = SshServer.setUpDefaultServer();
- sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
- sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
- sshd.setCommandFactory(new ScpCommandFactory());
- sshd.setShellFactory(new EchoShellFactory());
- sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
- sshd.start();
- port = sshd.getPort();
- }
-
- @After
- public void tearDown() throws Exception {
- sshd.stop(true);
- }
-
- @Test
- public void testFileSystem() throws Exception {
- Utils.deleteRecursive(new File("target/sftp"));
-
- String uri = "sftp://x:x@localhost:" + port + "/";
-
- try(FileSystem fs = FileSystems.newFileSystem(URI.create(uri), null)) {
- Iterable<Path> rootDirs = fs.getRootDirectories();
- for (Path root : rootDirs) {
- try (DirectoryStream<Path> ds = Files.newDirectoryStream(root)) {
- for (Path child : ds) {
- System.out.println(child);
- }
- } catch(IOException | RuntimeException e) {
- // TODO on Windows one might get share problems for *.sys files
- // e.g. "C:\hiberfil.sys: The process cannot access the file because it is being used by another process"
- // for now, Windows is less of a target so we are lenient with it
- if (OsUtils.isWin32()) {
- System.err.println(e.getClass().getSimpleName() + " while accessing children of root=" + root + ": " + e.getMessage());
- } else {
- throw e;
- }
- }
- }
-
- Path current = fs.getPath(".").toRealPath();
- Path file = fs.getPath("target/sftp/client/test.txt");
- Files.createDirectories(file.getParent());
- Files.write(file, "Hello world\n".getBytes());
- String buf = new String(Files.readAllBytes(file));
- assertEquals("Hello world\n", buf);
-
- Path file2 = fs.getPath("target/sftp/client/test2.txt");
- Path file3 = fs.getPath("target/sftp/client/test3.txt");
- try {
- Files.move(file2, file3);
- fail("Expected an IOException");
- } catch (NoSuchFileException e) {
- // expected
- }
- Files.write(file2, "h".getBytes());
- try {
- Files.move(file, file2);
- fail("Expected an IOException");
- } catch (FileAlreadyExistsException e) {
- // expected
- }
- Files.move(file, file2, StandardCopyOption.REPLACE_EXISTING);
- Files.move(file2, file);
-
- Map<String, Object> attrs = Files.readAttributes(file, "*");
- System.out.println(attrs);
-
- // TODO: symbolic links only work for absolute files
- // Path link = fs.getPath("target/sftp/client/test2.txt");
- // Files.createSymbolicLink(link, link.relativize(file));
- // assertTrue(Files.isSymbolicLink(link));
- // assertEquals("test.txt", Files.readSymbolicLink(link).toString());
-
- // TODO there are many issues with Windows and symbolic links - for now they are of a lesser interest
- if (OsUtils.isUNIX()) {
- Path link = fs.getPath("target/sftp/client/test2.txt");
- Files.createSymbolicLink(link, link.getParent().relativize(file));
- assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
- assertEquals("test.txt", Files.readSymbolicLink(link).toString());
- Files.delete(link);
- }
-
- attrs = Files.readAttributes(file, "*", LinkOption.NOFOLLOW_LINKS);
- System.out.println(attrs);
-
- buf = new String(Files.readAllBytes(file));
- assertEquals("Hello world\n", buf);
-
- try (FileChannel channel = FileChannel.open(file)) {
- try (FileLock lock = channel.lock()) {
- System.out.println("Locked " + lock.toString());
-
- try (FileChannel channel2 = FileChannel.open(file)) {
- try (FileLock lock2 = channel2.lock()) {
- System.out.println("Locked " + lock2.toString());
- fail("Expected an exception");
- } catch (OverlappingFileLockException e) {
- // expected
- }
- }
-
- }
- }
-
- Files.delete(file);
- }
- }
-
- @Test
- public void testAttributes() throws Exception {
- Utils.deleteRecursive(new File("target/sftp"));
-
- try (FileSystem fs = FileSystems.newFileSystem(URI.create("sftp://x:x@localhost:" + port + "/"), null)) {
- Path file = fs.getPath("target/sftp/client/test.txt");
- Files.createDirectories(file.getParent());
- Files.write(file, "Hello world\n".getBytes());
-
- Map<String, Object> attrs = Files.readAttributes(file, "posix:*");
- assertNotNull("NO attributes read for " + file, attrs);
-
- Files.setAttribute(file, "basic:size", Long.valueOf(2l));
- Files.setAttribute(file, "posix:permissions", PosixFilePermissions.fromString("rwxr-----"));
- Files.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(100000l));
-
- FileSystem fileSystem = file.getFileSystem();
- try {
- UserPrincipalLookupService userLookupService = fileSystem.getUserPrincipalLookupService();
- GroupPrincipal group = userLookupService.lookupPrincipalByGroupName("everyone");
- Files.setAttribute(file, "posix:group", group);
- } catch (UserPrincipalNotFoundException e) {
- // Also, according to the Javadoc:
- // "Where an implementation does not support any notion of
- // group then this method always throws UserPrincipalNotFoundException."
- // Therefore we are lenient with this exception for Windows
- if (OsUtils.isWin32()) {
- System.err.println(e.getClass().getSimpleName() + ": " + e.getMessage());
- } else {
- throw e;
- }
- }
- }
- }
-
- @Test
- public void testRootFileSystem() throws Exception {
- Path rootNative = Paths.get("target/root").toAbsolutePath();
- Utils.deleteRecursive(rootNative.toFile());
- Files.createDirectories(rootNative);
-
- FileSystem fs = FileSystems.newFileSystem(URI.create("root:" + rootNative.toUri().toString() + "!/"), null);
- Files.createDirectories(fs.getPath("test/foo"));
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b6166cc8/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
deleted file mode 100644
index b2b0cbd..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * 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;
-
-import static org.apache.sshd.common.sftp.SftpConstants.SSH_FX_FILE_ALREADY_EXISTS;
-import static org.apache.sshd.common.sftp.SftpConstants.SSH_FX_NO_SUCH_FILE;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IRUSR;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IWUSR;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.Vector;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SftpClient;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.command.ScpCommandFactory;
-import org.apache.sshd.server.sftp.SftpSubsystemFactory;
-import org.apache.sshd.util.BaseTestSupport;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.JSchLogger;
-import org.apache.sshd.util.SimpleUserInfo;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.jcraft.jsch.ChannelSftp;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.SftpException;
-
-public class SftpTest extends BaseTestSupport {
-
- private SshServer sshd;
- private int port;
- private com.jcraft.jsch.Session session;
-
- @Before
- public void setUp() throws Exception {
- sshd = SshServer.setUpDefaultServer();
- sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
- sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
- sshd.setCommandFactory(new ScpCommandFactory());
- sshd.setShellFactory(new EchoShellFactory());
- sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
- sshd.start();
- port = sshd.getPort();
-
- JSchLogger.init();
- JSch sch = new JSch();
- session = sch.getSession("sshd", "localhost", port);
- session.setUserInfo(new SimpleUserInfo("sshd"));
- session.connect();
- }
-
- @After
- public void tearDown() throws Exception {
- session.disconnect();
- sshd.stop(true);
- }
-
- @Test
- @Ignore
- public void testExternal() throws Exception {
- System.out.println("SFTP subsystem available on port " + port);
- Thread.sleep(5 * 60000);
- }
-
- @Test
- public void testOpen() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
-
- try (ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
- session.addPasswordIdentity("x");
- session.auth().verify();
-
- String file = "target/sftp/client/testOpen.txt";
- File javaFile = new File(file);
-
- assertHierarchyTargetFolderExists(javaFile.getParentFile());
- javaFile.createNewFile();
- javaFile.setWritable(false, false);
- javaFile.setReadable(false, false);
-
- try (SftpClient sftp = session.createSftpClient()) {
- SftpClient.Handle h;
-
- boolean isWindows = OsUtils.isWin32();
-
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
- // NOTE: on Windows files are always readable
- // see https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
- assertTrue("Empty read should have failed", isWindows);
- sftp.close(h);
- } catch (IOException e) {
- if (isWindows) {
- throw e;
- }
- }
-
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- fail("Empty write should have failed");
- } catch (IOException e) {
- // ok
- }
-
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
- // NOTE: on Windows files are always readable
- assertTrue("Empty truncate should have failed", isWindows);
- sftp.close(h);
- } catch (IOException e) {
- // ok
- }
-
- // NOTE: on Windows files are always readable
- int perms=sftp.stat(file).perms;
- int permsMask=S_IWUSR | (isWindows ? 0 : S_IRUSR);
- assertEquals("Mismatched permissions - 0x" + Integer.toHexString(perms), 0, (perms & permsMask));
-
- javaFile.setWritable(true, false);
-
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
- sftp.close(h);
-
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- byte[] d = "0123456789\n".getBytes();
- sftp.write(h, 0, d, 0, d.length);
- sftp.write(h, d.length, d, 0, d.length);
- sftp.close(h);
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- sftp.write(h, d.length * 2, d, 0, d.length);
- sftp.close(h);
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- sftp.write(h, 3, "-".getBytes(), 0, 1);
- sftp.close(h);
-
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
- // NOTE: on Windows files are always readable
- assertTrue("Data read should have failed", isWindows);
- sftp.close(h);
- } catch (IOException e) {
- if (isWindows) {
- throw e;
- }
- }
-
- javaFile.setReadable(true, false);
-
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
- byte[] buf = new byte[3];
- int l = sftp.read(h, 2l, buf, 0, 3);
- assertEquals("Mismatched read data", "2-4", new String(buf, 0, l));
- sftp.close(h);
- }
- } finally {
- client.stop();
- }
- }
-
- @Test
- public void testClient() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- try (ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
- session.addPasswordIdentity("x");
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- Utils.deleteRecursive(new File("target/sftp"));
- new File("target/sftp").mkdirs();
- new File("target/sftp/client/test.txt").delete();
- new File("target/sftp/client").delete();
-
- try (SftpClient sftp = session.createSftpClient()) {
- sftp.mkdir("target/sftp/client");
-
- SftpClient.Handle h = sftp.open("target/sftp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- byte[] d = "0123456789\n".getBytes();
- sftp.write(h, 0, d, 0, d.length);
- sftp.write(h, d.length, d, 0, d.length);
-
- SftpClient.Attributes attrs = sftp.stat(h);
- assertNotNull("No handle attributes", attrs);
-
- sftp.close(h);
-
- h = sftp.openDir("target/sftp/client");
- SftpClient.DirEntry[] dir = sftp.readDir(h);
- assertNotNull("No dir entries", dir);
- assertEquals("Mismatced number of dir entries", 1, dir.length);
- assertNull("Unexpected entry read", sftp.readDir(h));
- sftp.close(h);
-
- sftp.remove("target/sftp/client/test.txt");
-
- byte[] workBuf = new byte[1024 * 128];
- try (OutputStream os = sftp.write("target/sftp/client/test.txt")) {
- os.write(workBuf);
- }
-
- try (InputStream is = sftp.read("target/sftp/client/test.txt")) {
- int readLen = is.read(workBuf);
- assertEquals("Mismatched read data length", workBuf.length, readLen);
-
- int i = is.read();
- assertEquals("Unexpected read past EOF", -1, i);
- }
-
- SftpClient.Attributes attributes = sftp.stat("target/sftp/client/test.txt");
- assertTrue("Test file not detected as regular", attributes.isRegularFile());
-
- attributes = sftp.stat("target/sftp/client");
- assertTrue("Test directory not reported as such", attributes.isDirectory());
-
- int nb = 0;
- for (SftpClient.DirEntry entry : sftp.readDir("target/sftp/client")) {
- assertNotNull("Unexpected null entry", entry);
- nb++;
- }
- assertEquals("Mismatched read dir entries", 1, nb);
-
- sftp.remove("target/sftp/client/test.txt");
-
- sftp.rmdir("target/sftp/client/");
- }
- } finally {
- client.stop();
- }
- }
-
- /**
- * this test is meant to test out write's logic, to ensure that internal chunking (based on Buffer.MAX_LEN) is
- * functioning properly. To do this, we write a variety of file sizes, both smaller and larger than Buffer.MAX_LEN.
- * in addition, this test ensures that improper arguments passed in get caught with an IllegalArgumentException
- * @throws Exception upon any uncaught exception or failure
- */
- @Test
- public void testWriteChunking() throws Exception {
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try(ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
- session.addPasswordIdentity("x");
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- Utils.deleteRecursive(new File("target/sftp"));
- new File("target/sftp").mkdirs();
- new File("target/sftp/client").delete();
-
- try(SftpClient sftp = session.createSftpClient()) {
- sftp.mkdir("target/sftp/client");
-
- uploadAndVerifyFile(sftp, 0, "emptyFile.txt");
- uploadAndVerifyFile(sftp, 1000, "smallFile.txt");
- uploadAndVerifyFile(sftp, ByteArrayBuffer.MAX_LEN - 1, "bufferMaxLenMinusOneFile.txt");
- uploadAndVerifyFile(sftp, ByteArrayBuffer.MAX_LEN, "bufferMaxLenFile.txt");
- // were chunking not implemented, these would fail. these sizes should invoke our internal chunking mechanism
- uploadAndVerifyFile(sftp, ByteArrayBuffer.MAX_LEN + 1, "bufferMaxLenPlusOneFile.txt");
- uploadAndVerifyFile(sftp, (int)(1.5 * ByteArrayBuffer.MAX_LEN), "1point5BufferMaxLenFile.txt");
- uploadAndVerifyFile(sftp, (2 * ByteArrayBuffer.MAX_LEN) - 1, "2TimesBufferMaxLenMinusOneFile.txt");
- uploadAndVerifyFile(sftp, 2 * ByteArrayBuffer.MAX_LEN, "2TimesBufferMaxLenFile.txt");
- uploadAndVerifyFile(sftp, (2 * ByteArrayBuffer.MAX_LEN) + 1, "2TimesBufferMaxLenPlusOneFile.txt");
- uploadAndVerifyFile(sftp, 200000, "largerFile.txt");
-
- // test erroneous calls that check for negative values
- testInvalidParams(sftp);
-
- // cleanup
- sftp.rmdir("target/sftp/client");
- }
- } finally {
- client.stop();
- }
- }
- }
-
- private void testInvalidParams(SftpClient sftp) throws Exception {
- // generate random file and upload it
- final String filePath = "target/sftp/client/invalid";
- SftpClient.Handle handle = sftp.open(filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- String randomData = randomString(5);
- try {
- sftp.write(handle, -1, randomData.getBytes(), 0, 0);
- fail("should not have been able to write file with invalid file offset");
- } catch (IllegalArgumentException e) {
- // expected
- }
- try {
- sftp.write(handle, 0, randomData.getBytes(), -1, 0);
- fail("should not have been able to write file with invalid source offset");
- } catch (IllegalArgumentException e) {
- // expected
- }
- try {
- sftp.write(handle, 0, randomData.getBytes(), 0, -1);
- fail("should not have been able to write file with invalid length");
- } catch (IllegalArgumentException e) {
- // expected
- }
- try {
- sftp.write(handle, 0, randomData.getBytes(), 0, randomData.length() + 1);
- fail("should not have been able to write file with length bigger than array itself (no offset)");
- } catch (IllegalArgumentException e) {
- // expected
- }
- try {
- sftp.write(handle, 0, randomData.getBytes(), randomData.length(), 1);
- fail("should not have been able to write file with length bigger than array itself (with offset)");
- } catch (IllegalArgumentException e) {
- // expected
- }
-
- // cleanup
- sftp.close(handle);
- sftp.remove(filePath);
- assertFalse("file should not be there", new File(filePath).exists());
- }
-
- private void uploadAndVerifyFile(SftpClient sftp, int size, String filename) throws Exception {
- // generate random file and upload it
- final String filePath = "target/sftp/client/" + filename;
- SftpClient.Handle handle = sftp.open(filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- String randomData = randomString(size);
- sftp.write(handle, 0, randomData.getBytes(), 0, randomData.length());
- sftp.close(handle);
-
- // verify results
- File resultFile = new File(filePath);
- assertTrue("file should exist on disk", resultFile.exists());
- assertTrue("file contents should match", randomData.equals(readFile(filePath)));
-
- // cleanup
- sftp.remove(filePath);
- assertFalse("file should have been removed", resultFile.exists());
- }
-
- @Test
- public void testSftp() throws Exception {
- String d = "0123456789\n";
-
- File root = new File("target/sftp");
- File target = new File("target/sftp/out.txt");
- Utils.deleteRecursive(root);
- root.mkdirs();
- assertTrue(root.exists());
-
- for (int j = 10; j <= 10; j++) {
- String data = "";
- for (int i = 0; i < j; i++) {
- data = data + d;
- }
-
- target.delete();
- assertFalse(target.exists());
- sendFile("target/sftp/out.txt", data);
- assertFileLength(target, data.length(), 5000);
-
- target.delete();
- assertFalse(target.exists());
- }
- root.delete();
- }
-
- @Test
- public void testReadWriteWithOffset() throws Exception {
- File root = new File("target/sftp");
- Utils.deleteRecursive(root);
- assertHierarchyTargetFolderExists(root);
-
- String unixPath = "target/sftp/out.txt";
- File target = new File(unixPath);
-
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
- try {
- c.put(new ByteArrayInputStream("0123456789".getBytes()), unixPath);
-
- assertTrue("Target not created after initial write: " + target.getAbsolutePath(), target.exists());
- assertEquals("0123456789", readFile(unixPath));
-
- try(OutputStream os = c.put(unixPath, null, ChannelSftp.APPEND, -5)) {
- os.write("a".getBytes());
- }
- } finally {
- c.disconnect();
- }
-
- assertTrue("Target not created after data update: " + target.getAbsolutePath(), target.exists());
- assertEquals("Mismatched file data", "01234a6789", readFile(unixPath));
-
- assertTrue("Failed to delete " + target.getAbsolutePath(), target.delete());
- assertFalse("Target not deleted: " + target.getAbsolutePath(), target.exists());
- root.delete();
- }
-
- @Test
- public void testReadDir() throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
- try {
- URI url = getClass().getClassLoader().getResource(SshClient.class.getName().replace('.', '/') + ".class").toURI();
- URI base = new File(System.getProperty("user.dir")).getAbsoluteFile().toURI();
- String path = new File(base.relativize(url).getPath()).getParent() + "/";
- path = path.replace('\\', '/');
- Vector<?> res = c.ls(path);
- for (Object f : res) {
- System.out.println(f.toString());
- }
- } finally {
- c.disconnect();
- }
- }
-
- @Test
- public void testRealPath() throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
-
- try {
- URI url = getClass().getClassLoader().getResource(SshClient.class.getName().replace('.', '/') + ".class").toURI();
- URI base = new File(System.getProperty("user.dir")).getAbsoluteFile().toURI();
- String path = new File(base.relativize(url).getPath()).getParent() + "/";
- path = path.replace('\\', '/');
- String real = c.realpath(path);
- System.out.println(real);
- try {
- real = c.realpath(path + "/foobar");
- System.out.println(real);
- fail("Expected SftpException");
- } catch (SftpException e) {
- // ok
- }
- } finally {
- c.disconnect();
- }
- }
-
- @Test
- public void testRename() throws Exception {
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try(ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
- session.addPasswordIdentity("x");
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- Utils.deleteRecursive(new File("target/sftp"));
- new File("target/sftp").mkdirs();
- new File("target/sftp/client").delete();
-
- try(SftpClient sftp = session.createSftpClient()) {
- try (OutputStream os = sftp.write("target/sftp/test.txt")) {
- os.write("Hello world!\n".getBytes());
- }
-
- try {
- sftp.rename("target/sftp/test2.txt", "target/sftp/test3.txt");
- fail("Expected an SftpException");
- } catch (org.apache.sshd.client.SftpException e) {
- assertEquals(SSH_FX_NO_SUCH_FILE, e.getStatus());
- }
-
- try (OutputStream os = sftp.write("target/sftp/test2.txt")) {
- os.write("H".getBytes());
- }
-
- try {
- sftp.rename("target/sftp/test.txt", "target/sftp/test2.txt");
- fail("Expected an SftpException");
- } catch (org.apache.sshd.client.SftpException e) {
- assertEquals(SSH_FX_FILE_ALREADY_EXISTS, e.getStatus());
- }
- sftp.rename("target/sftp/test.txt", "target/sftp/test2.txt", SftpClient.CopyMode.Overwrite);
- }
- } finally {
- client.stop();
- }
- }
- }
-
- @Test
- public void testCreateSymbolicLink() throws Exception {
- // Do not execute on windows as the file system does not support symlinks
- if (System.getProperty("os.name").toLowerCase().contains("win")) {
- return;
- }
-
- File root = new File("target/sftp");
- String unixPath = "target/sftp/out.txt";
- String linkUnixPath = "target/sftp/link.txt";
- File target = new File(unixPath);
- File link = new File(linkUnixPath);
- Utils.deleteRecursive(root);
- root.mkdirs();
- assertTrue(root.exists());
-
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
- try {
- c.put(new ByteArrayInputStream("0123456789".getBytes()), unixPath);
-
- assertTrue(target.exists());
- assertEquals("0123456789", readFile(unixPath));
-
- c.symlink(unixPath, linkUnixPath);
-
- assertTrue(link.exists());
- assertEquals("0123456789", readFile(linkUnixPath));
-
- String str1 = c.readlink(linkUnixPath);
- String str2 = c.realpath(unixPath);
- assertEquals(str1, str2);
- } finally {
- c.disconnect();
- }
- }
-
- protected void assertFileLength(File file, long length, long timeout) throws Exception {
- boolean ok = false;
- while (timeout > 0) {
- if (file.exists() && file.length() == length) {
- if (!ok) {
- ok = true;
- } else {
- return;
- }
- } else {
- ok = false;
- }
- Thread.sleep(100);
- timeout -= 100;
- }
- assertTrue(file.exists());
- assertEquals(length, file.length());
- }
-
- protected String readFile(String path) throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
-
- try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
- InputStream is = c.get(path)) {
-
- byte[] buffer = new byte[256];
- int count;
- while (-1 != (count = is.read(buffer))) {
- bos.write(buffer, 0, count);
- }
-
- return bos.toString();
- } finally {
- c.disconnect();
- }
- }
-
- protected void sendFile(String path, String data) throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
- c.connect();
- try {
- c.put(new ByteArrayInputStream(data.getBytes()), path);
- } finally {
- c.disconnect();
- }
- }
-
- private String randomString(int size) {
- StringBuilder sb = new StringBuilder(size);
- for (int i = 0; i < size; i++) {
- sb.append((char) ((i % 10) + '0'));
- }
- return sb.toString();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b6166cc8/sshd-core/src/test/java/org/apache/sshd/client/ScpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ScpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ScpTest.java
new file mode 100644
index 0000000..2fb871a
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ScpTest.java
@@ -0,0 +1,935 @@
+/*
+ * 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.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.file.root.RootedFileSystemProvider;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.JSchLogger;
+import org.apache.sshd.util.SimpleUserInfo;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.SCPClient;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+
+/**
+ * Test for SCP support.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ScpTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private int port;
+ private com.jcraft.jsch.Session session;
+ private final FileSystemFactory fileSystemFactory;
+
+ public ScpTest() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ final FileSystem fileSystem = new RootedFileSystemProvider().newFileSystem(parentPath, Collections.<String,Object>emptyMap());
+ fileSystemFactory = new FileSystemFactory() {
+ @Override
+ public FileSystem createFileSystem(Session session) throws IOException {
+ return fileSystem;
+ }
+ };
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setCommandFactory(new ScpCommandFactory());
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setFileSystemFactory(fileSystemFactory);
+ sshd.start();
+ port = sshd.getPort();
+ }
+
+ protected com.jcraft.jsch.Session getJschSession() throws JSchException {
+ JSchLogger.init();
+ JSch sch = new JSch();
+ session = sch.getSession("sshd", "localhost", port);
+ session.setUserInfo(new SimpleUserInfo("sshd"));
+ session.connect();
+ return session;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (session != null) {
+ session.disconnect();
+ }
+
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ }
+
+ @Test
+ @Ignore
+ public void testExternal() throws Exception {
+ System.out.println("Scp available on port " + port);
+ Thread.sleep(5 * 60000);
+ }
+
+ @Test
+ public void testUploadAbsoluteDriveLetter() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try {
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path localFile = localDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(localFile, (getCurrentTestName() + "\n"));
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path remoteFile = remoteDir.resolve(localFile.getFileName().toString());
+ String localPath = localFile.toString();
+ String remotePath = Utils.resolveRelativeRemotePath(parentPath, remoteFile);
+ scp.upload(localPath, remotePath);
+ assertFileLength(remoteFile, data.length, 5000);
+
+ Path secondRemote = remoteDir.resolve(getCurrentTestName() + "-2.txt");
+ String secondPath = Utils.resolveRelativeRemotePath(parentPath, secondRemote);
+ scp.upload(localPath, secondPath);
+ assertFileLength(secondRemote, data.length, 5000);
+
+ Path pathRemote = remoteDir.resolve(getCurrentTestName() + "-path.txt");
+ String pathPath = Utils.resolveRelativeRemotePath(parentPath, pathRemote);
+ scp.upload(localFile, pathPath);
+ assertFileLength(pathRemote, data.length, 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpUploadOverwrite() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try {
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ String data = getCurrentTestName() + "\n";
+
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path localFile = localDir.resolve(getCurrentTestName() + ".txt");
+ writeFile(localFile, data);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path remoteFile = remoteDir.resolve(localFile.getFileName());
+ writeFile(remoteFile, data + data);
+
+ String remotePath = Utils.resolveRelativeRemotePath(parentPath, remoteFile);
+ scp.upload(localFile.toString(), remotePath);
+ assertFileLength(remoteFile, data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpUploadZeroLengthFile() throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path zeroLocal = localDir.resolve(getCurrentTestName());
+
+ try (FileChannel fch = FileChannel.open(zeroLocal, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
+ if (fch.size() > 0L) {
+ fch.truncate(0L);
+ }
+ }
+ assertEquals("Non-zero size for local file=" + zeroLocal, 0L, Files.size(zeroLocal));
+
+ Path zeroRemote = remoteDir.resolve(zeroLocal.getFileName());
+ if (Files.exists(zeroRemote)) {
+ Files.delete(zeroRemote);
+ }
+
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ try {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ String remotePath = Utils.resolveRelativeRemotePath(targetPath.getParent(), zeroRemote);
+ scp.upload(zeroLocal.toString(), remotePath);
+ assertFileLength(zeroRemote, 0L, TimeUnit.SECONDS.toMillis(5L));
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpDownloadZeroLengthFile() throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path zeroLocal = localDir.resolve(getCurrentTestName());
+ if (Files.exists(zeroLocal)) {
+ Files.delete(zeroLocal);
+ }
+
+ Path zeroRemote = remoteDir.resolve(zeroLocal.getFileName());
+ try (FileChannel fch = FileChannel.open(zeroRemote, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
+ if (fch.size() > 0L) {
+ fch.truncate(0L);
+ }
+ }
+ assertEquals("Non-zero size for remote file=" + zeroRemote, 0L, Files.size(zeroRemote));
+
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ try {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ String remotePath = Utils.resolveRelativeRemotePath(targetPath.getParent(), zeroRemote);
+ scp.download(remotePath, zeroLocal.toString());
+ assertFileLength(zeroLocal, 0L, TimeUnit.SECONDS.toMillis(5L));
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativeOnSingleFile() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try {
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ String data = getCurrentTestName() + "\n";
+
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path localOutFile = localDir.resolve(getCurrentTestName() + "-1.txt");
+ writeFile(localOutFile, data);
+
+ Path remoteDir = scpRoot.resolve("remote");
+ Path remoteOutFile = remoteDir.resolve(localOutFile.getFileName());
+ assertFalse("Remote folder already exists: " + remoteDir, Files.exists(remoteDir));
+
+ String localOutPath = localOutFile.toString();
+ String remoteOutPath = Utils.resolveRelativeRemotePath(parentPath, remoteOutFile);
+ try {
+ scp.upload(localOutPath, remoteOutPath);
+ fail("Expected IOException for 1st time " + remoteOutPath);
+ } catch(IOException e) {
+ // ok
+ }
+
+ Files.createDirectories(remoteDir);
+ scp.upload(localOutPath, remoteOutPath);
+ assertFileLength(remoteOutFile, data.length(), 5000);
+
+ Path secondLocal = localDir.resolve(localOutFile.getFileName());
+ scp.download(remoteOutPath, Utils.resolveRelativeRemotePath(parentPath, secondLocal));
+ assertFileLength(secondLocal, data.length(), 5000);
+
+ Path localPath = localDir.resolve(getCurrentTestName() + "-path.txt");
+ scp.download(remoteOutPath, Utils.resolveRelativeRemotePath(parentPath, localPath));
+ assertFileLength(localPath, data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativeOnMultipleFiles() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try {
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path local1 = localDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(local1, getCurrentTestName() + "\n");
+
+ Path local2 = localDir.resolve(getCurrentTestName() + "-2.txt");
+ Files.write(local2, data);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path remote1 = remoteDir.resolve(local1.getFileName());
+ String remote1Path = Utils.resolveRelativeRemotePath(parentPath, remote1);
+ String[] locals = { local1.toString(), local2.toString() };
+ try {
+ scp.upload(locals, remote1Path);
+ fail("Unexpected upload success to missing remote file: " + remote1Path);
+ } catch (IOException e) {
+ // Ok
+ }
+
+ Files.write(remote1, data);
+ try {
+ scp.upload(locals, remote1Path);
+ fail("Unexpected upload success to existing remote file: " + remote1Path);
+ } catch (IOException e) {
+ // Ok
+ }
+
+ Path remoteSubDir = assertHierarchyTargetFolderExists(remoteDir.resolve("dir"));
+ scp.upload(locals, Utils.resolveRelativeRemotePath(parentPath, remoteSubDir));
+
+ Path remoteSub1 = remoteSubDir.resolve(local1.getFileName());
+ assertFileLength(remoteSub1, data.length, 5000);
+
+ Path remoteSub2 = remoteSubDir.resolve(local2.getFileName());
+ assertFileLength(remoteSub2, data.length, 5000);
+
+ String[] remotes = {
+ Utils.resolveRelativeRemotePath(parentPath, remoteSub1),
+ Utils.resolveRelativeRemotePath(parentPath, remoteSub2),
+ };
+
+ try {
+ scp.download(remotes, Utils.resolveRelativeRemotePath(parentPath, local1));
+ fail("Unexpected download success to existing local file: " + local1);
+ } catch (IOException e) {
+ // Ok
+ }
+
+ Path localSubDir = localDir.resolve("dir");
+ try {
+ scp.download(remotes, localSubDir);
+ fail("Unexpected download success to non-existing folder: " + localSubDir);
+ } catch (IOException e) {
+ // Ok
+ }
+
+ Files.createDirectories(localSubDir);
+ scp.download(remotes, localSubDir);
+
+ assertFileLength(localSubDir.resolve(remoteSub1.getFileName()), data.length, 5000);
+ assertFileLength(localSubDir.resolve(remoteSub2.getFileName()), data.length, 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativeOnRecursiveDirs() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = scpRoot.resolve("local");
+ Path localSubDir = assertHierarchyTargetFolderExists(localDir.resolve("dir"));
+ Path localSub1 = localSubDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(localSub1, getCurrentTestName() + "\n");
+ Path localSub2 = localSubDir.resolve(getCurrentTestName() + "-2.txt");
+ Files.write(localSub2, data);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ scp.upload(localSubDir, Utils.resolveRelativeRemotePath(parentPath, remoteDir), ScpClient.Option.Recursive);
+
+ Path remoteSubDir = remoteDir.resolve(localSubDir.getFileName());
+ assertFileLength(remoteSubDir.resolve(localSub1.getFileName()), data.length, 5000);
+ assertFileLength(remoteSubDir.resolve(localSub2.getFileName()), data.length, 5000);
+
+ Utils.deleteRecursive(localSubDir);
+
+ scp.download(Utils.resolveRelativeRemotePath(parentPath, remoteSubDir), localDir, ScpClient.Option.Recursive);
+ assertFileLength(localSub1, data.length, 5000);
+ assertFileLength(localSub2, data.length, 5000);
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativeOnDirWithPattern() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path local1 = localDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(local1, getCurrentTestName() + "\n");
+ Path local2 = localDir.resolve(getCurrentTestName() + "-2.txt");
+ Files.write(local2, data);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ String remotePath = Utils.resolveRelativeRemotePath(parentPath, remoteDir);
+ scp.upload(localDir.toString() + File.separator + "*", remotePath);
+ assertFileLength(remoteDir.resolve(local1.getFileName()), data.length, 5000);
+ assertFileLength(remoteDir.resolve(local2.getFileName()), data.length, 5000);
+
+ Files.delete(local1);
+ Files.delete(local2);
+ scp.download(remotePath + "/*", localDir);
+ assertFileLength(local1, data.length, 5000);
+ assertFileLength(local2, data.length, 5000);
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativeOnMixedDirAndFiles() throws Exception {
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = scpRoot.resolve("local");
+ Path localSubDir = assertHierarchyTargetFolderExists(localDir.resolve("dir"));
+ Path local1 = localDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(local1, getCurrentTestName() + "\n");
+ Path localSub2 = localSubDir.resolve(getCurrentTestName() + "-2.txt");
+ Files.write(localSub2, data);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ String remotePath = Utils.resolveRelativeRemotePath(parentPath, remoteDir);
+ scp.upload(localDir.toString() + File.separator + "*", remotePath, ScpClient.Option.Recursive);
+ assertFileLength(remoteDir.resolve(local1.getFileName()), data.length, 5000);
+
+ Path remoteSubDir = remoteDir.resolve(localSubDir.getFileName());
+ assertFileLength(remoteSubDir.resolve(localSub2.getFileName()), data.length, 5000);
+
+ Files.delete(local1);
+ Utils.deleteRecursive(localSubDir);
+
+ scp.download(remotePath + "/*", localDir);
+ assertFileLength(local1, data.length, 5000);
+ assertFalse("Unexpected recursive local file: " + localSub2, Files.exists(localSub2));
+
+ Files.delete(local1);
+ scp.download(remotePath + "/*", localDir, ScpClient.Option.Recursive);
+ assertFileLength(local1, data.length, 5000);
+ assertFileLength(localSub2, data.length, 5000);
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testScpNativePreserveAttributes() throws Exception {
+ // Ignore this test if running a Windows system
+ Assume.assumeFalse("Skip test for Windows", OsUtils.isWin32());
+
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ ScpClient scp = createScpClient(session);
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = Utils.resolve(targetPath, "scp", getClass().getSimpleName());
+ Utils.deleteRecursive(scpRoot);
+
+ Path localDir = scpRoot.resolve("local");
+ Path localSubDir = assertHierarchyTargetFolderExists(localDir.resolve("dir"));
+ long lastMod = Files.getLastModifiedTime(localSubDir).toMillis() - TimeUnit.DAYS.toMillis(1);
+ Path local1 = localDir.resolve(getCurrentTestName() + "-1.txt");
+ byte[] data = writeFile(local1, getCurrentTestName() + "\n");
+ File lclFile1 = local1.toFile();
+ lclFile1.setLastModified(lastMod);
+ lclFile1.setExecutable(true, true);
+ lclFile1.setWritable(false, false);
+
+ Path localSub2 = localSubDir.resolve(getCurrentTestName() + "-2.txt");
+ Files.write(localSub2, data);
+ File lclSubFile2 = localSub2.toFile();
+ lclSubFile2.setLastModified(lastMod);
+
+ Path remoteDir = assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ String remotePath = Utils.resolveRelativeRemotePath(parentPath, remoteDir);
+ scp.upload(localDir.toString() + File.separator + "*", remotePath, ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
+
+ Path remote1 = remoteDir.resolve(local1.getFileName());
+ assertFileLength(remote1, data.length, 5000);
+
+ File remFile1 = remote1.toFile();
+ assertEquals("Mismatched uploaded last-modified time for " + remFile1, lastMod, remFile1.lastModified());
+
+ Path remoteSubDir = remoteDir.resolve(localSubDir.getFileName());
+ Path remoteSub2 = remoteSubDir.resolve(localSub2.getFileName());
+ assertFileLength(remoteSub2, data.length, 5000);
+
+ File remSubFile2 = remoteSub2.toFile();
+ assertEquals("Mismatched uploaded last-modified time for " + remSubFile2, lastMod, remSubFile2.lastModified());
+
+ Utils.deleteRecursive(localDir);
+ Files.createDirectories(localDir);
+
+ scp.download(remotePath + "/*", localDir, ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
+ assertFileLength(local1, data.length, 5000);
+ assertEquals("Mismatched downloaded last-modified time for " + lclFile1, lastMod, lclFile1.lastModified());
+ assertFileLength(localSub2, data.length, 5000);
+ assertEquals("Mismatched downloaded last-modified time for " + lclSubFile2, lastMod, lclSubFile2.lastModified());
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ private static byte[] writeFile(Path path, String data) throws IOException {
+ try(OutputStream fos = Files.newOutputStream(path)) {
+ byte[] bytes = data.getBytes();
+ fos.write(bytes);
+ return bytes;
+ }
+ }
+
+ @Test
+ public void testJschScp() throws Exception {
+ session = getJschSession();
+ try {
+ String data = getCurrentTestName() + "\n";
+
+ String unixDir = "target/scp";
+ String fileName = getCurrentTestName() + ".txt";
+ String unixPath = unixDir + "/" + fileName;
+ File root = new File(unixDir);
+ File target = new File(unixPath);
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ assertTrue(root.exists());
+
+ target.delete();
+ assertFalse(target.exists());
+ sendFile(unixPath, fileName, data);
+ assertFileLength(target, data.length(), 5000);
+
+ target.delete();
+ assertFalse(target.exists());
+ sendFile(unixDir, fileName, data);
+ assertFileLength(target, data.length(), 5000);
+
+ sendFileError("target", "scp", data);
+
+ readFileError(unixDir);
+
+ assertEquals("Mismatched file data", data, readFile(unixPath, target.length()));
+ assertEquals("Mismatched dir data", data, readDir(unixDir, fileName, target.length()));
+
+ target.delete();
+ root.delete();
+
+ sendDir("target", "scp", fileName, data);
+ assertFileLength(target, data.length(), 5000);
+ } finally {
+ session.disconnect();
+ }
+ }
+
+ @Test
+ public void testWithGanymede() throws Exception {
+ // begin client config
+ final Connection conn = new Connection("localhost", port);
+ try {
+ conn.connect(null, 5000, 0);
+ conn.authenticateWithPassword("sshd", "sshd");
+ final SCPClient scp_client = new SCPClient(conn);
+ final Properties props = new Properties();
+ props.setProperty("test", "test-passed");
+ File f = new File("target/scp/gan");
+ Utils.deleteRecursive(f);
+ f.mkdirs();
+ assertTrue(f.exists());
+
+ String name = "test.properties";
+ scp_client.put(toBytes(props, ""), name, "target/scp/gan");
+ assertTrue(new File(f, name).exists());
+ assertTrue(new File(f, name).delete());
+
+ name = "test2.properties";
+ scp_client.put(toBytes(props, ""), name, "target/scp/gan");
+ assertTrue(new File(f, name).exists());
+ assertTrue(new File(f, name).delete());
+
+ assertTrue(f.delete());
+ } finally {
+ conn.close();
+ }
+ }
+
+ private byte[] toBytes(final Properties properties, final String comments) {
+ try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ properties.store(baos, comments);
+ baos.close();
+ return baos.toByteArray();
+ } catch(IOException cause) {
+ throw new RuntimeException("Failed to output properties to byte[]", cause);
+ }
+ }
+
+ protected String readFile(String path, long expectedSize) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ c.setCommand("scp -f " + path);
+ c.connect();
+
+ int namePos = path.lastIndexOf('/');
+ String fileName = (namePos >= 0) ? path.substring(namePos + 1) : path;
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ os.write(0);
+ os.flush();
+ String header = readLine(is);
+ assertEquals("Mismatched header for " + path, "C0644 " + expectedSize + " " + fileName, header);
+
+ int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
+ os.write(0);
+ os.flush();
+
+ byte[] buffer = new byte[length];
+ length = is.read(buffer, 0, buffer.length);
+ assertEquals("Mismatched read data length for " + path, length, buffer.length);
+ assertAckReceived(is, "Read data of " + path);
+
+ os.write(0);
+ os.flush();
+
+ return new String(buffer);
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ protected String readDir(String path, String fileName, long expectedSize) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ c.setCommand("scp -r -f " + path);
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+ os.write(0);
+ os.flush();
+
+ String header = readLine(is);
+ assertTrue("Bad header prefix for " + path + ": " + header, header.startsWith("D0755 0 "));
+ os.write(0);
+ os.flush();
+
+ header = readLine(is);
+ assertEquals("Mismatched dir header for " + path, "C0644 " + expectedSize + " " + fileName, header);
+ int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
+ os.write(0);
+ os.flush();
+
+ byte[] buffer = new byte[length];
+ length = is.read(buffer, 0, buffer.length);
+ assertEquals("Mismatched read buffer size for " + path, length, buffer.length);
+ assertAckReceived(is, "Read date of " + path);
+
+ os.write(0);
+ os.flush();
+
+ header = readLine(is);
+ assertEquals("Mismatched end value for " + path, "E", header);
+ os.write(0);
+ os.flush();
+
+ return new String(buffer);
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ protected String readFileError(String path) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ String command = "scp -f " + path;
+ c.setCommand(command);
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ os.write(0);
+ os.flush();
+ assertEquals("Mismatched response for command: " + command, 2, is.read());
+ return null;
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ protected void sendFile(String path, String name, String data) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ String command = "scp -t " + path;
+ c.setCommand(command);
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ assertAckReceived(is, command);
+ assertAckReceived(os, is, "C7777 " + data.length() + " " + name);
+
+ os.write(data.getBytes());
+ os.flush();
+ assertAckReceived(is, "Sent data (length=" + data.length() + ") for " + path + "[" + name + "]");
+
+ os.write(0);
+ os.flush();
+
+ Thread.sleep(100);
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ protected void assertAckReceived(OutputStream os, InputStream is, String command) throws IOException {
+ os.write((command + "\n").getBytes());
+ os.flush();
+ assertAckReceived(is, command);
+ }
+
+ protected void assertAckReceived(InputStream is, String command) throws IOException {
+ assertEquals("No ACK for command=" + command, 0, is.read());
+ }
+
+ protected void sendFileError(String path, String name, String data) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ String command = "scp -t " + path;
+ c.setCommand(command);
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ assertAckReceived(is, command);
+
+ command = "C7777 " + data.length() + " " + name;
+ os.write((command + "\n").getBytes());
+ os.flush();
+ assertEquals("Mismatched response for command=" + command, 2, is.read());
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ protected void sendDir(String path, String dirName, String fileName, String data) throws Exception {
+ ChannelExec c = (ChannelExec) session.openChannel("exec");
+ String command = "scp -t -r " + path;
+ c.setCommand(command);
+ c.connect();
+
+ try(OutputStream os = c.getOutputStream();
+ InputStream is = c.getInputStream()) {
+
+ assertAckReceived(is, command);
+ assertAckReceived(os, is, "D0755 0 " + dirName);
+ assertAckReceived(os, is, "C7777 " + data.length() + " " + fileName);
+
+ os.write(data.getBytes());
+ os.flush();
+ assertAckReceived(is, "Send data of " + path);
+
+ os.write(0);
+ os.flush();
+
+ os.write("E\n".getBytes());
+ os.flush();
+ assertAckReceived(is, "Signal end of " + path);
+ } finally {
+ c.disconnect();
+ }
+ }
+
+ private static String readLine(InputStream in) throws IOException {
+ OutputStream baos = new ByteArrayOutputStream();
+ try {
+ for (; ; ) {
+ int c = in.read();
+ if (c == '\n') {
+ return baos.toString();
+ } else if (c == -1) {
+ throw new IOException("End of stream");
+ } else {
+ baos.write(c);
+ }
+ }
+ } finally {
+ baos.close();
+ }
+ }
+
+ private ScpClient createScpClient(ClientSession session) {
+ final Logger logger = LoggerFactory.getLogger(getClass().getName() + "[" + getCurrentTestName() + "]");
+ return session.createScpClient(new ScpTransferEventListener() {
+ @Override
+ public void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms) {
+ logEvent("starFolderEvent", op, file, false, -1L, perms, null);
+ }
+
+ @Override
+ public void startFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms) {
+ logEvent("startFileEvent", op, file, true, length, perms, null);
+
+ }
+
+ @Override
+ public void endFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms, Throwable thrown) {
+ logEvent("endFolderEvent", op, file, false, -1L, perms, thrown);
+ }
+
+ @Override
+ public void endFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms, Throwable thrown) {
+ logEvent("endFileEvent", op, file, true, length, perms, thrown);
+ }
+
+ private void logEvent(String type, FileOperation op, Path path, boolean isFile, long length, Collection<PosixFilePermission> perms, Throwable t) {
+ StringBuilder sb = new StringBuilder(Byte.MAX_VALUE);
+ sb.append('\t').append(type)
+ .append('[').append(op).append(']')
+ .append(' ').append(isFile ? "File" : "Directory").append('=').append(path)
+ .append(' ').append("length=").append(length)
+ .append(' ').append("perms=").append(perms)
+ ;
+ if (t != null) {
+ sb.append(' ').append("ERROR=").append(t.getClass().getSimpleName()).append(": ").append(t.getMessage());
+ }
+ logger.info(sb.toString());
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b6166cc8/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
new file mode 100644
index 0000000..3187f63
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
@@ -0,0 +1,260 @@
+/*
+ * 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.client.sftp;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.GroupPrincipal;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.attribute.UserPrincipalNotFoundException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.file.root.RootedFileSystemProvider;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.sftp.SftpSubsystemFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SftpFileSystemTest extends BaseTestSupport {
+
+ private SshServer sshd;
+ private int port;
+ private final FileSystemFactory fileSystemFactory;
+
+ public SftpFileSystemTest() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ final FileSystem fileSystem = new RootedFileSystemProvider().newFileSystem(parentPath, Collections.<String,Object>emptyMap());
+ fileSystemFactory = new FileSystemFactory() {
+ @Override
+ public FileSystem createFileSystem(Session session) throws IOException {
+ return fileSystem;
+ }
+ };
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
+ sshd.setCommandFactory(new ScpCommandFactory());
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setFileSystemFactory(fileSystemFactory);
+ sshd.start();
+ port = sshd.getPort();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ }
+
+ @Test
+ public void testFileSystem() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Utils.deleteRecursive(lclSftp);
+
+ try(FileSystem fs = FileSystems.newFileSystem(URI.create("sftp://x:x@localhost:" + port + "/"), Collections.<String,Object>emptyMap())) {
+ Iterable<Path> rootDirs = fs.getRootDirectories();
+ for (Path root : rootDirs) {
+ String rootName = root.toString();
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(root)) {
+ for (Path child : ds) {
+ System.out.append('\t').append('[').append(rootName).append("] ").println(child);
+ }
+ } catch(IOException | RuntimeException e) {
+ // TODO on Windows one might get share problems for *.sys files
+ // e.g. "C:\hiberfil.sys: The process cannot access the file because it is being used by another process"
+ // for now, Windows is less of a target so we are lenient with it
+ if (OsUtils.isWin32()) {
+ System.err.println(e.getClass().getSimpleName() + " while accessing children of root=" + root + ": " + e.getMessage());
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ Path current = fs.getPath(".").toRealPath().normalize();
+ System.out.append("CWD: ").println(current);
+
+ Path parentPath = targetPath.getParent();
+ Path clientFolder = lclSftp.resolve("client");
+ String remFile1Path = Utils.resolveRelativeRemotePath(parentPath, clientFolder.resolve(getCurrentTestName() + "-1.txt"));
+ Path file1 = fs.getPath(remFile1Path);
+ Files.createDirectories(file1.getParent());
+
+ String expected="Hello world: " + getCurrentTestName();
+ {
+ Files.write(file1, expected.getBytes());
+ String buf = new String(Files.readAllBytes(file1));
+ assertEquals("Mismatched read test data", expected, buf);
+ }
+
+ String remFile2Path = Utils.resolveRelativeRemotePath(parentPath, clientFolder.resolve(getCurrentTestName() + "-2.txt"));
+ Path file2 = fs.getPath(remFile2Path);
+ String remFile3Path = Utils.resolveRelativeRemotePath(parentPath, clientFolder.resolve(getCurrentTestName() + "-3.txt"));
+ Path file3 = fs.getPath(remFile3Path);
+ try {
+ Files.move(file2, file3);
+ fail("Unexpected success in moving " + file2 + " => " + file3);
+ } catch (NoSuchFileException e) {
+ // expected
+ }
+
+ Files.write(file2, "h".getBytes());
+ try {
+ Files.move(file1, file2);
+ fail("Unexpected success in moving " + file1 + " => " + file2);
+ } catch (FileAlreadyExistsException e) {
+ // expected
+ }
+ Files.move(file1, file2, StandardCopyOption.REPLACE_EXISTING);
+ Files.move(file2, file1);
+
+ Map<String, Object> attrs = Files.readAttributes(file1, "*");
+ System.out.append(file1.toString()).append(" attributes: ").println(attrs);
+
+ // TODO: symbolic links only work for absolute files
+ // Path link = fs.getPath("target/sftp/client/test2.txt");
+ // Files.createSymbolicLink(link, link.relativize(file));
+ // assertTrue(Files.isSymbolicLink(link));
+ // assertEquals("test.txt", Files.readSymbolicLink(link).toString());
+
+ // TODO there are many issues with Windows and symbolic links - for now they are of a lesser interest
+ if (OsUtils.isUNIX()) {
+ Path link = fs.getPath(remFile2Path);
+ Path linkParent = link.getParent();
+ Path relPath = linkParent.relativize(file1);
+ Files.createSymbolicLink(link, relPath);
+ assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
+
+ Path symLink = Files.readSymbolicLink(link);
+ assertEquals("mismatched symbolic link name", relPath.toString(), symLink.toString());
+ Files.delete(link);
+ }
+
+ attrs = Files.readAttributes(file1, "*", LinkOption.NOFOLLOW_LINKS);
+ System.out.append(file1.toString()).append(" no-follow attributes: ").println(attrs);
+
+ assertEquals("Mismatched symlink data", expected, new String(Files.readAllBytes(file1)));
+
+ try (FileChannel channel = FileChannel.open(file1)) {
+ try (FileLock lock = channel.lock()) {
+ System.out.println("Locked " + lock.toString());
+
+ try (FileChannel channel2 = FileChannel.open(file1)) {
+ try (FileLock lock2 = channel2.lock()) {
+ System.out.println("Locked " + lock2.toString());
+ fail("Unexpected success in re-locking " + file1);
+ } catch (OverlappingFileLockException e) {
+ // expected
+ }
+ }
+ }
+ }
+
+ Files.delete(file1);
+ }
+ }
+
+ @Test
+ public void testAttributes() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Utils.deleteRecursive(lclSftp);
+
+ try (FileSystem fs = FileSystems.newFileSystem(URI.create("sftp://x:x@localhost:" + port + "/"), null)) {
+ Path parentPath = targetPath.getParent();
+ Path clientFolder = lclSftp.resolve("client");
+ String remFilePath = Utils.resolveRelativeRemotePath(parentPath, clientFolder.resolve(getCurrentTestName() + ".txt"));
+ Path file = fs.getPath(remFilePath);
+ Files.createDirectories(file.getParent());
+ Files.write(file, (getCurrentTestName() + "\n").getBytes());
+
+ Map<String, Object> attrs = Files.readAttributes(file, "posix:*");
+ assertNotNull("NO attributes read for " + file, attrs);
+
+ Files.setAttribute(file, "basic:size", Long.valueOf(2L));
+ Files.setAttribute(file, "posix:permissions", PosixFilePermissions.fromString("rwxr-----"));
+ Files.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(100000L));
+
+ FileSystem fileSystem = file.getFileSystem();
+ try {
+ UserPrincipalLookupService userLookupService = fileSystem.getUserPrincipalLookupService();
+ GroupPrincipal group = userLookupService.lookupPrincipalByGroupName("everyone");
+ Files.setAttribute(file, "posix:group", group);
+ } catch (UserPrincipalNotFoundException e) {
+ // Also, according to the Javadoc:
+ // "Where an implementation does not support any notion of
+ // group then this method always throws UserPrincipalNotFoundException."
+ // Therefore we are lenient with this exception for Windows
+ if (OsUtils.isWin32()) {
+ System.err.println(e.getClass().getSimpleName() + ": " + e.getMessage());
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testRootFileSystem() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path rootNative = targetPath.resolve("root").toAbsolutePath();
+ Utils.deleteRecursive(rootNative);
+ Files.createDirectories(rootNative);
+
+ try(FileSystem fs = FileSystems.newFileSystem(URI.create("root:" + rootNative.toUri().toString() + "!/"), null)) {
+ Path dir = Files.createDirectories(fs.getPath("test/foo"));
+ System.out.println("Created " + dir);
+ }
+ }
+}