Skip to content

Commit

Permalink
Fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
wellyfrs committed Aug 8, 2024
1 parent 2a1e0e5 commit 4dcd406
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 38 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MessagingConfig {

@Bean
fun createPaymentSender(snsTemplate: SnsTemplate,
@Value("\${topic.response-payment}") topicName: String,
@Value("\${sns.topics.response-payment}") topicName: String,
objectMapper: ObjectMapper): PaymentSender {
return PaymentSenderImpl(snsTemplate, topicName, objectMapper)
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/com/fiap/payments/config/JWTSecurityConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.fiap.payments.config

import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
import io.swagger.v3.oas.annotations.security.SecurityScheme
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
Expand All @@ -19,6 +20,11 @@ import org.springframework.security.web.SecurityFilterChain
bearerFormat = "JWT",
scheme = "bearer"
)
@ConditionalOnProperty(
value = ["security.enable"],
havingValue = "true",
matchIfMissing = true
)
class JWTSecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ class DynamoDBConfig {
* For local run.
*/
@Bean("amazonDynamoDB")
@ConditionalOnProperty("aws.dynamodb.local", havingValue = "true")
@ConditionalOnProperty("local", havingValue = "true")
fun amazonDynamoDB(
@Value("\${aws.dynamodb.endpoint}") endpoint: String,
@Value("\${aws.dynamodb.region}") region: String,
@Value("\${spring.cloud.aws.endpoint}") endpoint: String,
@Value("\${spring.cloud.aws.region.static}") region: String,
): AmazonDynamoDB {
return AmazonDynamoDBClientBuilder.standard()
// using default credentials provider chain, which searches for environment variables
Expand All @@ -53,7 +53,7 @@ class DynamoDBConfig {
* we need to keep as v1 and include token provider to the chain.
*/
@Bean("amazonDynamoDB")
@ConditionalOnProperty("aws.dynamodb.local", havingValue = "false")
@ConditionalOnProperty("local", havingValue = "false")
fun awsCredentialsProvider(): AmazonDynamoDB {
return AmazonDynamoDBClientBuilder.standard()
// AWS_WEB_IDENTITY_TOKEN_FILE is present.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.fiap.payments.driver.messaging.event.PaymentRequestEvent
import com.fiap.payments.usecases.ProvidePaymentRequestUseCase
import io.awspring.cloud.sqs.annotation.SqsListener
import org.slf4j.LoggerFactory
import org.springframework.context.event.EventListener
import org.springframework.messaging.MessageHeaders
import org.springframework.messaging.handler.annotation.Headers
import org.springframework.scheduling.annotation.EnableAsync
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"properties": [
{
"name": "admin.access-token",
"type": "java.lang.String",
"description": "Description for admin-access-token."
},
{
"name": "payment-provider.mock",
"type": "java.lang.String",
Expand Down
10 changes: 10 additions & 0 deletions src/main/resources/application-live.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
security:
enable: true

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${COGNITO_ISSUER_URI}
jwk-set-uri: ${COGNITO_JWK_SET_URI}
12 changes: 4 additions & 8 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
aws:
dynamodb:
local: true
endpoint: ${AWS_DYNAMODB_ENDPOINT}
region: ${AWS_REGION}
local: true

payment-provider:
mock: true
Expand All @@ -21,9 +17,9 @@ sqs:
queues:
request-payment: request-payment_queue

topic:
response-payment: arn:aws:sns:us-east-2:000000000000:payment-response_topic

sns:
topics:
response-payment: arn:aws:sns:us-east-2:000000000000:payment-response_topic

server:
port: 8081
5 changes: 2 additions & 3 deletions src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
admin:
access-token: token
local: true

payment-provider:
mock: true
mock: true
24 changes: 12 additions & 12 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
spring:
application:
name: payments
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ygM5FRn7D
jwk-set-uri: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ygM5FRn7D/.well-known/jwks.json

admin:
access-token: ${ADMIN_ACCESS_TOKEN}

payment-provider:
mock: ${MOCK_PAYMENT_PROVIDER}
Expand All @@ -23,13 +14,22 @@ mercadopago:
posId: ${MP_POS_ID}
webhookBaseUrl: ${MP_WEBHOOK_BASE_URL}

aws:
dynamodb:
local: false
local: false

sqs:
queues:
request-payment: request-payment_queue

sns:
topics:
response-payment: ${SNS_TOPIC_RESPONSE_PAYMENT_ARN}

clients:
orders-api:
url: ${ORDERS_SERVICE_URL}

server:
port: 8082

security:
enable: false
8 changes: 8 additions & 0 deletions src/test/kotlin/com/fiap/payments/TestAnnotations.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package com.fiap.payments

import com.fiap.payments.it.LocalStackContainerInitializer
import org.junit.jupiter.api.Tag
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration

@Tag("IntegrationTest")
@ActiveProfiles("test")
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
annotation class IntegrationTest

@ContextConfiguration(initializers = [LocalStackContainerInitializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
annotation class WithLocalstack
15 changes: 15 additions & 0 deletions src/test/kotlin/com/fiap/payments/it/BasicIntegrationTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fiap.payments.it

import com.fiap.payments.IntegrationTest
import com.fiap.payments.WithLocalstack
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest

@IntegrationTest
@WithLocalstack
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BasicIntegrationTest {

@Test
fun contextLoads() { }
}
145 changes: 145 additions & 0 deletions src/test/kotlin/com/fiap/payments/it/LocalstackContainerInitializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.fiap.payments.it

import org.springframework.boot.test.util.TestPropertyValues
import org.springframework.context.ApplicationContextInitializer
import org.springframework.context.ConfigurableApplicationContext
import org.testcontainers.containers.localstack.LocalStackContainer
import org.testcontainers.containers.wait.strategy.Wait.forListeningPort
import org.testcontainers.utility.DockerImageName
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.sns.SnsClient
import software.amazon.awssdk.services.sns.model.CreateTopicRequest
import software.amazon.awssdk.services.sns.model.SubscribeRequest
import software.amazon.awssdk.services.sqs.SqsClient
import software.amazon.awssdk.services.sqs.model.CreateQueueRequest
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest
import software.amazon.awssdk.services.sqs.model.QueueAttributeName

class LocalStackContainerInitializer :
ApplicationContextInitializer<ConfigurableApplicationContext>,
LocalStackContainer(
DockerImageName.parse("localstack/localstack")
) {

companion object {
private val instance: LocalStackContainer = LocalStackContainerInitializer()
.withServices(
Service.DYNAMODB,
Service.SQS,
Service.SNS
)
.withEnv(
mapOf(
"DEBUG" to "1",
"DEFAULT_REGION" to "us-east-1",
)
)
.waitingFor(forListeningPort())
}

override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) {
instance.start()

val awsCredentials = AwsBasicCredentials.create(
instance.accessKey,
instance.secretKey
)

val region = Region.of(instance.region)

val sqsClient = SqsClient.builder()
.endpointOverride(instance.getEndpointOverride(Service.SQS))
.region(region)
.credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
.build()

val snsClient = SnsClient.builder()
.endpointOverride(instance.getEndpointOverride(Service.SNS))
.region(region)
.credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
.build()

createQueues(sqsClient)
createTopics(snsClient)
subscribeToTopics(snsClient, sqsClient)

TestPropertyValues.of(
"spring.cloud.aws.endpoint=${instance.endpoint}",
"spring.cloud.aws.credentials.access-key=${instance.accessKey}",
"spring.cloud.aws.credentials.secret-key=${instance.secretKey}",
"spring.cloud.aws.region.static=${instance.region}",
"sns.topics.response-payment=${getTopicArn(snsClient, "payment-response_topic")}",
).applyTo(configurableApplicationContext)
}

private fun createQueues(sqsClient: SqsClient) {
val queues = listOf("request-payment_queue", "payment-response_queue")

queues.forEach { queue ->
val dlqName = "${queue}_dlq"
sqsClient.createQueue(CreateQueueRequest.builder().queueName(dlqName).build())
println("DLQ queue [$dlqName] created")

val dlqArn = getQueueArn(sqsClient, dlqName)

val redrivePolicy = """{"deadLetterTargetArn":"$dlqArn","maxReceiveCount":"3"}"""

sqsClient.createQueue(
CreateQueueRequest.builder()
.queueName(queue)
.attributes(
mapOf(
QueueAttributeName.DELAY_SECONDS to "5",
QueueAttributeName.REDRIVE_POLICY to redrivePolicy
)
)
.build()
)
println("Queue [$queue] created")
}
}

private fun createTopics(snsClient: SnsClient) {
val topics = listOf("request-payment_topic", "payment-response_topic")

topics.forEach { topic ->
snsClient.createTopic(CreateTopicRequest.builder().name(topic).build())
println("Topic [$topic] created")
}
}

private fun getQueueArn(sqsClient: SqsClient, queueName: String) =
sqsClient.getQueueAttributes(
GetQueueAttributesRequest.builder()
.queueUrl(sqsClient.getQueueUrl { it.queueName(queueName) }.queueUrl())
.attributeNames(QueueAttributeName.QUEUE_ARN)
.build()
).attributes()[QueueAttributeName.QUEUE_ARN]

private fun getTopicArn(snsClient: SnsClient, topicName: String) =
snsClient.createTopic { it.name(topicName) }.topicArn()

private fun subscribeToTopics(snsClient: SnsClient, sqsClient: SqsClient) {
val subscriptions = listOf(
Pair("request-payment_topic", "request-payment_queue"),
Pair("payment-response_topic", "payment-response_queue")
)

subscriptions.forEach { (topicName, queueName) ->
val topicArn = getTopicArn(snsClient, topicName)
val queueArn = getQueueArn(sqsClient, queueName)

snsClient.subscribe(
SubscribeRequest.builder()
.topicArn(topicArn)
.protocol("sqs")
.endpoint(queueArn)
.attributes(mapOf("RawMessageDelivery" to "true"))
.build()
)
println("Queue [$queueName] subscribed to Topic [$topicName]")
}
}
}
8 changes: 4 additions & 4 deletions terraform/secrets.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ module "secrets_manager" {

# For security reasons, insert values manually after apply
secret_string = jsonencode({
token = null
userId = null
posId = null
webhookBaseUrl = null
token = ""
userId = ""
posId = ""
webhookBaseUrl = ""
})

tags = var.tags
Expand Down

0 comments on commit 4dcd406

Please sign in to comment.