masterdany88
masterdany88

Reputation: 5331

How to wait in integration test for some operations

I have integration test with docker using test containers. On container I run jms. In test I am putting message on queue.

How I can wait in test to make it populated on jms?

On local machine it works, but on jenkins it fails, so I have to add

    Thread.sleep(3000);

but this is nasty. org.awaitility seems to be missed usage:

await().atMost(2, TimeUnit.SECONDS).until(() -> return true));

I just need to do a pause to make jms propagate (put on jms queue) and wait for listener to act, which is putting message to database. Then I have to call get rest endpoint to see it worked.

With topic it would be easier, because I would create test listener on topic. But it is queue, there can be on listener that will get message.

Upvotes: 0

Views: 2389

Answers (3)

masterdany88
masterdany88

Reputation: 5331

My solution is to use org.awaitility lib and replace asserts with return statement:

await().atMost(30, TimeUnit.SECONDS).until(
    () -> {
        //
        // assertTrue(condition);
        return condition == true;
    }

Upvotes: -1

Justin Bertram
Justin Bertram

Reputation: 34998

Use org.awaitility with a JMS QueueBrowser, e.g.:

@Test
public void myTest() throws Exception {
   ...
   await().atMost(2, TimeUnit.SECONDS).until(() -> return queueIsEmpty(queueName)));
   ...
}

private boolean queueIsEmpty(String queueName) {
   ConnectionFactory cf = new MyBrokersConnectionFactory();
   Connection connection = cf.createConnection();
   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   QueueBrowser browser = session.createBrowser(session.createQueue(queueName));
   Enumeration enumeration = senderBrowser.getEnumeration();
   while (enumeration.hasMoreElements()) {
      return false;
   }
   return true;
}

A QueueBrowser is read only so there is no danger that it will actually consume the message.

Another potential option would be to create a consumer with a transacted session and then try to receive the message. If you actually did receive a message you could rollback the transaction and close the consumer.

Upvotes: 1

Daniel Steinmann
Daniel Steinmann

Reputation: 2199

Use retries (e.g. Spring RetryTemplate or Failsafe Retry Policy) to improve integration test execution time:

  • Retry the SQL query until record is present
  • Retry the REST endpoint until it is successful

Here an example to wait for a DB record; tweak the policies to your needs:

RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new FixedBackOffPolicy());
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(
         10, Collections.singletonMap(AssertionError.class, true)));
retryTemplate.execute(retryContext -> {
    List<MyRecord> records = jdbcTemplate.query("select ...");
    Assert.assertEquals(1, records.size());
    return null;
});

Upvotes: 0

Related Questions