- Playwright 테스트 정리용 internal API 추가
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- /internal/test-cleanup/{org,user,orphans} 신설
- dev 프로필 전용, 토큰+IP allowlist 이중 가드
- 13개 고아 테이블 cascade/스윕 삭제 서비스
- 리포지토리 deleteBy 메서드 추가, 단위테스트 포함
This commit is contained in:
Rinjae
2026-08-21 17:57:51 +09:00
parent bac9a54dee
commit f1d6181210
11 changed files with 756 additions and 1 deletions
@@ -0,0 +1,55 @@
package com.eactive.apim.portal.djb.testcleanup.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
import javax.persistence.EntityManager;
import javax.persistence.Query;
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.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.test.util.ReflectionTestUtils;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class OrphanCleanupServiceTest {
@Mock private Environment environment;
@Mock private EntityManager entityManager;
@Mock private Query query;
private OrphanCleanupService service;
@BeforeEach
void setUp() {
service = new OrphanCleanupService(environment);
ReflectionTestUtils.setField(service, "entityManager", entityManager);
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(false);
when(entityManager.createNativeQuery(org.mockito.ArgumentMatchers.anyString())).thenReturn(query);
when(query.executeUpdate()).thenReturn(0);
}
@Test
void sweep_runsAllThirteenTablesAndReportsCounts() {
when(query.executeUpdate()).thenReturn(3);
TestCleanupResult result = service.sweep();
assertEquals(13, result.getDeletedCounts().size());
result.getDeletedCounts().values().forEach(count -> assertEquals(3L, count));
}
@Test
void sweep_prodProfile_throws() {
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(true);
assertThrows(IllegalStateException.class, () -> service.sweep());
}
}
@@ -0,0 +1,194 @@
package com.eactive.apim.portal.djb.testcleanup.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.eactive.apim.portal.app.repository.CredentialRepository;
import com.eactive.apim.portal.apps.community.partnership.repository.PartnershipApplicationRepository;
import com.eactive.apim.portal.apps.community.qna.repository.InquiryRepository;
import com.eactive.apim.portal.apps.user.repository.PortalOrgRepository;
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;
import com.eactive.apim.portal.djb.webhook.repository.WebhookRequestRepository;
import com.eactive.apim.portal.djb.webhook.repository.entity.WebhookRequest;
import com.eactive.apim.portal.djb.webhook.service.WebhookService;
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.portaluser.repository.PortalUserPrivacyAgreementRepository;
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
import com.eactive.apim.portal.portaluser.repository.UserPasswordHistoryRepository;
import com.eactive.apim.portal.portaluser.repository.UserRoleHistoryRepository;
import com.eactive.apim.portal.user.repository.UserLogRepository;
import java.util.Collections;
import java.util.Optional;
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.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class TestCleanupServiceTest {
@Mock private Environment environment;
@Mock private PortalOrgRepository portalOrgRepository;
@Mock private PortalUserRepository portalUserRepository;
@Mock private InquiryRepository inquiryRepository;
@Mock private InquiryCommentRepository inquiryCommentRepository;
@Mock private PartnershipApplicationRepository partnershipApplicationRepository;
@Mock private UserRoleHistoryRepository userRoleHistoryRepository;
@Mock private PortalUserPrivacyAgreementRepository portalUserPrivacyAgreementRepository;
@Mock private UserPasswordHistoryRepository userPasswordHistoryRepository;
@Mock private UserLogRepository userLogRepository;
@Mock private CredentialRepository credentialRepository;
@Mock private WebhookRequestRepository webhookRequestRepository;
@Mock private WebhookRequestApiRepository webhookRequestApiRepository;
@Mock private WebhookRequestEventRepository webhookRequestEventRepository;
@Mock private WebhookService webhookService;
@Mock private TestCleanupNativeQueries nativeQueries;
private TestCleanupService service;
private static final String ORG_ID = "ORG1";
private static final String USER_ID = "USER1";
private static final String LOGIN_ID = "user1@test.com";
private static final String COMP_REG_NO = "1234567890";
private static final String EMAIL = "user1@test.com";
@BeforeEach
void setUp() {
service = new TestCleanupService(environment, portalOrgRepository, portalUserRepository,
inquiryRepository, inquiryCommentRepository, partnershipApplicationRepository,
userRoleHistoryRepository, portalUserPrivacyAgreementRepository, userPasswordHistoryRepository,
userLogRepository, credentialRepository, webhookRequestRepository, webhookRequestApiRepository,
webhookRequestEventRepository, webhookService, nativeQueries);
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(false);
}
private PortalUser user() {
PortalUser u = new PortalUser();
u.setId(USER_ID);
u.setLoginId(LOGIN_ID);
return u;
}
@Test
void deleteOrgCascade_notFound() {
when(portalOrgRepository.findByCompRegNo(COMP_REG_NO)).thenReturn(Optional.empty());
TestCleanupResult result = service.deleteOrgCascade(COMP_REG_NO);
assertFalse(result.isFound());
assertTrue(result.getDeletedCounts().isEmpty());
verifyNoInteractions(webhookService, portalUserRepository);
}
@Test
void deleteOrgCascade_found_cascadesUsersAndOrg() {
PortalOrg org = org();
PortalUser member = user();
when(portalOrgRepository.findByCompRegNo(COMP_REG_NO)).thenReturn(Optional.of(org));
when(portalUserRepository.findAllByPortalOrg_Id(ORG_ID)).thenReturn(Collections.singletonList(member));
when(webhookRequestRepository.findByOrgId(ORG_ID)).thenReturn(Optional.empty());
when(nativeQueries.deleteCredentialApiByOrgId(ORG_ID)).thenReturn(2);
when(credentialRepository.deleteByOrgid(ORG_ID)).thenReturn(1L);
TestCleanupResult result = service.deleteOrgCascade(COMP_REG_NO);
assertTrue(result.isFound());
assertEquals(ORG_ID, result.getTargetId());
assertEquals(1L, result.getDeletedCounts().get("PTL_USER"));
assertEquals(2L, result.getDeletedCounts().get("PTL_CREDENTIAL_API"));
assertEquals(1L, result.getDeletedCounts().get("PTL_CREDENTIAL"));
assertEquals(1L, result.getDeletedCounts().get("PTL_ORG"));
assertEquals(0L, result.getDeletedCounts().get("PTL_WEBHOOK_REQ"));
verify(inquiryCommentRepository).deleteByInquiry_Inquirer_Id(USER_ID);
verify(inquiryRepository).deleteByInquirer_Id(USER_ID);
verify(userRoleHistoryRepository).deleteByUserId(LOGIN_ID);
verify(userPasswordHistoryRepository).deleteByUserId(USER_ID);
verify(portalUserRepository).delete(member);
verify(webhookService, never()).delete(anyLong(), anyString());
verify(portalOrgRepository).delete(org);
}
@Test
void deleteOrgCascade_withWebhook_delegatesToWebhookService() {
PortalOrg org = org();
WebhookRequest webhook = new WebhookRequest();
webhook.setId(99L);
when(portalOrgRepository.findByCompRegNo(COMP_REG_NO)).thenReturn(Optional.of(org));
when(portalUserRepository.findAllByPortalOrg_Id(ORG_ID)).thenReturn(Collections.emptyList());
when(webhookRequestRepository.findByOrgId(ORG_ID)).thenReturn(Optional.of(webhook));
when(webhookRequestApiRepository.findByWebhookReqId(99L)).thenReturn(Collections.emptyList());
when(webhookRequestEventRepository.findByWebhookReqId(99L)).thenReturn(Collections.emptyList());
TestCleanupResult result = service.deleteOrgCascade(COMP_REG_NO);
verify(webhookService, times(1)).delete(99L, ORG_ID);
assertEquals(1L, result.getDeletedCounts().get("PTL_WEBHOOK_REQ"));
}
@Test
void deleteUserCascade_notFound() {
when(portalUserRepository.findPortalUserByEmailAddr(EMAIL)).thenReturn(Optional.empty());
TestCleanupResult result = service.deleteUserCascade(EMAIL);
assertFalse(result.isFound());
assertTrue(result.getDeletedCounts().isEmpty());
}
@Test
void deleteUserCascade_found_deletesOrphanDataAndUser() {
PortalUser target = user();
when(portalUserRepository.findPortalUserByEmailAddr(EMAIL)).thenReturn(Optional.of(target));
TestCleanupResult result = service.deleteUserCascade(EMAIL);
assertTrue(result.isFound());
assertEquals(USER_ID, result.getTargetId());
verify(inquiryCommentRepository).deleteByInquiry_Inquirer_Id(USER_ID);
verify(inquiryRepository).deleteByInquirer_Id(USER_ID);
verify(partnershipApplicationRepository).deleteByCreatedBy(USER_ID);
verify(userRoleHistoryRepository).deleteByUserId(LOGIN_ID);
verify(portalUserPrivacyAgreementRepository).deleteByCreatedBy(USER_ID);
verify(userPasswordHistoryRepository).deleteByUserId(USER_ID);
verify(userLogRepository).deleteByLoginId(LOGIN_ID);
verify(portalUserRepository).delete(target);
}
@Test
void deleteOrgCascade_prodProfile_throws() {
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(true);
assertThrows(IllegalStateException.class, () -> service.deleteOrgCascade(COMP_REG_NO));
}
@Test
void deleteUserCascade_prodProfile_throws() {
when(environment.acceptsProfiles(Profiles.of("stage", "prod"))).thenReturn(true);
assertThrows(IllegalStateException.class, () -> service.deleteUserCascade(EMAIL));
}
private PortalOrg org() {
PortalOrg o = new PortalOrg();
o.setId(ORG_ID);
return o;
}
}