Description
Hi Localstack Team/Users
I am getting to grips with this amazing package and have a few issues I hope you guys will know how to fix.
- In a
@ExtendWith(LocalstackDockerExtension.class)
Junit5 test docker image is initalised after Spring Boot
I'm finding an issue that I have a test SQS config created from some examples around the web and when I create a test listener I get the following error:
2018-12-21 08:47:30 ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMessageListenerContainer' defined in org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration: Invocation of init method failed; nested exception is com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to localhost:4576 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused (Connection refused)
Which in a sense, is totally accurate because the docker image isn't properly initalised yet.
Q. Is there a way to ensure the Localstack Image is fully initialised prior to the spring context booting up when I use these annotations?
My test looks like this:
@ActiveProfiles({"mock"})
@Tag("unit")
@SpringBootTest(
webEnvironment = RANDOM_PORT,
classes = {MyTestApplication.class})
@ExtendWith(LocalstackDockerExtension.class)
@LocalstackDockerProperties() // randomizePorts = false, services = {"sqs", "s3"})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ContextConfiguration(classes = {
MessagingAdapterTest.SqsTestConfiguration.class,
SqsConfiguration.class
})
@Slf4j
public class MessagingAdapterTest {
@Autowired
private AmazonSQS amazonSQS;
@Autowired
private SimpleMessageListenerContainer container;
private static final String QUEUE_NAME = "test_queue.fifo";
private String queueUrl;
@BeforeAll
void setUp() {
CreateQueueRequest req = new CreateQueueRequest(QUEUE_NAME)
.addAttributesEntry("FifoQueue", "true")
.addAttributesEntry("ContentBasedDeduplication", "true");
CreateQueueResult queue = amazonSQS.createQueue(req);
queueUrl = queue.getQueueUrl();
}
@AfterAll
void tearDown() {
}
@Autowired
private QueueMessagingTemplate queueMessagingTemplate;
void send(Object object) {
Map<String, Object> headers = new HashMap<>();
headers.put(SqsMessageHeaders.SQS_GROUP_ID_HEADER, "lodgementVerification");
headers.put(SqsMessageHeaders.SQS_DEDUPLICATION_ID_HEADER, UUID.randomUUID().toString());
queueMessagingTemplate.convertAndSend(QUEUE_NAME, object, headers);
}
@Test
@DisplayName("Given Localstack - SNS queue connects and configures")
void givenSnsWeConfigureConnectSuccessfully() throws InterruptedException {
log.info("Working on Queue %s", queueUrl);
send(new MyMsg("message 1"));
log.info("isRunning:" + container.isRunning());
log.info("isActive:" + container.isActive());
log.info("isRunningOnQueue:" + container.isRunning("my_queue"));
Thread.sleep(10_000);
log.info("GOT MESSAGE: " + amazonSQS.receiveMessage(queueUrl).getMessages().size());
}
@TestConfiguration
public static class SqsTestConfiguration {
@Component
public class MyListener {
@SqsListener(value = QUEUE_NAME, deletionPolicy = ON_SUCCESS)
public void receive(final MyMsg msg) {
log.info("GOT THE MESSAGE: "+ msg.toString());
}
}
@Primary
@Bean(destroyMethod = "shutdown")
public AmazonSQSAsync amazonSQS() {
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.
EndpointConfiguration("http://localhost:4576", DEFAULT_REGION);
return AmazonSQSAsyncClientBuilder.standard().
withEndpointConfiguration(endpointConfiguration).
withCredentials(getCredentialsProvider()).build();
}
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSqsClient, ResourceIdResolver resourceIdResolver) {
return new QueueMessagingTemplate(amazonSqsClient, resourceIdResolver);
}
}
@Data
@AllArgsConstructor
private static class MyMsg {
private String message;
}
}
So when I don't add in the listener its working, you also notice when I build the AmazonSQSAsync
bean I hard code the url, this is due to the fact that I was getting a not initialized bean error here as well.
Is there a way to lazy
or hold bean/context creation until some semaphore is triggered from Localstack? Otherwise I can't see how this is going to work longer term for us as we are integrating a spring AWS messaging stack and need this kind of functionality.
Thanks in advance!