8000 Spring Boot Junit Docker Test - Issues with timing of things being ready · Issue #1067 · localstack/localstack · GitHub
[go: up one dir, main page]

Skip to content
Spring Boot Junit Docker Test - Issues with timing of things being ready #1067
Closed
@mb-3000

Description

@mb-3000

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.

  1. 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0