diff --git a/.gitignore b/.gitignore index 8643541..7f5bb0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ +# Eclipse +.settings/ +.classpath +.project + +# IntelliJ IDEA +.idea/ +*.iml + +# Maven +target/ .flattened-pom.xml -target diff --git a/pom.xml b/pom.xml index 2562113..6333c7c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ fake-sftp-server-lambda - 2.0.0 + 2.0.1-SNAPSHOT jar Fake SFTP Server Lambda diff --git a/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/CloseableFakeSftpServer.java b/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/CloseableFakeSftpServer.java new file mode 100644 index 0000000..f56ba23 --- /dev/null +++ b/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/CloseableFakeSftpServer.java @@ -0,0 +1,56 @@ +package com.github.stefanbirkner.fakesftpserver.lambda; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.FileSystem; + +/** + * This extension of {@link FakeSftpServer} can be instantiated, configured and closed manually, + * if doing everything within a single lambda expression is undesirable for your use case. + *

For example, in BDD (behaviour-driven development) you want to test in a given-when-then + * fashion, i.e. separate the stimulus to the system under test (when) from verifying results later + * (then). Some test frameworks like Spock even require separate blocks, making the use of a single + * lambda feel somewhat unnatural and clunky there. + *

Because this class implements {@link AutoCloseable}, if you like you can instantiate it in a + * try with resources structure. + *

A parametrised Spock (Groovy) example test looks like this: + *

+ * class MySFTPServerTest extends Specification {
+ *   @AutoCleanup
+ *   def server = new CloseableFakeSftpServer()
+ *
+ *   @Unroll("user #user downloads file #file")
+ *   def "users can download text files"() {
+ *     given: "a preconfigured fake SFTP server"
+ *     server.addUser(user, password)
+ *     server.putFile(file, content, UTF_8)
+ *
+ *     and: "an SFTP client under test"
+ *     def client = new SFTPFileDownloader("localhost", server.port, user, password)
+ *
+ *     expect:
+ *     client.getFileContent(file) == content
+ *
+ *     where:
+ *     user    | password | file                   | content
+ *     "me"    | "xoxox"  | "/a/b/c/one.txt"       | "First line\nSecondLine\n"
+ *     "you"   | "mypass" | "/etc/two.xml"         | "abc"
+ *     "admin" | "secret" | "/home/admin/three.sh" | "#!/usr/bin/bash\n\nls -al\n"
+ *   }
+ * }
+ * 
+ */ +public class CloseableFakeSftpServer extends FakeSftpServer implements AutoCloseable { + protected final Closeable closeServer; + + public CloseableFakeSftpServer() throws IOException { + super(FakeSftpServer.createFileSystem()); + closeServer = start(0); + } + + @Override + public void close() throws Exception { + fileSystem.close(); + closeServer.close(); + } +} diff --git a/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/FakeSftpServer.java b/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/FakeSftpServer.java index 6bf01cc..b7e4f2f 100644 --- a/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/FakeSftpServer.java +++ b/src/main/java/com/github/stefanbirkner/fakesftpserver/lambda/FakeSftpServer.java @@ -214,18 +214,19 @@ public FileVisitResult postVisitDirectory( } }; private static final Random RANDOM = new Random(); - private final FileSystem fileSystem; + protected final FileSystem fileSystem; private SshServer server; private boolean withSftpServerFinished = false; private final Map usernamesAndPasswords = new HashMap<>(); /** - * {@code FakeSftpServer} cannot be created manually. It is always provided + * {@code FakeSftpServer} should not be created manually (unless by + * subclasses which know what they are doing). It is always provided * to an {@link ExceptionThrowingConsumer} * by {@link #withSftpServer(ExceptionThrowingConsumer)}. * @param fileSystem the file system that is used for storing the files */ - private FakeSftpServer( + protected FakeSftpServer( FileSystem fileSystem ) { this.fileSystem = fileSystem; @@ -423,12 +424,12 @@ public void deleteAllFilesAndDirectories() throws IOException { walkFileTree(directory, DELETE_FILES_AND_DIRECTORIES); } - private static FileSystem createFileSystem( + protected static FileSystem createFileSystem( ) throws IOException { return newLinux().build("FakeSftpServer-" + RANDOM.nextInt()); } - private Closeable start( + protected Closeable start( int port ) throws IOException { SshServer server = SshServer.setUpDefaultServer();