AuthServiceTest.java 7.32 KB
package com.example.erp.module.usr;

import com.example.erp.common.exception.BizException;
import com.example.erp.common.util.JwtUtil;
import com.example.erp.module.usr.dto.LoginReqDTO;
import com.example.erp.module.usr.entity.BrandEntity;
import com.example.erp.module.usr.entity.UsrUserEntity;
import com.example.erp.module.usr.mapper.BrandMapper;
import com.example.erp.module.usr.mapper.UsrUserMapper;
import com.example.erp.module.usr.service.impl.AuthServiceImpl;
import com.example.erp.module.usr.vo.BrandVO;
import com.example.erp.module.usr.vo.LoginVO;
import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.BeforeEach;
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 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class AuthServiceTest {

    @Mock private BrandMapper brandMapper;
    @Mock private UsrUserMapper userMapper;
    @Mock private JwtUtil jwtUtil;
    @Mock private BCryptPasswordEncoder passwordEncoder;

    @InjectMocks
    private AuthServiceImpl authService;

    private LoginReqDTO req;
    private BrandEntity brand;
    private UsrUserEntity user;

    @BeforeEach
    void setUp() {
        req = new LoginReqDTO();
        req.setBrandNo("STD");
        req.setUsername("admin");
        req.setPassword("666666");

        brand = new BrandEntity();
        brand.setSId("b1");
        brand.setSNo("STD");
        brand.setSName("标准版");

        user = new UsrUserEntity();
        user.setSId("u1");
        user.setSUsername("admin");
        user.setSPasswordHash("$2a$10$hashed");
        user.setSUserType("普通用户");
        user.setSLanguage("中文");
        user.setBIsDisabled(0);
        user.setILoginFailCount(0);
        user.setTLockUntil(null);
    }

    @Test
    void login_brandNotFound_throws40100() {
        when(brandMapper.selectOne(any())).thenReturn(null);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40100, ex.getCode());
    }

    @Test
    void login_userNotFound_throws40100() {
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(null);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40100, ex.getCode());
    }

    @Test
    void login_accountDisabled_throws40101() {
        user.setBIsDisabled(1);
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(user);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40101, ex.getCode());
    }

    @Test
    void login_accountLocked_throws40102WithRemainingMinutes() {
        user.setTLockUntil(LocalDateTime.now().plusMinutes(20));
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(user);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40102, ex.getCode());
        assertTrue(ex.getMessage().contains("分钟"));
    }

    @Test
    void login_wrongPassword_firstTime_throws40100AndIncrementsCount() {
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(user);
        when(passwordEncoder.matches(anyString(), anyString())).thenReturn(false);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40100, ex.getCode());
        verify(userMapper).update(isNull(), any());
    }

    @Test
    void login_wrongPassword_5thTime_setsLockAndThrows40102() {
        user.setILoginFailCount(4);
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(user);
        when(passwordEncoder.matches(anyString(), anyString())).thenReturn(false);
        BizException ex = assertThrows(BizException.class, () -> authService.login(req));
        assertEquals(40102, ex.getCode());
        verify(userMapper).update(isNull(), any());
    }

    @Test
    void login_success_resetsCountAndReturnsTokens() {
        when(brandMapper.selectOne(any())).thenReturn(brand);
        when(userMapper.selectOne(any())).thenReturn(user);
        when(passwordEncoder.matches(anyString(), anyString())).thenReturn(true);
        when(jwtUtil.generateAccessToken(anyString(), anyString(), anyString(), anyString())).thenReturn("access-token");
        when(jwtUtil.generateRefreshToken(anyString(), anyString())).thenReturn("refresh-token");

        LoginVO result = authService.login(req);

        assertEquals("access-token", result.getAccessToken());
        assertEquals("refresh-token", result.getRefreshToken());
        assertEquals(86400L, result.getExpiresIn());
        assertNotNull(result.getUserInfo());
        assertEquals("u1", result.getUserInfo().getUserId());
        verify(userMapper).update(isNull(), any());
    }

    // ---- Task 6: refresh + getBrands tests ----

    @Test
    void refresh_validRefreshToken_returnsNewAccessToken() {
        Claims claims = mock(Claims.class);
        when(claims.getSubject()).thenReturn("u1");
        when(claims.get("brandId", String.class)).thenReturn("b1");
        when(jwtUtil.parseRefreshToken("valid-refresh")).thenReturn(claims);
        when(userMapper.selectOne(any())).thenReturn(user);
        when(jwtUtil.generateAccessToken(anyString(), anyString(), anyString(), anyString())).thenReturn("new-access-token");

        String newToken = authService.refresh("valid-refresh");
        assertEquals("new-access-token", newToken);
    }

    @Test
    void refresh_lockedUser_throws40103() {
        Claims claims = mock(Claims.class);
        when(claims.getSubject()).thenReturn("u1");
        when(claims.get("brandId", String.class)).thenReturn("b1");
        when(jwtUtil.parseRefreshToken("valid-refresh")).thenReturn(claims);
        user.setTLockUntil(LocalDateTime.now().plusMinutes(25));
        when(userMapper.selectOne(any())).thenReturn(user);

        BizException ex = assertThrows(BizException.class, () -> authService.refresh("valid-refresh"));
        assertEquals(40103, ex.getCode());
    }

    @Test
    void refresh_invalidRefreshToken_throws40103() {
        when(jwtUtil.parseRefreshToken("bad-token"))
                .thenThrow(new BizException(40103, "Refresh Token 已失效,请重新登录"));
        BizException ex = assertThrows(BizException.class, () -> authService.refresh("bad-token"));
        assertEquals(40103, ex.getCode());
    }

    @Test
    void getBrands_returnsListSortedByName() {
        BrandEntity b1 = new BrandEntity();
        b1.setSNo("STD"); b1.setSName("标准版");
        BrandEntity b2 = new BrandEntity();
        b2.setSNo("ENT"); b2.setSName("企业版");
        when(brandMapper.selectList(any())).thenReturn(List.of(b1, b2));

        List<BrandVO> result = authService.getBrands();
        assertEquals(2, result.size());
        assertEquals("标准版", result.get(0).getSName());
    }
}