Skip to content

Commit

Permalink
#356 Read file content on client side for validation
Browse files Browse the repository at this point in the history
  • Loading branch information
christophd committed Mar 28, 2018
1 parent df3ef7d commit 4fec9e4
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 36 deletions.
Expand Up @@ -24,6 +24,7 @@
import org.springframework.core.io.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -257,11 +258,26 @@ public static Resource getFileResource(String filePath, TestContext context) {
* @return
*/
public static Resource getFileResource(String filePath) {
String path;

if (filePath.contains(FILE_PATH_CHARSET_PARAMETER)) {
return new PathMatchingResourcePatternResolver().getResource(filePath.substring(0, filePath.indexOf(FileUtils.FILE_PATH_CHARSET_PARAMETER)));
path = filePath.substring(0, filePath.indexOf(FileUtils.FILE_PATH_CHARSET_PARAMETER));
} else {
return new PathMatchingResourcePatternResolver().getResource(filePath);
path = filePath;
}

if (path.startsWith(ResourceUtils.FILE_URL_PREFIX)) {
return new FileSystemResource(path.substring(ResourceUtils.FILE_URL_PREFIX.length() - 1));
} else if (path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
return new PathMatchingResourcePatternResolver().getResource(path);
}

Resource file = new FileSystemResource(path);
if (!file.exists()) {
return new PathMatchingResourcePatternResolver().getResource(path);
}

return file;
}

/**
Expand Down
Expand Up @@ -134,6 +134,12 @@ private boolean isPositive(int reply) {
return FTPReply.isPositiveCompletion(reply) || FTPReply.isPositivePreliminary(reply);
}

/**
* Perform list files operation and provide file information as response.
* @param list
* @param context
* @return
*/
private FtpMessage listFiles(ListCommand list, TestContext context) {
String remoteFilePath = Optional.ofNullable(list.getTarget())
.map(ListCommand.Target::getPath)
Expand All @@ -153,7 +159,7 @@ private FtpMessage listFiles(ListCommand list, TestContext context) {
fileNames.add(ftpFile.getName());
}

return FtpMessage.listResult(ftpClient.getReplyCode(), ftpClient.getReplyString(), fileNames);
return FtpMessage.result(ftpClient.getReplyCode(), ftpClient.getReplyString(), fileNames);
} catch (IOException e) {
throw new CitrusRuntimeException(String.format("Failed to list files in path '%s'", remoteFilePath), e);
}
Expand Down Expand Up @@ -274,11 +280,16 @@ private FtpMessage retrieveFile(GetCommand command, TestContext context) {
+ ". Local file path: " + localFilePath + ". FTP reply: " + ftpClient.getReplyString());
}
}

if (getEndpointConfiguration().isAutoReadFiles()) {
String fileContent = FileUtils.readToString(FileUtils.getFileResource(localFilePath));
return FtpMessage.result(ftpClient.getReplyCode(), ftpClient.getReplyString(), localFilePath, fileContent);
} else {
return FtpMessage.result(ftpClient.getReplyCode(), ftpClient.getReplyString(), localFilePath, null);
}
} catch (IOException e) {
throw new CitrusRuntimeException("Failed to get file from FTP server", e);
}

return FtpMessage.result(ftpClient.getReplyCode(), ftpClient.getReplyString(), isPositive(ftpClient.getReplyCode()));
}

/**
Expand Down
Expand Up @@ -54,6 +54,16 @@ public FtpClientBuilder port(int port) {
return this;
}

/**
* Sets the auto read files property.
* @param autoReadFiles
* @return
*/
public FtpClientBuilder autoReadFiles(boolean autoReadFiles) {
endpoint.getEndpointConfiguration().setAutoReadFiles(autoReadFiles);
return this;
}

/**
* Sets the client username.
* @param username
Expand Down
Expand Up @@ -56,6 +56,9 @@ public class FtpEndpointConfiguration extends AbstractPollableEndpointConfigurat
/** Comma delimited list of ftp commands to auto handle on server */
private String autoHandleCommands;

