mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 07:09:09 +00:00
STT 테스트 환경 구성 및 유저스토리 업데이트
- docker-compose.test.yml 추가: 테스트용 컨테이너 환경 구성 - STT 테스트 설정 및 컨트롤러 테스트 코드 추가 - application.yml 업데이트 - 테스트 스크립트 추가 - 유저스토리 문서 업데이트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,9 @@ spring:
|
||||
|
||||
# Database Configuration
|
||||
datasource:
|
||||
url: jdbc:${DB_KIND:postgresql}://${DB_HOST:4.230.65.89}:${DB_PORT:5432}/${DB_NAME:sttdb}
|
||||
username: ${DB_USERNAME:hgzerouser}
|
||||
password: ${DB_PASSWORD:Hi5Jessica!}
|
||||
url: jdbc:${DB_KIND:postgresql}://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:sttdb}
|
||||
username: ${DB_USERNAME:stt_user}
|
||||
password: ${DB_PASSWORD:}
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 20
|
||||
@@ -30,9 +30,9 @@ spring:
|
||||
# Redis Configuration
|
||||
data:
|
||||
redis:
|
||||
host: ${REDIS_HOST:20.249.177.114}
|
||||
host: ${REDIS_HOST:localhost}
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: ${REDIS_PASSWORD:Hi5Jessica!}
|
||||
password: ${REDIS_PASSWORD:}
|
||||
timeout: 2000ms
|
||||
lettuce:
|
||||
pool:
|
||||
@@ -40,7 +40,7 @@ spring:
|
||||
max-idle: 8
|
||||
min-idle: 0
|
||||
max-wait: -1ms
|
||||
database: ${REDIS_DATABASE:2}
|
||||
database: ${REDIS_DATABASE:3}
|
||||
|
||||
# Server Configuration
|
||||
server:
|
||||
@@ -48,9 +48,9 @@ server:
|
||||
|
||||
# JWT Configuration
|
||||
jwt:
|
||||
secret: ${JWT_SECRET:}
|
||||
access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:3600}
|
||||
refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:604800}
|
||||
secret: ${JWT_SECRET:HGZero_Secret_Key_For_Development_Only}
|
||||
access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:1800}
|
||||
refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:86400}
|
||||
|
||||
# CORS Configuration
|
||||
cors:
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.unicorn.hgzero.stt.config;
|
||||
|
||||
import com.unicorn.hgzero.stt.event.publisher.EventPublisher;
|
||||
import com.unicorn.hgzero.stt.repository.jpa.RecordingRepository;
|
||||
import com.unicorn.hgzero.stt.repository.jpa.SpeakerRepository;
|
||||
import com.unicorn.hgzero.stt.repository.jpa.TranscriptionRepository;
|
||||
import com.unicorn.hgzero.stt.repository.jpa.TranscriptSegmentRepository;
|
||||
import com.unicorn.hgzero.stt.service.RecordingService;
|
||||
import com.unicorn.hgzero.stt.service.SpeakerService;
|
||||
import com.unicorn.hgzero.stt.service.TranscriptionService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* 테스트용 설정 클래스
|
||||
* Embedded Redis 서버와 Mock Bean들을 제공
|
||||
*/
|
||||
@TestConfiguration
|
||||
@EnableJpaRepositories(basePackages = "com.unicorn.hgzero.stt.repository.jpa")
|
||||
@EntityScan(basePackages = "com.unicorn.hgzero.stt.repository.entity")
|
||||
@ComponentScan(basePackages = {"com.unicorn.hgzero.stt.service", "com.unicorn.hgzero.stt.config"})
|
||||
public class TestConfig {
|
||||
|
||||
private RedisServer redisServer;
|
||||
|
||||
@PostConstruct
|
||||
public void startRedis() {
|
||||
try {
|
||||
redisServer = new RedisServer(6370);
|
||||
redisServer.start();
|
||||
} catch (Exception e) {
|
||||
// Redis 서버 시작 실패 시 로그만 남기고 계속 진행
|
||||
System.err.println("Failed to start embedded Redis server: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stopRedis() {
|
||||
if (redisServer != null && redisServer.isActive()) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public EventPublisher eventPublisher() {
|
||||
return mock(EventPublisher.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
// Embedded Redis에 연결하는 실제 ConnectionFactory
|
||||
return new LettuceConnectionFactory("localhost", 6370);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.unicorn.hgzero.stt.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
|
||||
/**
|
||||
* WebMvcTest용 최소한의 설정 클래스
|
||||
* Repository는 MockBean으로 별도 처리
|
||||
*/
|
||||
@TestConfiguration
|
||||
@ComponentScan(basePackages = "com.unicorn.hgzero.stt.config")
|
||||
public class WebMvcTestConfig {
|
||||
|
||||
private RedisServer redisServer;
|
||||
|
||||
@PostConstruct
|
||||
public void startRedis() {
|
||||
try {
|
||||
redisServer = new RedisServer(6371); // 다른 포트 사용
|
||||
redisServer.start();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to start embedded Redis server: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stopRedis() {
|
||||
if (redisServer != null && redisServer.isActive()) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
return new LettuceConnectionFactory("localhost", 6371);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.unicorn.hgzero.stt.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.hgzero.stt.dto.RecordingDto;
|
||||
import com.unicorn.hgzero.stt.service.RecordingService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
/**
|
||||
* 간단한 녹음 컨트롤러 테스트
|
||||
*/
|
||||
@WebMvcTest(RecordingController.class)
|
||||
@DisplayName("간단한 녹음 컨트롤러 테스트")
|
||||
class SimpleRecordingControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@MockBean
|
||||
private RecordingService recordingService;
|
||||
|
||||
private RecordingDto.PrepareRequest prepareRequest;
|
||||
private RecordingDto.PrepareResponse prepareResponse;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
prepareRequest = RecordingDto.PrepareRequest.builder()
|
||||
.meetingId("MEETING-001")
|
||||
.sessionId("SESSION-001")
|
||||
.language("ko-KR")
|
||||
.build();
|
||||
|
||||
prepareResponse = RecordingDto.PrepareResponse.builder()
|
||||
.recordingId("REC-20250123-001")
|
||||
.sessionId("SESSION-001")
|
||||
.status("READY")
|
||||
.streamUrl("wss://api.example.com/stt/v1/ws/stt/SESSION-001")
|
||||
.storagePath("recordings/MEETING-001/SESSION-001.wav")
|
||||
.estimatedInitTime(1100)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("녹음 준비 API 성공")
|
||||
void prepareRecording_Success() throws Exception {
|
||||
// Given
|
||||
when(recordingService.prepareRecording(any(RecordingDto.PrepareRequest.class)))
|
||||
.thenReturn(prepareResponse);
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(post("/api/v1/stt/recordings/prepare")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(prepareRequest)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.data.recordingId").value("REC-20250123-001"))
|
||||
.andExpect(jsonPath("$.data.sessionId").value("SESSION-001"))
|
||||
.andExpect(jsonPath("$.data.status").value("READY"));
|
||||
|
||||
verify(recordingService).prepareRecording(any(RecordingDto.PrepareRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("녹음 시작 API 성공")
|
||||
void startRecording_Success() throws Exception {
|
||||
// Given
|
||||
String recordingId = "REC-20250123-001";
|
||||
RecordingDto.StartRequest startRequest = RecordingDto.StartRequest.builder()
|
||||
.startedBy("user001")
|
||||
.build();
|
||||
|
||||
RecordingDto.StatusResponse statusResponse = RecordingDto.StatusResponse.builder()
|
||||
.recordingId(recordingId)
|
||||
.status("RECORDING")
|
||||
.startTime(LocalDateTime.now())
|
||||
.duration(0)
|
||||
.build();
|
||||
|
||||
when(recordingService.startRecording(eq(recordingId), any(RecordingDto.StartRequest.class)))
|
||||
.thenReturn(statusResponse);
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(post("/api/v1/stt/recordings/{recordingId}/start", recordingId)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(startRequest)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.data.recordingId").value(recordingId))
|
||||
.andExpect(jsonPath("$.data.status").value("RECORDING"));
|
||||
|
||||
verify(recordingService).startRecording(eq(recordingId), any(RecordingDto.StartRequest.class));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user