테스트 코드 추가:
- API 상태 관련 서비스 테스트 클래스 신규 작성 (총 7개) - 테스트 코드에서 `visibleApiIds` 필터 적용 확인 및 조회 로직 검증 포함 - `TestCleanupService` 확장: 그룹 제한 데이터 관련 신규 Fixture 및 Mock 추가
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
package com.eactive.apim.portal.apps.auth.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSpecInfoDto;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceDTO;
|
||||
import com.eactive.apim.portal.apps.user.dto.PortalOrgDTO;
|
||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
/**
|
||||
* org 축·role 축은 각자 독립적으로 선택적 제한이며 AND 로 합쳐야 한다.
|
||||
*
|
||||
* <p>과거 OR 합성 결함: displayRoleCode 를 비워두면(=역할 제한 없음) roleMatch 가
|
||||
* "로그인만 했으면" 무조건 true 가 되어, displayOrg 만 설정한 법인전용 API 가 다른 법인
|
||||
* 로그인 사용자에게도 그대로 보였다 — 오직 비로그인 사용자만 걸러졌다.</p>
|
||||
*/
|
||||
class ApiPermissionFilterTest {
|
||||
|
||||
private static final String ORG_A = "org-a";
|
||||
private static final String ORG_B = "org-b";
|
||||
private static final String ROLE_MANAGER = "ROLE_CORP_MANAGER";
|
||||
private static final String ROLE_USER = "ROLE_CORP_USER";
|
||||
|
||||
// ── checkApiPermissions (ApiSpecInfoDto) ──────────────────────────
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_noRestriction_visibleToAnonymous() {
|
||||
ApiSpecInfoDto spec = apiSpec(null, null);
|
||||
assertTrue(ApiPermissionFilter.checkApiPermissions(spec, false, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_orgOnlyRestriction_hiddenFromAnonymous() {
|
||||
ApiSpecInfoDto spec = apiSpec(ORG_A, null);
|
||||
assertFalse(ApiPermissionFilter.checkApiPermissions(spec, false, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_orgOnlyRestriction_visibleToMatchingOrg() {
|
||||
ApiSpecInfoDto spec = apiSpec(ORG_A, null);
|
||||
assertTrue(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_A, ROLE_MANAGER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_orgOnlyRestriction_hiddenFromDifferentOrg() {
|
||||
// 회귀 케이스 — 과거 OR 버그에서는 displayRoleCode 가 비어 roleMatch=true 가 되어 여기서 true 가 나왔다.
|
||||
ApiSpecInfoDto spec = apiSpec(ORG_A, null);
|
||||
assertFalse(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_B, ROLE_MANAGER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_roleOnlyRestriction_hiddenFromNonMatchingRole() {
|
||||
ApiSpecInfoDto spec = apiSpec(null, ROLE_MANAGER);
|
||||
assertFalse(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_A, ROLE_USER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_roleOnlyRestriction_visibleRegardlessOfOrg() {
|
||||
ApiSpecInfoDto spec = apiSpec(null, ROLE_MANAGER);
|
||||
assertTrue(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_B, ROLE_MANAGER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkApiPermissions_bothRestrictions_requireIntersection() {
|
||||
ApiSpecInfoDto spec = apiSpec(ORG_A, ROLE_MANAGER);
|
||||
assertTrue(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_A, ROLE_MANAGER));
|
||||
// org 는 맞지만 role 이 안 맞음 → 여전히 숨겨져야 한다(AND)
|
||||
assertFalse(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_A, ROLE_USER));
|
||||
// role 은 맞지만 org 가 안 맞음
|
||||
assertFalse(ApiPermissionFilter.checkApiPermissions(spec, true, ORG_B, ROLE_MANAGER));
|
||||
}
|
||||
|
||||
// ── checkServicePermissions (ApiServiceDTO, 현재 호출부 없음 — 동일 규칙 유지 확인) ──
|
||||
|
||||
@Test
|
||||
void checkServicePermissions_orgOnlyRestriction_hiddenFromDifferentOrg() {
|
||||
ApiServiceDTO spec = new ApiServiceDTO();
|
||||
spec.setDisplayOrg(ORG_A);
|
||||
assertFalse(ApiPermissionFilter.checkServicePermissions(spec, true, ORG_B, ROLE_MANAGER));
|
||||
assertTrue(ApiPermissionFilter.checkServicePermissions(spec, true, ORG_A, ROLE_MANAGER));
|
||||
}
|
||||
|
||||
// ── filterApisByPermissions (SecurityUtil 정적 메서드 경유 통합 경로) ──
|
||||
|
||||
@Test
|
||||
void filterApisByPermissions_orgOnlyRestriction_excludesAuthenticatedDifferentOrg() {
|
||||
ApiSpecInfoDto visibleToOrgA = apiSpec(ORG_A, null);
|
||||
visibleToOrgA.setApiId("API-ORG-A");
|
||||
ApiSpecInfoDto publicApi = apiSpec(null, null);
|
||||
publicApi.setApiId("API-PUBLIC");
|
||||
List<ApiSpecInfoDto> apis = Arrays.asList(visibleToOrgA, publicApi);
|
||||
|
||||
PortalAuthenticatedUser user = org.mockito.Mockito.mock(PortalAuthenticatedUser.class);
|
||||
PortalOrgDTO userOrg = new PortalOrgDTO();
|
||||
userOrg.setId(ORG_B);
|
||||
|
||||
try (MockedStatic<SecurityUtil> securityUtil = mockStatic(SecurityUtil.class)) {
|
||||
securityUtil.when(SecurityUtil::isAuthenticated).thenReturn(true);
|
||||
securityUtil.when(SecurityUtil::getPortalAuthenticatedUser).thenReturn(user);
|
||||
securityUtil.when(SecurityUtil::getUserOrg).thenReturn(userOrg);
|
||||
when(user.getRoleCode()).thenReturn(com.eactive.apim.portal.portaluser.entity.PortalUserEnums.RoleCode.ROLE_CORP_MANAGER);
|
||||
|
||||
List<ApiSpecInfoDto> filtered = ApiPermissionFilter.filterApisByPermissions(apis);
|
||||
|
||||
assertEquals(1, filtered.size());
|
||||
assertEquals("API-PUBLIC", filtered.get(0).getApiId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterApisByPermissions_anonymous_onlyPublicApisVisible() {
|
||||
ApiSpecInfoDto restricted = apiSpec(ORG_A, null);
|
||||
restricted.setApiId("API-ORG-A");
|
||||
ApiSpecInfoDto publicApi = apiSpec(null, null);
|
||||
publicApi.setApiId("API-PUBLIC");
|
||||
|
||||
try (MockedStatic<SecurityUtil> securityUtil = mockStatic(SecurityUtil.class)) {
|
||||
securityUtil.when(SecurityUtil::isAuthenticated).thenReturn(false);
|
||||
|
||||
List<ApiSpecInfoDto> filtered =
|
||||
ApiPermissionFilter.filterApisByPermissions(Arrays.asList(restricted, publicApi));
|
||||
|
||||
assertEquals(1, filtered.size());
|
||||
assertEquals("API-PUBLIC", filtered.get(0).getApiId());
|
||||
}
|
||||
}
|
||||
|
||||
private ApiSpecInfoDto apiSpec(String displayOrg, String displayRoleCode) {
|
||||
ApiSpecInfoDto dto = new ApiSpecInfoDto();
|
||||
dto.setDisplayOrg(displayOrg);
|
||||
dto.setDisplayRoleCode(displayRoleCode);
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.eactive.apim.portal.djb.apistatus.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.portal.apispec.repository.ApiSpecInfoRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.IncidentKind;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentApiRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.repository.ApiStatusIncidentQueryRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* API 개별 현재상태(P11, 정상/점검/지연/장애) 판정이 진행 중 장애·점검·최근 이슈를
|
||||
* 모두 현재 사용자의 조회가능 API 집합으로 필터링해서 조회하는지 검증한다.
|
||||
* {@code apiId} 를 직접 지정해 호출하는 {@code /apistatus/current.json} 도 이 경로를 탄다 -
|
||||
* 조회 권한 없는 apiId 를 직접 넣어도 실제 상태(장애 여부)가 새어나가지 않아야 한다.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ApiCurrentStatusServiceTest {
|
||||
|
||||
@Mock private ApiStatusIncidentQueryRepository incidentQueryRepository;
|
||||
@Mock private DjbApistatusIncidentApiRepository incidentApiRepository;
|
||||
@Mock private ApiSpecInfoRepository apiSpecInfoRepository;
|
||||
@Mock private ApiStatusUptimeService uptimeService;
|
||||
@Mock private ApiStatusCatalogService catalogService;
|
||||
|
||||
private ApiCurrentStatusService service;
|
||||
private Set<String> visibleApiIds;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ApiCurrentStatusService(
|
||||
incidentQueryRepository, incidentApiRepository, apiSpecInfoRepository, uptimeService, catalogService);
|
||||
visibleApiIds = Collections.singleton("API-PUBLIC");
|
||||
when(catalogService.getVisibleApiIdsForQuery()).thenReturn(visibleApiIds);
|
||||
when(catalogService.getWindowDays()).thenReturn(90);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveStatuses_passesVisibleApiIdsToOpenMaintenanceAndOverlapQueries() {
|
||||
when(incidentQueryRepository.findVisibleOpenIncidents(
|
||||
eq(IncidentKind.DEGRADING), any(), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
when(incidentQueryRepository.findVisibleOngoingMaintenance(
|
||||
eq(IncidentKind.MAINTENANCE), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
when(incidentQueryRepository.findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.resolveStatuses(Collections.singleton("API1"));
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOpenIncidents(
|
||||
eq(IncidentKind.DEGRADING), any(), eq(visibleApiIds));
|
||||
verify(incidentQueryRepository).findVisibleOngoingMaintenance(
|
||||
eq(IncidentKind.MAINTENANCE), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
verify(incidentQueryRepository).findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.eactive.apim.portal.djb.apistatus.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.gateway.data.statistics.repository.GwApiStatusRepository;
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSpecInfoDto;
|
||||
import com.eactive.apim.portal.apps.apis.service.ApiSearchFacade;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiGroupSearch;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* getVisibleApiIdsForQuery() 는 ApiStatusIncidentQueryRepository 의 {@code :visibleApiIds}
|
||||
* 바인딩 소스다. API 그룹 공개범위(ApiSearchFacade → ApiPermissionFilter 경로)를 그대로
|
||||
* 재사용하는지, 조회 가능한 API 가 하나도 없을 때 Oracle {@code IN ()} 구문 오류를 피하는
|
||||
* 더미값으로 대체하는지를 검증한다.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ApiStatusCatalogServiceTest {
|
||||
|
||||
@Mock private ApiSearchFacade apiSearchFacade;
|
||||
@Mock private PortalPropertyService portalPropertyService;
|
||||
@Mock private GwApiStatusRepository gwApiStatusRepository;
|
||||
|
||||
private ApiStatusCatalogService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ApiStatusCatalogService(apiSearchFacade, portalPropertyService, gwApiStatusRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getVisibleApiIdsForQuery_returnsApiIdsVisibleToCurrentUser() {
|
||||
stubSearchApis(apiSpec("API1", "결제 API"), apiSpec("API2", "조회 API"));
|
||||
|
||||
Collection<String> visibleApiIds = service.getVisibleApiIdsForQuery();
|
||||
|
||||
assertEquals(2, visibleApiIds.size());
|
||||
assertTrue(visibleApiIds.contains("API1"));
|
||||
assertTrue(visibleApiIds.contains("API2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getVisibleApiIdsForQuery_whenNothingVisible_returnsDummyThatMatchesNoRealApiId() {
|
||||
stubSearchApis();
|
||||
|
||||
Collection<String> visibleApiIds = service.getVisibleApiIdsForQuery();
|
||||
|
||||
assertEquals(1, visibleApiIds.size());
|
||||
assertFalse(visibleApiIds.contains("API1"));
|
||||
assertFalse(visibleApiIds.isEmpty());
|
||||
}
|
||||
|
||||
private void stubSearchApis(ApiSpecInfoDto... apis) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("apis", Arrays.asList(apis));
|
||||
when(apiSearchFacade.searchApis(any(ApiGroupSearch.class))).thenReturn(result);
|
||||
}
|
||||
|
||||
private ApiSpecInfoDto apiSpec(String apiId, String apiName) {
|
||||
ApiSpecInfoDto dto = new ApiSpecInfoDto();
|
||||
dto.setApiId(apiId);
|
||||
dto.setApiName(apiName);
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.eactive.apim.portal.djb.apistatus.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.portal.djb.apistatus.repository.ApiStatusIncidentQueryRepository;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
/**
|
||||
* 전체 장애 이력 페이지(P8) 의 일자 인덱스(P9)·목록(P10) 조회가 현재 사용자의
|
||||
* 조회가능 API 집합을 {@link ApiStatusIncidentQueryRepository} 에 그대로 전달하는지 검증한다.
|
||||
* 이 테스트가 다루는 대상이 원 분석에서 지적된 "그룹 전용 API 장애가 전체 사용자에게
|
||||
* 노출되던" 경로다.
|
||||
*
|
||||
* <p>mock 이라 JPQL 자체의 필터링 정확성은 검증 범위 밖이다 - 실제 쿼리 실행 검증은
|
||||
* 별도 통합 테스트(@DataJpaTest 등)가 필요하다.</p>
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ApiStatusIssueHistoryServiceTest {
|
||||
|
||||
@Mock private ApiStatusIncidentQueryRepository incidentQueryRepository;
|
||||
@Mock private ApiStatusAssembler assembler;
|
||||
@Mock private ApiStatusCatalogService catalogService;
|
||||
|
||||
private ApiStatusIssueHistoryService service;
|
||||
private Set<String> visibleApiIds;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ApiStatusIssueHistoryService(incidentQueryRepository, assembler, catalogService);
|
||||
visibleApiIds = Collections.singleton("API-PUBLIC");
|
||||
when(catalogService.getVisibleApiIdsForQuery()).thenReturn(visibleApiIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIssueDates_withoutApiFilter_passesVisibleApiIdsToOverlapQuery() {
|
||||
when(incidentQueryRepository.findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getIssueDates(30, null, null);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIssueDates_withApiFilter_apiIdItselfMustBeVisibleTooOrRowsAreExcluded() {
|
||||
when(incidentQueryRepository.findVisibleOverlappingByApi(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq("API-RESTRICTED"), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getIssueDates(30, "API-RESTRICTED", null);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlappingByApi(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq("API-RESTRICTED"), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIssues_withoutApiFilter_passesVisibleApiIdsToOverlapQuery() {
|
||||
when(incidentQueryRepository.findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getIssues(null, null, null, PageRequest.of(0, 20));
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIssues_withApiFilter_passesVisibleApiIdsToPerApiQuery() {
|
||||
when(incidentQueryRepository.findVisibleOverlappingByApi(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq("API-RESTRICTED"), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getIssues(LocalDate.now(), "API-RESTRICTED", null, PageRequest.of(0, 20));
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlappingByApi(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq("API-RESTRICTED"), eq(visibleApiIds));
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package com.eactive.apim.portal.djb.apistatus.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.DjbApistatusIncident;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.IncidentKind;
|
||||
import com.eactive.apim.portal.djb.apistatus.repository.ApiStatusIncidentQueryRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
/**
|
||||
* API Status 메인 화면(P3 진행중 장애 / P5 점검 / P6 최근 이슈 / P7 상세) 조회가
|
||||
* 현재 사용자의 조회가능 API 집합({@link ApiStatusCatalogService#getVisibleApiIdsForQuery()})을
|
||||
* {@link ApiStatusIncidentQueryRepository} 에 그대로 전달하는지 검증한다.
|
||||
*
|
||||
* <p>mock 이라 JPQL 자체의 필터링 정확성(그룹 전용 API 의 인시던트가 실제로 걸러지는지)은
|
||||
* 검증 범위 밖이다 - 실제 쿼리 실행 검증은 별도 통합 테스트가 필요하다.</p>
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ApiStatusQueryServiceTest {
|
||||
|
||||
@Mock private ApiStatusIncidentQueryRepository incidentQueryRepository;
|
||||
@Mock private ApiStatusAssembler assembler;
|
||||
@Mock private ApiStatusCatalogService catalogService;
|
||||
|
||||
private ApiStatusQueryService service;
|
||||
private Set<String> visibleApiIds;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ApiStatusQueryService(incidentQueryRepository, assembler, catalogService);
|
||||
visibleApiIds = Collections.singleton("API-PUBLIC");
|
||||
when(catalogService.getVisibleApiIdsForQuery()).thenReturn(visibleApiIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getActiveIncidents_passesVisibleApiIds() {
|
||||
when(incidentQueryRepository.findVisibleOpenIncidents(
|
||||
eq(IncidentKind.DEGRADING), eq(ApiStatusSupport.CLOSED_STATES), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
when(assembler.toActiveIncidents(anyList(), any(LocalDateTime.class)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getActiveIncidents();
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOpenIncidents(
|
||||
eq(IncidentKind.DEGRADING), eq(ApiStatusSupport.CLOSED_STATES), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOngoingMaintenance_passesVisibleApiIds() {
|
||||
when(incidentQueryRepository.findVisibleOngoingMaintenance(
|
||||
eq(IncidentKind.MAINTENANCE), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
when(assembler.toMaintenanceCards(anyList())).thenReturn(Collections.emptyList());
|
||||
|
||||
service.getOngoingMaintenance();
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOngoingMaintenance(
|
||||
eq(IncidentKind.MAINTENANCE), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRecentClosedIssues_passesVisibleApiIds() {
|
||||
List<DjbApistatusIncident> empty = Collections.emptyList();
|
||||
when(incidentQueryRepository.findVisibleClosedIssues(
|
||||
eq(ApiStatusSupport.CLOSED_STATES), any(LocalDateTime.class), eq(visibleApiIds),
|
||||
eq(PageRequest.of(0, 5))))
|
||||
.thenReturn(new PageImpl<>(empty));
|
||||
when(assembler.toPastIssueCards(anyList())).thenReturn(Collections.emptyList());
|
||||
|
||||
service.getRecentClosedIssues(0);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleClosedIssues(
|
||||
eq(ApiStatusSupport.CLOSED_STATES), any(LocalDateTime.class), eq(visibleApiIds),
|
||||
eq(PageRequest.of(0, 5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIssueDetail_passesVisibleApiIds() {
|
||||
when(incidentQueryRepository.findVisibleById(eq(1L), eq(visibleApiIds)))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
service.getIssueDetail(1L);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleById(eq(1L), eq(visibleApiIds));
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.eactive.apim.portal.djb.apistatus.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentApiRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.repository.ApiStatusIncidentQueryRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* 90일 가동률 집계(P2) 가 인시던트 조회를 현재 사용자의 조회가능 API 집합으로
|
||||
* 필터링하는지 검증한다. 필터링 전에는 그룹 전용 API 의 장애가 전체 가동률과
|
||||
* 일자별 이슈 제목({@code DailyStatDTO.issues})에 그대로 섞여 들어갔다.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ApiStatusUptimeServiceTest {
|
||||
|
||||
@Mock private ApiStatusIncidentQueryRepository incidentQueryRepository;
|
||||
@Mock private DjbApistatusIncidentApiRepository incidentApiRepository;
|
||||
@Mock private ApiStatusCatalogService catalogService;
|
||||
|
||||
private ApiStatusUptimeService service;
|
||||
private Set<String> visibleApiIds;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new ApiStatusUptimeService(incidentQueryRepository, incidentApiRepository, catalogService);
|
||||
visibleApiIds = Collections.singleton("API-PUBLIC");
|
||||
when(catalogService.getVisibleApiIdsForQuery()).thenReturn(visibleApiIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDailyStats_passesVisibleApiIds() {
|
||||
when(incidentQueryRepository.findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getDailyStats(7);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getApiUptimeRatios_passesVisibleApiIds() {
|
||||
when(incidentQueryRepository.findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds)))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
service.getApiUptimeRatios(Collections.singleton("API1"), 7);
|
||||
|
||||
verify(incidentQueryRepository).findVisibleOverlapping(
|
||||
any(LocalDateTime.class), any(LocalDateTime.class), eq(visibleApiIds));
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -23,6 +23,9 @@ import com.eactive.apim.portal.apps.community.partnership.repository.Partnership
|
||||
import com.eactive.apim.portal.apps.community.qna.repository.InquiryRepository;
|
||||
import com.eactive.apim.portal.apps.user.repository.PortalOrgRepository;
|
||||
import com.eactive.apim.portal.apps.user.service.PortalUserService;
|
||||
import com.eactive.apim.portal.apispec.repository.ApiSpecInfoRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentApiRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentRepository;
|
||||
import com.eactive.apim.portal.djb.community.qna.comment.repository.InquiryCommentRepository;
|
||||
import com.eactive.apim.portal.djb.webhook.repository.WebhookRequestApiRepository;
|
||||
import com.eactive.apim.portal.djb.webhook.repository.WebhookRequestEventRepository;
|
||||
@@ -77,6 +80,10 @@ class TestCleanupServiceTest {
|
||||
@Mock private TestCleanupNativeQueries nativeQueries;
|
||||
@Mock private PortalUserService portalUserService;
|
||||
@Mock private PasswordEncoder passwordEncoder;
|
||||
@Mock private ApiSpecInfoRepository apiSpecInfoRepository;
|
||||
@Mock private DjbApistatusIncidentRepository djbApistatusIncidentRepository;
|
||||
@Mock private DjbApistatusIncidentApiRepository djbApistatusIncidentApiRepository;
|
||||
@Mock private com.eactive.apim.portal.apps.apis.service.ApiSearchFacade apiSearchFacade;
|
||||
|
||||
private TestCleanupService service;
|
||||
|
||||
@@ -94,7 +101,9 @@ class TestCleanupServiceTest {
|
||||
userLogRepository, credentialRepository, appRequestRepository, approvalService,
|
||||
webhookRequestRepository, webhookRequestApiRepository,
|
||||
webhookRequestEventRepository, webhookService, userInvitationRepository, fileService,
|
||||
nativeQueries, portalUserService, passwordEncoder);
|
||||
nativeQueries, portalUserService, passwordEncoder,
|
||||
apiSpecInfoRepository, djbApistatusIncidentRepository, djbApistatusIncidentApiRepository,
|
||||
apiSearchFacade);
|
||||
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(false);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user