I have the following integration test that starts with sending message to sqs queue and ends with checking elastic search if the associated object added to db.
The part of application I want to test works like:
1- Takes event from sqs queue
2- persist venue object which is inside the event object in elastic search
Things I do in the following test are
1- Create localstack container to mock sqs behaviour
2- Create elastic search container to test if data successfully persisted
3- Send a message over sqs
4- Check elastic if data is persisted.
5- Reset elastic index after each test.
I came up with the following working solution. Can you review and present opinions?
@Testcontainers
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class VenueCreatedEventFlowTest {
private static final String LOCAL_STACK_IMAGE_NAME = "localstack/localstack:0.13.0";
private static final String ELASTIC_IMAGE_NAME = "docker.elastic.co/elasticsearch/elasticsearch:7.16.3";
private static final String QUEUE_NAME = "venue-created-event";
private VenueCreatedEvent venueCreatedEvent;
private Venue venue;
@Autowired
private QueueMessagingTemplate queueMessagingTemplate; // for sending messages over sqs
@Autowired
private VenueRepository venueRepository;
@Container
static LocalStackContainer localStackContainer =
new LocalStackContainer(DockerImageName.parse(LOCAL_STACK_IMAGE_NAME))
.withServices(LocalStackContainer.Service.SQS);
@Container
static ElasticsearchContainer elasticsearchContainer =
new ElasticsearchContainer(ELASTIC_IMAGE_NAME).withExposedPorts(9200);
@BeforeAll
static void start() throws IOException, InterruptedException {
localStackContainer.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", QUEUE_NAME);
elasticsearchContainer.start();
}
@AfterAll
static void destroy() {
localStackContainer.stop();
elasticsearchContainer.stop();
}
@BeforeEach
void testIsContainerRunning() {
Assertions.assertTrue(elasticsearchContainer.isRunning());
resetIndex();
}
@BeforeEach
public void prepareData() {
venueCreatedEvent = new VenueCreatedEvent();
venue = new Venue();
venue.setId("1");
venue.setActive(true);
venue.setName("Test Venue");
venue.setCreatedAt(LocalDateTime.now());
venue.setUpdatedAt(LocalDateTime.now());
venueCreatedEvent.setVenue(venue);
}
private void resetIndex() {
venueRepository.deleteAll();
}
@DynamicPropertySource
static void overrideConfiguration(DynamicPropertyRegistry registry) {
// sqs
registry.add("cloud.aws.credentials.access-key", localStackContainer::getAccessKey);
registry.add("cloud.aws.credentials.secret-key", localStackContainer::getSecretKey);
registry.add("cloud.aws.end-point.uri", () -> localStackContainer.getEndpointOverride(LocalStackContainer.Service.SQS));
registry.add("sqs.venue.event.queue.name", () -> QUEUE_NAME);
// elasticsearch
registry.add("elastic-search.url", () -> elasticsearchContainer.getHttpHostAddress());
}
@Test
public void whenVenueCreatedEventPublished_VenueShouldBeLocatedInElastic() {
queueMessagingTemplate.convertAndSend(QUEUE_NAME, venueCreatedEvent);
Awaitility.given().await().atMost(3, TimeUnit.SECONDS).untilAsserted(() -> {
Assertions.assertTrue(venueRepository.findById(venue.getId()).isPresent());
});
}
}