1
1
package com .server .domain .event .controller ;
2
2
3
+ import com .fasterxml .jackson .databind .ObjectMapper ;
4
+ import com .server .domain .event .dto .CrawlingEventDto ;
5
+ import com .server .domain .event .dto .CrawlingEventDtoList ;
3
6
import com .server .domain .event .dto .EventDto ;
4
7
import com .server .domain .event .service .EventService ;
5
8
import com .server .global .dto .ApiResponseDto ;
9
+ import com .server .global .etc .HmacUtil ;
10
+ import jakarta .servlet .http .HttpServletRequest ;
11
+ import lombok .RequiredArgsConstructor ;
6
12
import org .junit .jupiter .api .BeforeEach ;
7
13
import org .junit .jupiter .api .DisplayName ;
8
14
import org .junit .jupiter .api .Test ;
9
15
import org .junit .jupiter .api .extension .ExtendWith ;
10
16
import org .mockito .InjectMocks ;
11
17
import org .mockito .Mock ;
12
18
import org .mockito .junit .jupiter .MockitoExtension ;
19
+ import org .springframework .beans .factory .annotation .Value ;
13
20
import org .springframework .http .HttpStatus ;
14
21
import org .springframework .test .web .servlet .MockMvc ;
15
22
import org .springframework .test .web .servlet .setup .MockMvcBuilders ;
16
23
24
+ import java .lang .reflect .Field ;
17
25
import java .time .LocalDate ;
26
+ import java .time .format .DateTimeFormatter ;
18
27
import java .util .ArrayList ;
28
+ import java .util .Arrays ;
19
29
import java .util .List ;
20
30
21
31
import static org .junit .jupiter .api .Assertions .assertEquals ;
22
- import static org .mockito .Mockito .when ;
32
+ import static org .junit .jupiter .api .Assertions .assertThrows ;
33
+ import static org .mockito .ArgumentMatchers .any ;
34
+ import static org .mockito .Mockito .*;
23
35
import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .get ;
24
36
import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .post ;
25
37
import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .status ;
26
38
39
+
27
40
@ ExtendWith (MockitoExtension .class )
28
41
public class EventControllerTest {
29
42
30
43
@ Mock
31
44
private EventService eventService ;
32
45
33
- @ InjectMocks
34
46
private EventController eventController ;
35
47
48
+ private String SECRET_KEY ;
49
+ private ObjectMapper objectMapper ;
50
+
36
51
private MockMvc mockMvc ;
37
52
private List <EventDto > sampleEvents ;
38
53
39
54
@ BeforeEach
40
55
void setUp () {
56
+ objectMapper = new ObjectMapper ();
57
+ SECRET_KEY = "test_secret_key_7a8b9c0d1e2f3g4h5i6j7k8l9m0n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5c6d" ;
58
+
59
+
60
+ eventController = new EventController (eventService , objectMapper );
61
+
62
+
63
+ // @Value("${hmac.secret-key}")를 수동으로 주입
64
+ injectSecretKey (eventController , SECRET_KEY );
65
+
41
66
mockMvc = MockMvcBuilders .standaloneSetup (eventController ).build ();
42
67
68
+
69
+
43
70
sampleEvents = new ArrayList <>();
44
71
sampleEvents .add (EventDto .builder ().ranking (1 ).genre ("콘서트" ).title ("Sample Concert" )
45
72
.place ("Seoul Arena" ).startDate (LocalDate .now ())
@@ -68,20 +95,107 @@ void getEventsSuccessTest() {
68
95
assertEquals (sampleEvents .get (1 ).getGenre (), response .getData ().get (1 ).getGenre ());
69
96
}
70
97
71
- /* @Test
72
- @DisplayName("이벤트 저장하기 성공 테스트")
73
- void saveEventsSuccessTest () throws Exception {
98
+ @ Test
99
+ @ DisplayName ("외부 크롤러에서 이벤트 저장하기 성공 테스트" )
100
+ void saveEventsFromExternalSuccessTest () throws Exception {
74
101
// Given
75
- when(eventService.saveEvents()).thenReturn(sampleEvents);
102
+ CrawlingEventDtoList crawlingEventDtoList = new CrawlingEventDtoList ();
103
+ List <CrawlingEventDto > eventList = new ArrayList <>();
104
+
105
+ // 첫 번째 이벤트
106
+ CrawlingEventDto dto1 = new CrawlingEventDto ();
107
+ dto1 .setRanking (1 );
108
+ dto1 .setGenre ("콘서트" );
109
+ dto1 .setTitle ("Sample Concert" );
110
+ dto1 .setPlace ("Seoul Arena" );
111
+ dto1 .setDate (LocalDate .now ().format (DateTimeFormatter .ofPattern ("yyyy.M.d" )) + " ~ " +
112
+ LocalDate .now ().plusDays (30 ).format (DateTimeFormatter .ofPattern ("yyyy.M.d" )));
113
+ dto1 .setImage ("http://example.com/image.jpg" );
114
+
115
+ // 두 번째 이벤트
116
+ CrawlingEventDto dto2 = new CrawlingEventDto ();
117
+ dto2 .setRanking (2 );
118
+ dto2 .setGenre ("뮤지컬" );
119
+ dto2 .setTitle ("Sample Musical" );
120
+ dto2 .setPlace ("LG Arts Center" );
121
+ dto2 .setDate (LocalDate .now ().format (DateTimeFormatter .ofPattern ("yyyy.M.d" )) + " ~ " +
122
+ LocalDate .now ().plusDays (60 ).format (DateTimeFormatter .ofPattern ("yyyy.M.d" )));
123
+ dto2 .setImage ("http://example.com/musical.jpg" );
124
+
125
+ eventList .add (dto1 );
126
+ eventList .add (dto2 );
127
+ crawlingEventDtoList .setEvents (eventList );
128
+
129
+ // 요청 본문 JSON 문자열로 직렬화
130
+ String requestBody = objectMapper .writeValueAsString (crawlingEventDtoList );
131
+
132
+ // HMAC 서명 생성
133
+ String signature = HmacUtil .hmacSha256 (requestBody , SECRET_KEY );
134
+
135
+ // Mock HttpServletRequest 설정
136
+ HttpServletRequest mockRequest = mock (HttpServletRequest .class );
137
+ when (mockRequest .getHeader ("X-Signature" )).thenReturn (signature );
138
+
139
+ // EventService의 saveEvents 메서드 모킹
140
+ when (eventService .saveEvents (any (CrawlingEventDtoList .class ))).thenReturn (sampleEvents );
76
141
77
142
// When
78
- ApiResponseDto<List<EventDto>> response = eventController.saveEvents( );
143
+ ApiResponseDto <List <EventDto >> response = eventController .saveEventsFromExternal ( mockRequest , crawlingEventDtoList );
79
144
80
145
// Then
81
146
assertEquals (HttpStatus .OK .value (), response .getStatus ());
82
147
assertEquals (sampleEvents .size (), response .getData ().size ());
83
148
assertEquals (sampleEvents .get (0 ).getTitle (), response .getData ().get (0 ).getTitle ());
84
- }*/
149
+ assertEquals (sampleEvents .get (1 ).getTitle (), response .getData ().get (1 ).getTitle ());
150
+
151
+ // EventService의 saveEvents 메서드가 호출되었는지 확인
152
+ verify (eventService ).saveEvents (any (CrawlingEventDtoList .class ));
153
+
154
+ // 헤더에서 시그니처를 가져왔는지 확인
155
+ verify (mockRequest ).getHeader ("X-Signature" );
156
+ }
157
+
158
+
159
+ @ Test
160
+ @ DisplayName ("외부 크롤러에서 이벤트 저장 시 HMAC 검증 실패 테스트" )
161
+ void saveEventsFromExternalHmacFailureTest () throws Exception {
162
+ // Given
163
+ CrawlingEventDtoList crawlingEventDtoList = new CrawlingEventDtoList ();
164
+ List <CrawlingEventDto > eventList = new ArrayList <>();
165
+
166
+ CrawlingEventDto dto = new CrawlingEventDto ();
167
+ dto .setRanking (1 );
168
+ dto .setGenre ("콘서트" );
169
+ dto .setTitle ("Sample Concert" );
170
+ dto .setPlace ("Seoul Arena" );
171
+ dto .setDate (LocalDate .now ().format (DateTimeFormatter .ofPattern ("yyyy.M.d" )) + " ~ " +
172
+ LocalDate .now ().plusDays (30 ).format (DateTimeFormatter .ofPattern ("yyyy.M.d" )));
173
+ dto .setImage ("http://example.com/image.jpg" );
174
+
175
+ eventList .add (dto );
176
+ crawlingEventDtoList .setEvents (eventList );
177
+
178
+ // 요청 본문 JSON 문자열로 직렬화
179
+ String requestBody = objectMapper .writeValueAsString (crawlingEventDtoList );
180
+
181
+ // 잘못된 서명 설정
182
+ String invalidSignature = "invalid_signature" ;
183
+
184
+ // Mock HttpServletRequest 설정
185
+ HttpServletRequest mockRequest = mock (HttpServletRequest .class );
186
+ when (mockRequest .getHeader ("X-Signature" )).thenReturn (invalidSignature );
187
+ when (mockRequest .getRequestURI ()).thenReturn ("/api/events/external" );
188
+
189
+ // When & Then
190
+ assertThrows (Exception .class , () -> {
191
+ eventController .saveEventsFromExternal (mockRequest , crawlingEventDtoList );
192
+ });
193
+
194
+ // EventService의 saveEvents 메서드가 호출되지 않았는지 확인
195
+ verify (eventService , never ()).saveEvents (any (CrawlingEventDtoList .class ));
196
+
197
+ }
198
+
85
199
86
200
@ Test
87
201
@ DisplayName ("이벤트 API 엔드포인트 GET 접근 테스트" )
@@ -93,13 +207,61 @@ void getEventsEndpointTest() throws Exception {
93
207
mockMvc .perform (get ("/api/events" )).andExpect (status ().isOk ());
94
208
}
95
209
96
- /* @Test
210
+ @ Test
97
211
@ DisplayName ("이벤트 API 엔드포인트 POST 접근 테스트" )
98
212
void saveEventsEndpointTest () throws Exception {
99
213
// Given
100
- when(eventService.saveEvents()).thenReturn(sampleEvents);
214
+ CrawlingEventDtoList crawlingEventDtoList = new CrawlingEventDtoList ();
215
+ CrawlingEventDto event1 = new CrawlingEventDto ();
216
+ event1 .setRanking (1 );
217
+ event1 .setGenre ("콘서트" );
218
+ event1 .setTitle ("Sample Concert" );
219
+ event1 .setPlace ("Seoul Arena" );
220
+ event1 .setDate ("2025.05.11 ~ 2025.06.11" );
221
+ event1 .setImage ("http://example.com/image.jpg" );
222
+
223
+ CrawlingEventDto event2 = new CrawlingEventDto ();
224
+ event2 .setRanking (2 );
225
+ event2 .setGenre ("뮤지컬" );
226
+ event2 .setTitle ("Sample Musical" );
227
+ event2 .setPlace ("LG Arts Center" );
228
+ event2 .setDate ("2025.05.11 ~ 2025.07.11" );
229
+ event2 .setImage ("http://example.com/musical.jpg" );
230
+
231
+ List <CrawlingEventDto > eventList = Arrays .asList (event1 , event2 );
232
+ crawlingEventDtoList .setEvents (eventList );
233
+
234
+ // 요청 본문 JSON 문자열로 직렬화
235
+ String requestBody = objectMapper .writeValueAsString (crawlingEventDtoList );
236
+
237
+ // HMAC 서명 생성
238
+ String signature = HmacUtil .hmacSha256 (requestBody , SECRET_KEY );
239
+
240
+ // Mock HttpServletRequest 설정
241
+ HttpServletRequest mockRequest = mock (HttpServletRequest .class );
242
+ lenient ().when (mockRequest .getHeader ("X-Signature" )).thenReturn (signature );
243
+
244
+ // EventService의 saveEvents 메서드 모킹
245
+ when (eventService .saveEvents (any (CrawlingEventDtoList .class ))).thenReturn (sampleEvents );
101
246
102
247
// When & Then
103
- mockMvc.perform(post("/api/events")).andExpect(status().isOk());
104
- }*/
248
+ mockMvc .perform (post ("/api/events/external" )
249
+ .contentType ("application/json" )
250
+ .content (requestBody )
251
+ .header ("X-Signature" , signature ))
252
+ .andExpect (status ().isOk ()); // 응답 상태가 200인지 확인
253
+ }
254
+
255
+
256
+
257
+ private void injectSecretKey (EventController controller , String secretKey ) {
258
+ try {
259
+ Field field = EventController .class .getDeclaredField ("SECRET_KEY" );
260
+ field .setAccessible (true );
261
+ field .set (controller , secretKey );
262
+ } catch (Exception e ) {
263
+ throw new RuntimeException ("Failed to inject secret key into controller" , e );
264
+ }
265
+ }
266
+
105
267
}
0 commit comments