Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to await for event happening more than once #41

Closed
wants to merge 1 commit into from
Closed

Conversation

SimY4
Copy link

@SimY4 SimY4 commented Feb 2, 2016

It would be nice to have a built-in feature that will allow awaiting for some event happening more than once. For example, I'm sending three messages to the queue and expecting that they all three will be received at some point in time.

for (Message message : messages) {
    sendMessageToTheQueue(message);
}

List<Message> messages = await().until(receiveMessage(), hasMyId(), times(3));

...
Callable<Message> receiveMessage();
Matcher<Message> hasMyId();

@johanhaleby
Copy link
Collaborator

That is a good idea but I don't think it belongs in the library. You could quite easily write a custom Hamcrest matcher for this already. Perhaps there's not even a need to write a customer matcher. Maybe you can just compose some of the existing ones such as:

List<Message> messages = await().until(receiveMessage(), allOf(hasItem(hasMyId()), hasSize(3)))

So I'll close this issue. Please tell me if you disagree.

@SimY4
Copy link
Author

SimY4 commented Feb 2, 2016

Unfortunately it's imporssible in my case. Let me explain.

I'm using awaitility for writing system tests of our product. It's a JMS based processing service. The case that I'm frequently have is such that if I post single message to the inbound queue of this service it may produce more than one messages to it's outbound topic.

The API for listening JMS topic is limited and all I can get is just one message at a time. And to check whether it's the message that I'm looking for, I need to match it with my Hamcrest cryteria.

Right now for this taks I made my own Callable function that aggregates the matching results inside. But think that it would probably be a nice-to-have feature built-in awaitility.

@johanhaleby
Copy link
Collaborator

Oh so you mean that you want to wait for just ONE specific message but there may be other messages that arrive as well (before or after the message you're looking for)? We're using Awaitility for exactly this in my current project. We do something like this (rabbitmq):

MyEvent event = (MyEvent) await().until(() -> rabbitTemplate.receiveAndConvert(queue.getName()), instanceOf(MyEvent.class));

Using this approach we get the first event of the MyEvent. If you have several events of the same type you should be able to do something like:

MyEvent event = (MyEvent) await().until(() -> rabbitTemplate.receiveAndConvert(queue.getName()), allOf(instanceOf(MyEvent.class), hasProperty("id", equalTo("123-454-ABC")));

@SimY4
Copy link
Author

SimY4 commented Feb 2, 2016

No no, I want to catch more than one message that matches cryteria. Something like:

 MyEvent event = (MyEvent) await().until(() -> rabbitTemplate.receiveAndConvert(queue.getName()), anyOf(hasProperty("id", equalTo("123-454-ABC"), hasProperty("id", equalTo("456-789-CDE")));

But this case will return only the first event that matches one of listed cryteria. But I want to catch, for example, exatcly three events from the stream.

@johanhaleby
Copy link
Collaborator

Ah I see. Then I would probably create a custom Hamcrest matcher for this (perhaps that's what you're already doing?). I'm a bit hesitant on extending the API since you should be able to do it from a Hamcrest matcher. However if more users requests something like this I might change my mind. Or perhaps you just need to convince me even more? :)

@SimY4
Copy link
Author

SimY4 commented Feb 2, 2016

Hamcrest matcher can match only something that would Callable return. So for the case when you may want to catch three events from the stream their aggregation must happen inside of the Callable class.

What I'm trying to do right now is wrapping the Callable into some sort of the aggregating Callable with it's own matcher. Following our previous RabbitMQ exmaple, I propably would look something like this:

 await().until(receiveAllOf(() -> rabbitTemplate.receiveAndConvert(queue.getName()), anyOf(hasProperty("id", equalTo("123-454-ABC"), hasProperty("id", equalTo("456-789-CDE"))), hasSize(3));

Here we have two matchers. One for the actual event filtering. And the other for size of the aggregating collection.

@SimY4
Copy link
Author

SimY4 commented Feb 2, 2016

Here's a simple patch that implements aggregational feature

@johanhaleby
Copy link
Collaborator

Sorry for not getting back to you earlier. I see what you mean, I'll have to think about it a bit though. The way I see this is essentially as a reduce of what Awaitility returns. So perhaps it should be generalized and the reduce should be made explicit. Something like:

await().until(reduce( (list, x)  -> list.add(x), new ArrayList<>()), () -> somethingThatReturnXs());

That would save all values to the list. Perhaps a context should be supplied so that you can capture all intermediate values as well? Something like this (if we pretend that list.add returns a new list):

await().until(reduce((list, ctx) -> ctx.isMatching() ? list.add(ctx.getEntity()) : list), new ArrayList<>()), () -> somethingThatReturnXs());

If you don't specify a reduce (default behavoir) the reduce function would look something like this:

await().until(reduce( (__, ctx) -> ctx.isMatching() ? ctx.getEntity() : null, null)), () -> somethingThatReturnXs());

@SimY4
Copy link
Author

SimY4 commented Feb 8, 2016

My only consern is: please, make it coincise for pour souls who still use java 7 (like me).

@johanhaleby
Copy link
Collaborator

I suppose it would be possible to supply some connivence methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants