You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by idioma <co...@gmail.com> on 2016/11/09 08:19:13 UTC

Help in testing a custom processor

I have the following route:

<camelContext xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="activemq:topic:inbox" />
            <log message="To: ${in.header.recipients}" />
            <to uri="bean:myLogger" />
        </route>
</camelContext>

bean:myLogger is my custom processor for formatting the log messages I am
getting. The process method in my custom processor simply calls a private
method that appends the type of message (e.g. CC) and the recipients' email.
I am struggling to see how to test the actual resulting logs. I am using
CamelSpringTestSupportand I am OK when it comes to testing the myLogger
endpoint:

@Produce(uri = "activemq:topic:inbox")
    protected ProducerTemplate template;

    @Override
    protected AbstractApplicationContext createApplicationContext() {
        return new
ClassPathXmlApplicationContext("file:src/main/resources/my-camel-context.xml");
    }

    @Test
        public void testLogEndpoint() throws Exception {
            String body = "Hello World";
            template.sendBody("activemq:topic:inbox", body);
            LOG.info("This is the message body we sent {} ", body);
        }
However, I am not really sure how to test the format of the returned logs.
Do I send the email of the recipients in a similar fashion as the example
above? But then how do I check whether the format is the correct one? I am
really looking more for the approach than the actual solution.

Thank you so much for your help,



--
View this message in context: http://camel.465427.n5.nabble.com/Help-in-testing-a-custom-processor-tp5789934.html
Sent from the Camel Development mailing list archive at Nabble.com.

Re: Help in testing a custom processor

Posted by idioma <co...@gmail.com>.
Hi,
thanks for your reply. I took a different direction because I felt that
writing a custom appender was overengineering a bit. I have gotten the
Log4j2 properties to work in order to write the logs into a file and have
written two utilities: one for reading the Logs from the abovementioned file
and another one to make sure that each time I run that time the existing
logs are removed (I would like to avoid that the test passes because of the
same log entries are already present). The utility for reading the logs
returns a boolean, so my Unit Test will simply assert whether the expected
message matches the content of the line from the logs. 

Thanks for your help,

I. 



--
View this message in context: http://camel.465427.n5.nabble.com/Help-in-testing-a-custom-processor-tp5789934p5790009.html
Sent from the Camel Development mailing list archive at Nabble.com.

Re: Help in testing a custom processor

Posted by Quinn Stevenson <qu...@pronoia-solutions.com>.
I’ve never done this with Log4j2, so I don’t know how convoluted the appender is.

However, I wouldn’t make the appender actually write the data - I’d just validate the payload is what I wanted.  

I’d try and create the appender in the unit test, install the appender during the initialization of the test, and then call a method on the appender to validate the format inside a JUnit assert.  Hopefully that makes sense - I don’t have time to work up an example at the moment.

HTH

> On Nov 9, 2016, at 10:28 AM, idioma <co...@gmail.com> wrote:
> 
> Hi, thanks for your reply. It is exactly what I am trying to do as my
> processor is calling a void method that if a certain condition is met prints
> out LOG.info("some text {}", arg1, arg2). The issue is that I can't really
> Unit test the format of the message because it is a void method. I have had
> a look around in terms of custom appenders and found out that with Log4j2
> (which I am currently using) requires a slightly more convoluted solution.
> Here an example:
> 
> import java.io.Serializable;
> import java.util.concurrent.locks.*;
> import org.apache.logging.log4j.core.*;
> import org.apache.logging.log4j.core.appender.AbstractAppender;
> import org.apache.logging.log4j.core.appender.AppenderLoggingException;
> import org.apache.logging.log4j.core.config.plugins.*;
> import org.apache.logging.log4j.core.layout.PatternLayout;
> 
> // note: class name need not match the @Plugin name.
> @Plugin(name="MyCustomAppender", category="Core", elementType="appender",
> printObject=true)
> public final class MyCustomAppenderImpl extends AbstractAppender {
> 
>    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
>    private final Lock readLock = rwLock.readLock();
> 
>    protected MyCustomAppenderImpl(String name, Filter filter,
>            Layout<? extends Serializable> layout, final boolean
> ignoreExceptions) {
>        super(name, filter, layout, ignoreExceptions);
>    }
> 
>    // The append method is where the appender does the work.
>    // Given a log event, you are free to do with it what you want.
>    // This example demonstrates:
>    // 1. Concurrency: this method may be called by multiple threads
> concurrently
>    // 2. How to use layouts
>    // 3. Error handling
>    @Override
>    public void append(LogEvent event) {
>        readLock.lock();
>        try {
>            final byte[] bytes = getLayout().toByteArray(event);
>            System.out.write(bytes);
>        } catch (Exception ex) {
>            if (!ignoreExceptions()) {
>                throw new AppenderLoggingException(ex);
>            }
>        } finally {
>            readLock.unlock();
>        }
>    }
> 
>    // Your custom appender needs to declare a factory method
>    // annotated with `@PluginFactory`. Log4j will parse the configuration
>    // and call this factory method to construct an appender instance with
>    // the configured attributes.
>    @PluginFactory
>    public static MyCustomAppenderImpl createAppender(
>            @PluginAttribute("name") String name,
>            @PluginElement("Layout") Layout<? extends Serializable> layout,
>            @PluginElement("Filter") final Filter filter,
>            @PluginAttribute("otherAttribute") String otherAttribute) {
>        if (name == null) {
>            LOGGER.error("No name provided for MyCustomAppenderImpl");
>            return null;
>        }
>        if (layout == null) {
>            layout = PatternLayout.createDefaultLayout();
>        }
>        return new MyCustomAppenderImpl(name, filter, layout, true);
>    }
> }
> 
> I wonder whether I am going too far in order to test the log output. I have
> tried to have the log4j2 configurations for the file output working with the
> intent to read the content of the log file, but with no luck. I am not sure
> I can see how to use the above implementation in my test, any idea?
> 
> Thank you,
> 
> I. 
> 
> 
> 
> --
> View this message in context: http://camel.465427.n5.nabble.com/Help-in-testing-a-custom-processor-tp5789934p5789963.html
> Sent from the Camel Development mailing list archive at Nabble.com.


