- 인증번호 재발송 제한 메시지 개선 - 남은 초 표시 추가
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- 비밀번호 확인 필드명 일괄 변경(password2 → confirmPassword)
- 법인 관리자 탈퇴 제한 경고 메시지 추가 및 관련 로직 수정
- 임시 비밀번호 발급 시 기존 비밀번호 이력 저장 로직 추가
This commit is contained in:
Rinjae
2026-08-24 13:17:14 +09:00
parent b41a81bda3
commit 78b1edff5a
13 changed files with 198 additions and 26 deletions
@@ -0,0 +1,65 @@
package com.eactive.apim.portal.apps.auth.service;
import com.eactive.apim.portal.portaluser.entity.TwoFactorAuth;
import com.eactive.apim.portal.portaluser.service.AuthNumberException;
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.test.util.ReflectionTestUtils;
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class AuthNumberServiceImplTest {
private static final Pattern RETRY_SECONDS = Pattern.compile(
"인증번호 재발송 제한이 적용 중입니다\\. (\\d+)초 후 다시 시도해 주세요\\.");
@Mock
private AuthNumberStorage storage;
@Mock
private AuthNumberGenerator generator;
@Mock
private MessageSender messageSender;
private AuthNumberServiceImpl service;
@BeforeEach
void setUp() {
service = new AuthNumberServiceImpl(storage, generator, messageSender);
ReflectionTestUtils.setField(service, "authNumberExpirationTime", 300);
ReflectionTestUtils.setField(service, "resendLimitSeconds", 30);
}
@Test
void resendLimitMessageIncludesRemainingSeconds() {
String recipient = "01099121100";
TwoFactorAuth existing = new TwoFactorAuth(
recipient, "123456", LocalDateTime.now().plusSeconds(300));
when(storage.getAuthNumber(recipient)).thenReturn(Optional.of(existing));
AuthNumberException exception = assertThrows(
AuthNumberException.class,
() -> service.sendRequestAuthNumber(recipient, "SMS")
);
Matcher matcher = RETRY_SECONDS.matcher(exception.getMessage());
assertTrue(matcher.matches(), "남은 재시도 초가 안내 메시지에 포함되어야 함");
long remainingSeconds = Long.parseLong(matcher.group(1));
assertTrue(remainingSeconds >= 1 && remainingSeconds <= 30,
"남은 초는 1~30 범위여야 함: " + remainingSeconds);
assertNull(exception.getReason());
verifyNoInteractions(generator, messageSender);
}
}
@@ -0,0 +1,83 @@
package com.eactive.apim.portal.apps.user;
import com.eactive.apim.portal.apps.agreements.service.AgreementsFacade;
import com.eactive.apim.portal.apps.user.facade.MessageRequestFacade;
import com.eactive.apim.portal.apps.user.facade.UserFacadeImpl;
import com.eactive.apim.portal.apps.user.mapper.PortalUserMapper;
import com.eactive.apim.portal.apps.user.service.PasswordService;
import com.eactive.apim.portal.apps.user.service.PortalOrgService;
import com.eactive.apim.portal.apps.user.service.PortalUserService;
import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.RoleCode;
import com.eactive.apim.portal.template.service.MessageHandlerService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserFacadeImplTest {
@Mock
private PortalUserService portalUserService;
@Mock
private PortalOrgService portalOrgService;
@Mock
private PasswordService passwordService;
@Mock
private PortalUserMapper portalUserMapper;
@Mock
private MessageHandlerService messageHandlerService;
@Mock
private AgreementsFacade agreementsFacade;
@Mock
private MessageRequestFacade messageRequestFacade;
@InjectMocks
private UserFacadeImpl userFacade;
@Test
void corporateManagerCannotWithdraw() {
PortalUser manager = new PortalUser();
manager.setId("manager-1");
manager.setRoleCode(RoleCode.ROLE_CORP_MANAGER);
when(portalUserService.findById("manager-1")).thenReturn(manager);
IllegalArgumentException exception = assertThrows(
IllegalArgumentException.class,
() -> userFacade.withdrawUser("manager-1", "withdrawal reason")
);
assertEquals(
"법인 관리자는 회원 탈퇴를 할 수 없습니다. "
+ "관리자 권한을 다른 사용자에게 이관하거나 담당자에게 연락해 주세요.",
exception.getMessage()
);
verifyNoInteractions(agreementsFacade, messageRequestFacade);
verify(portalUserService, never()).deleteUser(manager, "withdrawal reason");
}
@Test
void corporateUserCanWithdraw() {
PortalUser user = new PortalUser();
user.setId("user-1");
user.setLoginId("corp-user@example.com");
user.setUserName("법인 사용자");
user.setRoleCode(RoleCode.ROLE_CORP_USER);
when(portalUserService.findById("user-1")).thenReturn(user);
userFacade.withdrawUser("user-1", "withdrawal reason");
verify(agreementsFacade).deleteUserAgreements("user-1");
verify(messageRequestFacade).deleteUserMessage("법인 사용자", "corp-user@example.com");
verify(portalUserService).deleteUser(user, "withdrawal reason");
}
}