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,236 @@
|
||||
package com.eactive.eai.manage.inflow;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.eactive.eai.common.inflow.InflowGroupVO;
|
||||
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
||||
|
||||
/**
|
||||
* InflowGroupMetricService 단위 테스트.
|
||||
*
|
||||
* <p>getManager()를 protected로 오버라이드하는 내부 테스트 서브클래스를 사용하여
|
||||
* mockito-inline(static mock) 없이 DualInflowControlManager 의존성을 주입한다.
|
||||
*/
|
||||
class InflowGroupMetricServiceTest {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 테스트용 서브클래스 — getManager()를 오버라이드하여 mock 주입
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static InflowGroupMetricService serviceWith(DualInflowControlManager manager) {
|
||||
return new InflowGroupMetricService() {
|
||||
@Override
|
||||
protected DualInflowControlManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private InflowGroupVO makeGroupVO(String groupId, String groupName) {
|
||||
InflowGroupVO vo = new InflowGroupVO();
|
||||
vo.setGroupId(groupId);
|
||||
vo.setGroupName(groupName);
|
||||
vo.setActivate(true);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private DualInflowControlManager.TargetMetrics makeMetrics(long allowed, long rejPs, long rejTh) {
|
||||
DualInflowControlManager.TargetMetrics m = new DualInflowControlManager.TargetMetrics();
|
||||
m.allowed.set(allowed);
|
||||
m.rejectedPerSecond.set(rejPs);
|
||||
m.rejectedThreshold.set(rejTh);
|
||||
return m;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// getGroupMetric
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void getGroupMetric_managerIsNull_returnsNull() {
|
||||
assertNull(serviceWith(null).getGroupMetric("G1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_groupNotFound_returnsNull() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(null);
|
||||
|
||||
assertNull(serviceWith(manager).getGroupMetric("G1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_noMetricsYet_returnsZeroCounters() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "결제그룹"));
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(null);
|
||||
|
||||
GroupMetricDTO dto = serviceWith(manager).getGroupMetric("G1");
|
||||
|
||||
assertNotNull(dto);
|
||||
assertEquals("G1", dto.getGroupId());
|
||||
assertEquals("결제그룹", dto.getGroupName());
|
||||
assertTrue(dto.isActivate());
|
||||
assertEquals(0, dto.getAllowed());
|
||||
assertEquals(0, dto.getRejectedPerSecond());
|
||||
assertEquals(0, dto.getRejectedThreshold());
|
||||
assertEquals(0, dto.getTotalRequests());
|
||||
assertEquals(0.0, dto.getRejectRatio());
|
||||
assertEquals(0, dto.getLastResetTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_withMetrics_returnsCorrectValues() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "결제그룹"));
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(makeMetrics(900, 60, 40));
|
||||
|
||||
GroupMetricDTO dto = serviceWith(manager).getGroupMetric("G1");
|
||||
|
||||
assertEquals(900, dto.getAllowed());
|
||||
assertEquals(60, dto.getRejectedPerSecond());
|
||||
assertEquals(40, dto.getRejectedThreshold());
|
||||
assertEquals(1000, dto.getTotalRequests());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_rejectRatioCalculation() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "G1"));
|
||||
// allowed=90, rejPs=5, rejTh=5 → reject=10/100 = 10.00%
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(makeMetrics(90, 5, 5));
|
||||
|
||||
GroupMetricDTO dto = serviceWith(manager).getGroupMetric("G1");
|
||||
|
||||
assertEquals(10.0, dto.getRejectRatio(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_zeroTotal_rejectRatioIsZero() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "G1"));
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(makeMetrics(0, 0, 0));
|
||||
|
||||
GroupMetricDTO dto = serviceWith(manager).getGroupMetric("G1");
|
||||
|
||||
assertEquals(0.0, dto.getRejectRatio(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGroupMetric_lastResetTimeIsPropagated() {
|
||||
DualInflowControlManager.TargetMetrics m = makeMetrics(10, 0, 0);
|
||||
m.lastResetTime = 1234567890L;
|
||||
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "G1"));
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(m);
|
||||
|
||||
GroupMetricDTO dto = serviceWith(manager).getGroupMetric("G1");
|
||||
|
||||
assertEquals(1234567890L, dto.getLastResetTime());
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// getAllGroupMetrics
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_managerIsNull_returnsEmptyList() {
|
||||
List<GroupMetricDTO> result = serviceWith(null).getAllGroupMetrics();
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_noGroups_returnsEmptyList() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupAllKeys()).thenReturn(new String[]{});
|
||||
|
||||
assertTrue(serviceWith(manager).getAllGroupMetrics().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_twoGroups_returnsBoth() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupAllKeys()).thenReturn(new String[]{"G1", "G2"});
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "그룹1"));
|
||||
when(manager.getGroupInflowThreshold("G2")).thenReturn(makeGroupVO("G2", "그룹2"));
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(makeMetrics(10, 0, 0));
|
||||
when(manager.getGroupMetrics("G2")).thenReturn(makeMetrics(20, 5, 0));
|
||||
|
||||
List<GroupMetricDTO> result = serviceWith(manager).getAllGroupMetrics();
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertEquals("G1", result.get(0).getGroupId());
|
||||
assertEquals("G2", result.get(1).getGroupId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllGroupMetrics_groupNotFoundIsSkipped() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupAllKeys()).thenReturn(new String[]{"G1", "GHOST"});
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "그룹1"));
|
||||
when(manager.getGroupInflowThreshold("GHOST")).thenReturn(null);
|
||||
when(manager.getGroupMetrics("G1")).thenReturn(makeMetrics(5, 0, 0));
|
||||
|
||||
List<GroupMetricDTO> result = serviceWith(manager).getAllGroupMetrics();
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("G1", result.get(0).getGroupId());
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// resetGroupMetric
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void resetGroupMetric_managerIsNull_returnsFalse() {
|
||||
assertFalse(serviceWith(null).resetGroupMetric("G1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetGroupMetric_groupNotFound_returnsFalse() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(null);
|
||||
|
||||
assertFalse(serviceWith(manager).resetGroupMetric("G1"));
|
||||
verify(manager, never()).resetGroupMetrics(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetGroupMetric_success_returnsTrueAndCallsManager() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
when(manager.getGroupInflowThreshold("G1")).thenReturn(makeGroupVO("G1", "그룹1"));
|
||||
|
||||
assertTrue(serviceWith(manager).resetGroupMetric("G1"));
|
||||
verify(manager).resetGroupMetrics("G1");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// resetAllGroupMetrics
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
void resetAllGroupMetrics_managerIsNull_noException() {
|
||||
assertDoesNotThrow(() -> serviceWith(null).resetAllGroupMetrics());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetAllGroupMetrics_callsManagerReset() {
|
||||
DualInflowControlManager manager = mock(DualInflowControlManager.class);
|
||||
|
||||
serviceWith(manager).resetAllGroupMetrics();
|
||||
|
||||
verify(manager).resetAllGroupMetrics();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user