Skip to content

Commit a8b876b

Browse files
authored
Merge pull request #96 from Central-MakeUs/dev
운영 배포
2 parents b8d87cb + b34819b commit a8b876b

File tree

7 files changed

+111
-187
lines changed

7 files changed

+111
-187
lines changed
Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package server.yakssok.domain.feedback.application.service;
22

33

4-
import java.util.Optional;
54

65
import org.springframework.amqp.rabbit.core.RabbitTemplate;
76
import org.springframework.stereotype.Service;
@@ -11,8 +10,6 @@
1110
import server.yakssok.domain.feedback.domain.entity.Feedback;
1211
import server.yakssok.domain.feedback.domain.repository.FeedbackRepository;
1312
import server.yakssok.domain.feedback.presentation.dto.request.CreateFeedbackRequest;
14-
import server.yakssok.domain.friend.domain.entity.Friend;
15-
import server.yakssok.domain.friend.domain.repository.FriendRepository;
1613
import server.yakssok.domain.notification.presentation.dto.NotificationDTO;
1714
import server.yakssok.domain.user.application.service.UserService;
1815
import server.yakssok.domain.user.domain.entity.User;
@@ -22,7 +19,6 @@
2219
@RequiredArgsConstructor
2320
public class FeedbackService {
2421
private final FeedbackRepository feedbackRepository;
25-
private final FriendRepository friendRepository;
2622
private final UserService userService;
2723
private final RabbitTemplate rabbitTemplate;
2824
private final FeedbackQueueProperties feedbackQueueProperties;
@@ -39,11 +35,7 @@ public void sendFeedback(Long userId, CreateFeedbackRequest request) {
3935
}
4036

4137
private void pushFeedBackNotification(User sender, User receiver, Feedback feedback) {
42-
Optional<Friend> receiverFollowSender = friendRepository.findByUserIdAndFollowingId(receiver.getId(), sender.getId());
43-
44-
NotificationDTO notificationDTO = receiverFollowSender
45-
.map(friend -> createMutualFeedbackNotificationDto(sender, receiver, feedback, friend))
46-
.orElseGet(() -> createOneWayFeedbackNotificationDto(sender, receiver, feedback));
38+
NotificationDTO notificationDTO = createFeedbackNotificationDto(sender, receiver, feedback);
4739
pushFeedBackQueue(notificationDTO);
4840
}
4941

@@ -53,23 +45,12 @@ private void pushFeedBackQueue(NotificationDTO notificationDTO) {
5345
rabbitTemplate.convertAndSend(feedbackExchange, feedbackRoutingKey, notificationDTO);
5446
}
5547

56-
private static NotificationDTO createOneWayFeedbackNotificationDto(User sender, User receiver, Feedback feedback) {
57-
return NotificationDTO.fromOneWayFollowFeedback(
48+
private static NotificationDTO createFeedbackNotificationDto(User sender, User receiver, Feedback feedback) {
49+
return NotificationDTO.fromFeedback(
5850
sender.getId(),
5951
sender.getNickName(),
6052
receiver.getId(),
6153
feedback
6254
);
6355
}
64-
65-
private static NotificationDTO createMutualFeedbackNotificationDto(User sender, User receiver, Feedback feedback,
66-
Friend friend) {
67-
return NotificationDTO.fromMutualFollowFeedback(
68-
sender.getId(),
69-
receiver.getId(),
70-
receiver.getNickName(),
71-
sender.getNickName(),
72-
feedback
73-
);
74-
}
7556
}

yakssok/src/main/java/server/yakssok/domain/medication_schedule/application/service/MedicationScheduleService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,9 @@ public void createTodaySchedules(
104104
public void deleteAllByMedicationIds(List<Long> medicationIds) {
105105
medicationScheduleManager.deleteAllByMedicationIds(medicationIds);
106106
}
107+
108+
public void generateDateSchedules(LocalDate date) {
109+
List<MedicationSchedule> schedules = medicationScheduleGenerator.generateAllTodaySchedules(date.atStartOfDay());
110+
medicationScheduleJdbcRepository.batchInsert(schedules);
111+
}
107112
}

yakssok/src/main/java/server/yakssok/domain/medication_schedule/batch/job/MedicationScheduleJob.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package server.yakssok.domain.medication_schedule.batch.job;
22

3+
import java.time.LocalDate;
4+
35
import org.springframework.stereotype.Component;
46

57
import lombok.RequiredArgsConstructor;
@@ -13,4 +15,8 @@ public class MedicationScheduleJob {
1315
public void runToday() {
1416
medicationScheduleService.generateTodaySchedules();
1517
}
18+
19+
public void runFor(LocalDate parse) {
20+
medicationScheduleService.generateDateSchedules(parse);
21+
}
1622
}

yakssok/src/main/java/server/yakssok/domain/medication_schedule/presentation/controller/MedicationScheduleController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.springframework.security.core.annotation.AuthenticationPrincipal;
88
import org.springframework.web.bind.annotation.GetMapping;
99
import org.springframework.web.bind.annotation.PathVariable;
10+
import org.springframework.web.bind.annotation.PostMapping;
1011
import org.springframework.web.bind.annotation.PutMapping;
1112
import org.springframework.web.bind.annotation.RequestMapping;
1213
import org.springframework.web.bind.annotation.RequestParam;
@@ -17,6 +18,7 @@
1718
import io.swagger.v3.oas.annotations.tags.Tag;
1819
import lombok.RequiredArgsConstructor;
1920
import server.yakssok.domain.medication_schedule.application.service.MedicationScheduleService;
21+
import server.yakssok.domain.medication_schedule.batch.job.MedicationScheduleJob;
2022
import server.yakssok.domain.medication_schedule.presentation.dto.response.MedicationScheduleGroupResponse;
2123
import server.yakssok.global.common.reponse.ApiResponse;
2224
import server.yakssok.global.common.security.YakssokUserDetails;
@@ -30,6 +32,7 @@
3032
@Tag(name = "Medication Schedule", description = "복약 스케줄 API")
3133
public class MedicationScheduleController {
3234
private final MedicationScheduleService medicationScheduleService;
35+
private final MedicationScheduleJob job;
3336

3437
@Operation(summary = "나의 복약 스케줄 조회 (오늘)")
3538
@GetMapping("/today")
@@ -92,4 +95,9 @@ public ApiResponse<MedicationScheduleGroupResponse> findFriendRangeMedicationSch
9295
Long userId = userDetails.getUserId();
9396
return ApiResponse.success(medicationScheduleService.getFriendRangeSchedules(userId, friendId, startDate, endDate));
9497
}
98+
99+
@PostMapping("/backfill/{date}") // yyyy-MM-dd
100+
public void backfill(@PathVariable String date) {
101+
job.runFor(LocalDate.parse(date));
102+
}
95103
}

yakssok/src/main/java/server/yakssok/domain/notification/presentation/dto/NotificationDTO.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,7 @@ public static NotificationDTO fromNotTakenMedicationSchedule(MedicationScheduleA
3434
.build();
3535
}
3636

37-
public static NotificationDTO fromMutualFollowFeedback(
38-
Long senderId,
39-
Long receiverId,
40-
String receiverName,
41-
String relationName,
42-
Feedback feedback
43-
) {
44-
return NotificationDTO.builder()
45-
.senderId(senderId)
46-
.receiverId(receiverId)
47-
.title(NotificationTitleUtils.createFeedbackTitleMutual(feedback.getFeedbackType(), receiverName, relationName))
48-
.body(feedback.getMessage())
49-
.type(feedback.getFeedbackType().toNotificationType())
50-
.build();
51-
}
52-
53-
public static NotificationDTO fromOneWayFollowFeedback(
37+
public static NotificationDTO fromFeedback(
5438
Long senderId,
5539
String senderName,
5640
Long receiverId,

yakssok/src/test/java/server/yakssok/domain/feedback/application/service/FeedbackServiceTest.java

Lines changed: 58 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,18 @@
22

33
import static org.mockito.Mockito.*;
44

5-
import java.util.Optional;
6-
75
import org.junit.jupiter.api.DisplayName;
8-
import org.junit.jupiter.api.Nested;
96
import org.junit.jupiter.api.Test;
107
import org.junit.jupiter.api.extension.ExtendWith;
11-
import org.mockito.*;
12-
import org.mockito.junit.jupiter.MockitoExtension;
8+
import org.mockito.InjectMocks;
9+
import org.mockito.Mock;
1310
import org.mockito.MockedStatic;
11+
import org.mockito.junit.jupiter.MockitoExtension;
1412
import org.springframework.amqp.rabbit.core.RabbitTemplate;
1513

1614
import server.yakssok.domain.feedback.domain.entity.Feedback;
1715
import server.yakssok.domain.feedback.domain.repository.FeedbackRepository;
1816
import server.yakssok.domain.feedback.presentation.dto.request.CreateFeedbackRequest;
19-
import server.yakssok.domain.friend.domain.entity.Friend;
20-
import server.yakssok.domain.friend.domain.repository.FriendRepository;
2117
import server.yakssok.domain.notification.presentation.dto.NotificationDTO;
2218
import server.yakssok.domain.user.application.service.UserService;
2319
import server.yakssok.domain.user.domain.entity.User;
@@ -30,139 +26,67 @@ class FeedbackServiceTest {
3026
private FeedbackService feedbackService;
3127

3228
@Mock private FeedbackRepository feedbackRepository;
33-
@Mock private FriendRepository friendRepository;
3429
@Mock private UserService userService;
3530
@Mock private RabbitTemplate rabbitTemplate;
3631
@Mock private FeedbackQueueProperties feedbackQueueProperties;
3732

3833
@Mock private CreateFeedbackRequest createFeedbackRequest;
3934

40-
@Nested
41-
@DisplayName("sendFeedback")
42-
class SendFeedback {
43-
44-
private final Long SENDER_ID = 10L;
45-
private final Long RECEIVER_ID = 20L;
46-
47-
private User mockSender() {
48-
User u = mock(User.class);
49-
when(u.getId()).thenReturn(SENDER_ID);
50-
return u;
51-
}
52-
53-
private User mockReceiver() {
54-
User u = mock(User.class);
55-
when(u.getId()).thenReturn(RECEIVER_ID);
56-
return u;
57-
}
58-
59-
private void stubCommonQueueProps() {
60-
when(feedbackQueueProperties.exchange()).thenReturn("ex.feedback");
61-
when(feedbackQueueProperties.routingKey()).thenReturn("rk.feedback");
62-
}
63-
64-
@Test
65-
@DisplayName("상대가 나를 팔로우하지 않을 때: OneWay 알림을 만들어 큐에 푸시한다")
66-
void oneWayFollow_pushesOneWayNotification() {
67-
// given
68-
User sender = mockSender();
69-
User receiver = mockReceiver();
70-
Feedback feedback = mock(Feedback.class);
71-
NotificationDTO oneWayDto = mock(NotificationDTO.class);
72-
73-
when(sender.getNickName()).thenReturn("senderNick");
74-
when(createFeedbackRequest.receiverId()).thenReturn(RECEIVER_ID);
75-
when(userService.getActiveUser(SENDER_ID)).thenReturn(sender);
76-
when(userService.getActiveUser(RECEIVER_ID)).thenReturn(receiver);
77-
78-
when(createFeedbackRequest.toFeedback(sender, receiver)).thenReturn(feedback);
79-
when(friendRepository.findByUserIdAndFollowingId(RECEIVER_ID, SENDER_ID))
80-
.thenReturn(Optional.empty());
81-
82-
stubCommonQueueProps();
83-
84-
// NotificationDTO 정적 팩토리 모킹
85-
try (MockedStatic<NotificationDTO> staticMock = mockStatic(NotificationDTO.class)) {
86-
staticMock.when(() ->
87-
NotificationDTO.fromOneWayFollowFeedback(
88-
eq(SENDER_ID),
89-
eq("senderNick"),
90-
eq(RECEIVER_ID),
91-
eq(feedback)))
92-
.thenReturn(oneWayDto);
93-
94-
// when
95-
feedbackService.sendFeedback(SENDER_ID, createFeedbackRequest);
96-
97-
// then
98-
verify(userService).getActiveUser(SENDER_ID);
99-
verify(userService).getActiveUser(RECEIVER_ID);
100-
101-
verify(feedbackRepository).save(feedback);
102-
103-
// 정적 메서드가 호출되었는지 검증
104-
staticMock.verify(() ->
105-
NotificationDTO.fromOneWayFollowFeedback(
106-
SENDER_ID, "senderNick", RECEIVER_ID, feedback));
107-
108-
// 큐 전송 검증
109-
verify(rabbitTemplate).convertAndSend("ex.feedback", "rk.feedback", oneWayDto);
110-
verifyNoMoreInteractions(rabbitTemplate);
111-
}
112-
}
113-
114-
@Test
115-
@DisplayName("상대가 나를 팔로우할 때(맞팔): Mutual 알림을 만들어 큐에 푸시한다")
116-
void mutualFollow_pushesMutualNotification() {
117-
// given
118-
User sender = mockSender();
119-
User receiver = mockReceiver();
120-
Feedback feedback = mock(Feedback.class);
121-
Friend friend = mock(Friend.class);
122-
NotificationDTO mutualDto = mock(NotificationDTO.class);
123-
124-
when(receiver.getNickName()).thenReturn("receiverNick");
125-
when(createFeedbackRequest.receiverId()).thenReturn(RECEIVER_ID);
126-
when(userService.getActiveUser(SENDER_ID)).thenReturn(sender);
127-
when(userService.getActiveUser(RECEIVER_ID)).thenReturn(receiver);
128-
129-
when(createFeedbackRequest.toFeedback(sender, receiver)).thenReturn(feedback);
130-
131-
when(friendRepository.findByUserIdAndFollowingId(RECEIVER_ID, SENDER_ID))
132-
.thenReturn(Optional.of(friend));
133-
when(friend.getRelationName()).thenReturn("bestie");
134-
135-
stubCommonQueueProps();
136-
137-
// NotificationDTO 정적 팩토리 모킹
138-
try (MockedStatic<NotificationDTO> staticMock = mockStatic(NotificationDTO.class)) {
139-
staticMock.when(() ->
140-
NotificationDTO.fromMutualFollowFeedback(
141-
eq(SENDER_ID),
142-
eq(RECEIVER_ID),
143-
eq("receiverNick"),
144-
eq("bestie"),
145-
eq(feedback)))
146-
.thenReturn(mutualDto);
147-
148-
// when
149-
feedbackService.sendFeedback(SENDER_ID, createFeedbackRequest);
150-
151-
// then
152-
verify(userService).getActiveUser(SENDER_ID);
153-
verify(userService).getActiveUser(RECEIVER_ID);
154-
155-
verify(feedbackRepository).save(feedback);
156-
157-
// 정적 메서드 호출 검증
158-
staticMock.verify(() ->
159-
NotificationDTO.fromMutualFollowFeedback(
160-
SENDER_ID, RECEIVER_ID, "receiverNick", "bestie", feedback));
161-
162-
// 큐 전송 검증
163-
verify(rabbitTemplate).convertAndSend("ex.feedback", "rk.feedback", mutualDto);
164-
verifyNoMoreInteractions(rabbitTemplate);
165-
}
35+
@Test
36+
@DisplayName("피드백 전송: Feedback 저장 후 DTO를 만들어 큐에 푸시한다")
37+
void sendFeedback_pushesNotificationToQueue() {
38+
// given
39+
final Long SENDER_ID = 10L;
40+
final Long RECEIVER_ID = 20L;
41+
42+
User sender = mock(User.class);
43+
User receiver = mock(User.class);
44+
Feedback feedback = mock(Feedback.class);
45+
NotificationDTO dto = mock(NotificationDTO.class);
46+
47+
when(sender.getId()).thenReturn(SENDER_ID);
48+
when(sender.getNickName()).thenReturn("senderNick");
49+
when(receiver.getId()).thenReturn(RECEIVER_ID);
50+
51+
when(createFeedbackRequest.receiverId()).thenReturn(RECEIVER_ID);
52+
when(userService.getActiveUser(SENDER_ID)).thenReturn(sender);
53+
when(userService.getActiveUser(RECEIVER_ID)).thenReturn(receiver);
54+
55+
when(createFeedbackRequest.toFeedback(sender, receiver)).thenReturn(feedback);
56+
57+
when(feedbackQueueProperties.exchange()).thenReturn("ex.feedback");
58+
when(feedbackQueueProperties.routingKey()).thenReturn("rk.feedback");
59+
60+
// NotificationDTO 정적 팩토리 모킹
61+
try (MockedStatic<NotificationDTO> staticMock = mockStatic(NotificationDTO.class)) {
62+
staticMock.when(() ->
63+
NotificationDTO.fromFeedback(
64+
eq(SENDER_ID),
65+
eq("senderNick"),
66+
eq(RECEIVER_ID),
67+
eq(feedback)))
68+
.thenReturn(dto);
69+
70+
// when
71+
feedbackService.sendFeedback(SENDER_ID, createFeedbackRequest);
72+
73+
// then
74+
// 유저 조회 및 저장 호출
75+
verify(userService).getActiveUser(SENDER_ID);
76+
verify(userService).getActiveUser(RECEIVER_ID);
77+
verify(feedbackRepository).save(feedback);
78+
79+
// 정적 메서드 호출 검증
80+
staticMock.verify(() ->
81+
NotificationDTO.fromFeedback(SENDER_ID, "senderNick", RECEIVER_ID, feedback));
82+
83+
// 큐 전송 검증
84+
verify(feedbackQueueProperties).exchange();
85+
verify(feedbackQueueProperties).routingKey();
86+
verify(rabbitTemplate).convertAndSend("ex.feedback", "rk.feedback", dto);
87+
88+
// 불필요 상호작용 없음
89+
verifyNoMoreInteractions(rabbitTemplate, feedbackRepository, userService, feedbackQueueProperties);
16690
}
16791
}
16892
}

0 commit comments

Comments
 (0)