citrus icon indicating copy to clipboard operation
citrus copied to clipboard

jms queue purge

Open bbortt opened this issue 1 year ago • 1 comments

reported in https://citrusframework.zulipchat.com/#narrow/stream/259943-citrus/topic/Problems.20with.20purgeQueues.20action.

The purgeQueues-action does not work for me as expected; the queue does not seem to get purged.

For the setup: my system under tests receives a text/plain body via http/post and sends this body to an artemis topic.

For the test, I simply send some string to the system under test and then receive the corresponding JMS message. The JMS-setup on the citrus-side looks like this:

@Configuration
public class Jms {
  public static final String ENDPOINT = "JMS_ENDPOINT";
  public static final String CONNECTION_FACTORY = "CONNECTION_FACTORY";

  @Bean
  @Qualifier(CONNECTION_FACTORY)
  public ConnectionFactory purgeConnectionFactory(
      @Value("${test-config.artemis.url}") String url,
      @Value("${test-config.artemis.username}") String username,
      @Value("${test-config.artemis.password}") String password) {
    return new ActiveMQJMSConnectionFactory(url, username, password);
  }

  @Bean
  @Qualifier(ENDPOINT)
  public JmsEndpoint jmsEndpoint(
      @Qualifier(CONNECTION_FACTORY) ConnectionFactory connectionFactory,
      @Value("${test-config.artemis.receive.fqqn}") String fqqn) { // fqqn in this case is `messages::citrus`
    return new JmsEndpointBuilder()
        .connectionFactory(connectionFactory)
        .pubSubDomain(true)
        .destination(fqqn)
        .autoStart(true)
        .build();
  }
}

This works fine and as expected.

Now what I want to do is to clear the queue identified by the fqqn, so I implemented the following:

@Configuration
public class BeforeTestSequence {
  @Bean
  public SequenceBeforeTest beforeTest(
      @Qualifier(Jms.CONNECTION_FACTORY) ConnectionFactory connectionFactory,
      @Value("${test-config.artemis.receive.fqqn}") String fqqn) {
    return SequenceBeforeTest.Builder.beforeTest()
        .actions(
            purgeQueues()
                .connectionFactory(connectionFactory)
                .queue(fqqn))
        .build();
  }
}

This does not work as expected. In a "normal run", the test is green. However, if the queue messages::citrus already exists (from a previous run for example) and I write some message to that queue and THEN trigger the tests, the validation fails. The test "sees" the message i send beforehand, so the cleanup that should be happening does not happfen. In fact, I debugged into PurgeJmsQueuesAction::purgeDestination and the message received was always null.

If you need a full reproducer: https://github.com/turing85/citrus-playground/tree/feature/before-test-sequence

To reproduce:

start artemis (docker-compose --file local-deployment/docker-compose.yml up --detach) start service (./mvnw --projects service quarkus:dev) run the citrus tests however you like To send an interfering message to the queue, execute the following curl after the tests have run at least once (i.e. after the queue for citrus was created)`:

curl -v -X POST localhost:8080/send --data "ouch" --header "Content-Type: text/plain"

If you want to access the artemis broker, go to localhost:8161/console, credentials are artemis/artemis.****

bbortt avatar Oct 09 '24 08:10 bbortt

cc: @turing85

bbortt avatar Oct 09 '24 08:10 bbortt

I tried to find out what is happening and I think it could be related to

  • the topic consumer configured with .autoStart(true) and
  • the purge-queue-action interfering.

A scenario could be: 1. The topic consumer starts up at the beginning of the test and immediately reads the message (in the documentation https://citrusframework.org/citrus/reference/4.5.0/html/index.html#jms-topic-subscriber this sentence sounds like it: "Now with auto-start set to true the Citrus JMS endpoint will setup a subscription at the very beginning when the endpoint is loaded in the project." )

2. After this, the purge-queue-action can't consume the message anymore.

3. Once

runner.then(
      receive(jmsEndpoint)
          .message()
          .body("${message}"));

in the test is executed, it finds the message read by the topic consumer in the beginning (which should have been deleted by the purge-queue-action, but was not... ).

I don't know how to avoid that interference itself, but I found a purgeEndpoints()-action in the docs and that worked for me. I extended the reproducer here: https://github.com/louisa-frison/citrus-playground/tree/try-fix/purge-endpoint

louisa-frison avatar Jan 05 '25 22:01 louisa-frison

Hi @bbortt / @christophd , @turing85 tested the purge-endpoint way of fixing the issue and on his machine it worked, too.

The question arose, whether: a) calling purgeQueues() and purgeEndpoints() both explicitly is not the desired way and purgeQueues() should call purgeEndpoints() internally to make the purging more straightforward / compact b) calling purgeQueues() and purgeEndpoints() both explicitly is the correct way to do it

Optionally, if b) is the case:
As someone who only knows citrus from a user perspective and is not so familiar with its inner workings, it took me some time to find out about purgeEndpoints() If that sounds reasonable, I could maybe improve the documentation a bit, e.g. in the jms topic subscriber .autoStart() section, adding a hint to the purgeEndpoints()-section saying it might be necessary in some cases or something like that.

louisa-frison avatar Jan 07 '25 22:01 louisa-frison

It is because you are using a JMS topic subscriber. The JMS topic broadcasts each message to all consumers subscribed. So purging the JMS topic will not affect other subscribers that have already received the message. In this specific case you need to also purge the endpoints meaning all Citrus topic subscribers, too.

This is the nature of publish-subscribe topics compared to JMS queues. With JMS queue the purge operation on the queue itself would be sufficient without the purge on the Citrus endpoint.

So option a) is not the right way, because many endpoints may consumer from one single queue/topic. Option b) is right only for JMS topics where you need to explicitly also purge the Citrus topic subscriber endpoints.

Hope that helps. Any updates/improvements to the documentation are highly appreciated. Many thanks!

christophd avatar Jan 08 '25 08:01 christophd

Thanks, that cleared things up ! Then I will think about whether there is something helpful I could add to the documentation or not

louisa-frison avatar Jan 08 '25 23:01 louisa-frison

I opened a small PR for the documentation: https://github.com/citrusframework/citrus/pull/1305. Comments and of course also nit-pick comments are welcome : P

louisa-frison avatar Jan 28 '25 19:01 louisa-frison

I think we can close this as done. Many thanks!

christophd avatar Feb 25 '25 07:02 christophd