/** Auto read file content retrieved from server */
private boolean autoReadFiles = true;

/**
* Gets the ftp host.
* @return
Expand Down Expand Up @@ -225,4 +228,22 @@ public String getAutoHandleCommands() {
public void setAutoHandleCommands(String autoHandleCommands) {
this.autoHandleCommands = autoHandleCommands;
}

/**
* Gets the autoReadFiles.
*
* @return
*/
public boolean isAutoReadFiles() {
return autoReadFiles;
}

/**
* Sets the autoReadFiles.
*
* @param autoReadFiles
*/
public void setAutoReadFiles(boolean autoReadFiles) {
this.autoReadFiles = autoReadFiles;
}
}
Expand Up @@ -42,6 +42,12 @@
*/
int port() default 22222;

/**
* Auto read files
* @return
*/
boolean autoReadFiles() default true;

/**
* Username
* @return
Expand Down
Expand Up @@ -47,6 +47,7 @@ public FtpClient parse(FtpClientConfig annotation) {
}

builder.port(annotation.port());
builder.autoReadFiles(annotation.autoReadFiles());

if (StringUtils.hasText(annotation.username())) {
builder.username(annotation.username());
Expand Down
Expand Up @@ -39,6 +39,7 @@ protected void parseEndpointConfiguration(BeanDefinitionBuilder endpointConfigur

BeanDefinitionParserUtils.setPropertyValue(endpointConfiguration, element.getAttribute("host"), "host");
BeanDefinitionParserUtils.setPropertyValue(endpointConfiguration, element.getAttribute("port"), "port");
BeanDefinitionParserUtils.setPropertyValue(endpointConfiguration, element.getAttribute("auto-read-files"), "autoReadFiles");
BeanDefinitionParserUtils.setPropertyValue(endpointConfiguration, element.getAttribute("username"), "user");
BeanDefinitionParserUtils.setPropertyValue(endpointConfiguration, element.getAttribute("password"), "password");

Expand Down
Expand Up @@ -135,7 +135,7 @@ public static FtpMessage result(CommandResultType commandResult) {
return ftpMessage;
}

public static FtpMessage listResult(int replyCode, String replyString, List<String> fileNames) {
public static FtpMessage result(int replyCode, String replyString, List<String> fileNames) {
ListCommandResult listCommandResult = new ListCommandResult();
listCommandResult.setReplyCode(String.valueOf(replyCode));
listCommandResult.setReplyString(replyString);
Expand All @@ -153,6 +153,21 @@ public static FtpMessage listResult(int replyCode, String replyString, List<Stri
return result(listCommandResult);
}

public static FtpMessage result(int replyCode, String replyString, String path, String content) {
GetCommandResult getCommandResult = new GetCommandResult();
getCommandResult.setReplyCode(String.valueOf(replyCode));
getCommandResult.setReplyString(replyString);
getCommandResult.setSuccess(true);

GetCommandResult.File file = new GetCommandResult.File();
file.setPath(path);
file.setData(content);

getCommandResult.setFile(file);

return result(getCommandResult);
}

/**
* Sets the command args.
* @param arguments
Expand Down
Expand Up @@ -20,18 +20,16 @@
import com.consol.citrus.exceptions.CitrusRuntimeException;
import com.consol.citrus.ftp.client.FtpEndpointConfiguration;
import com.consol.citrus.ftp.message.FtpMessage;
import com.consol.citrus.ftp.model.*;
import com.consol.citrus.ftp.model.Command;
import com.consol.citrus.ftp.model.CommandResultType;
import org.apache.commons.net.ftp.FTPCmd;
import org.apache.ftpserver.filesystem.nativefs.NativeFileSystemFactory;
import org.apache.ftpserver.ftplet.*;
import org.apache.ftpserver.impl.LocalizedFileActionFtpReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.xml.transform.StringResult;

import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
Expand Down Expand Up @@ -130,26 +128,6 @@ public FtpletResult afterCommand(FtpSession session, FtpRequest request, FtpRepl
return FtpletResult.DEFAULT;
}

private FtpReply getFtpReply(FtpMessage ftpMessage, FtpSession session) {
CommandResultType commandResult = ftpMessage.getPayload(CommandResultType.class);

try {
if (commandResult instanceof GetCommandResult) {
return new LocalizedFileActionFtpReply(Integer.valueOf(commandResult.getReplyCode()), commandResult.getReplyString(),
new NativeFileSystemFactory().createFileSystemView(session.getUser()).getFile(((GetCommandResult) commandResult).getFile().getPath()));
} else if (commandResult instanceof ListCommandResult) {
return new DefaultFtpReply(Integer.valueOf(commandResult.getReplyCode()),
((ListCommandResult) commandResult).getFiles().getFiles().stream()
.map(ListCommandResult.Files.File::getPath)
.collect(Collectors.joining(" ")));
}
} catch (FtpException e) {
throw new CitrusRuntimeException("Failed to get file from local file system view", e);
}

return new DefaultFtpReply(Integer.valueOf(commandResult.getReplyCode()), commandResult.getReplyString());
}

@Override
public FtpletResult onConnect(FtpSession session) {
if (log.isDebugEnabled()) {
Expand Down Expand Up @@ -191,9 +169,10 @@ public FtpletResult onDisconnect(FtpSession session) {
* @param response
*/
private void writeFtpReply(FtpSession session, FtpMessage response) {
FtpReply reply = getFtpReply(response, session);

try {
CommandResultType commandResult = response.getPayload(CommandResultType.class);
FtpReply reply = new DefaultFtpReply(Integer.valueOf(commandResult.getReplyCode()), commandResult.getReplyString());

session.write(reply);
} catch (FtpException e) {
throw new CitrusRuntimeException("Failed to write ftp reply", e);
Expand Down
Expand Up @@ -44,6 +44,7 @@ public class FtpClientConfigParserTest extends AbstractTestNGUnitTest {
@CitrusEndpoint
@FtpClientConfig(host = "localhost",
port=22222,
autoReadFiles = false,
username="user",
password="consol",
timeout=10000L)
Expand Down Expand Up @@ -93,6 +94,7 @@ public void testFtpClientParser() {
Assert.assertEquals(ftpClient1.getEndpointConfiguration().getCorrelator().getClass(), DefaultMessageCorrelator.class);
Assert.assertEquals(ftpClient1.getEndpointConfiguration().getErrorHandlingStrategy(), ErrorHandlingStrategy.PROPAGATE);
Assert.assertEquals(ftpClient1.getEndpointConfiguration().getTimeout(), 5000L);
Assert.assertTrue(ftpClient1.getEndpointConfiguration().isAutoReadFiles());

// 2nd ftp client
Assert.assertEquals(ftpClient2.getEndpointConfiguration().getHost(), "localhost");
Expand All @@ -101,6 +103,7 @@ public void testFtpClientParser() {
Assert.assertEquals(ftpClient2.getEndpointConfiguration().getUser(), "user");
Assert.assertEquals(ftpClient2.getEndpointConfiguration().getPassword(), "consol");
Assert.assertEquals(ftpClient2.getEndpointConfiguration().getTimeout(), 10000L);
Assert.assertFalse(ftpClient2.getEndpointConfiguration().isAutoReadFiles());

// 3rd ftp client
Assert.assertEquals(ftpClient3.getEndpointConfiguration().getHost(), "localhost");
Expand Down
Expand Up @@ -43,6 +43,7 @@ public void testFtpClientParser() {
Assert.assertEquals(ftpClient.getEndpointConfiguration().getHost(), "localhost");
Assert.assertEquals(ftpClient.getEndpointConfiguration().getPort(), new Integer(22222));
Assert.assertEquals(ftpClient.getEndpointConfiguration().getCorrelator().getClass(), DefaultMessageCorrelator.class);
Assert.assertTrue(ftpClient.getEndpointConfiguration().isAutoReadFiles());
Assert.assertEquals(ftpClient.getEndpointConfiguration().getTimeout(), 5000L);
Assert.assertEquals(ftpClient.getEndpointConfiguration().getErrorHandlingStrategy(), ErrorHandlingStrategy.PROPAGATE);

Expand All @@ -53,6 +54,7 @@ public void testFtpClientParser() {
Assert.assertEquals(ftpClient.getEndpointConfiguration().getCorrelator().getClass(), DefaultMessageCorrelator.class);
Assert.assertEquals(ftpClient.getEndpointConfiguration().getUser(), "user");
Assert.assertEquals(ftpClient.getEndpointConfiguration().getPassword(), "consol");
Assert.assertFalse(ftpClient.getEndpointConfiguration().isAutoReadFiles());
Assert.assertEquals(ftpClient.getEndpointConfiguration().getTimeout(), 10000L);
Assert.assertEquals(ftpClient.getEndpointConfiguration().getErrorHandlingStrategy(), ErrorHandlingStrategy.THROWS_EXCEPTION);

Expand Down
Expand Up @@ -15,6 +15,7 @@
host="localhost"
port="22222"
error-strategy="throwsException"
auto-read-files="false"
username="user"
password="consol"
timeout="10000"/>
Expand Down
Expand Up @@ -208,11 +208,14 @@
<receive endpoint="ftpClient">
<message>
<payload>
<ftp:command-result>
<ftp:get-command-result>
<ftp:success>true</ftp:success>
<ftp:reply-code>226</ftp:reply-code>
<ftp:reply-string>@contains('Transfer complete')@</ftp:reply-string>
</ftp:command-result>
<ftp:file path="target/ftp/hello.txt">
<ftp:data>Hello FTP server!</ftp:data>
</ftp:file>
</ftp:get-command-result>
</payload>
</message>
</receive>
Expand Down
Expand Up @@ -53,6 +53,7 @@
<xs:attribute name="message-correlator" type="xs:string"/>
<xs:attribute name="actor" type="xs:string"/>
<xs:attribute name="timeout" type="xs:string"/>
<xs:attribute name="auto-read-files" type="xs:boolean"/>
<xs:attribute name="polling-interval" type="xs:string"/>
<xs:attribute name="error-strategy">
<xs:simpleType>
Expand Down
Expand Up @@ -53,6 +53,7 @@
<xs:attribute name="message-correlator" type="xs:string"/>
<xs:attribute name="actor" type="xs:string"/>
<xs:attribute name="timeout" type="xs:string"/>
<xs:attribute name="auto-read-files" type="xs:boolean"/>
<xs:attribute name="polling-interval" type="xs:string"/>
<xs:attribute name="error-strategy">
<xs:simpleType>
Expand Down
Expand Up @@ -100,7 +100,7 @@
<xs:element name="file">
<xs:complexType>
<xs:attribute name="path" type="xs:string" use="required"/>
<xs:attribute name="type">
<xs:attribute name="type" default="BINARY">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="ASCII"/>
Expand Down Expand Up @@ -134,7 +134,7 @@
<xs:element name="file">
<xs:complexType>
<xs:attribute name="path" type="xs:string" use="required"/>
<xs:attribute name="type">
<xs:attribute name="type" default="BINARY">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="ASCII"/>
Expand Down Expand Up @@ -266,6 +266,9 @@
<xs:sequence>
<xs:element name="file">
<xs:complexType>
<xs:sequence>
<xs:element name="data" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="path" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
Expand Down
Expand Up @@ -266,6 +266,9 @@
<xs:sequence>
<xs:element name="file">
<xs:complexType>
<xs:sequence>
<xs:element name="data" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="path" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
Expand Down

0 comments on commit 4fec9e4

Please sign in to comment.