feat: 그룹 유량제어 메트릭 API 추가
- GroupMetricDTO: allowed/rejectedPerSecond/rejectedThreshold/rejectRatio 등
- InflowGroupMetricService: DualInflowControlManager를 통한 메트릭 조회·초기화
(getManager() protected 처리 — 단위 테스트 서브클래싱 지원)
- InflowGroupMetricController: 4개 엔드포인트
GET /{groupId}/metric, GET /metric
POST /{groupId}/metric/reset, POST /metric/reset
- 단위 테스트 2종 (Service 16건, Controller 8건) 전체 통과
- elink-online-common 서브모듈 포인터 업데이트
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
package com.eactive.eai.manage.inflow;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* InflowGroupMetricController 단위 테스트.
|
||||
*
|
||||
* <p>Spring MVC를 기동하지 않고 컨트롤러를 직접 인스턴스화하여
|
||||
* 응답 구조(success, data, count, message)를 검증한다.
|
||||
*/
|
||||
class InflowGroupMetricControllerTest {
|
||||
|
||||
private InflowGroupMetricController controller;
|
||||
private InflowGroupMetricService mockService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
controller = new InflowGroupMetricController();
|
||||
mockService = mock(InflowGroupMetricService.class);
|
||||
ReflectionTestUtils.setField(controller, "metricService", mockService);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helper
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private GroupMetricDTO makeDTO(String groupId, String groupName,
|
||||
long allowed, long rejPs, long rejTh) {
|
||||
GroupMetricDTO dto = new GroupMetricDTO();
|
||||
dto.setGroupId(groupId);
|
||||
dto.setGroupName(groupName);
|
||||
dto.setActivate(true);
|
||||
dto.setAllowed(allowed);
|
||||
dto.setRejectedPerSecond(rejPs);
|
||||
dto.setRejectedThreshold(rejTh);
|
||||
long total = allowed + rejPs + rejTh;
|
||||
dto.setTotalRequests(total);
|
||||
dto.setRejectRatio(total > 0 ? (double)(rejPs + rejTh) / total * 100 : 0.0);
|
||||
dto.setLastResetTime(System.currentTimeMillis());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> body(ResponseEntity<?> response) {
|
||||
return (Map<String, Object>) response.getBody();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// GET /{groupId}/metric
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void getGroupMetric_found_successTrueAndDataPresent() {
|
||||
GroupMetricDTO dto = makeDTO("G1", "결제그룹", 900, 60, 40);
|
||||
when(mockService.getGroupMetric("G1")).thenReturn(dto);
|
||||
|
||||
ResponseEntity<?> response = controller.getGroupMetric("G1");
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(200, response.getStatusCodeValue());
|
||||
assertEquals(Boolean.TRUE, body.get("success"));
|
||||
assertSame(dto, body.get("data"));
|
||||
assertFalse(body.containsKey("message"), "성공 응답에 message 필드는 없어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_notFound_successFalseWithMessage() {
|
||||
when(mockService.getGroupMetric("GHOST")).thenReturn(null);
|
||||
|
||||
ResponseEntity<?> response = controller.getGroupMetric("GHOST");
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(200, response.getStatusCodeValue());
|
||||
assertEquals(Boolean.FALSE, body.get("success"));
|
||||
assertTrue(body.get("message").toString().contains("GHOST"),
|
||||
"오류 메시지에 groupId가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// GET /metric
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_returnsListAndCount() {
|
||||
List<GroupMetricDTO> list = Arrays.asList(
|
||||
makeDTO("G1", "그룹1", 100, 5, 0),
|
||||
makeDTO("G2", "그룹2", 200, 0, 10)
|
||||
);
|
||||
when(mockService.getAllGroupMetrics()).thenReturn(list);
|
||||
|
||||
ResponseEntity<?> response = controller.getAllGroupMetrics();
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(Boolean.TRUE, body.get("success"));
|
||||
assertSame(list, body.get("data"));
|
||||
assertEquals(2, body.get("count"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_emptyList_countZero() {
|
||||
when(mockService.getAllGroupMetrics()).thenReturn(Collections.emptyList());
|
||||
|
||||
ResponseEntity<?> response = controller.getAllGroupMetrics();
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(Boolean.TRUE, body.get("success"));
|
||||
assertEquals(0, body.get("count"));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// POST /{groupId}/metric/reset
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void resetGroupMetric_success_successTrueWithGroupId() {
|
||||
when(mockService.resetGroupMetric("G1")).thenReturn(true);
|
||||
|
||||
ResponseEntity<?> response = controller.resetGroupMetric("G1");
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(Boolean.TRUE, body.get("success"));
|
||||
assertTrue(body.get("message").toString().contains("G1"),
|
||||
"성공 메시지에 groupId가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetGroupMetric_notFound_successFalseWithGroupId() {
|
||||
when(mockService.resetGroupMetric("GHOST")).thenReturn(false);
|
||||
|
||||
ResponseEntity<?> response = controller.resetGroupMetric("GHOST");
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(Boolean.FALSE, body.get("success"));
|
||||
assertTrue(body.get("message").toString().contains("GHOST"),
|
||||
"오류 메시지에 groupId가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// POST /metric/reset
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void resetAllGroupMetrics_alwaysSuccessTrue() {
|
||||
doNothing().when(mockService).resetAllGroupMetrics();
|
||||
|
||||
ResponseEntity<?> response = controller.resetAllGroupMetrics();
|
||||
Map<String, Object> body = body(response);
|
||||
|
||||
assertEquals(Boolean.TRUE, body.get("success"));
|
||||
assertNotNull(body.get("message"));
|
||||
verify(mockService).resetAllGroupMetrics();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetAllGroupMetrics_callsDelegateOnce() {
|
||||
doNothing().when(mockService).resetAllGroupMetrics();
|
||||
|
||||
controller.resetAllGroupMetrics();
|
||||
|
||||
verify(mockService, times(1)).resetAllGroupMetrics();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user