Skip to content

Commit d27b409

Browse files
authored
Merge pull request #165 from Industry-Academic-SW-Capstone/feat/#164
[Test] 테스트 컨테이너 설정 및 동시성 제어 테스트
2 parents 73e3c2c + 09587b1 commit d27b409

File tree

9 files changed

+619
-8
lines changed

9 files changed

+619
-8
lines changed

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ dependencies {
6464
testImplementation 'org.springframework.boot:spring-boot-starter-test'
6565
testImplementation 'org.springframework.security:spring-security-test'
6666
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
67+
68+
// Testcontainers
69+
testImplementation platform('org.testcontainers:testcontainers-bom:1.19.8')
70+
testImplementation 'org.testcontainers:testcontainers'
71+
testImplementation 'org.testcontainers:junit-jupiter'
72+
testImplementation 'org.testcontainers:postgresql'
6773

6874
// WebClient
6975
implementation 'org.springframework.boot:spring-boot-starter-webflux'

src/main/java/grit/stockIt/domain/notification/controller/TestNotificationController.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@
1717
@RestController
1818
@RequestMapping("/api/test/notifications")
1919
@Tag(name = "test-notifications", description = "알림 테스트 API (개발용)")
20-
@RequiredArgsConstructor
2120
public class TestNotificationController {
2221

2322
private final FcmService fcmService;
2423
private final MemberRepository memberRepository;
2524

25+
public TestNotificationController(
26+
@org.springframework.beans.factory.annotation.Autowired(required = false) FcmService fcmService,
27+
MemberRepository memberRepository) {
28+
this.fcmService = fcmService;
29+
this.memberRepository = memberRepository;
30+
}
31+
2632
@Operation(
2733
summary = "테스트 or 관리자 전용 알림 전송"
2834
)
@@ -56,6 +62,14 @@ public ResponseEntity<Map<String, Object>> sendTestNotification(
5662
data.put("timestamp", String.valueOf(System.currentTimeMillis()));
5763

5864
// FCM 푸시 알림 전송
65+
if (fcmService == null) {
66+
Map<String, Object> response = new HashMap<>();
67+
response.put("success", false);
68+
response.put("message", "FCM 서비스를 사용할 수 없습니다.");
69+
response.put("memberId", memberId);
70+
return ResponseEntity.badRequest().body(response);
71+
}
72+
5973
boolean success = fcmService.sendExecutionNotification(member.getFcmToken(), data);
6074

6175
// 응답

src/main/java/grit/stockIt/domain/notification/service/AdminNotificationService.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,21 @@
1919

2020
@Slf4j
2121
@Service
22-
@RequiredArgsConstructor
2322
public class AdminNotificationService {
2423

2524
private final FcmService fcmService;
2625
private final NotificationRepository notificationRepository;
2726
private final ObjectMapper objectMapper;
2827

28+
public AdminNotificationService(
29+
@org.springframework.beans.factory.annotation.Autowired(required = false) FcmService fcmService,
30+
NotificationRepository notificationRepository,
31+
ObjectMapper objectMapper) {
32+
this.fcmService = fcmService;
33+
this.notificationRepository = notificationRepository;
34+
this.objectMapper = objectMapper;
35+
}
36+
2937
// 모든 회원에게 알림을 전송
3038
@Async
3139
@Transactional
@@ -61,7 +69,7 @@ public CompletableFuture<BroadcastResult> sendBroadcastNotification(
6169
savedCount++;
6270

6371
// FCM 푸시 알림 전송 (토큰이 있는 경우만)
64-
if (member.hasFcmToken()) {
72+
if (member.hasFcmToken() && fcmService != null) {
6573
// executionNotificationEnabled 체크 안 함
6674
boolean success = fcmService.sendExecutionNotification(
6775
member.getFcmToken(),

src/main/java/grit/stockIt/domain/notification/service/FcmService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.google.firebase.messaging.WebpushFcmOptions;
99
import lombok.RequiredArgsConstructor;
1010
import lombok.extern.slf4j.Slf4j;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
1112
import org.springframework.stereotype.Service;
1213

1314
import java.util.Map;
@@ -16,7 +17,7 @@
1617
// FirebaseMessaging Bean이 있을 때만 활성화됨
1718
@Slf4j
1819
@Service
19-
@org.springframework.context.annotation.DependsOn("firebaseMessaging")
20+
@ConditionalOnBean(FirebaseMessaging.class)
2021
@RequiredArgsConstructor
2122
public class FcmService {
2223

src/main/java/grit/stockIt/domain/ranking/service/RankingService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import lombok.extern.slf4j.Slf4j;
1919
import org.springframework.cache.annotation.CacheEvict;
2020
import org.springframework.cache.annotation.Cacheable;
21+
import org.springframework.core.env.Environment;
2122
import org.springframework.scheduling.annotation.Scheduled;
2223
import org.springframework.stereotype.Service;
2324
import org.springframework.transaction.annotation.Transactional;
@@ -47,6 +48,7 @@ public class RankingService {
4748
private final MissionService missionService;
4849
private final RedisMarketDataRepository redisMarketDataRepository;
4950
private final StockDetailService stockDetailService;
51+
private final Environment environment;
5052

5153
// Rate Limiter: KIS API 초당 30개 제한 (안전하게 25개로 설정)
5254
private final RateLimiter kisApiRateLimiter = RateLimiter.create(25.0);
@@ -62,6 +64,12 @@ public class RankingService {
6264
@CacheEvict(value = "rankings", allEntries = true)
6365
@Transactional
6466
public void updateAllRankings() {
67+
// 테스트 환경에서는 스케줄러 비활성화
68+
String schedulingEnabled = environment.getProperty("spring.task.scheduling.enabled", "true");
69+
if ("false".equals(schedulingEnabled)) {
70+
return;
71+
}
72+
6573
log.info("🔄 [스케줄러] 랭킹 갱신 시작: {}", LocalDateTime.now());
6674

6775
try {

src/main/java/grit/stockIt/global/config/FlywayConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import jakarta.annotation.PostConstruct;
44
import org.flywaydb.core.Flyway;
55
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
67
import org.springframework.context.annotation.Configuration;
78

89
import javax.sql.DataSource;
910

1011
@Configuration
12+
@ConditionalOnProperty(name = "spring.flyway.enabled", havingValue = "true", matchIfMissing = true)
1113
public class FlywayConfig {
1214

1315
@Autowired

0 commit comments

Comments
 (0)