클라이언트 유량제어 eapim-online 이동
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
package com.eactive.eai.agent.command;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
||||||
|
import com.eactive.eai.common.inflow.InflowControlUtil;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
|
||||||
|
|
||||||
|
public class ReloadInflowClientControlCommand extends Command {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public ReloadInflowClientControlCommand() {
|
||||||
|
super("ReloadInflowClientControlCommand");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object execute() throws CommandException {
|
||||||
|
Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
if (logger.isInfo())
|
||||||
|
logger.info(this.name + " is executed");
|
||||||
|
|
||||||
|
if (!(args instanceof String)) {
|
||||||
|
String rspErrorCode = "RECEAIMCM001";
|
||||||
|
String msg = makeException(rspErrorCode, null);
|
||||||
|
if (logger.isError())
|
||||||
|
logger.error(msg);
|
||||||
|
throw new CommandException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyName = (String) args;
|
||||||
|
try {
|
||||||
|
AbstractInflowControlManager base = InflowControlUtil.getInflowControlManager();
|
||||||
|
if (!(base instanceof ClientDualInflowControlManager)) {
|
||||||
|
throw new IllegalStateException("ClientDualInflowControlManager 가 활성화되지 않았습니다.");
|
||||||
|
}
|
||||||
|
ClientDualInflowControlManager manager = (ClientDualInflowControlManager) base;
|
||||||
|
|
||||||
|
if (keyName != null) {
|
||||||
|
if ("ALL".equals(keyName)) {
|
||||||
|
manager.reloadClient();
|
||||||
|
if (logger.isWarn())
|
||||||
|
logger.warn(this.name + "] all rule Reload.");
|
||||||
|
} else {
|
||||||
|
manager.reloadClient(keyName);
|
||||||
|
if (logger.isWarn())
|
||||||
|
logger.warn(this.name + "] " + keyName + " Reload.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
String rspErrorCode = "RECEAIMCM002";
|
||||||
|
String msg = makeException(rspErrorCode, e);
|
||||||
|
if (logger.isError())
|
||||||
|
logger.error(msg, e);
|
||||||
|
throw new CommandException(msg);
|
||||||
|
}
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.eactive.eai.agent.command;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
||||||
|
import com.eactive.eai.common.inflow.InflowControlUtil;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
|
||||||
|
|
||||||
|
public class RemoveInflowClientControlCommand extends Command {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public RemoveInflowClientControlCommand() {
|
||||||
|
super("RemoveInflowClientControlCommand");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object execute() throws CommandException {
|
||||||
|
Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
if (logger.isInfo())
|
||||||
|
logger.info(this.name + " is executed");
|
||||||
|
|
||||||
|
if (!(args instanceof String)) {
|
||||||
|
String rspErrorCode = "RECEAIMCM001";
|
||||||
|
String msg = makeException(rspErrorCode, null);
|
||||||
|
if (logger.isError())
|
||||||
|
logger.error(msg);
|
||||||
|
throw new CommandException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = (String) args;
|
||||||
|
try {
|
||||||
|
AbstractInflowControlManager base = InflowControlUtil.getInflowControlManager();
|
||||||
|
if (!(base instanceof ClientDualInflowControlManager)) {
|
||||||
|
throw new IllegalStateException("ClientDualInflowControlManager 가 활성화되지 않았습니다.");
|
||||||
|
}
|
||||||
|
ClientDualInflowControlManager manager = (ClientDualInflowControlManager) base;
|
||||||
|
manager.removeClient(key);
|
||||||
|
if (logger.isWarn())
|
||||||
|
logger.warn(this.name + "] " + key + " removed.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
String rspErrorCode = "RECEAIMCM002";
|
||||||
|
String msg = makeException(rspErrorCode, e);
|
||||||
|
if (logger.isError())
|
||||||
|
logger.error(msg, e);
|
||||||
|
throw new CommandException(msg);
|
||||||
|
}
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import com.eactive.eai.common.inflow.Bucket;
|
import com.eactive.eai.common.inflow.Bucket;
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualBucket;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualBucket;
|
import com.eactive.eai.common.inflow.dual.DualBucket;
|
||||||
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
|
import com.eactive.eai.custom.inflow.ClientDualBucket;
|
||||||
import com.eactive.eai.inbound.processor.RequestProcessor;
|
import com.eactive.eai.inbound.processor.RequestProcessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.eactive.eai.custom.inflow;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
|
import com.eactive.eai.common.inflow.dual.DualBucket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DualBucket에 클라이언트 유량제어 메서드를 추가한 인터페이스.
|
||||||
|
* {@link ClientDualInflowControlManager}가 구현한다.
|
||||||
|
*/
|
||||||
|
public interface ClientDualBucket extends DualBucket {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 클라이언트 유량제어 체크 — 차단 원인 포함.
|
||||||
|
* @return null이면 통과, "PER_SECOND" 또는 "THRESHOLD"이면 해당 버킷에서 차단
|
||||||
|
*/
|
||||||
|
String isClientPassDetail(String clientId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 클라이언트 유량제어 설정 조회 — 에러 메시지 생성용.
|
||||||
|
* @return 등록된 설정이 없으면 null
|
||||||
|
*/
|
||||||
|
InflowTargetVO getClientInflowThreshold(String clientId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package com.eactive.eai.custom.inflow;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.inflow.Bucket;
|
||||||
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
|
import com.eactive.eai.common.inflow.InflowType;
|
||||||
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
|
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
||||||
|
import com.eactive.eai.common.lifecycle.LifecycleException;
|
||||||
|
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||||
|
import com.eactive.eai.common.util.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 어댑터/인터페이스 이중 버킷(DualInflowControlManager)에 클라이언트 유량제어를 추가한 관리자.
|
||||||
|
*
|
||||||
|
* <p>적용 방법: INFLOW.properties에 아래 한 줄 추가.
|
||||||
|
* <pre>inflow.control.bucket.className=com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager</pre>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ClientDualInflowControlManager extends DualInflowControlManager implements ClientDualBucket {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
|
|
||||||
|
public static synchronized Bucket getBucket() {
|
||||||
|
return ApplicationContextProvider.getContext().getBean(ClientDualInflowControlManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile Map<String, DualCustomBucket> clientBucketMap = new ConcurrentHashMap<>();
|
||||||
|
private final ConcurrentHashMap<String, TargetMetrics> clientMetricsMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Lifecycle
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() throws LifecycleException {
|
||||||
|
super.start();
|
||||||
|
try {
|
||||||
|
initClients();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new LifecycleException("ClientDualInflowControlManager init failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 초기화 / 리로드
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private void initClients() throws Exception {
|
||||||
|
this.clientBucketMap = loadBucketMap(InflowType.CLIENT);
|
||||||
|
if (logger.isInfo()) logger.info("ClientDualInflowControlManager] initClients: " + clientBucketMap.size() + " buckets");
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reloadClient() throws Exception {
|
||||||
|
initClients();
|
||||||
|
clientMetricsMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reloadClient(String clientId) throws Exception {
|
||||||
|
reloadBucketMap(clientBucketMap, InflowType.CLIENT, clientId);
|
||||||
|
TargetMetrics m = clientMetricsMap.get(clientId);
|
||||||
|
if (m != null) m.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeClient(String clientId) {
|
||||||
|
clientBucketMap.remove(clientId);
|
||||||
|
clientMetricsMap.remove(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 클라이언트 메트릭 접근자
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public TargetMetrics getClientMetrics(String clientId) { return clientMetricsMap.get(clientId); }
|
||||||
|
public Map<String, TargetMetrics> getAllClientMetrics() { return Collections.unmodifiableMap(clientMetricsMap); }
|
||||||
|
public void resetClientMetrics(String clientId) { TargetMetrics m = clientMetricsMap.get(clientId); if (m != null) m.reset(); }
|
||||||
|
public void resetAllClientMetrics() { clientMetricsMap.values().forEach(TargetMetrics::reset); }
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ClientDualBucket — 클라이언트 유량제어
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String isClientPassDetail(String clientId) {
|
||||||
|
DualCustomBucket b = clientBucketMap.get(clientId);
|
||||||
|
if (b == null) return DualCustomBucket.RESULT_PASS;
|
||||||
|
String result = b.tryConsume();
|
||||||
|
recordMetrics(clientMetricsMap, clientId, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InflowTargetVO getClientInflowThreshold(String clientId) {
|
||||||
|
DualCustomBucket b = clientBucketMap.get(clientId);
|
||||||
|
return (b == null) ? null : b.getInflowTargetVo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 모니터링용 접근자
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public DualCustomBucket getClientBucket(String clientId) {
|
||||||
|
return clientBucketMap.get(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, DualCustomBucket> getClientBucketMap() {
|
||||||
|
return clientBucketMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import org.springframework.stereotype.Service;
|
|||||||
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
||||||
import com.eactive.eai.common.inflow.InflowControlUtil;
|
import com.eactive.eai.common.inflow.InflowControlUtil;
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
|
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
|
||||||
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
|
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import org.springframework.stereotype.Service;
|
|||||||
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
|
||||||
import com.eactive.eai.common.inflow.InflowControlUtil;
|
import com.eactive.eai.common.inflow.InflowControlUtil;
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
||||||
import com.eactive.eai.manage.inflow.TargetMetricDTO;
|
import com.eactive.eai.manage.inflow.TargetMetricDTO;
|
||||||
|
|
||||||
|
|||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
package com.eactive.eai.custom.inbound.processor;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
|
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
||||||
|
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
|
||||||
|
|
||||||
|
import io.github.bucket4j.Bandwidth;
|
||||||
|
import io.github.bucket4j.Bucket4j;
|
||||||
|
import io.github.bucket4j.local.LocalBucket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientDualInflowControlManager 클라이언트 메트릭 단위 테스트.
|
||||||
|
*/
|
||||||
|
class ClientDualInflowControlManagerMetricsTest {
|
||||||
|
|
||||||
|
private ClientDualInflowControlManager manager;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
manager = new ClientDualInflowControlManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private InflowTargetVO makeTargetVO(String name) {
|
||||||
|
InflowTargetVO vo = new InflowTargetVO();
|
||||||
|
vo.setName(name);
|
||||||
|
vo.setThresholdPerSecond(100);
|
||||||
|
vo.setThreshold(10000);
|
||||||
|
vo.setThresholdTimeUnit("DAY");
|
||||||
|
vo.setActivate(true);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalBucket stableBucket(long capacity) {
|
||||||
|
return Bucket4j.builder()
|
||||||
|
.addLimit(Bandwidth.simple(capacity, Duration.ofHours(1)))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalBucket exhaustedBucket(long capacity) {
|
||||||
|
LocalBucket b = stableBucket(capacity);
|
||||||
|
b.tryConsume(capacity);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DualCustomBucket passDualBucket(String name) {
|
||||||
|
return new DualCustomBucket(stableBucket(100), null, makeTargetVO(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DualCustomBucket blockedPerSecondDualBucket(String name) {
|
||||||
|
return new DualCustomBucket(exhaustedBucket(1), null, makeTargetVO(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DualCustomBucket blockedThresholdDualBucket(String name) {
|
||||||
|
return new DualCustomBucket(stableBucket(100), exhaustedBucket(1), makeTargetVO(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void injectClientMap(Map<String, DualCustomBucket> map) {
|
||||||
|
ReflectionTestUtils.setField(manager, "clientBucketMap", map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// isClientPassDetail() — 카운터 증가
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isClientPassDetail_bucketNotRegistered_noMetricsCreated() {
|
||||||
|
manager.isClientPassDetail("UNKNOWN");
|
||||||
|
|
||||||
|
assertNull(manager.getClientMetrics("UNKNOWN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isClientPassDetail_pass_incrementsAllowed() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", passDualBucket("C1"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
|
||||||
|
assertEquals(1, manager.getClientMetrics("C1").allowed.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isClientPassDetail_blockedThreshold_incrementsRejectedThreshold() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", blockedThresholdDualBucket("C1"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
|
||||||
|
assertEquals(1, manager.getClientMetrics("C1").rejectedThreshold.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isClientPassDetail_blockedPerSecond_incrementsRejectedPerSecond() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", blockedPerSecondDualBucket("C1"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
|
||||||
|
assertEquals(1, manager.getClientMetrics("C1").rejectedPerSecond.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// getAllClientMetrics — 조회 및 불변성
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAllClientMetrics_empty_returnsEmptyMap() {
|
||||||
|
assertTrue(manager.getAllClientMetrics().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAllClientMetrics_afterCalls_containsEntries() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", passDualBucket("C1"));
|
||||||
|
map.put("C2", passDualBucket("C2"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
manager.isClientPassDetail("C2");
|
||||||
|
|
||||||
|
Map<String, DualInflowControlManager.TargetMetrics> all = manager.getAllClientMetrics();
|
||||||
|
assertEquals(2, all.size());
|
||||||
|
assertTrue(all.containsKey("C1"));
|
||||||
|
assertTrue(all.containsKey("C2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// resetClientMetrics / resetAllClientMetrics
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resetClientMetrics_resetsTargetClient() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", passDualBucket("C1"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
manager.resetClientMetrics("C1");
|
||||||
|
|
||||||
|
assertEquals(0, manager.getClientMetrics("C1").allowed.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resetAllClientMetrics_resetsAll() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", passDualBucket("C1"));
|
||||||
|
map.put("C2", passDualBucket("C2"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
manager.isClientPassDetail("C2");
|
||||||
|
manager.resetAllClientMetrics();
|
||||||
|
|
||||||
|
assertEquals(0, manager.getClientMetrics("C1").allowed.get());
|
||||||
|
assertEquals(0, manager.getClientMetrics("C2").allowed.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// removeClient — 메트릭 자동 삭제
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void removeClient_cleansUpMetrics() {
|
||||||
|
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
|
||||||
|
map.put("C1", passDualBucket("C1"));
|
||||||
|
injectClientMap(map);
|
||||||
|
|
||||||
|
manager.isClientPassDetail("C1");
|
||||||
|
assertNotNull(manager.getClientMetrics("C1"));
|
||||||
|
|
||||||
|
manager.removeClient("C1");
|
||||||
|
|
||||||
|
assertNull(manager.getClientMetrics("C1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.eactive.eai.custom.inbound.processor;
|
package com.eactive.eai.custom.inbound.processor;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -10,11 +15,11 @@ import org.springframework.test.util.ReflectionTestUtils;
|
|||||||
|
|
||||||
import com.eactive.eai.common.inflow.Bucket;
|
import com.eactive.eai.common.inflow.Bucket;
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualBucket;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualBucket;
|
import com.eactive.eai.common.inflow.dual.DualBucket;
|
||||||
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
import com.eactive.eai.common.server.EAIServerManager;
|
import com.eactive.eai.common.server.EAIServerManager;
|
||||||
import com.eactive.eai.common.util.ApplicationContextProvider;
|
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||||
|
import com.eactive.eai.custom.inflow.ClientDualBucket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DJBRequestProcessor 단위 테스트.
|
* DJBRequestProcessor 단위 테스트.
|
||||||
|
|||||||
+6
-3
@@ -1,7 +1,11 @@
|
|||||||
package com.eactive.eai.custom.inflow;
|
package com.eactive.eai.custom.inflow;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -11,7 +15,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||||
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
|
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
|
||||||
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
|
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
|
||||||
|
|||||||
+11
-3
@@ -1,14 +1,22 @@
|
|||||||
package com.eactive.eai.custom.inflow;
|
package com.eactive.eai.custom.inflow;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.eactive.eai.common.inflow.InflowTargetVO;
|
import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||||
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
|
|
||||||
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
|
||||||
import com.eactive.eai.manage.inflow.TargetMetricDTO;
|
import com.eactive.eai.manage.inflow.TargetMetricDTO;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user