Search code examples
spring-integration

spring integration advice afterReceive method not called in unit test


Hello i'am trying to add an advice to handle the case of empty files in a directory , the use case is when the directory is empty we should stop the application which is a springbok application .

here is my configuration file :

@Configuration
public class FlowConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(FlowConfiguration.class);

    @Bean("creFileInboundChannel")
    MessageChannel fileInputChannel() {
        return new DirectChannel();
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata poller() {
        return Pollers.fixedRate(1000)
                      .advice(emptyFolderAdvice())
                      .get();
    }

    @Bean
    DirectoryScanner directoryScanner(@Value("${inbound.filename.regex:.*}") String regex) {
        RecursiveDirectoryScanner scanner = new RecursiveDirectoryScanner();
        CompositeFileListFilter filter = new CompositeFileListFilter<>(
                Arrays.asList(new AcceptOnceFileListFilter<>(),
                        new RegexPatternFileListFilter(regex))
        );
        scanner.setFilter(filter);
        return scanner;
    }

    @Bean
    @InboundChannelAdapter(value = "creFileInboundChannel", poller = @Poller(fixedDelay = "1000"))
    MessageSource<File> fileReadingMessageSource(DirectoryScanner directoryScanner, CreConfiguration creConfiguration) {
        FileReadingMessageSource source = new FileReadingMessageSource();
        source.setDirectory(new File(creConfiguration.getInputDir()));
        source.setScanner(directoryScanner);
        return source;
    }

    @Bean
    @ServiceActivator(inputChannel = "creOutputChannel")
    MessageHandler logOutputCreFileHandler() {
        return message -> {
            if (message.getPayload() instanceof Optional) {
                Optional<File> filteredFile = (Optional<File>) message.getPayload();

                if (filteredFile.isPresent()) {
                    LOGGER.info("end of process {}, writing file in the output directory", filteredFile.get());
                }
            }
        };
    }

    @Bean
    @ServiceActivator(inputChannel = "creFileInboundChannel")
    MessageHandler creFileInFolderHandler(TraitementCreService traitementCreService) {
        List<Advice> advices = new ArrayList<>();
        advices.add(emptyFolderAdvice());
        ServiceActivatingHandler serviceActivatingHandler = new ServiceActivatingHandler(traitementCreService, "invoke");
        serviceActivatingHandler.setOutputChannelName("creOutputChannel");
        serviceActivatingHandler.setAdviceChain(advices);
        return serviceActivatingHandler;
    }

    @Bean
    @ServiceActivator(inputChannel = "errorChannel")
    MessageHandler erreurHandler() {
        return message ->
                LOGGER.info("Error when treating file : {}", ((ErrorMessage) message).getOriginalMessage().getPayload());
    }

    @Bean("errorChannel")
    QueueChannel errorChannel() {
        return new QueueChannel(500);
    }

    @Bean
    public EmptyFolderAdvice emptyFolderAdvice() {
        return new EmptyFolderAdvice();
    }

}

here is my advice class that handles shutdown when directory is empty :

public class EmptyFolderAdvice extends AbstractMessageSourceAdvice {


    @Override
    public Message<?> afterReceive(Message<?> message, MessageSource<?> source) {
        File directory = (File) source;
        File[] files = directory.listFiles();
        if (files == null || files.length == 0) {
            System.exit(0); // Stop the application if no files exist
        }
        return message;
    }
}

here is my integration test :

@SpringIntegrationTest
@SpringBootTest
@ContextConfiguration(classes = FiltrageApp.class)//{FlowConfiguration.class, FiltrageConfiguration.class})
public class StopApplicationTest {

    @MockBean
    private EmptyFolderAdvice advice; // Inject the advice under test

    @Qualifier("creFileInboundChannel")
    @Autowired
    private MessageChannel inputChannel;

    @MockBean
    TraitementCreService traitementCreService;

    @Autowired
    private MessageSource<?> messageSource;

    @Autowired
    private ApplicationContext context;

    @Autowired
    private MessageHandler creFileInFolderHandler;

    @Test
    public void testAfterReceiveIsCalled() throws TechnicalException {

        // Create a test message
        Message<?> message = MessageBuilder.withPayload("").build();

        // Send the message to the input channel
        //traitementCreService.invoke(null);
        inputChannel.send(message);

        traitementCreService.invoke(null);
        // Verify that the afterReceive method is called
        Mockito.verify(advice).afterReceive(Mockito.any(Message.class), Mockito.any(MessageSource.class));

        // You can also verify the number of times the method is called, e.g., Mockito.verify(mockAdvice, Mockito.times(1)).afterReceive(...)
    }

my problem is that is does not work and the afterReceive method of the advice is never called.

thanks


Solution

  • You use an explicit poller in your configuration:

    @InboundChannelAdapter(value = "creFileInboundChannel", poller = @Poller(fixedDelay = "1000"))
    

    But you apply your emptyFolderAdvice() which is out of use.

    You still need to have a PollerMetadata bean, but that must not be a PollerMetadata.DEFAULT_POLLER and use its name in the @Poller:

    /**
     * @return The {@link org.springframework.integration.scheduling.PollerMetadata} bean
     * name.
     */
    String value() default "";
    

    The logic in your EmptyFolderAdvice is also wrong:

    public Message<?> afterReceive(Message<?> message, MessageSource<?> source) {
        File directory = (File) source;
    

    How a MessageSource can be casted to a File?

    You just need to check for message == null: if no files to produce from a FileReadingMessageSource, then this afterReceive() method is called with null.