/*
* Copyright 2002-2016 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.samples.filesplit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
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.util.List;
import org.apache.commons.net.ftp.FTPFile;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.test.mail.TestMailServer;
import org.springframework.integration.test.mail.TestMailServer.SmtpServer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ApplicationTests {
private static final SmtpServer smtpServer = TestMailServer.smtp(0);
@Autowired
private Session<FTPFile> session;
@BeforeClass
public static void setup() {
// Configure the boot property to send email to the test email server.
System.setProperty("spring.mail.port", Integer.toString(smtpServer.getPort()));
new File("/tmp/in/foo.txt").delete();
new File("/tmp/in/foo.txt.success").delete();
new File("/tmp/in/foo.txt.failed").delete();
}
@Before
public void beforeTest() {
smtpServer.getMessages().clear();
}
@SuppressWarnings("unchecked")
@Test
public void testSuccess() throws Exception {
reset(this.session);
String message = runTest(false);
assertThat(message).contains("File successfully split and transferred");
assertThat(message).contains(TestUtils.applySystemFileSeparator("/tmp/in/foo.txt"));
}
@Test
public void testFailure() throws Exception {
willThrow(new RuntimeException("fail test exception"))
.given(this.session).write(any(InputStream.class), eq("foo/002.txt.writing"));
String message = runTest(true);
assertThat(message).contains("File split and transfer failed");
assertThat(message).contains("fail test exception");
assertThat(message).contains(TestUtils.applySystemFileSeparator("/tmp/out/002.txt"));
}
/*
* Create a test file containing one row per account.
* Verify the three files appear, with the correct contents.
* Verify the input file was renamed based on success/failure.
* Verify the email was sent.
*/
private String runTest(boolean fail) throws Exception {
File in = new File("/tmp/in/", "foo");
FileOutputStream fos = new FileOutputStream(in);
fos.write("*002,foo,bar\n*006,baz,qux\n*009,fiz,buz\n".getBytes());
fos.close();
in.renameTo(new File("/tmp/in/", "foo.txt"));
File out = new File("/tmp/out/002.txt");
int n = 0;
while(n++ < 100 && (!out.exists() || out.length() < 12)) {
Thread.sleep(100);
}
assertThat(out.exists()).isTrue();
BufferedReader br = new BufferedReader(new FileReader(out));
assertThat(br.readLine()).isEqualTo("*002,foo,bar");
br.close();
out.delete();
out = new File("/tmp/out/006.txt");
n = 0;
while(n++ < 100 && (!out.exists() || out.length() < 12)) {
Thread.sleep(100);
}
assertThat(out.exists()).isTrue();
br = new BufferedReader(new FileReader(out));
assertThat(br.readLine()).isEqualTo("*006,baz,qux");
br.close();
out.delete();
out = new File("/tmp/out/009.txt");
n = 0;
while(n++ < 100 && (!out.exists() || out.length() < 12)) {
Thread.sleep(100);
}
assertThat(out.exists()).isTrue();
br = new BufferedReader(new FileReader(out));
assertThat(br.readLine()).isEqualTo("*009,fiz,buz");
br.close();
out.delete();
if (!fail) {
in = new File("/tmp/in/", "foo.txt.success");
}
else {
in = new File("/tmp/in/", "foo.txt.failed");
}
n = 0;
while(n++ < 100 && !in.exists()) {
Thread.sleep(100);
}
assertThat(in.exists()).isTrue();
in.delete();
// verify FTP
verify(this.session).write(any(InputStream.class), eq("foo/002.txt.writing"));
if (!fail) {
verify(this.session).write(any(InputStream.class), eq("foo/006.txt.writing"));
verify(this.session).write(any(InputStream.class), eq("foo/009.txt.writing"));
verify(this.session).rename("foo/002.txt.writing", "foo/002.txt");
verify(this.session).rename("foo/006.txt.writing", "foo/006.txt");
verify(this.session).rename("foo/009.txt.writing", "foo/009.txt");
}
String message = verifyMail();
assertThat(message).contains("From: foo@bar");
assertThat(message).contains("To: bar@baz");
return message;
}
public String verifyMail() throws Exception {
List<String> messages = smtpServer.getMessages();
int n = 0;
while (n++ < 100 && messages.size() < 1) {
Thread.sleep(100);
}
assertThat(messages).hasSize(1);
return messages.get(0);
}
/**
* Overrides the ftp session factories with mocks.
*
*/
@Configuration
@Import(Application.class)
public static class Config {
@Bean
public SessionFactory<FTPFile> ftp1() throws IOException {
return mockSf();
}
@Bean
public SessionFactory<FTPFile> ftp2() throws IOException {
return mockSf();
}
@Bean
public SessionFactory<FTPFile> ftp3() throws IOException {
return mockSf();
}
private SessionFactory<FTPFile> mockSf() throws IOException {
@SuppressWarnings("unchecked")
SessionFactory<FTPFile> mocksf = mock(SessionFactory.class);
given(mocksf.getSession()).willReturn(mockSession());
return mocksf;
}
@SuppressWarnings("unchecked")
@Bean
public Session<FTPFile> mockSession() throws IOException {
return mock(Session.class);
}
}
}