/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed 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.springframework.integration.file.remote.gateway;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.file.FileHeaders;
import org.springframework.integration.file.filters.AbstractSimplePatternFileListFilter;
import org.springframework.integration.file.remote.AbstractFileInfo;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Gary Russell
* @author Liu Jiong
* @author Artem Bilan
*
* @since 2.1
*/
@SuppressWarnings("rawtypes")
public class RemoteFileOutboundGatewayTests {
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private final String tmpDir = System.getProperty("java.io.tmpdir");
@Rule
public final TemporaryFolder tempFolder = new TemporaryFolder();
@Test(expected = IllegalArgumentException.class)
public void testBad() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "bad", "payload");
gw.afterPropertiesSet();
}
@Test
public void testBadFilterGet() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setFilter(new TestPatternFilter(""));
try {
gw.afterPropertiesSet();
fail("Exception expected");
}
catch (IllegalArgumentException e) {
assertTrue(e.getMessage().startsWith("Filters are not supported"));
}
}
@Test
public void testBadFilterRm() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "rm", "payload");
gw.setFilter(new TestPatternFilter(""));
try {
gw.afterPropertiesSet();
fail("Exception expected");
}
catch (IllegalArgumentException e) {
assertTrue(e.getMessage().startsWith("Filters are not supported"));
}
}
@Test
public void testLs() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/x/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<TestLsEntry>> out = (MessageBuilder<List<TestLsEntry>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/x"));
assertEquals(2, out.getPayload().size());
assertSame(files[1], out.getPayload().get(0)); // sort by default
assertSame(files[0], out.getPayload().get(1));
assertEquals("testremote/x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
@Test
public void testMGetWild() throws Exception {
testMGetWildGuts("f1", "f2");
}
/**
* Test a wildcard mget where the full path is returned for each file
*
* @throws Exception
*/
@Test
public void testMGetWildFullPath() throws Exception {
testMGetWildGuts("testremote/f1", "testremote/f2");
}
private void testMGetWildGuts(final String path1, final String path2) {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mget", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
new File(this.tmpDir + "/f2").delete();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
int n;
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
if (n++ == 0) {
assertEquals("testremote/f1", source);
}
else {
assertEquals("testremote/f2", source);
}
outputStream.write("testData".getBytes());
}
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry(path1.replaceFirst("testremote/", ""), 123, false, false, 1234, "-r--r--r--"),
new TestLsEntry(path2.replaceFirst("testremote/", ""), 123, false, false, 1234, "-r--r--r--") };
}
});
@SuppressWarnings("unchecked")
MessageBuilder<List<File>> out = (MessageBuilder<List<File>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/*"));
assertEquals(2, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0).getName());
assertEquals("f2", out.getPayload().get(1).getName());
assertEquals("testremote/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
@Test
public void testMGetSingle() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mget", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testData".getBytes());
}
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] { new TestLsEntry("f1", 123, false, false, 1234, "-r--r--r--") };
}
});
@SuppressWarnings("unchecked")
MessageBuilder<List<File>> out = (MessageBuilder<List<File>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/f1"));
assertEquals(1, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0).getName());
assertEquals("testremote/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
@Test(expected = MessagingException.class)
public void testMGetEmpty() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mget", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.setOptions(" -x ");
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
new File(this.tmpDir + "/f2").delete();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testData".getBytes());
}
});
gw.handleRequestMessage(new GenericMessage<String>("testremote/*"));
}
@Test
public void testMove() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mv", "payload");
gw.afterPropertiesSet();
Session<?> session = mock(Session.class);
final AtomicReference<String> args = new AtomicReference<String>();
doAnswer(invocation -> {
Object[] arguments = invocation.getArguments();
args.set((String) arguments[0] + (String) arguments[1]);
return null;
}).when(session).rename(anyString(), anyString());
when(sessionFactory.getSession()).thenReturn(session);
Message<String> requestMessage = MessageBuilder.withPayload("foo")
.setHeader(FileHeaders.RENAME_TO, "bar")
.build();
MessageBuilder<?> out = (MessageBuilder<?>) gw.handleRequestMessage(requestMessage);
assertEquals("foo", out.getHeaders().get(FileHeaders.REMOTE_FILE));
assertEquals("foobar", args.get());
assertEquals(Boolean.TRUE, out.getPayload());
}
@Test
public void testMoveWithExpression() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mv", "payload");
gw.setRenameExpression(PARSER.parseExpression("payload.substring(1)"));
gw.afterPropertiesSet();
Session<?> session = mock(Session.class);
final AtomicReference<String> args = new AtomicReference<String>();
doAnswer(invocation -> {
Object[] arguments = invocation.getArguments();
args.set((String) arguments[0] + arguments[1]);
return null;
}).when(session).rename(anyString(), anyString());
when(sessionFactory.getSession()).thenReturn(session);
MessageBuilder<?> out = (MessageBuilder<?>) gw.handleRequestMessage(new GenericMessage<>("foo"));
assertEquals("oo", out.getHeaders().get(FileHeaders.RENAME_TO));
assertEquals("foo", out.getHeaders().get(FileHeaders.REMOTE_FILE));
assertEquals("foooo", args.get());
assertEquals(Boolean.TRUE, out.getPayload());
}
@Test
public void testMoveWithMkDirs() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "mv", "payload");
gw.setRenameExpression(PARSER.parseExpression("'foo/bar/baz'"));
gw.afterPropertiesSet();
Session<?> session = mock(Session.class);
final AtomicReference<String> args = new AtomicReference<String>();
doAnswer(invocation -> {
Object[] arguments = invocation.getArguments();
args.set((String) arguments[0] + (String) arguments[1]);
return null;
}).when(session).rename(anyString(), anyString());
final List<String> madeDirs = new ArrayList<String>();
doAnswer(invocation -> {
madeDirs.add(invocation.getArgument(0));
return null;
}).when(session).mkdir(anyString());
when(sessionFactory.getSession()).thenReturn(session);
Message<String> requestMessage = MessageBuilder.withPayload("foo")
.setHeader(FileHeaders.RENAME_TO, "bar")
.build();
MessageBuilder<?> out = (MessageBuilder<?>) gw.handleRequestMessage(requestMessage);
assertEquals("foo", out.getHeaders().get(FileHeaders.REMOTE_FILE));
assertEquals("foofoo/bar/baz", args.get());
assertEquals(Boolean.TRUE, out.getPayload());
assertEquals(2, madeDirs.size());
assertEquals("foo", madeDirs.get(0));
assertEquals("foo/bar", madeDirs.get(1));
}
public TestLsEntry[] fileList() {
TestLsEntry[] files = new TestLsEntry[6];
files[0] = new TestLsEntry("f2", 123, false, false, 1234, "-r--r--r--");
files[1] = new TestLsEntry("f1", 1234, false, false, 12345, "-rw-r--r--");
files[2] = new TestLsEntry("f3", 12345, true, false, 123456, "drw-r--r--");
files[3] = new TestLsEntry("f4", 12346, false, true, 1234567, "lrw-r--r--");
files[4] = new TestLsEntry(".f5", 12347, false, false, 12345678, "-rw-r--r--");
files[5] = new TestLsEntry(".f6", 12347, true, false, 123456789, "drw-r--r--");
return files;
}
@Test
public void testLs_f() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-f");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/x/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<TestLsEntry>> out = (MessageBuilder<List<TestLsEntry>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/x"));
assertEquals(2, out.getPayload().size());
assertSame(files[0], out.getPayload().get(0));
assertSame(files[1], out.getPayload().get(1));
assertEquals("testremote/x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
public TestLsEntry[] level1List() {
return new TestLsEntry[] {
new TestLsEntry("f1", 123, false, false, 1234, "-r--r--r--"),
new TestLsEntry("d1", 0, true, false, 12345, "drw-r--r--"),
new TestLsEntry("f2", 12345, false, false, 123456, "-rw-r--r--")
};
}
public TestLsEntry[] level2List() {
return new TestLsEntry[] {
new TestLsEntry("d2", 0, true, false, 12345, "drw-r--r--"),
new TestLsEntry("f3", 12345, false, false, 123456, "-rw-r--r--")
};
}
public TestLsEntry[] level3List() {
return new TestLsEntry[] {
new TestLsEntry("f4", 12345, false, false, 123456, "-rw-r--r--")
};
}
@Test
public void testLs_f_R() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-f -R");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] level1 = level1List();
TestLsEntry[] level2 = level2List();
TestLsEntry[] level3 = level3List();
when(session.list("testremote/x/")).thenReturn(level1);
when(session.list("testremote/x/d1/")).thenReturn(level2);
when(session.list("testremote/x/d1/d2/")).thenReturn(level3);
@SuppressWarnings("unchecked")
MessageBuilder<List<TestLsEntry>> out = (MessageBuilder<List<TestLsEntry>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/x"));
assertEquals(4, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0).getFilename());
assertEquals("d1/d2/f4", out.getPayload().get(1).getFilename());
assertEquals("d1/f3", out.getPayload().get(2).getFilename());
assertEquals("f2", out.getPayload().get(3).getFilename());
assertEquals("testremote/x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
@Test
public void testLs_f_R_dirs() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-f -R -dirs");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] level1 = level1List();
TestLsEntry[] level2 = level2List();
TestLsEntry[] level3 = level3List();
when(session.list("testremote/x/")).thenReturn(level1);
when(session.list("testremote/x/d1/")).thenReturn(level2);
when(session.list("testremote/x/d1/d2/")).thenReturn(level3);
@SuppressWarnings("unchecked")
MessageBuilder<List<TestLsEntry>> out = (MessageBuilder<List<TestLsEntry>>) gw
.handleRequestMessage(new GenericMessage<>("testremote/x"));
assertEquals(6, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0).getFilename());
assertEquals("d1", out.getPayload().get(1).getFilename());
assertEquals("d1/d2", out.getPayload().get(2).getFilename());
assertEquals("d1/d2/f4", out.getPayload().get(3).getFilename());
assertEquals("d1/f3", out.getPayload().get(4).getFilename());
assertEquals("f2", out.getPayload().get(5).getFilename());
assertEquals("testremote/x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
}
@Test
public void testLs_None() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = new TestLsEntry[0];
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<TestLsEntry>> out = (MessageBuilder<List<TestLsEntry>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(0, out.getPayload().size());
}
@Test
public void testLs_1() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(2, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0));
assertEquals("f2", out.getPayload().get(1));
}
@Test
public void testLs_1_f() throws Exception { //no sort
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1 -f");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(2, out.getPayload().size());
assertEquals("f2", out.getPayload().get(0));
assertEquals("f1", out.getPayload().get(1));
}
@Test
public void testLs_1_dirs() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1 -dirs");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(3, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0));
assertEquals("f2", out.getPayload().get(1));
assertEquals("f3", out.getPayload().get(2));
}
@Test
public void testLs_1_dirs_links() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1 -dirs -links");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(4, out.getPayload().size());
assertEquals("f1", out.getPayload().get(0));
assertEquals("f2", out.getPayload().get(1));
assertEquals("f3", out.getPayload().get(2));
assertEquals("f4", out.getPayload().get(3));
}
@Test
public void testLs_1_a_f_dirs_links() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1 -a -f -dirs -links");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(6, out.getPayload().size());
assertEquals("f2", out.getPayload().get(0));
assertEquals("f1", out.getPayload().get(1));
assertEquals("f3", out.getPayload().get(2));
assertEquals("f4", out.getPayload().get(3));
assertEquals(".f5", out.getPayload().get(4));
assertEquals(".f6", out.getPayload().get(5));
}
@Test
public void testLs_1_a_f_dirs_links_filtered() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "ls", "payload");
gw.setOptions("-1 -a -f -dirs -links");
gw.setFilter(new TestPatternFilter("*4"));
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
TestLsEntry[] files = fileList();
when(session.list("testremote/")).thenReturn(files);
@SuppressWarnings("unchecked")
MessageBuilder<List<String>> out = (MessageBuilder<List<String>>) gw
.handleRequestMessage(new GenericMessage<>("testremote"));
assertEquals(1, out.getPayload().size());
assertEquals("f4", out.getPayload().get(0));
}
@Test
public void testGet() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry("f1", 1234, false, false, 12345, "-rw-r--r--")
};
}
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testfile".getBytes());
}
});
@SuppressWarnings("unchecked")
MessageBuilder<File> out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
File outFile = new File(this.tmpDir + "/f1");
assertEquals(outFile, out.getPayload());
assertTrue(outFile.exists());
outFile.delete();
assertNull(out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
assertEquals("f1", out.getHeaders().get(FileHeaders.REMOTE_FILE));
}
@SuppressWarnings("unchecked")
@Test
public void testGetExists() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.afterPropertiesSet();
File outFile = new File(this.tmpDir + "/f1");
FileOutputStream fos = new FileOutputStream(outFile);
fos.write("foo".getBytes());
fos.close();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry("f1", 1234, false, false, 12345, "-rw-r--r--")
};
}
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testfile".getBytes());
}
});
// default (null)
MessageBuilder<File> out;
try {
out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
fail("Exception expected");
}
catch (MessageHandlingException e) {
assertThat(e.getMessage(), containsString("already exists"));
}
gw.setFileExistsMode(FileExistsMode.FAIL);
try {
out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
fail("Exception expected");
}
catch (MessageHandlingException e) {
assertThat(e.getMessage(), containsString("already exists"));
}
gw.setFileExistsMode(FileExistsMode.IGNORE);
out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
assertEquals(outFile, out.getPayload());
assertContents("foo", outFile);
gw.setFileExistsMode(FileExistsMode.APPEND);
out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
assertEquals(outFile, out.getPayload());
assertContents("footestfile", outFile);
gw.setFileExistsMode(FileExistsMode.REPLACE);
out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("f1"));
assertEquals(outFile, out.getPayload());
assertContents("testfile", outFile);
outFile.delete();
}
private void assertContents(String expected, File outFile) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader(outFile));
assertEquals(expected, reader.readLine());
reader.close();
}
@Test
public void testGetTempFileDelete() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry("f1", 1234, false, false, 12345, "-rw-r--r--")
};
}
@Override
public void read(String source, OutputStream outputStream) {
throw new RuntimeException("test remove .writing");
}
});
try {
gw.handleRequestMessage(new GenericMessage<String>("f1"));
fail("Expected exception");
}
catch (MessagingException e) {
assertThat(e.getCause(), instanceOf(RuntimeException.class));
assertEquals("test remove .writing", e.getCause().getMessage());
@SuppressWarnings("unchecked")
RemoteFileTemplate template = new RemoteFileTemplate(sessionFactory);
File outFile = new File(this.tmpDir + "/f1" + template.getTemporaryFileSuffix());
assertFalse(outFile.exists());
}
}
@Test
public void testGet_P() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setLocalDirectory(new File(this.tmpDir));
gw.setOptions("-P");
gw.afterPropertiesSet();
new File(this.tmpDir + "/f1").delete();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
final Date modified = new Date(cal.getTime().getTime() / 1000 * 1000);
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry("f1", 1234, false, false, modified.getTime(), "-rw-r--r--")
};
}
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testfile".getBytes());
}
});
@SuppressWarnings("unchecked")
MessageBuilder<File> out = (MessageBuilder<File>) gw.handleRequestMessage(new GenericMessage<>("x/f1"));
File outFile = new File(this.tmpDir + "/f1");
assertEquals(outFile, out.getPayload());
assertTrue(outFile.exists());
assertEquals(modified.getTime(), outFile.lastModified());
outFile.delete();
assertEquals("x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
assertEquals("f1",
out.getHeaders().get(FileHeaders.REMOTE_FILE));
}
@Test
public void testGet_create_dir() throws Exception {
new File(this.tmpDir + "/x/f1").delete();
new File(this.tmpDir + "/x").delete();
SessionFactory sessionFactory = mock(SessionFactory.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "get", "payload");
gw.setLocalDirectory(new File(this.tmpDir + "/x"));
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(new TestSession() {
@Override
public TestLsEntry[] list(String path) throws IOException {
return new TestLsEntry[] {
new TestLsEntry("f1", 1234, false, false, 12345, "-rw-r--r--")
};
}
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
outputStream.write("testfile".getBytes());
}
});
gw.handleRequestMessage(new GenericMessage<String>("f1"));
File out = new File(this.tmpDir + "/x/f1");
assertTrue(out.exists());
out.delete();
}
@Test
public void testRm() throws Exception {
SessionFactory sessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(sessionFactory, "rm", "payload");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
when(session.remove("testremote/x/f1")).thenReturn(Boolean.TRUE);
@SuppressWarnings("unchecked")
MessageBuilder<Boolean> out = (MessageBuilder<Boolean>) gw
.handleRequestMessage(new GenericMessage<>("testremote/x/f1"));
assertEquals(Boolean.TRUE, out.getPayload());
verify(session).remove("testremote/x/f1");
assertEquals("testremote/x/",
out.getHeaders().get(FileHeaders.REMOTE_DIRECTORY));
assertEquals("f1",
out.getHeaders().get(FileHeaders.REMOTE_FILE));
}
@Test
public void testPut() throws Exception {
@SuppressWarnings("unchecked")
SessionFactory<TestLsEntry> sessionFactory = mock(SessionFactory.class);
@SuppressWarnings("unchecked")
Session<TestLsEntry> session = mock(Session.class);
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<TestLsEntry>(sessionFactory) {
@Override
public boolean exists(String path) {
return false;
}
};
template.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
template.setBeanFactory(mock(BeanFactory.class));
template.afterPropertiesSet();
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", null);
FileTransferringMessageHandler<TestLsEntry> handler = new FileTransferringMessageHandler<TestLsEntry>(sessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
Message<String> requestMessage = MessageBuilder.withPayload("hello")
.setHeader(FileHeaders.FILENAME, "bar.txt")
.build();
String path = (String) gw.handleRequestMessage(requestMessage);
assertEquals("foo/bar.txt", path);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(session).write(any(InputStream.class), captor.capture());
assertEquals("foo/bar.txt.writing", captor.getValue());
verify(session).rename("foo/bar.txt.writing", "foo/bar.txt");
}
@Test
public void testPutExists() throws Exception {
@SuppressWarnings("unchecked")
SessionFactory<TestLsEntry> sessionFactory = mock(SessionFactory.class);
@SuppressWarnings("unchecked")
Session<TestLsEntry> session = mock(Session.class);
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<TestLsEntry>(sessionFactory) {
@Override
public boolean exists(String path) {
return true;
}
};
template.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
template.setBeanFactory(mock(BeanFactory.class));
template.afterPropertiesSet();
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "put", null);
FileTransferringMessageHandler<TestLsEntry> handler = new FileTransferringMessageHandler<TestLsEntry>(sessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
Message<String> requestMessage = MessageBuilder.withPayload("hello")
.setHeader(FileHeaders.FILENAME, "bar.txt")
.build();
// default (null) == REPLACE
String path = (String) gw.handleRequestMessage(requestMessage);
assertEquals("foo/bar.txt", path);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(session).write(any(InputStream.class), captor.capture());
assertEquals("foo/bar.txt.writing", captor.getValue());
verify(session).rename("foo/bar.txt.writing", "foo/bar.txt");
gw.setFileExistsMode(FileExistsMode.FAIL);
try {
path = (String) gw.handleRequestMessage(requestMessage);
fail("Exception expected");
}
catch (Exception e) {
assertThat(e.getMessage(), containsString("The destination file already exists"));
}
gw.setFileExistsMode(FileExistsMode.REPLACE);
path = (String) gw.handleRequestMessage(requestMessage);
assertEquals("foo/bar.txt", path);
captor = ArgumentCaptor.forClass(String.class);
verify(session, times(2)).write(any(InputStream.class), captor.capture());
assertEquals("foo/bar.txt.writing", captor.getValue());
verify(session, times(2)).rename("foo/bar.txt.writing", "foo/bar.txt");
gw.setFileExistsMode(FileExistsMode.APPEND);
path = (String) gw.handleRequestMessage(requestMessage);
assertEquals("foo/bar.txt", path);
captor = ArgumentCaptor.forClass(String.class);
verify(session).append(any(InputStream.class), captor.capture());
assertEquals("foo/bar.txt", captor.getValue());
gw.setFileExistsMode(FileExistsMode.IGNORE);
path = (String) gw.handleRequestMessage(requestMessage);
assertEquals("foo/bar.txt", path);
// no more writes/appends
verify(session, times(2)).write(any(InputStream.class), anyString());
verify(session, times(1)).append(any(InputStream.class), anyString());
}
@Test
public void testMput() throws Exception {
@SuppressWarnings("unchecked")
SessionFactory<TestLsEntry> sessionFactory = mock(SessionFactory.class);
@SuppressWarnings("unchecked")
Session<TestLsEntry> session = mock(Session.class);
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<TestLsEntry>(sessionFactory);
template.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
template.setBeanFactory(mock(BeanFactory.class));
template.afterPropertiesSet();
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", null);
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
final AtomicReference<String> written = new AtomicReference<String>();
doAnswer(invocation -> {
written.set(invocation.getArgument(1));
return null;
}).when(session).write(any(InputStream.class), anyString());
tempFolder.newFile("baz.txt");
tempFolder.newFile("qux.txt");
Message<File> requestMessage = MessageBuilder.withPayload(tempFolder.getRoot())
.build();
@SuppressWarnings("unchecked")
List<String> out = (List<String>) gw.handleRequestMessage(requestMessage);
assertEquals(2, out.size());
assertThat(out.get(0),
not(equalTo(out.get(1))));
assertThat(out.get(0), anyOf(
equalTo("foo/baz.txt"), equalTo("foo/qux.txt")));
assertThat(out.get(1), anyOf(
equalTo("foo/baz.txt"), equalTo("foo/qux.txt")));
}
@Test
public void testMputRecursive() throws Exception {
@SuppressWarnings("unchecked")
SessionFactory<TestLsEntry> sessionFactory = mock(SessionFactory.class);
@SuppressWarnings("unchecked")
Session<TestLsEntry> session = mock(Session.class);
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<TestLsEntry>(sessionFactory);
template.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
template.setBeanFactory(mock(BeanFactory.class));
template.afterPropertiesSet();
TestRemoteFileOutboundGateway gw = new TestRemoteFileOutboundGateway(template, "mput", null);
gw.setOptions("-R");
gw.afterPropertiesSet();
when(sessionFactory.getSession()).thenReturn(session);
final AtomicReference<String> written = new AtomicReference<String>();
doAnswer(invocation -> {
written.set(invocation.getArgument(1));
return null;
}).when(session).write(any(InputStream.class), anyString());
tempFolder.newFile("baz.txt");
tempFolder.newFile("qux.txt");
File dir1 = tempFolder.newFolder();
File file3 = File.createTempFile("foo", ".txt", dir1);
Message<File> requestMessage = MessageBuilder.withPayload(tempFolder.getRoot())
.build();
@SuppressWarnings("unchecked")
List<String> out = (List<String>) gw.handleRequestMessage(requestMessage);
assertEquals(3, out.size());
assertThat(out.get(0),
not(equalTo(out.get(1))));
assertThat(out.get(0), anyOf(
equalTo("foo/baz.txt"), equalTo("foo/qux.txt"), equalTo("foo/" + dir1.getName() + "/" + file3.getName())));
assertThat(out.get(1), anyOf(
equalTo("foo/baz.txt"), equalTo("foo/qux.txt"), equalTo("foo/" + dir1.getName() + "/" + file3.getName())));
assertThat(out.get(2), anyOf(
equalTo("foo/baz.txt"), equalTo("foo/qux.txt"), equalTo("foo/" + dir1.getName() + "/" + file3.getName())));
}
abstract static class TestSession implements Session<TestLsEntry> {
private boolean open;
@Override
public boolean remove(String path) throws IOException {
return false;
}
@Override
public TestLsEntry[] list(String path) throws IOException {
return null;
}
@Override
public void read(String source, OutputStream outputStream)
throws IOException {
}
@Override
public void write(InputStream inputStream, String destination)
throws IOException {
}
@Override
public void append(InputStream inputStream, String destination)
throws IOException {
}
@Override
public boolean mkdir(String directory) throws IOException {
return true;
}
@Override
public boolean rmdir(String directory) throws IOException {
return true;
}
@Override
public void rename(String pathFrom, String pathTo)
throws IOException {
}
@Override
public void close() {
open = false;
}
@Override
public boolean isOpen() {
return open;
}
@Override
public boolean exists(String path) throws IOException {
return true;
}
@Override
public String[] listNames(String path) throws IOException {
return null;
}
@Override
public InputStream readRaw(String source) throws IOException {
return null;
}
@Override
public boolean finalizeRaw() throws IOException {
return false;
}
@Override
public Object getClientInstance() {
return null;
}
}
static class TestRemoteFileOutboundGateway extends AbstractRemoteFileOutboundGateway<TestLsEntry> {
@SuppressWarnings("unchecked")
TestRemoteFileOutboundGateway(SessionFactory sessionFactory,
String command, String expression) {
super(sessionFactory, Command.toCommand(command), expression);
this.setBeanFactory(mock(BeanFactory.class));
}
TestRemoteFileOutboundGateway(RemoteFileTemplate<TestLsEntry> remoteFileTemplate, String command,
String expression) {
super(remoteFileTemplate, command, expression);
this.setBeanFactory(mock(BeanFactory.class));
}
@Override
protected boolean isDirectory(TestLsEntry file) {
return file.isDirectory();
}
@Override
protected boolean isLink(TestLsEntry file) {
return file.isLink();
}
@Override
protected String getFilename(TestLsEntry file) {
return file.getFilename();
}
@Override
protected String getFilename(AbstractFileInfo<TestLsEntry> file) {
return file.getFilename();
}
@Override
protected long getModified(TestLsEntry file) {
return file.getModified();
}
@Override
protected List<AbstractFileInfo<TestLsEntry>> asFileInfoList(
Collection<TestLsEntry> files) {
return new ArrayList<AbstractFileInfo<TestLsEntry>>(files);
}
@Override
protected TestLsEntry enhanceNameWithSubDirectory(TestLsEntry file, String directory) {
file.setFilename(directory + file.getFilename());
return file;
}
}
static class TestLsEntry extends AbstractFileInfo<TestLsEntry> {
private volatile String filename;
private final long size;
private final boolean dir;
private final boolean link;
private final long modified;
private final String permissions;
TestLsEntry(String filename, long size, boolean dir, boolean link,
long modified, String permissions) {
this.filename = filename;
this.size = size;
this.dir = dir;
this.link = link;
this.modified = modified;
this.permissions = permissions;
}
@Override
public boolean isDirectory() {
return this.dir;
}
@Override
public long getModified() {
return this.modified;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public boolean isLink() {
return this.link;
}
@Override
public long getSize() {
return this.size;
}
@Override
public String getPermissions() {
return this.permissions;
}
@Override
public TestLsEntry getFileInfo() {
return this;
}
public void setFilename(String filename) {
this.filename = filename;
}
}
static class TestPatternFilter extends AbstractSimplePatternFileListFilter<TestLsEntry> {
TestPatternFilter(String path) {
super(path);
}
@Override
protected String getFilename(TestLsEntry file) {
return file.getFilename();
}
@Override
protected boolean isDirectory(TestLsEntry file) {
return file.isDirectory();
}
}
}