Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing FTP consumer with Apache Camel

I have the below route. In unit test, since I doesn't have the FTP server available, I'd like to use camel's test support and send an invalid message to "ftp://hostname/input" and verify that it failed and routed to "ftp://hostname/error".

I gone through the documentation which mainly talks about using the "mock:" endpoint but I am not sure how to use it in this scenario.

public class MyRoute extends RouteBuilder
{
    @Override
    public void configure()
    {
        onException(EdiOrderParsingException.class).handled(true).to("ftp://hostname/error");

        from("ftp://hostname/input")
            .bean(new OrderEdiTocXml())
            .convertBodyTo(String.class)
            .convertBodyTo(Document.class)
            .choice()
            .when(xpath("/cXML/Response/Status/@text='OK'"))
            .to("ftp://hostname/valid").otherwise()
            .to("ftp://hostname/invalid");
    }
}
like image 422
Aravind Yarram Avatar asked Dec 05 '22 17:12

Aravind Yarram


2 Answers

As Ben says you can either setup a FTP server and use the real components. The FTP server can be embedded, or you can setup a FTP server in-house. The latter is more like an integration testing, where you may have a dedicated test environment.

Camel is very flexible in its test kit, and if you want to build an unit test that do not use the real FTP component, then you can replace that before the test. For example in your example you can replace the input endpoint of a route to a direct endpoint to make it easier to send a message to the route. Then you can use an interceptor to intercept the sending to the ftp endpoints, and detour the message.

The advice with part of the test kit offers these capabilities: http://camel.apache.org/advicewith.html. And is also discussed in chapter 6 of the Camel in action book, such as section 6.3, that talks about simulating errors.

In your example you could do something a like

public void testSendError() throws Exception {
    // first advice the route to replace the input, and catch sending to FTP servers
    context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
        @Override
        public void configure() throws Exception {
            replaceFromWith("direct:input");

            // intercept valid messages
            interceptSendToEndpoint("ftp://hostname/valid")
                .skipSendToOriginalEndpoint()
                .to("mock:valid");

            // intercept invalid messages
            interceptSendToEndpoint("ftp://hostname/invalid")
                .skipSendToOriginalEndpoint()
                .to("mock:invalid");
        }
    });

     // we must manually start when we are done with all the advice with
    context.start();

    // setup expectations on the mocks
    getMockEndpoint("mock:invalid").expectedMessageCount(1);
    getMockEndpoint("mock:valid").expectedMessageCount(0);

    // send the invalid message to the route
    template.sendBody("direct:input", "Some invalid content here");

    // assert that the test was okay
    assertMockEndpointsSatisfied();
}

From Camel 2.10 onwards we will make the intercept and mock a bit easier when using advice with. As well we are introducing a stub component. http://camel.apache.org/stub

like image 139
Claus Ibsen Avatar answered Dec 22 '22 08:12

Claus Ibsen


Have a look at MockFtPServer!

<dependency>
    <groupId>org.mockftpserver</groupId>
    <artifactId>MockFtpServer</artifactId>
    <version>2.2</version>
    <scope>test</scope>
</dependency>

With this one you can simulate all sorts of behaviors like permission problems, etc:

Example:

fakeFtpServer = new FakeFtpServer();

fakeFtpServer.setServerControlPort(FTPPORT);

FileSystem fileSystem = new UnixFakeFileSystem();
fileSystem.add(new DirectoryEntry(FTPDIRECTORY));
fakeFtpServer.setFileSystem(fileSystem);
fakeFtpServer.addUserAccount(new UserAccount(USERNAME, PASSWORD, FTPDIRECTORY));

...

assertTrue("Expected file to be transferred", fakeFtpServer.getFileSystem().exists(FTPDIRECTORY + "/" + FILENAME)); 
like image 38
Brimstedt Avatar answered Dec 22 '22 10:12

Brimstedt