Re: Help in testing a custom processor

Posted by idioma <co...@gmail.com>.
Hi, thanks for your reply. It is exactly what I am trying to do as my
processor is calling a void method that if a certain condition is met prints
out LOG.info("some text {}", arg1, arg2). The issue is that I can't really
Unit test the format of the message because it is a void method. I have had
a look around in terms of custom appenders and found out that with Log4j2
(which I am currently using) requires a slightly more convoluted solution.
Here an example:

import java.io.Serializable;
import java.util.concurrent.locks.*;
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.config.plugins.*;
import org.apache.logging.log4j.core.layout.PatternLayout;

// note: class name need not match the @Plugin name.
@Plugin(name="MyCustomAppender", category="Core", elementType="appender",
printObject=true)
public final class MyCustomAppenderImpl extends AbstractAppender {

    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();

    protected MyCustomAppenderImpl(String name, Filter filter,
            Layout<? extends Serializable> layout, final boolean
ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions);
    }

    // The append method is where the appender does the work.
    // Given a log event, you are free to do with it what you want.
    // This example demonstrates:
    // 1. Concurrency: this method may be called by multiple threads
concurrently
    // 2. How to use layouts
    // 3. Error handling
    @Override
    public void append(LogEvent event) {
        readLock.lock();
        try {
            final byte[] bytes = getLayout().toByteArray(event);
            System.out.write(bytes);
        } catch (Exception ex) {
            if (!ignoreExceptions()) {
                throw new AppenderLoggingException(ex);
            }
        } finally {
            readLock.unlock();
        }
    }

    // Your custom appender needs to declare a factory method
    // annotated with `@PluginFactory`. Log4j will parse the configuration
    // and call this factory method to construct an appender instance with
    // the configured attributes.
    @PluginFactory
    public static MyCustomAppenderImpl createAppender(
            @PluginAttribute("name") String name,
            @PluginElement("Layout") Layout<? extends Serializable> layout,
            @PluginElement("Filter") final Filter filter,
            @PluginAttribute("otherAttribute") String otherAttribute) {
        if (name == null) {
            LOGGER.error("No name provided for MyCustomAppenderImpl");
            return null;
        }
        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }
        return new MyCustomAppenderImpl(name, filter, layout, true);
    }
}

I wonder whether I am going too far in order to test the log output. I have
tried to have the log4j2 configurations for the file output working with the
intent to read the content of the log file, but with no luck. I am not sure
I can see how to use the above implementation in my test, any idea?

Thank you,

I. 



--
View this message in context: http://camel.465427.n5.nabble.com/Help-in-testing-a-custom-processor-tp5789934p5789963.html
Sent from the Camel Development mailing list archive at Nabble.com.

Re: Help in testing a custom processor

Posted by Quinn Stevenson <qu...@pronoia-solutions.com>.
If I’m understanding you correctly, you’re trying to test the content of a log message being sent to the logging subsystem.  If that’s the case, you could write a custom Appender (assuming you use Log4j) that verifies the log event has the correct content.

HTH


> On Nov 9, 2016, at 1:19 AM, idioma <co...@gmail.com> wrote:
> 
> I have the following route:
> 
> <camelContext xmlns="http://camel.apache.org/schema/spring">
>        <route>
>            <from uri="activemq:topic:inbox" />
>            <log message="To: ${in.header.recipients}" />
>            <to uri="bean:myLogger" />
>        </route>
> </camelContext>
> 
> bean:myLogger is my custom processor for formatting the log messages I am
> getting. The process method in my custom processor simply calls a private
> method that appends the type of message (e.g. CC) and the recipients' email.
> I am struggling to see how to test the actual resulting logs. I am using
> CamelSpringTestSupportand I am OK when it comes to testing the myLogger
> endpoint:
> 
> @Produce(uri = "activemq:topic:inbox")
>    protected ProducerTemplate template;
> 
>    @Override
>    protected AbstractApplicationContext createApplicationContext() {
>        return new
> ClassPathXmlApplicationContext("file:src/main/resources/my-camel-context.xml");
>    }
> 
>    @Test
>        public void testLogEndpoint() throws Exception {
>            String body = "Hello World";
>            template.sendBody("activemq:topic:inbox", body);
>            LOG.info("This is the message body we sent {} ", body);
>        }
> However, I am not really sure how to test the format of the returned logs.
> Do I send the email of the recipients in a similar fashion as the example
> above? But then how do I check whether the format is the correct one? I am
> really looking more for the approach than the actual solution.
> 
> Thank you so much for your help,
> 
> 
> 
> --
> View this message in context: http://camel.465427.n5.nabble.com/Help-in-testing-a-custom-processor-tp5789934.html
> Sent from the Camel Development mailing list archive at Nabble.com.