After moving to spring boot 3 and spring-cloud-aws-starter-sqs 3.0.2 I am now trying to create an integrationtest with SQS. I try to find an example, but so far none of the examples I found are this recent and adapting my test does not seem to work.
I have a listener and a publisher.
@Service
class Listener {
val logger = LoggerFactory.getLogger(this::class.java)
@SqsListener("list-queue")
fun processCacheRequest(items: List<Item?>?) {
logger.info("items: $items")
return
}
@SqsListener("single-queue")
fun processCacheRequest(item: Item?) {
logger.info("item: $item")
return
}
}
@Service
class Publisher {
@Autowired
lateinit var sqsTemplate: SqsTemplate
fun publish() {
val items = listOf(Item("foo", "bar"), Item("foo"), Item(bar = "bar"))
sqsTemplate.send("list-queue", items)
}
fun publishSingle() {
sqsTemplate.send("single-queue", Item("foo", "bar"))
}
}
I then have an integration test, that starts a SQS via testcontainer localstack.
@Testcontainers
@DirtiesContext
@WebAppConfiguration
@ContextConfiguration(initializers = [SqsUrlInitializer::class])
@SpringBootTest(
classes = [DemoApplication::class, SqsIntegrationTest.TestConfig::class],
properties = ["spring.main.allow-bean-definition-overriding=true"],
)
class SqsIntegrationTest : DescribeSpec() {
@Autowired
lateinit var publisher: Publisher
@Value("\${cloud.aws.sqs.endpoint}")
lateinit var endpoint: String
init {
it("should publish and read message") {
shouldNotThrow<Exception> {
publisher.publish()
}
}
}
@TestConfiguration
class TestConfig {
@Bean
@Primary
fun awsCredentialsProvider(): AwsCredentialsProvider {
if (!localStack.isRunning) localStack.start()
val creds = AwsBasicCredentials.create(localStack.accessKey, localStack.secretKey)
return StaticCredentialsProvider.create(creds)
}
@Bean
@Primary
fun awsRegionProvider(): AwsRegionProvider {
return StaticRegionProvider(Region.EU_CENTRAL_1.id())
}
/**
* Just configures Localstack's SQS server endpoint in the application
*/
companion object {
@JvmStatic
val localStack: LocalStackContainer = LocalStackContainer(DockerImageName.parse("localstack/localstack:latest"))
.withServices(SQS)
}
class SqsUrlInitializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(applicationContext: ConfigurableApplicationContext) {
localStack.start()
localStack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", "single-queue")
localStack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", "list-queue")
TestPropertyValues.of("cloud.aws.sqs.endpoint=${localStack.getEndpointOverride(SQS)}")
.applyTo(applicationContext.environment)
}
}
}
}
Unfortunately the test does not even start and shows the following error:
Failed to start bean 'io.awspring.cloud.messaging.internalEndpointRegistryBeanName'
org.springframework.context.ApplicationContextException: Failed to start bean 'io.awspring.cloud.messaging.internalEndpointRegistryBeanName'
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
[...]
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: io.awspring.cloud.sqs.QueueAttributesResolvingException: Error resolving attributes for queue single-queue with strategy CREATE and queueAttributesNames []
at io.awspring.cloud.sqs.QueueAttributesResolver.wrapException(QueueAttributesResolver.java:90)
at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:990)
at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:974)
... 41 more
Caused by: software.amazon.awssdk.services.sqs.model.SqsException: The security token included in the request is invalid. (Service: Sqs, Status Code: 403, Request ID: 2c38dd48-e9e1-5670-98ba-803c3343f84e)
at software.amazon.awssdk.services.sqs.model.SqsException$BuilderImpl.build(SqsException.java:104)
When I create breakpoints I can see that the queues are created and docker exec <container> awslocal sqs list-queues
showa:
{
"QueueUrls": [
"http://localhost:4566/000000000000/single-queue",
"http://localhost:4566/000000000000/list-queue"
]
}
When I run this application against my AWS account it works fine.
Anybody any idea what I am doing wrong here? The whole project can be found here.
so I found out my problem had nothing to do with the credentials, but that I used the wrong property for the endpoint.
instead of
TestPropertyValues.of("cloud.aws.sqs.endpoint=${localStack.getEndpointOverride(SQS)}")
.applyTo(applicationContext.environment)
I need to use
TestPropertyValues.of("spring.cloud.aws.sqs.endpoint=${localStack.getEndpointOverride(SQS)}")
.applyTo(applicationContext.environment)