diff --git a/build.gradle.kts b/build.gradle.kts index 37cdf45a..8a0cd146 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,11 +75,14 @@ dependencies { // file mimetype check implementation("org.apache.tika:tika-core:3.2.0") - developmentOnly("org.springframework.boot:spring-boot-devtools") - runtimeOnly("com.h2database:h2") runtimeOnly("com.mysql:mysql-connector-j") + + testRuntimeOnly("com.h2database:h2") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") + testImplementation("com.github.codemonstur:embedded-redis:1.4.3") + + developmentOnly("org.springframework.boot:spring-boot-devtools") } allOpen { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/AndroidPublisherConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/AndroidPublisherConfig.kt index 8dada68c..b33a9167 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/AndroidPublisherConfig.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/AndroidPublisherConfig.kt @@ -14,17 +14,24 @@ import java.io.FileInputStream @Configuration class AndroidPublisherConfig( @Value("\${firebase.secret-key-path}") - private val secretKeyPath: String + private val secretKeyPath: String, + @Value("\${android-publisher.enabled:true}") + private val enabled: Boolean ) { @Bean fun androidPublisher(): AndroidPublisher { val jsonFactory = GsonFactory.getDefaultInstance() val httpTransport = NetHttpTransport() + val credential = if (enabled) { + HttpCredentialsAdapter( + GoogleCredentials.fromStream(FileInputStream(secretKeyPath)) + .createScoped(listOf(AndroidPublisherScopes.ANDROIDPUBLISHER)) + ) + } else { + null + } - val credential = GoogleCredentials.fromStream(FileInputStream(secretKeyPath)) - .createScoped(listOf(AndroidPublisherScopes.ANDROIDPUBLISHER)) - - return AndroidPublisher.Builder(httpTransport, jsonFactory, HttpCredentialsAdapter(credential)) + return AndroidPublisher.Builder(httpTransport, jsonFactory, credential) .setApplicationName("소다라이브") .build() } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/FirebaseConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/FirebaseConfig.kt index abf31328..c9961020 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/FirebaseConfig.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/FirebaseConfig.kt @@ -4,11 +4,13 @@ import com.google.auth.oauth2.GoogleCredentials import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Configuration import java.io.FileInputStream import javax.annotation.PostConstruct @Configuration +@ConditionalOnProperty(name = ["firebase.enabled"], havingValue = "true", matchIfMissing = true) class FirebaseConfig( @Value("\${firebase.secret-key-path}") private val secretKeyPath: String diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt index eea5eabb..d6ec21a6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/RedisConfig.kt @@ -27,15 +27,17 @@ class RedisConfig( @Value("\${spring.redis.host}") private val host: String, @Value("\${spring.redis.port}") - private val port: Int + private val port: Int, + @Value("\${spring.redis.ssl-enabled:true}") + private val sslEnabled: Boolean ) { @Bean(destroyMethod = "shutdown") fun redissonClient(): RedissonClient { val config = Config() + val scheme = if (sslEnabled) "rediss" else "redis" config.useSingleServer() - .setAddress("rediss://$host:$port") - .setSslEnableEndpointIdentification(true) - .setSslTruststore(null) + .setAddress("$scheme://$host:$port") + .setSslEnableEndpointIdentification(sslEnabled) .setDnsMonitoringInterval(30000) .setConnectionMinimumIdleSize(0) .setConnectionPoolSize(5) @@ -44,12 +46,14 @@ class RedisConfig( @Bean fun redisConnectionFactory(): RedisConnectionFactory { - val clientConfiguration = LettuceClientConfiguration.builder() - .useSsl() - .disablePeerVerification() - .build() + val clientConfigurationBuilder = LettuceClientConfiguration.builder() + if (sslEnabled) { + clientConfigurationBuilder + .useSsl() + .disablePeerVerification() + } - return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfiguration) + return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfigurationBuilder.build()) } @Bean diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/support/EmbeddedRedisInitializer.kt b/src/test/kotlin/kr/co/vividnext/sodalive/support/EmbeddedRedisInitializer.kt new file mode 100644 index 00000000..22c17661 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/support/EmbeddedRedisInitializer.kt @@ -0,0 +1,47 @@ +package kr.co.vividnext.sodalive.support + +import org.springframework.context.ApplicationContextInitializer +import org.springframework.context.ConfigurableApplicationContext +import redis.embedded.RedisServer + +class EmbeddedRedisInitializer : ApplicationContextInitializer { + override fun initialize(applicationContext: ConfigurableApplicationContext) { + EmbeddedRedisHolder.start() + } +} + +private object EmbeddedRedisHolder { + private const val PORT = 16379 + private var redisServer: RedisServer? = null + private var shutdownHookRegistered = false + + @Synchronized + fun start() { + if (redisServer != null) { + return + } + + redisServer = RedisServer.newRedisServer() + .port(PORT) + .setting("bind 127.0.0.1") + .setting("daemonize no") + .setting("appendonly no") + .build() + .also { it.start() } + + if (!shutdownHookRegistered) { + Runtime.getRuntime().addShutdownHook( + Thread { + stop() + } + ) + shutdownHookRegistered = true + } + } + + @Synchronized + fun stop() { + redisServer?.stop() + redisServer = null + } +} diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/support/SpringBootIntegrationSampleTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/support/SpringBootIntegrationSampleTest.kt new file mode 100644 index 00000000..0cf4ad10 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/support/SpringBootIntegrationSampleTest.kt @@ -0,0 +1,31 @@ +package kr.co.vividnext.sodalive.support + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.redis.core.StringRedisTemplate +import javax.persistence.EntityManager + +@SpringBootTest +class SpringBootIntegrationSampleTest { + @Autowired + private lateinit var entityManager: EntityManager + + @Autowired + private lateinit var stringRedisTemplate: StringRedisTemplate + + @Test + fun shouldUseH2AndRedisInSpringBootIntegrationTest() { + val databaseResult = entityManager + .createNativeQuery("select 1") + .singleResult + + val redisKey = "test:integration-sample" + stringRedisTemplate.opsForValue().set(redisKey, "ok") + val redisResult = stringRedisTemplate.opsForValue().get(redisKey) + + assertEquals(1, (databaseResult as Number).toInt()) + assertEquals("ok", redisResult) + } +} diff --git a/src/test/resources/META-INF/spring.factories b/src/test/resources/META-INF/spring.factories new file mode 100644 index 00000000..6e462409 --- /dev/null +++ b/src/test/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.context.ApplicationContextInitializer=\ +kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index a4d9db8d..d646aa87 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -1,3 +1,6 @@ +server: + env: test + logging: level: com: @@ -5,23 +8,72 @@ logging: util: EC2MetadataUtils: error +weraser: + apiUrl: "" + apiKey: "" + +payverse: + host: "" + inboundIp: "" + mid: "" + clientKey: "" + secretKey: "" + usdMid: "" + usdClientKey: "" + usdSecretKey: "" + jpyMid: "" + jpyClientKey: "" + jpySecretKey: "" + +bootpay: + applicationId: "" + privateKey: "" + hectoApplicationId: "" + hectoPrivateKey: "" + apple: iapVerifyUrl: https://buy.itunes.apple.com/verifyReceipt iapVerifySandboxUrl: https://sandbox.itunes.apple.com/verifyReceipt + bundleId: "" + serviceId: "" + +line: + channelId: "" agora: - appId: ${AGORA_APP_ID} - appCertificate: ${AGORA_APP_CERTIFICATE} + appId: "" + appCertificate: "" + +firebase: + enabled: false + secretKeyPath: "" + +android-publisher: + enabled: false + +google: + webClientId: "" cloud: + naver: + papagoClientId: "" + papagoClientSecret: "" + aws: credentials: - accessKey: ${APP_AWS_ACCESS_KEY} - secretKey: ${APP_AWS_SECRET_KEY} + accessKey: "" + secretKey: "" s3: - bucket: ${S3_BUCKET} + contentBucket: "" + bucket: "" + contentCloudFront: + host: "" + privateKeyFilePath: "" + keyPairId: "" cloudFront: - host: ${CLOUD_FRONT_HOST} + host: "" + sqs: + generateCouponUrl: "" region: static: ap-northeast-2 stack: @@ -29,15 +81,24 @@ cloud: jwt: header: Authorization - token-validity-in-seconds: ${JWT_TOKEN_VALIDITY_TIME} - secret: ${JWT_SECRET} + token-validity-in-seconds: ${JWT_TOKEN_VALIDITY_TIME:360000000} + secret: ${JWT_SECRET:abcdefghijklmnopqrstuvwxyz1234567890} spring: redis: host: localhost - port: 6379 + port: 16379 + ssl-enabled: false + + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:sodalive-test;MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: sa + password: jpa: + database: h2 + database-platform: kr.co.vividnext.sodalive.support.H2MySqlFunctionDialect hibernate: ddl-auto: create-drop properties: