package com.tourguide.modules.user.service; import com.tourguide.common.exception.BusinessException; import com.tourguide.modules.system.service.AdminPermissionService; import com.tourguide.modules.user.entity.GuideUser; import com.tourguide.modules.user.mapper.MiniUserMapper; import com.tourguide.security.JwtTokenService; import com.tourguide.security.TokenSessionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.security.crypto.password.PasswordEncoder; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class AuthServiceGuideLoginTest { private GuideUserService guideUserService; private JwtTokenService jwtTokenService; private TokenSessionService tokenSessionService; private GuideAutoDisableService guideAutoDisableService; private AuthService authService; @BeforeEach void setUp() { guideUserService = mock(GuideUserService.class); jwtTokenService = mock(JwtTokenService.class); tokenSessionService = mock(TokenSessionService.class); guideAutoDisableService = mock(GuideAutoDisableService.class); authService = new AuthService( mock(AdminUserService.class), mock(AdminPermissionService.class), mock(MiniUserService.class), guideUserService, guideAutoDisableService, mock(MiniUserMapper.class), mock(PasswordEncoder.class), jwtTokenService, tokenSessionService); } @Test void disabledGuideShouldReceiveExplicitMessageAndNoToken() { GuideUser guide = new GuideUser(); guide.setId(8L); guide.setStatus(GuideUserService.STATUS_DISABLED); when(guideUserService.findByPhone("13800138000")).thenReturn(guide); assertThatThrownBy(() -> authService.loginGuideByPhone("13800138000")) .isInstanceOf(BusinessException.class) .hasMessage("账号已被禁用,请联系后台工作人员") .extracting(error -> ((BusinessException) error).getCode()) .isEqualTo(AuthService.GUIDE_ACCOUNT_DISABLED_CODE); verify(jwtTokenService, never()).createToken( org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any()); verify(tokenSessionService, never()).save( org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyLong()); } @Test void unknownPhoneShouldNotBeReportedAsDisabled() { when(guideUserService.findByPhone("13800138000")).thenReturn(null); assertThatThrownBy(() -> authService.ensureGuidePhoneCanLogin("13800138000")) .isInstanceOf(BusinessException.class) .hasMessage("手机号未注册"); } @Test void eligibleGuideShouldBeDisabledBeforeTokenIsIssued() { GuideUser enabledGuide = guide(GuideUserService.STATUS_ENABLED); GuideUser disabledGuide = guide(GuideUserService.STATUS_DISABLED); when(guideUserService.findByPhone("13800138000")) .thenReturn(enabledGuide, disabledGuide); assertThatThrownBy(() -> authService.loginGuideByPhone("13800138000")) .isInstanceOf(BusinessException.class) .extracting(error -> ((BusinessException) error).getCode()) .isEqualTo(AuthService.GUIDE_ACCOUNT_DISABLED_CODE); verify(guideAutoDisableService).disableGuideIfEligible(8L); verify(jwtTokenService, never()).createToken( org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any()); } @Test void staleUsernameShouldNotAuthenticateAsPhoneAfterAdminUpdate() { GuideUser guide = guide(GuideUserService.STATUS_ENABLED); guide.setUsername("13800138000"); guide.setMobile("13900139000"); when(guideUserService.findByPhone("13800138000")).thenReturn(guide); assertThatThrownBy(() -> authService.ensureGuidePhoneCanLogin("13800138000")) .isInstanceOf(BusinessException.class) .hasMessage("手机号未注册"); verify(guideAutoDisableService, never()).disableGuideIfEligible(8L); } private GuideUser guide(int status) { GuideUser guide = new GuideUser(); guide.setId(8L); guide.setStatus(status); return guide; } }