Integration testing a projection

I’m writing integration tests to verify my projection works as expected. I’ve hit a stumbling block when trying to use the EventGateway.

Some background to the problem:

  • I’m running my axon application, a postgres DB, and Axon Server as part of the integration test using testcontainers.

  • I have an aggregate, say it is an ‘Order’ aggregate.

  • I have two integration tests, they do exactly the same thing, except the first one (1) uses a ‘CreateOrder’ command (on the command gateway) and the second one (2) uses an OrderCreated event (on the event gateway).

  • Each integration test:

    • Creates an instance of the command (1)/event (2).

    • Calls either commandGateway.send(cmd) (1) or eventGateway.publish(event) (2).

    • Uses the awaitility library to run code which asserts the entity has been created in the DB.
      For (1) - where a command is sent - everything works fine. The command is received, the event is stored in axon server (confirmed by inspecting the GUI), and the projection occurs. All assertions pass and so does the test.

However, for (2) where I publish an event - the event never appears in axon server, and the projection never occurs. No assertions pass and so the test fails.

The main difference I can see in the logs is that for (1) there seems to be some log output of actually connecting to Axon Server:

2020-08-13T13:21:16,228 DEBUG [main] o.a.a.c.c.AxonServerCommandBus: Dispatch command [com.example.CreateOrderCommand] with callback
2020-08-13T13:21:16,569 INFO [main] o.a.a.c.AxonServerConnectionManager: Connecting using unencrypted connection…
2020-08-13T13:21:17,710 INFO [main] o.a.a.c.AxonServerConnectionManager: Requesting connection details from localhost:32798
2020-08-13T13:21:18,632 DEBUG [main] o.a.a.c.AxonServerConnectionManager: Received PlatformInfo suggesting [4abe33a7d1f3] (4abe33a7d1f3:8124), reusing existing connection
2020-08-13T13:21:18,632 INFO [main] o.a.a.c.AxonServerConnectionManager: Reusing existing channel
2020-08-13T13:21:18,633 DEBUG [main] o.a.a.c.AxonServerConnectionManager: Start instruction stream to node [4abe33a7d1f3] for context [default]
2020-08-13T13:21:18,661 INFO [main] o.a.a.c.AxonServerConnectionManager: Re-subscribing commands and queries
2020-08-13T13:21:19,035 DEBUG [grpc-default-executor-0] o.a.a.c.c.AxonServerCommandBus$1: Received command response [message_identifier: “a651e4fa-2f10-4271-8560-97e29f0fd246”

For (2) it does not output anything like that. Am I missing some configuration for the EventGateway so that it is usable in my integration test?

Regards,
vab2048

bump…

any idea on how to configure the event gateway so it works with these types of tests?

How did you configure the application, are you using Spring boot autoconfiguration or the Axon configurer. It looks like the EventGateway does not have the AxonServerEventStore as its EventBus.

Marc

It looks like the EventGateway is not using AxonServerEventStore as its EventBus/EventStore. Could be that this is a configuration issue in the app itself. Marc has a point here.

You can always use AxonServerEventStore (eventbus) to send events directly if you do not want to use the gateway. Please check if you are sending Domain or a regular generic event in this case.

PS: I like the idea to split the integration test per Command and Query component as you have most probably designed your test scenarios. It is a bit more work, as you have to use await on the command side test and to use event gateway/evenBus to publish event on the query side. But it is decoupling the tests from the start, so once you deploy your components independently your tests will just work, unchanged.

Thanks Marc and Ivan for the thoughtful replies. It pointed me in the right direction to solve the issue.

The application is configured using Spring Boot autoconfiguration. And on Axon 4.4.1, adding the following configuration solves the issue:

@Bean
@Primary
public EventGateway eventGateway(EventStore eventStore) {
log.debug("Overriding default EventGateway bean to use AxonServerEventStore.");
return DefaultEventGateway.builder().eventBus(eventStore).build();
}

Surprisingly, if using Axon 4.4.2 there is no need to provide extra configuration - it just works. I’m not sure what changed but I’m not complaining :).

I’m curious about a few things now:

  • Ivan - you mentioned "Please check if you are sending Domain or a regular generic event in this case".
  • Could you please elaborate on the difference in the event types and how that would affect the event bus/application?- Regarding configuration - I’ve found explicitly configuring the ObjectMapper used for serialization in the application makes sense. Does it also make sense to explicitly configure the gateways/buses for the application?
  • This is the first time I’ve actually ever had to autowire in an EventGateway and the default for the command+query gateway always distributed the messages across JVMs without an issue (which is what I want).

Glad that upgrading the Axon versions resolved the issue.

Well, I believe that EventGateway will wrap and send a GenericEventMessage. Please note that there is a GenericDomainEventMessage as well. GenericDomainEventMessage originates from an Aggregate with the given **agregateIdentifier**, with given **sequenceNumber** and payload.
GenericEventMessage is not related to an aggregate/domain.

I can remember (in one of the past projects) that I had to calculate the sequence number first (EventStore#lastSequenceNumberFor(String aggregateIdentifier)) and then construct the GenericDomainEventMessage so it can be published on the eventBus (EventBus#publish(List<? extends EventMessage<?>> events) ). In this case, you can send a DomanEventMessage as it would be published by your aggregate. Please note that for testing the Query side you most probbably do not need this, you can use EventGateway to send GenericEventMessage.

Best,
Ivan