테스트 통합 환경 설정 추가

This commit is contained in:
2026-05-29 15:58:33 +09:00
parent 00316ba013
commit ebfbf7b597
8 changed files with 182 additions and 25 deletions

View File

@@ -75,11 +75,14 @@ dependencies {
// file mimetype check // file mimetype check
implementation("org.apache.tika:tika-core:3.2.0") 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") runtimeOnly("com.mysql:mysql-connector-j")
testRuntimeOnly("com.h2database:h2")
testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-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 { allOpen {

View File

@@ -14,17 +14,24 @@ import java.io.FileInputStream
@Configuration @Configuration
class AndroidPublisherConfig( class AndroidPublisherConfig(
@Value("\${firebase.secret-key-path}") @Value("\${firebase.secret-key-path}")
private val secretKeyPath: String private val secretKeyPath: String,
@Value("\${android-publisher.enabled:true}")
private val enabled: Boolean
) { ) {
@Bean @Bean
fun androidPublisher(): AndroidPublisher { fun androidPublisher(): AndroidPublisher {
val jsonFactory = GsonFactory.getDefaultInstance() val jsonFactory = GsonFactory.getDefaultInstance()
val httpTransport = NetHttpTransport() val httpTransport = NetHttpTransport()
val credential = if (enabled) {
HttpCredentialsAdapter(
GoogleCredentials.fromStream(FileInputStream(secretKeyPath))
.createScoped(listOf(AndroidPublisherScopes.ANDROIDPUBLISHER))
)
} else {
null
}
val credential = GoogleCredentials.fromStream(FileInputStream(secretKeyPath)) return AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
.createScoped(listOf(AndroidPublisherScopes.ANDROIDPUBLISHER))
return AndroidPublisher.Builder(httpTransport, jsonFactory, HttpCredentialsAdapter(credential))
.setApplicationName("소다라이브") .setApplicationName("소다라이브")
.build() .build()
} }

View File

@@ -4,11 +4,13 @@ import com.google.auth.oauth2.GoogleCredentials
import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions import com.google.firebase.FirebaseOptions
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import java.io.FileInputStream import java.io.FileInputStream
import javax.annotation.PostConstruct import javax.annotation.PostConstruct
@Configuration @Configuration
@ConditionalOnProperty(name = ["firebase.enabled"], havingValue = "true", matchIfMissing = true)
class FirebaseConfig( class FirebaseConfig(
@Value("\${firebase.secret-key-path}") @Value("\${firebase.secret-key-path}")
private val secretKeyPath: String private val secretKeyPath: String

View File

@@ -27,15 +27,17 @@ class RedisConfig(
@Value("\${spring.redis.host}") @Value("\${spring.redis.host}")
private val host: String, private val host: String,
@Value("\${spring.redis.port}") @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") @Bean(destroyMethod = "shutdown")
fun redissonClient(): RedissonClient { fun redissonClient(): RedissonClient {
val config = Config() val config = Config()
val scheme = if (sslEnabled) "rediss" else "redis"
config.useSingleServer() config.useSingleServer()
.setAddress("rediss://$host:$port") .setAddress("$scheme://$host:$port")
.setSslEnableEndpointIdentification(true) .setSslEnableEndpointIdentification(sslEnabled)
.setSslTruststore(null)
.setDnsMonitoringInterval(30000) .setDnsMonitoringInterval(30000)
.setConnectionMinimumIdleSize(0) .setConnectionMinimumIdleSize(0)
.setConnectionPoolSize(5) .setConnectionPoolSize(5)
@@ -44,12 +46,14 @@ class RedisConfig(
@Bean @Bean
fun redisConnectionFactory(): RedisConnectionFactory { fun redisConnectionFactory(): RedisConnectionFactory {
val clientConfiguration = LettuceClientConfiguration.builder() val clientConfigurationBuilder = LettuceClientConfiguration.builder()
.useSsl() if (sslEnabled) {
.disablePeerVerification() clientConfigurationBuilder
.build() .useSsl()
.disablePeerVerification()
}
return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfiguration) return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfigurationBuilder.build())
} }
@Bean @Bean

View File

@@ -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<ConfigurableApplicationContext> {
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
}
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.context.ApplicationContextInitializer=\
kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer

View File

@@ -1,3 +1,6 @@
server:
env: test
logging: logging:
level: level:
com: com:
@@ -5,23 +8,72 @@ logging:
util: util:
EC2MetadataUtils: error EC2MetadataUtils: error
weraser:
apiUrl: ""
apiKey: ""
payverse:
host: ""
inboundIp: ""
mid: ""
clientKey: ""
secretKey: ""
usdMid: ""
usdClientKey: ""
usdSecretKey: ""
jpyMid: ""
jpyClientKey: ""
jpySecretKey: ""
bootpay:
applicationId: ""
privateKey: ""
hectoApplicationId: ""
hectoPrivateKey: ""
apple: apple:
iapVerifyUrl: https://buy.itunes.apple.com/verifyReceipt iapVerifyUrl: https://buy.itunes.apple.com/verifyReceipt
iapVerifySandboxUrl: https://sandbox.itunes.apple.com/verifyReceipt iapVerifySandboxUrl: https://sandbox.itunes.apple.com/verifyReceipt
bundleId: ""
serviceId: ""
line:
channelId: ""
agora: agora:
appId: ${AGORA_APP_ID} appId: ""
appCertificate: ${AGORA_APP_CERTIFICATE} appCertificate: ""
firebase:
enabled: false
secretKeyPath: ""
android-publisher:
enabled: false
google:
webClientId: ""
cloud: cloud:
naver:
papagoClientId: ""
papagoClientSecret: ""
aws: aws:
credentials: credentials:
accessKey: ${APP_AWS_ACCESS_KEY} accessKey: ""
secretKey: ${APP_AWS_SECRET_KEY} secretKey: ""
s3: s3:
bucket: ${S3_BUCKET} contentBucket: ""
bucket: ""
contentCloudFront:
host: ""
privateKeyFilePath: ""
keyPairId: ""
cloudFront: cloudFront:
host: ${CLOUD_FRONT_HOST} host: ""
sqs:
generateCouponUrl: ""
region: region:
static: ap-northeast-2 static: ap-northeast-2
stack: stack:
@@ -29,15 +81,24 @@ cloud:
jwt: jwt:
header: Authorization header: Authorization
token-validity-in-seconds: ${JWT_TOKEN_VALIDITY_TIME} token-validity-in-seconds: ${JWT_TOKEN_VALIDITY_TIME:360000000}
secret: ${JWT_SECRET} secret: ${JWT_SECRET:abcdefghijklmnopqrstuvwxyz1234567890}
spring: spring:
redis: redis:
host: localhost 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: jpa:
database: h2
database-platform: kr.co.vividnext.sodalive.support.H2MySqlFunctionDialect
hibernate: hibernate:
ddl-auto: create-drop ddl-auto: create-drop
properties: properties: