格式修改

This commit is contained in:
2026-08-05 10:35:07 +08:00
parent 81c9c92f5d
commit 496fc58a90
241 changed files with 5600 additions and 2088 deletions
@@ -6,6 +6,8 @@ import com.baiyue.common.core.exception.BizException;
import com.baiyue.common.core.export.ExportContracts.ExportBatchRequest;
import com.baiyue.common.core.export.ExportContracts.ExportBatchResponse;
import com.baiyue.iam.service.CustomerListExportProviderService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -20,14 +22,15 @@ import java.security.MessageDigest;
@RestController
@RequestMapping("/internal/exports/v1/CUSTOMER_LIST")
public class CustomerListExportProviderController {
private final CustomerListExportProviderService service;
private final byte[] internalToken;
@Resource
private CustomerListExportProviderService service;
@Value("${baiyue.security.internal-service-token}")
private String internalTokenValue;
private byte[] internalToken;
public CustomerListExportProviderController(
CustomerListExportProviderService service,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this.service = service;
this.internalToken = internalToken.getBytes(StandardCharsets.UTF_8);
@PostConstruct
void initializeToken() {
this.internalToken = internalTokenValue.getBytes(StandardCharsets.UTF_8);
}
@PostMapping("/batches")
@@ -9,6 +9,7 @@ import com.baiyue.iam.service.TenantGuard;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
@@ -23,11 +24,8 @@ import org.springframework.web.bind.annotation.*;
@Validated
@Tag(name = "Platform user administration / 平台用户管理")
public class PlatformUserManagementController {
private final PlatformUserManagementService service;
public PlatformUserManagementController(PlatformUserManagementService service) {
this.service = service;
}
@Resource
private PlatformUserManagementService service;
@GetMapping
@PreAuthorize("hasAuthority('platform:user:list')")
@@ -3,6 +3,7 @@ package com.baiyue.iam.repository;
import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.mapper.IamTenantMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
@@ -11,11 +12,8 @@ import java.util.List;
/** Read-only customer queries used by the generic export provider. */
@Repository
public class CustomerListExportProviderRepository {
private final IamTenantMapper tenantMapper;
public CustomerListExportProviderRepository(IamTenantMapper tenantMapper) {
this.tenantMapper = tenantMapper;
}
@Resource
private IamTenantMapper tenantMapper;
public long maximumId(String keyword, String status) {
LambdaQueryWrapper<IamTenant> wrapper = filters(keyword, status)
@@ -8,6 +8,7 @@ import com.baiyue.iam.mapper.IamMembershipMapper;
import com.baiyue.iam.mapper.IamMembershipRoleMapper;
import com.baiyue.iam.mapper.IamUserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
@@ -18,16 +19,12 @@ import java.util.List;
/** 企业成员仓储,所有成员查询均显式携带租户条件。 */
@Repository
public class MemberRepository {
private final IamMembershipMapper membershipMapper;
private final IamUserMapper userMapper;
private final IamMembershipRoleMapper roleMapper;
public MemberRepository(IamMembershipMapper membershipMapper, IamUserMapper userMapper,
IamMembershipRoleMapper roleMapper) {
this.membershipMapper = membershipMapper;
this.userMapper = userMapper;
this.roleMapper = roleMapper;
}
@Resource
private IamMembershipMapper membershipMapper;
@Resource
private IamUserMapper userMapper;
@Resource
private IamMembershipRoleMapper roleMapper;
public List<IamMembership> findByTenant(long tenantId) {
return membershipMapper.selectList(new LambdaQueryWrapper<IamMembership>()
@@ -7,6 +7,7 @@ import com.baiyue.iam.mapper.IamTenantAddressMapper;
import com.baiyue.iam.mapper.IamTenantQualificationMapper;
import com.baiyue.iam.mapper.IamUserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import java.util.List;
@@ -16,16 +17,12 @@ import java.util.List;
*/
@Repository
public class ProfileResourceRepository {
private final IamUserMapper userMapper;
private final IamTenantAddressMapper addressMapper;
private final IamTenantQualificationMapper qualificationMapper;
public ProfileResourceRepository(IamUserMapper userMapper, IamTenantAddressMapper addressMapper,
IamTenantQualificationMapper qualificationMapper) {
this.userMapper = userMapper;
this.addressMapper = addressMapper;
this.qualificationMapper = qualificationMapper;
}
@Resource
private IamUserMapper userMapper;
@Resource
private IamTenantAddressMapper addressMapper;
@Resource
private IamTenantQualificationMapper qualificationMapper;
public IamUser findUserByAuthId(Long authUserId) { return userMapper.selectOne(new LambdaQueryWrapper<IamUser>().eq(IamUser::getAuthUserId, authUserId).last("LIMIT 1")); }
public void saveUser(IamUser user) { userMapper.updateById(user); }
@@ -3,6 +3,7 @@ package com.baiyue.iam.repository;
import com.baiyue.iam.entity.*;
import com.baiyue.iam.mapper.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
@@ -13,22 +14,16 @@ import java.util.Set;
/** RBAC 仓储,所有业务查询均显式携带租户和应用域。 */
@Repository
public class RbacRepository {
private final IamRoleMapper roleMapper;
private final IamPermissionMapper permissionMapper;
private final IamMembershipRoleMapper membershipRoleMapper;
private final IamRolePermissionMapper rolePermissionMapper;
private final IamDataScopeMapper dataScopeMapper;
public RbacRepository(IamRoleMapper roleMapper, IamPermissionMapper permissionMapper,
IamMembershipRoleMapper membershipRoleMapper,
IamRolePermissionMapper rolePermissionMapper,
IamDataScopeMapper dataScopeMapper) {
this.roleMapper = roleMapper;
this.permissionMapper = permissionMapper;
this.membershipRoleMapper = membershipRoleMapper;
this.rolePermissionMapper = rolePermissionMapper;
this.dataScopeMapper = dataScopeMapper;
}
@Resource
private IamRoleMapper roleMapper;
@Resource
private IamPermissionMapper permissionMapper;
@Resource
private IamMembershipRoleMapper membershipRoleMapper;
@Resource
private IamRolePermissionMapper rolePermissionMapper;
@Resource
private IamDataScopeMapper dataScopeMapper;
public IamRole findRole(Long id, long tenantId, String appCode) {
return roleMapper.selectOne(new LambdaQueryWrapper<IamRole>()
@@ -6,6 +6,7 @@ import com.baiyue.iam.entity.IamTenantReview;
import com.baiyue.iam.mapper.IamTenantMapper;
import com.baiyue.iam.mapper.IamTenantReviewMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
@@ -17,13 +18,10 @@ import java.util.List;
*/
@Repository
public class TenantRepository {
private final IamTenantMapper tenantMapper;
private final IamTenantReviewMapper reviewMapper;
public TenantRepository(IamTenantMapper tenantMapper, IamTenantReviewMapper reviewMapper) {
this.tenantMapper = tenantMapper;
this.reviewMapper = reviewMapper;
}
@Resource
private IamTenantMapper tenantMapper;
@Resource
private IamTenantReviewMapper reviewMapper;
public boolean existsByCreditCode(String creditCode) {
return tenantMapper.selectCount(new LambdaQueryWrapper<IamTenant>()
@@ -8,6 +8,8 @@ import com.baiyue.common.core.export.ExportContracts.ExportColumn;
import com.baiyue.common.core.export.ExportContracts.ExportColumnType;
import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.repository.CustomerListExportProviderRepository;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -54,13 +56,14 @@ public class CustomerListExportProviderService {
column("approvedAt", "审批时间", ExportColumnType.DATETIME, 21));
private static final String SCHEMA_HASH = schemaHash(COLUMNS);
private final CustomerListExportProviderRepository repository;
private final byte[] snapshotSigningKey;
@Resource
private CustomerListExportProviderRepository repository;
@Value("${baiyue.security.internal-service-token}")
private String internalServiceToken;
private byte[] snapshotSigningKey;
public CustomerListExportProviderService(
CustomerListExportProviderRepository repository,
@Value("${baiyue.security.internal-service-token}") String internalServiceToken) {
this.repository = repository;
@PostConstruct
void initializeSigningKey() {
this.snapshotSigningKey = internalServiceToken.getBytes(StandardCharsets.UTF_8);
}
@@ -13,6 +13,7 @@ import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import feign.FeignException;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -29,18 +30,14 @@ import org.slf4j.LoggerFactory;
public class MemberService {
private static final String GRANT_ROLE_PERMISSION = "merchant:member:grant-role";
private static final Logger log = LoggerFactory.getLogger(MemberService.class);
private final MemberRepository repository;
private final IamRoleMapper roleMapper;
private final AuthAccountClient authClient;
private final String internalToken;
public MemberService(MemberRepository repository, IamRoleMapper roleMapper, AuthAccountClient authClient,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this.repository = repository;
this.roleMapper = roleMapper;
this.authClient = authClient;
this.internalToken = internalToken;
}
@Resource
private MemberRepository repository;
@Resource
private IamRoleMapper roleMapper;
@Resource
private AuthAccountClient authClient;
@Value("${baiyue.security.internal-service-token}")
private String internalToken;
public List<MemberResponse> list(long tenantId) {
return repository.findByTenant(tenantId).stream().map(m -> response(tenantId, m)).toList();
@@ -7,6 +7,7 @@ import com.baiyue.iam.dto.ProfileDtos.UpdatePersonalProfileRequest;
import com.baiyue.iam.entity.IamMembership;
import com.baiyue.iam.entity.IamUser;
import com.baiyue.iam.repository.MemberRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baiyue.common.audit.BusinessAudit;
@@ -14,8 +15,8 @@ import com.baiyue.common.audit.BusinessAudit;
/** 当前用户个人资料服务,必须同时匹配认证账号与当前租户成员关系。 */
@Service
public class PersonalProfileService {
private final MemberRepository repository;
public PersonalProfileService(MemberRepository repository) { this.repository = repository; }
@Resource
private MemberRepository repository;
public PersonalProfileResponse get(long tenantId, Long authUserId, String username) {
return response(tenantId, authUserId, username);
@@ -13,6 +13,7 @@ import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import feign.FeignException;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@@ -31,19 +32,14 @@ public class PlatformInternalUserService {
private static final long PLATFORM_TENANT_ID = 0L;
private static final Logger log = LoggerFactory.getLogger(PlatformInternalUserService.class);
private final MemberRepository repository;
private final IamRoleMapper roleMapper;
private final AuthAccountClient authClient;
private final String internalToken;
public PlatformInternalUserService(MemberRepository repository, IamRoleMapper roleMapper,
AuthAccountClient authClient,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this.repository = repository;
this.roleMapper = roleMapper;
this.authClient = authClient;
this.internalToken = internalToken;
}
@Resource
private MemberRepository repository;
@Resource
private IamRoleMapper roleMapper;
@Resource
private AuthAccountClient authClient;
@Value("${baiyue.security.internal-service-token}")
private String internalToken;
@Transactional(readOnly = true)
public List<InternalUserResponse> list() {
@@ -15,6 +15,7 @@ import com.baiyue.iam.repository.MemberRepository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import feign.FeignException;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@@ -36,19 +37,14 @@ public class PlatformUserManagementService {
private static final long PLATFORM_TENANT_ID = 0L;
private static final Logger log = LoggerFactory.getLogger(PlatformUserManagementService.class);
private final MemberRepository members;
private final IamRoleMapper roleMapper;
private final AuthAccountClient authClient;
private final String internalToken;
public PlatformUserManagementService(MemberRepository members, IamRoleMapper roleMapper,
AuthAccountClient authClient,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this.members = members;
this.roleMapper = roleMapper;
this.authClient = authClient;
this.internalToken = internalToken;
}
@Resource
private MemberRepository members;
@Resource
private IamRoleMapper roleMapper;
@Resource
private AuthAccountClient authClient;
@Value("${baiyue.security.internal-service-token}")
private String internalToken;
@Transactional(readOnly = true)
public PageResult<UserResponse> page(long page, long size, String keyword, String status) {
@@ -13,9 +13,9 @@ import com.baiyue.iam.repository.MemberRepository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import feign.FeignException;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
@@ -37,28 +37,15 @@ public class TenantAdministratorProvisioningService implements TenantApprovalIni
private static final int USERNAME_SUFFIX_LENGTH = 8;
private static final int USERNAME_ATTEMPTS = 3;
private final MemberRepository members;
private final IamRoleMapper roles;
private final AuthAccountClient authClient;
private final String internalToken;
private final SecureRandom random;
@Autowired
public TenantAdministratorProvisioningService(MemberRepository members, IamRoleMapper roles,
AuthAccountClient authClient,
@Value("${baiyue.security.internal-service-token}") String internalToken) {
this(members, roles, authClient, internalToken, new SecureRandom());
}
TenantAdministratorProvisioningService(MemberRepository members, IamRoleMapper roles,
AuthAccountClient authClient, String internalToken,
SecureRandom random) {
this.members = members;
this.roles = roles;
this.authClient = authClient;
this.internalToken = internalToken;
this.random = random;
}
@Resource
private MemberRepository members;
@Resource
private IamRoleMapper roles;
@Resource
private AuthAccountClient authClient;
@Value("${baiyue.security.internal-service-token}")
private String internalToken;
private SecureRandom random = new SecureRandom();
@Override
public String name() { return "tenant-administrator"; }
@@ -8,6 +8,8 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
@@ -21,9 +23,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
@Service
public class TenantApprovalInitializationCoordinator {
private static final Logger log = LoggerFactory.getLogger(TenantApprovalInitializationCoordinator.class);
private final List<TenantApprovalInitializer> initializers;
@Resource
private List<TenantApprovalInitializer> initializers;
public TenantApprovalInitializationCoordinator(List<TenantApprovalInitializer> initializers) {
@PostConstruct
void initialize() {
List<TenantApprovalInitializer> ordered = new ArrayList<>(initializers);
AnnotationAwareOrderComparator.sort(ordered);
Set<String> names = new HashSet<>();
+1 -1
View File
@@ -38,6 +38,6 @@ logging:
rollingpolicy:
file-name-pattern: "${LOGGING_ROLLING_FILE_NAME_PATTERN:${LOG_PATH:./logs}/${spring.application.name}.%d{yyyy-MM-dd}.%i.log.gz}"
max-file-size: "${LOGGING_ROLLING_MAX_FILE_SIZE:100MB}"
max-history: "${LOGGING_ROLLING_MAX_HISTORY:30}"
max-history: "${LOGGING_ROLLING_MAX_HISTORY:7}"
total-size-cap: "${LOGGING_ROLLING_TOTAL_SIZE_CAP:5GB}"
clean-history-on-start: "${LOGGING_ROLLING_CLEAN_HISTORY_ON_START:false}"
@@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
class AuthorizationControllerContractTest {
@Test
void 当前权限接口不应依赖角色管理权限() throws Exception {
void shouldHandleCase01() throws Exception {
Method method = AuthorizationController.class.getMethod("permissions", String.class,
AuthenticatedUser.class);
@@ -6,6 +6,10 @@ import com.baiyue.common.core.export.ExportContracts.ExportBatchRequest;
import com.baiyue.common.core.export.ExportContracts.ExportBatchResponse;
import com.baiyue.iam.service.CustomerListExportProviderService;
import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -18,7 +22,11 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(CustomerListExportProviderController.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class CustomerListExportProviderControllerTest {
@MockBean private CustomerListExportProviderService service;
@Resource private CustomerListExportProviderController controller;
@Test
void exposesTheGenericCustomerListProviderPath() throws Exception {
assertEquals("/internal/exports/v1/CUSTOMER_LIST",
@@ -30,9 +38,6 @@ class CustomerListExportProviderControllerTest {
@Test
void requiresInternalTokenBeforeCallingProvider() {
CustomerListExportProviderService service = mock(CustomerListExportProviderService.class);
CustomerListExportProviderController controller =
new CustomerListExportProviderController(service, "internal-token");
ExportBatchRequest request = request();
BizException missing = assertThrows(BizException.class, () -> controller.batch(null, request));
@@ -11,7 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class IamOpenApiContractTest {
@Test
void OpenApi应声明权限分页和内部用户的真实响应结构() throws IOException {
void shouldHandleCase01() throws IOException {
String document;
try (var stream = getClass().getResourceAsStream("/openapi/iam-v1.yaml")) {
assertThat(stream).isNotNull();
@@ -7,26 +7,28 @@ import com.baiyue.iam.service.MerchantOnboardingService;
import com.baiyue.iam.service.ProfileResourceService;
import com.baiyue.iam.service.TenantService;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(InternalTenantController.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class InternalCustomerExportContractTest {
@MockBean private MerchantOnboardingService onboardingService;
@MockBean private ProfileResourceService profileResourceService;
@MockBean private TenantService service;
@Resource private InternalTenantController controller;
@Test
void rejectsMissingInternalTokenAndAcceptsConfiguredToken() {
TenantService service = mock(TenantService.class);
InternalTenantController controller = new InternalTenantController();
ReflectionTestUtils.setField(controller, "onboardingService", mock(MerchantOnboardingService.class));
ReflectionTestUtils.setField(controller, "profileResourceService", mock(ProfileResourceService.class));
ReflectionTestUtils.setField(controller, "tenantService", service);
ReflectionTestUtils.setField(controller, "internalTokenValue", "internal-token");
controller.initializeToken();
BizException denied = assertThrows(BizException.class,
() -> controller.exportCustomers(null, null, 100, null, null));
@@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
class PlatformCustomerResourceContractTest {
@Test
void 平台地址和资质只读查询统一使用客户查看权限() throws Exception {
void shouldHandleCase01() throws Exception {
assertReadOnlyViewContract("platformAddresses",
"/api/platform/v1/iam/tenants/{tenantId}/addresses");
assertReadOnlyViewContract("platformQualifications",
@@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.*;
class PlatformInternalUserContractTest {
@Test
void 内部用户列表必须校验列表权限() throws Exception {
void shouldHandleCase01() throws Exception {
Method method = ProfileResourceController.class.getMethod("internalUsers",
com.baiyue.common.security.AuthenticatedUser.class);
@@ -24,7 +24,7 @@ class PlatformInternalUserContractTest {
}
@Test
void 平台用户写接口以成员关系主键寻址() {
void shouldHandleCase02() {
assertMapping("updateInternalUser", "/api/platform/v1/iam/internal-users/{membershipId:\\d+}");
assertMapping("changeInternalUserStatus",
"/api/platform/v1/iam/internal-users/{membershipId:\\d+}/status");
@@ -21,7 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
class PlatformTenantControllerContractTest {
@Test
void 客户分页接口声明权限分页约束和错误状态() throws Exception {
void shouldHandleCase01() throws Exception {
Method method = PlatformTenantController.class.getMethod("page", long.class, long.class,
String.class, String.class, AuthenticatedUser.class);
@@ -41,7 +41,7 @@ class PlatformTenantControllerContractTest {
}
@Test
void 待审列表必须校验客户审核权限() throws Exception {
void shouldHandleCase02() throws Exception {
Method method = PlatformTenantController.class.getMethod("reviews", AuthenticatedUser.class);
assertEquals("hasAuthority('platform:customer:review')",
@@ -49,7 +49,7 @@ class PlatformTenantControllerContractTest {
}
@Test
void 客户详情必须使用独立查看权限() throws Exception {
void shouldHandleCase03() throws Exception {
Method method = PlatformTenantController.class.getMethod("tenant", long.class, AuthenticatedUser.class);
assertEquals("hasAuthority('platform:customer:view')",
@@ -57,7 +57,7 @@ class PlatformTenantControllerContractTest {
}
@Test
void 审核通过接口返回一次性管理员凭据结果() throws Exception {
void shouldHandleCase04() throws Exception {
Method method = PlatformTenantController.class.getMethod("approve", long.class,
com.baiyue.iam.dto.TenantDtos.ReviewRequest.class, AuthenticatedUser.class);
@@ -9,6 +9,9 @@ import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.junit.jupiter.api.Test;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.mockito.ArgumentCaptor;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
@@ -18,15 +21,15 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(CustomerListExportProviderRepository.class)
class CustomerListExportProviderRepositoryTest {
@MockBean private IamTenantMapper mapper;
@Resource private CustomerListExportProviderRepository repository;
@Test
void batchQueryAlwaysConstrainsMerchantSnapshotAndAscendingCursor() {
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "test"),
IamTenant.class);
IamTenantMapper mapper = mock(IamTenantMapper.class);
when(mapper.selectList(any())).thenReturn(List.of());
CustomerListExportProviderRepository repository =
new CustomerListExportProviderRepository(mapper);
repository.findBatch(100L, 200L, 501, "柏悦", "ACTIVE");
@@ -11,7 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class CustomerProfileMigrationContractTest {
@Test
void 企业审核初始化按角色自然键为全局管理员模板授权() throws IOException {
void shouldHandleCase01() throws IOException {
String sql;
try (var stream = getClass().getResourceAsStream("/db/phase1-onboarding.sql")) {
assertThat(stream).isNotNull();
@@ -26,7 +26,7 @@ class CustomerProfileMigrationContractTest {
}
@Test
void 客户档案迁移覆盖全部字段并通过元数据判断保持可重复执行() throws IOException {
void shouldHandleCase02() throws IOException {
String sql;
try (var stream = getClass().getResourceAsStream("/db/phase1-customer-profile.sql")) {
assertThat(stream).isNotNull();
@@ -49,7 +49,7 @@ class CustomerProfileMigrationContractTest {
}
@Test
void 统一测试环境入口包含客户字段查看权限和执行后核验() throws IOException {
void shouldHandleCase03() throws IOException {
Path repositoryRoot = Path.of(System.getProperty("maven.multiModuleProjectDirectory", ".."));
Path migration = repositoryRoot.resolve("deploy/sql/2026-07-31一期回归测试环境增量迁移.sql");
Path readme = repositoryRoot.resolve("deploy/sql/README.md");
@@ -85,8 +85,8 @@ class CustomerProfileMigrationContractTest {
.contains("phase1-platform-master-data-and-permission-management.sql")
.contains("phase1-customer-profile.sql")
.contains("phase1-onboarding.sql")
.contains("IAM 注册审核字段")
.contains("`PROFILE_REQUIRED` 默认状态、审核结果字段、资质审核备注及成员审计字段")
.contains("全局 `MERCHANT_OWNER` 角色模板")
.contains("测试环境只执行统一入口");
.contains("测试环境只执行当前固定入口");
}
}
@@ -6,27 +6,31 @@ import com.baiyue.iam.dto.AuthorizationDtos.SnapshotRequest;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.iam.mapper.AuthorizationQueryMapper;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(AuthorizationSnapshotService.class)
class AuthorizationSnapshotServiceTest {
@MockBean private AuthorizationQueryMapper mapper;
@Resource private AuthorizationSnapshotService service;
@Test
void loadsRolesAndPermissionsForActiveMerchantIdentity() {
AuthorizationQueryMapper mapper = mock(AuthorizationQueryMapper.class);
when(mapper.countActiveIdentity(42L, 7L, 9L)).thenReturn(1);
when(mapper.findRoles(42L, 7L, 9L, "MERCHANT"))
.thenReturn(List.of("ADMIN", "OPERATOR"));
when(mapper.findPermissions(42L, 7L, 9L, "MERCHANT"))
.thenReturn(List.of("order:read", "order:create"));
var result = service(mapper)
var result = service
.load(new SnapshotRequest(42L, 7L, 9L, "merchant"));
assertThat(result.getAppCode()).isEqualTo("MERCHANT");
@@ -37,9 +41,7 @@ class AuthorizationSnapshotServiceTest {
@Test
void rejectsPlatformIdentityOutsidePlatformTenant() {
AuthorizationQueryMapper mapper = mock(AuthorizationQueryMapper.class);
assertThatThrownBy(() -> service(mapper)
assertThatThrownBy(() -> service
.load(new SnapshotRequest(42L, 7L, 9L, "PLATFORM")))
.isInstanceOfSatisfying(BizException.class,
exception -> assertThat(exception.getResultCode()).isEqualTo(ResultCode.FORBIDDEN));
@@ -47,10 +49,9 @@ class AuthorizationSnapshotServiceTest {
@Test
void rejectsInactiveMembership() {
AuthorizationQueryMapper mapper = mock(AuthorizationQueryMapper.class);
when(mapper.countActiveIdentity(42L, 7L, 9L)).thenReturn(0);
assertThatThrownBy(() -> service(mapper)
assertThatThrownBy(() -> service
.load(new SnapshotRequest(42L, 7L, 9L, "MERCHANT")))
.isInstanceOfSatisfying(BizException.class,
exception -> assertThat(exception.getResultCode()).isEqualTo(ResultCode.FORBIDDEN));
@@ -59,13 +60,12 @@ class AuthorizationSnapshotServiceTest {
@Test
void loadsCurrentPlatformPermissionsWithoutRoleManagementPermission() {
AuthorizationQueryMapper mapper = mock(AuthorizationQueryMapper.class);
when(mapper.countActiveIdentity(42L, 0L, 9L)).thenReturn(1);
when(mapper.findRoles(42L, 0L, 9L, "PLATFORM")).thenReturn(List.of("ORDER_OPERATOR"));
when(mapper.findPermissions(42L, 0L, 9L, "PLATFORM"))
.thenReturn(List.of("platform:order:list"));
var result = service(mapper).currentPermissions(new AuthenticatedUser(42L, 0L, 0L, 9L,
var result = service.currentPermissions(new AuthenticatedUser(42L, 0L, 0L, 9L,
"operator", "PLATFORM", "PLATFORM", java.util.Set.of()), "PLATFORM");
assertThat(result).containsExactly("platform:order:list");
@@ -74,7 +74,7 @@ class AuthorizationSnapshotServiceTest {
@Test
void rejectsIncompleteCurrentIdentityAsBusinessError() {
assertThatThrownBy(() -> service(mock(AuthorizationQueryMapper.class))
assertThatThrownBy(() -> service
.currentPermissions(new AuthenticatedUser(42L, 0L, 0L, null,
"operator", "PLATFORM", "PLATFORM", java.util.Set.of()), "PLATFORM"))
.isInstanceOfSatisfying(BizException.class,
@@ -82,21 +82,15 @@ class AuthorizationSnapshotServiceTest {
}
@Test
void 空角色和权限查询结果不应触发五百错误() {
AuthorizationQueryMapper mapper = mock(AuthorizationQueryMapper.class);
void shouldHandleCase01() {
when(mapper.countActiveIdentity(42L, 0L, 9L)).thenReturn(1);
when(mapper.findRoles(42L, 0L, 9L, "PLATFORM")).thenReturn(null);
when(mapper.findPermissions(42L, 0L, 9L, "PLATFORM")).thenReturn(null);
var result = service(mapper).currentPermissions(new AuthenticatedUser(42L, 0L, 0L, 9L,
var result = service.currentPermissions(new AuthenticatedUser(42L, 0L, 0L, 9L,
"operator", "PLATFORM", "PLATFORM", java.util.Set.of()), "PLATFORM");
assertThat(result).isEmpty();
}
private AuthorizationSnapshotService service(AuthorizationQueryMapper mapper) {
AuthorizationSnapshotService service = new AuthorizationSnapshotService();
ReflectionTestUtils.setField(service, "mapper", mapper);
return service;
}
}
@@ -8,6 +8,10 @@ import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.repository.CustomerListExportProviderRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -23,15 +27,14 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(CustomerListExportProviderService.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=test-internal-service-token-at-least-32-bytes")
class CustomerListExportProviderServiceTest {
private CustomerListExportProviderRepository repository;
private CustomerListExportProviderService service;
@MockBean private CustomerListExportProviderRepository repository;
@Resource private CustomerListExportProviderService service;
@BeforeEach
void setUp() {
repository = mock(CustomerListExportProviderRepository.class);
service = new CustomerListExportProviderService(repository,
"test-internal-service-token-at-least-32-bytes");
}
@Test
@@ -12,6 +12,10 @@ import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
import java.util.Set;
@@ -20,11 +24,13 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
@SpringJUnitConfig(MemberService.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class MemberServiceTest {
private final MemberRepository repository = mock(MemberRepository.class);
private final IamRoleMapper roleMapper = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final MemberService service = new MemberService(repository, roleMapper, auth, "internal-token");
@MockBean private MemberRepository repository;
@MockBean private IamRoleMapper roleMapper;
@MockBean private AuthAccountClient auth;
@Resource private MemberService service;
private IamMembership member;
private IamUser user;
@@ -37,7 +43,7 @@ class MemberServiceTest {
when(repository.findRoleIds(100L, 20L)).thenReturn(List.of(50L));
}
@Test void 成员详情返回联系方式和已有角色() {
@Test void shouldHandleCase01() {
user.setPhone("13800138000"); user.setEmail("member@example.com");
MemberResponse result = service.detail(100L, 20L);
assertEquals("测试成员", result.displayName());
@@ -46,12 +52,12 @@ class MemberServiceTest {
verifyNoInteractions(auth);
}
@Test void 跨租户查询被拒绝() {
@Test void shouldHandleCase02() {
when(repository.findByTenantAndId(200L, 20L)).thenReturn(null);
assertThrows(BizException.class, () -> service.detail(200L, 20L));
}
@Test void 企业所有者不可停用() {
@Test void shouldHandleCase03() {
member.setMemberType("OWNER");
BizException exception = assertThrows(BizException.class, () -> service.changeStatus(100L, 20L,
new ChangeMemberStatusRequest("DISABLED"), 20L));
@@ -59,7 +65,7 @@ class MemberServiceTest {
verify(auth, never()).status(anyString(), anyLong(), any());
}
@Test void 停用成员同步认证账号并保存本地状态() {
@Test void shouldHandleCase04() {
when(auth.status(anyString(), eq(40L), any())).thenReturn(ApiResponse.success(null));
MemberResponse result = service.changeStatus(100L, 20L,
new ChangeMemberStatusRequest("DISABLED"), 99L);
@@ -68,14 +74,14 @@ class MemberServiceTest {
verify(repository).saveUser(user);
}
@Test void 认证服务失败时不得写入本地状态() {
@Test void shouldHandleCase05() {
when(auth.status(anyString(), eq(40L), any())).thenThrow(new RuntimeException("网络失败"));
assertThrows(RuntimeException.class, () -> service.changeStatus(100L, 20L,
new ChangeMemberStatusRequest("DISABLED"), 99L));
verify(repository, never()).save(member);
}
@Test void 企业所有者不能通过成员编辑接口降级或变更角色() {
@Test void shouldHandleCase06() {
member.setMemberType("OWNER");
UpdateMemberRequest request = new UpdateMemberRequest("所有者", null, null,
"EMPLOYEE", null, List.of());
@@ -85,7 +91,7 @@ class MemberServiceTest {
verify(repository, never()).replaceRoles(anyLong(), anyLong(), anyList());
}
@Test void 新增成员携带非空角色但无授权权限时返回403且不创建账号() {
@Test void shouldHandleCase07() {
CreateMemberRequest request = new CreateMemberRequest("member01", "Password1", "成员",
null, null, "EMPLOYEE", null, List.of(50L));
@@ -97,7 +103,7 @@ class MemberServiceTest {
verify(repository, never()).insert(any());
}
@Test void 编辑资料且角色集合未变化时不要求角色授权权限() {
@Test void shouldHandleCase08() {
IamRole role = activeMerchantRole(50L, 100L);
when(roleMapper.selectById(50L)).thenReturn(role);
UpdateMemberRequest request = new UpdateMemberRequest("新姓名", "13800138000", null,
@@ -110,7 +116,7 @@ class MemberServiceTest {
verify(repository).replaceRoles(100L, 20L, List.of(50L));
}
@Test void 编辑成员变更角色但无授权权限时返回403() {
@Test void shouldHandleCase09() {
UpdateMemberRequest request = new UpdateMemberRequest("测试成员", null, null,
"EMPLOYEE", null, List.of(60L));
@@ -122,7 +128,7 @@ class MemberServiceTest {
verify(repository, never()).replaceRoles(anyLong(), anyLong(), anyList());
}
@Test void 空集合清空已有角色同样要求角色授权权限() {
@Test void shouldHandleCase10() {
UpdateMemberRequest request = new UpdateMemberRequest("测试成员", null, null,
"EMPLOYEE", null, List.of());
@@ -133,7 +139,7 @@ class MemberServiceTest {
verify(repository, never()).replaceRoles(anyLong(), anyLong(), anyList());
}
@Test void 具有角色授权权限时允许清空已有角色() {
@Test void shouldHandleCase11() {
UpdateMemberRequest request = new UpdateMemberRequest("测试成员", null, null,
"EMPLOYEE", null, List.of());
@@ -143,7 +149,7 @@ class MemberServiceTest {
verify(repository).replaceRoles(100L, 20L, List.of());
}
@Test void 跨租户编辑先按目标租户查成员并返回404() {
@Test void shouldHandleCase12() {
when(repository.findByTenantAndId(200L, 20L)).thenReturn(null);
UpdateMemberRequest request = new UpdateMemberRequest("测试成员", null, null,
"EMPLOYEE", null, List.of(50L));
@@ -162,7 +168,7 @@ class MemberServiceTest {
return role;
}
@Test void 企业所有者密码不能被成员管理员重置() {
@Test void shouldHandleCase13() {
member.setMemberType("OWNER");
assertThrows(BizException.class, () -> service.resetPassword(100L, 20L,
@@ -16,37 +16,32 @@ import com.baiyue.iam.mapper.IamTenantReviewMapper;
import com.baiyue.iam.mapper.IamUserMapper;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(MerchantOnboardingService.class)
class MerchantOnboardingServiceTest {
@MockBean private IamTenantMapper tenants;
@MockBean private IamUserMapper users;
@MockBean private IamMembershipMapper memberships;
@MockBean private IamRoleMapper roles;
@MockBean private IamMembershipRoleMapper membershipRoles;
@MockBean private IamTenantAddressMapper addresses;
@MockBean private IamTenantQualificationMapper qualifications;
@MockBean private IamTenantReviewMapper reviews;
@Resource private MerchantOnboardingService service;
@Test
void clientRegistrationCreatesOwnerAndAssignsGlobalMerchantOwnerRole() {
IamTenantMapper tenants = mock(IamTenantMapper.class);
IamUserMapper users = mock(IamUserMapper.class);
IamMembershipMapper memberships = mock(IamMembershipMapper.class);
IamRoleMapper roles = mock(IamRoleMapper.class);
IamMembershipRoleMapper membershipRoles = mock(IamMembershipRoleMapper.class);
IamTenantAddressMapper addresses = mock(IamTenantAddressMapper.class);
IamTenantQualificationMapper qualifications = mock(IamTenantQualificationMapper.class);
IamTenantReviewMapper reviews = mock(IamTenantReviewMapper.class);
MerchantOnboardingService service = new MerchantOnboardingService();
ReflectionTestUtils.setField(service, "tenantMapper", tenants);
ReflectionTestUtils.setField(service, "userMapper", users);
ReflectionTestUtils.setField(service, "membershipMapper", memberships);
ReflectionTestUtils.setField(service, "roleMapper", roles);
ReflectionTestUtils.setField(service, "membershipRoleMapper", membershipRoles);
ReflectionTestUtils.setField(service, "addressMapper", addresses);
ReflectionTestUtils.setField(service, "qualificationMapper", qualifications);
ReflectionTestUtils.setField(service, "reviewMapper", reviews);
IamRole ownerRole = new IamRole();
ownerRole.setId(4000100L);
@@ -89,23 +84,6 @@ class MerchantOnboardingServiceTest {
@Test
void compensationRemovesOnlyAnUnstartedRegistration() {
IamTenantMapper tenants = mock(IamTenantMapper.class);
IamUserMapper users = mock(IamUserMapper.class);
IamMembershipMapper memberships = mock(IamMembershipMapper.class);
IamRoleMapper roles = mock(IamRoleMapper.class);
IamMembershipRoleMapper membershipRoles = mock(IamMembershipRoleMapper.class);
IamTenantAddressMapper addresses = mock(IamTenantAddressMapper.class);
IamTenantQualificationMapper qualifications = mock(IamTenantQualificationMapper.class);
IamTenantReviewMapper reviews = mock(IamTenantReviewMapper.class);
MerchantOnboardingService service = new MerchantOnboardingService();
ReflectionTestUtils.setField(service, "tenantMapper", tenants);
ReflectionTestUtils.setField(service, "userMapper", users);
ReflectionTestUtils.setField(service, "membershipMapper", memberships);
ReflectionTestUtils.setField(service, "roleMapper", roles);
ReflectionTestUtils.setField(service, "membershipRoleMapper", membershipRoles);
ReflectionTestUtils.setField(service, "addressMapper", addresses);
ReflectionTestUtils.setField(service, "qualificationMapper", qualifications);
ReflectionTestUtils.setField(service, "reviewMapper", reviews);
IamUser user = new IamUser();
user.setId(20001L);
@@ -135,23 +113,6 @@ class MerchantOnboardingServiceTest {
@Test
void compensationRefusesAfterQualificationUpload() {
IamTenantMapper tenants = mock(IamTenantMapper.class);
IamUserMapper users = mock(IamUserMapper.class);
IamMembershipMapper memberships = mock(IamMembershipMapper.class);
IamRoleMapper roles = mock(IamRoleMapper.class);
IamMembershipRoleMapper membershipRoles = mock(IamMembershipRoleMapper.class);
IamTenantAddressMapper addresses = mock(IamTenantAddressMapper.class);
IamTenantQualificationMapper qualifications = mock(IamTenantQualificationMapper.class);
IamTenantReviewMapper reviews = mock(IamTenantReviewMapper.class);
MerchantOnboardingService service = new MerchantOnboardingService();
ReflectionTestUtils.setField(service, "tenantMapper", tenants);
ReflectionTestUtils.setField(service, "userMapper", users);
ReflectionTestUtils.setField(service, "membershipMapper", memberships);
ReflectionTestUtils.setField(service, "roleMapper", roles);
ReflectionTestUtils.setField(service, "membershipRoleMapper", membershipRoles);
ReflectionTestUtils.setField(service, "addressMapper", addresses);
ReflectionTestUtils.setField(service, "qualificationMapper", qualifications);
ReflectionTestUtils.setField(service, "reviewMapper", reviews);
IamUser user = new IamUser();
user.setId(20001L);
@@ -6,7 +6,10 @@ import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.repository.ProfileResourceRepository;
import com.baiyue.iam.repository.TenantRepository;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
@@ -15,22 +18,20 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.times;
import com.baiyue.common.core.exception.BizException;
@SpringJUnitConfig(ProfileResourceService.class)
class MerchantQualificationUploadTest {
@MockBean private TenantRepository tenantRepository;
@MockBean private ProfileResourceRepository profileRepository;
@Resource private ProfileResourceService service;
@Test
void uploadsOneOptionalDraftQualificationWithoutCreatingAReview() {
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
ReflectionTestUtils.setField(service, "repository", profileRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
tenant.setTenantType("MERCHANT");
@@ -50,11 +51,6 @@ class MerchantQualificationUploadTest {
@Test
void requiredQualificationsRejectTheLegacySingleFilePath() {
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
ReflectionTestUtils.setField(service, "repository", profileRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
tenant.setTenantType("MERCHANT");
@@ -69,11 +65,6 @@ class MerchantQualificationUploadTest {
@Test
void requiredPackagePersistsBothFilesAndCreditCodeTogether() {
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
ReflectionTestUtils.setField(service, "repository", profileRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
tenant.setTenantType("MERCHANT");
@@ -94,11 +85,6 @@ class MerchantQualificationUploadTest {
@Test
void requiredPackageCannotOverwriteAnEstablishedCreditCode() {
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
ReflectionTestUtils.setField(service, "repository", profileRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
tenant.setTenantType("MERCHANT");
@@ -7,14 +7,18 @@ import com.baiyue.iam.entity.IamUser;
import com.baiyue.iam.repository.MemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@DisplayName("个人资料服务")
@SpringJUnitConfig(PersonalProfileService.class)
class PersonalProfileServiceTest {
private final MemberRepository repository = mock(MemberRepository.class);
private final PersonalProfileService service = new PersonalProfileService(repository);
@MockBean private MemberRepository repository;
@Resource private PersonalProfileService service;
@Test void canOnlyModifyOwnProfileWithinCurrentTenant() {
IamMembership membership = new IamMembership(); membership.setUserId(3L); membership.setStatus("ACTIVE");
@@ -12,6 +12,10 @@ import com.baiyue.iam.repository.MemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.List;
@@ -19,12 +23,13 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
@SpringJUnitConfig(PlatformInternalUserService.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class PlatformInternalUserServiceTest {
private final MemberRepository repository = mock(MemberRepository.class);
private final IamRoleMapper roleMapper = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final PlatformInternalUserService service =
new PlatformInternalUserService(repository, roleMapper, auth, "internal-token");
@MockBean private MemberRepository repository;
@MockBean private IamRoleMapper roleMapper;
@MockBean private AuthAccountClient auth;
@Resource private PlatformInternalUserService service;
private IamMembership membership;
private IamUser user;
@@ -45,7 +50,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 列表返回成员主键联系方式和当前角色() {
void shouldHandleCase01() {
when(repository.findByTenant(0L)).thenReturn(List.of(membership));
InternalUserResponse result = service.list().get(0);
@@ -57,7 +62,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 新建平台用户在Auth创建平台账号并写入IAM成员() {
void shouldHandleCase02() {
IamRole role = new IamRole();
role.setId(40L); role.setTenantId(0L); role.setAppCode("PLATFORM"); role.setStatus("ACTIVE");
when(roleMapper.selectById(40L)).thenReturn(role);
@@ -81,7 +86,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 本地创建失败会补偿认证账号且不记录密码() {
void shouldHandleCase03() {
when(auth.create(anyString(), any())).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(99L, "new.operator", "新运营", "ACTIVE")));
when(auth.compensate(anyString(), anyLong())).thenReturn(ApiResponse.success(null));
@@ -95,7 +100,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 不能停用当前登录的平台成员() {
void shouldHandleCase04() {
assertThrows(BizException.class, () -> service.changeStatus(30L,
new ChangeInternalUserStatusRequest("DISABLED"), 30L));
@@ -103,7 +108,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 状态本地写入失败时恢复Auth且成功后不再远程查询() {
void shouldHandleCase05() {
when(auth.status(anyString(), eq(10L), any())).thenReturn(ApiResponse.success(null));
doThrow(new RuntimeException("IAM 写入失败")).when(repository).saveUser(user);
@@ -118,7 +123,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 状态补偿应恢复Auth原状态而不是IAM旧状态() {
void shouldHandleCase06() {
when(auth.summary("internal-token", 10L)).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(10L, "operator", "平台运营", "DISABLED")));
when(auth.status(anyString(), eq(10L), any())).thenReturn(ApiResponse.success(null));
@@ -134,7 +139,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 重置密码只转交Auth不写入IAM() {
void shouldHandleCase07() {
when(auth.reset(anyString(), eq(10L), any())).thenReturn(ApiResponse.success(null));
service.resetPassword(30L, new ResetInternalUserPasswordRequest("ResetPass1"));
@@ -145,7 +150,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 角色分配只接受平台已启用角色并返回最新回显() {
void shouldHandleCase08() {
IamRole role = new IamRole();
role.setId(41L); role.setTenantId(0L); role.setAppCode("PLATFORM"); role.setStatus("ACTIVE");
when(roleMapper.selectById(41L)).thenReturn(role);
@@ -158,7 +163,7 @@ class PlatformInternalUserServiceTest {
}
@Test
void 禁止给平台用户分配商户角色() {
void shouldHandleCase09() {
IamRole merchantRole = new IamRole();
merchantRole.setId(42L); merchantRole.setTenantId(10001L);
merchantRole.setAppCode("MERCHANT"); merchantRole.setStatus("ACTIVE");
@@ -7,26 +7,27 @@ import com.baiyue.iam.repository.ProfileResourceRepository;
import com.baiyue.iam.repository.TenantRepository;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(ProfileResourceService.class)
class PlatformQualificationRegistrationTest {
@MockBean private ProfileResourceRepository repository;
@MockBean private TenantRepository tenantRepository;
@Resource private ProfileResourceService service;
@Test
void platformUploadRegistersOptionalMetadataWithoutCreatingReviewTicket() {
ProfileResourceRepository repository = mock(ProfileResourceRepository.class);
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L); tenant.setTenantType("MERCHANT"); tenant.setStatus("PROFILE_REQUIRED");
when(tenantRepository.findTenantForUpdate(10001L)).thenReturn(tenant);
@@ -48,11 +49,6 @@ class PlatformQualificationRegistrationTest {
@Test
void platformCanReplaceAnUploadedQualificationBeforeReview() {
ProfileResourceRepository repository = mock(ProfileResourceRepository.class);
TenantRepository tenantRepository = mock(TenantRepository.class);
ProfileResourceService service = new ProfileResourceService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "tenantRepository", tenantRepository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L); tenant.setTenantType("MERCHANT"); tenant.setStatus("PROFILE_REQUIRED");
IamTenantQualification existing = new IamTenantQualification();
@@ -12,6 +12,10 @@ import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.time.LocalDateTime;
import java.util.List;
@@ -21,12 +25,13 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
@SpringJUnitConfig(PlatformUserManagementService.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class PlatformUserManagementServiceTest {
private final MemberRepository members = mock(MemberRepository.class);
private final IamRoleMapper roles = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final PlatformUserManagementService service =
new PlatformUserManagementService(members, roles, auth, "internal-token");
@MockBean private MemberRepository members;
@MockBean private IamRoleMapper roles;
@MockBean private AuthAccountClient auth;
@Resource private PlatformUserManagementService service;
private IamRole platformRole;
private IamMembership membership;
private IamUser user;
@@ -15,13 +15,12 @@ import com.baiyue.iam.entity.IamPermission;
import com.baiyue.iam.entity.IamRole;
import com.baiyue.iam.repository.MemberRepository;
import com.baiyue.iam.repository.RbacRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Set;
@@ -30,21 +29,14 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
@SpringJUnitConfig(RbacService.class)
class RbacServiceTest {
@Mock private RbacRepository repository;
@Mock private MemberRepository memberRepository;
private RbacService service;
@BeforeEach
void setUp() {
service = new RbacService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "memberRepository", memberRepository);
}
@MockBean private RbacRepository repository;
@MockBean private MemberRepository memberRepository;
@Resource private RbacService service;
@Test
void 角色列表返回当前权限用于安全回显() {
void shouldHandleCase01() {
IamRole role = role(11L, 100L, "MERCHANT", "CUSTOM");
when(repository.findRoles(100L, "MERCHANT")).thenReturn(List.of(role));
when(repository.findRolePermissionIds(100L, 11L)).thenReturn(Set.of(21L, 22L));
@@ -56,7 +48,7 @@ class RbacServiceTest {
}
@Test
void 权限列表同码时优先当前租户并去除全局模板重复项() {
void shouldHandleCase02() {
IamPermission global = permission(21L, 0L, "merchant:member:list");
IamPermission tenant = permission(22L, 100L, "merchant:member:list");
IamPermission fallback = permission(23L, 0L, "merchant:member:status");
@@ -71,7 +63,7 @@ class RbacServiceTest {
}
@Test
void 跨租户角色访问被拒绝() {
void shouldHandleCase03() {
when(repository.findRole(11L, 200L, "MERCHANT")).thenReturn(null);
BizException exception = assertThrows(BizException.class,
@@ -81,7 +73,7 @@ class RbacServiceTest {
}
@Test
void 系统角色禁止删除() {
void shouldHandleCase04() {
when(repository.findRole(11L, 0L, "PLATFORM"))
.thenReturn(role(11L, 0L, "PLATFORM", "SYSTEM"));
@@ -93,7 +85,7 @@ class RbacServiceTest {
}
@Test
void 已分配成员的自定义角色禁止删除() {
void shouldHandleCase05() {
when(repository.findRole(11L, 100L, "MERCHANT"))
.thenReturn(role(11L, 100L, "MERCHANT", "CUSTOM"));
when(repository.isRoleAssigned(100L, 11L)).thenReturn(true);
@@ -106,7 +98,7 @@ class RbacServiceTest {
}
@Test
void 空权限集合可以明确清空授权() {
void shouldHandleCase06() {
when(repository.findRole(11L, 100L, "MERCHANT"))
.thenReturn(role(11L, 100L, "MERCHANT", "CUSTOM"));
@@ -116,7 +108,7 @@ class RbacServiceTest {
}
@Test
void 空角色集合可以明确清空成员授权() {
void shouldHandleCase07() {
IamMembership membership = new IamMembership();
membership.setId(31L);
membership.setTenantId(100L);
@@ -128,7 +120,7 @@ class RbacServiceTest {
}
@Test
void 成员角色回显只返回当前应用域角色() {
void shouldHandleCase08() {
IamMembership membership = new IamMembership();
membership.setId(31L);
membership.setTenantId(100L);
@@ -144,7 +136,7 @@ class RbacServiceTest {
}
@Test
void 同一租户同一应用角色编码重复时返回冲突() {
void shouldHandleCase09() {
when(repository.existsRoleCode(100L, "MERCHANT", "ORDER_ADMIN", null)).thenReturn(true);
BizException exception = assertThrows(BizException.class, () -> service.createRole(
@@ -155,7 +147,7 @@ class RbacServiceTest {
}
@Test
void 停用角色不得继续分配给成员() {
void shouldHandleCase10() {
IamMembership membership = new IamMembership();
membership.setId(31L);
membership.setTenantId(100L);
@@ -172,7 +164,7 @@ class RbacServiceTest {
}
@Test
void 自定义角色可以编辑和停用并保持权限回显() {
void shouldHandleCase11() {
IamRole role = role(11L, 100L, "MERCHANT", "CUSTOM");
when(repository.findRole(11L, 100L, "MERCHANT")).thenReturn(role);
when(repository.findRolePermissionIds(100L, 11L)).thenReturn(Set.of(21L));
@@ -189,7 +181,7 @@ class RbacServiceTest {
}
@Test
void 未使用的自定义角色可以安全删除() {
void shouldHandleCase12() {
when(repository.findRole(11L, 100L, "MERCHANT"))
.thenReturn(role(11L, 100L, "MERCHANT", "CUSTOM"));
when(repository.isRoleAssigned(100L, 11L)).thenReturn(false);
@@ -200,7 +192,7 @@ class RbacServiceTest {
}
@Test
void 企业所有者角色不能通过普通成员授权接口修改() {
void shouldHandleCase13() {
IamMembership owner = new IamMembership();
owner.setId(31L);
owner.setTenantId(100L);
@@ -215,7 +207,7 @@ class RbacServiceTest {
}
@Test
void 系统角色权限不能通过普通授权接口修改() {
void shouldHandleCase14() {
when(repository.findRole(11L, 0L, "PLATFORM"))
.thenReturn(role(11L, 0L, "PLATFORM", "SYSTEM"));
@@ -227,7 +219,7 @@ class RbacServiceTest {
}
@Test
void 企业所有者系统角色不能分配给普通成员() {
void shouldHandleCase15() {
IamMembership member = new IamMembership();
member.setId(31L);
member.setTenantId(100L);
@@ -245,7 +237,7 @@ class RbacServiceTest {
}
@Test
void 权限编码重复时返回稳定冲突且不写数据库() {
void shouldHandleCase16() {
when(repository.existsPermissionCode(100L, "MERCHANT", "merchant:role:test"))
.thenReturn(true);
CreatePermissionRequest request = new CreatePermissionRequest(
@@ -259,7 +251,7 @@ class RbacServiceTest {
}
@Test
void 系统预置权限不允许编辑启停或删除() {
void shouldHandleCase17() {
IamPermission builtIn = permission(21L, 0L, "platform:permission:list");
builtIn.setAppCode("PLATFORM");
builtIn.setBuiltIn(true);
@@ -274,7 +266,7 @@ class RbacServiceTest {
}
@Test
void 自定义权限能编辑和启停但保持编码不变() {
void shouldHandleCase18() {
IamPermission custom = permission(21L, 100L, "merchant:custom:edit");
when(repository.findOwnedPermission(21L, 100L, "MERCHANT")).thenReturn(custom);
@@ -290,7 +282,7 @@ class RbacServiceTest {
}
@Test
void 带子节点或角色绑定的权限资源拒绝删除() {
void shouldHandleCase19() {
IamPermission custom = permission(21L, 100L, "merchant:custom:edit");
when(repository.findOwnedPermission(21L, 100L, "MERCHANT")).thenReturn(custom);
when(repository.hasPermissionChildren(100L, "MERCHANT", 21L)).thenReturn(true);
@@ -308,7 +300,7 @@ class RbacServiceTest {
}
@Test
void 无引用的自定义权限可以删除() {
void shouldHandleCase20() {
IamPermission custom = permission(21L, 100L, "merchant:custom:edit");
when(repository.findOwnedPermission(21L, 100L, "MERCHANT")).thenReturn(custom);
when(repository.hasPermissionChildren(100L, "MERCHANT", 21L)).thenReturn(false);
@@ -11,8 +11,10 @@ import com.baiyue.iam.repository.MemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.security.SecureRandom;
import java.util.List;
@@ -27,34 +29,23 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(TenantAdministratorProvisioningService.class)
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class TenantAdministratorProvisioningServiceTest {
private final MemberRepository members = mock(MemberRepository.class);
private final IamRoleMapper roles = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final TenantAdministratorProvisioningService service =
new TenantAdministratorProvisioningService(members, roles, auth, "internal-token", new SecureRandom());
@MockBean private MemberRepository members;
@MockBean private IamRoleMapper roles;
@MockBean private AuthAccountClient auth;
@Resource private TenantAdministratorProvisioningService service;
private IamTenant tenant;
@Test
void springContextUsesProductionConstructorWhenTestConstructorAlsoExists() {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
TestPropertyValues.of("baiyue.security.internal-service-token=internal-token-at-least-32-bytes-long")
.applyTo(context);
context.registerBean(MemberRepository.class, () -> mock(MemberRepository.class));
context.registerBean(IamRoleMapper.class, () -> mock(IamRoleMapper.class));
context.registerBean(AuthAccountClient.class, () -> mock(AuthAccountClient.class));
context.register(TenantAdministratorProvisioningService.class);
context.refresh();
assertNotNull(context.getBean(TenantAdministratorProvisioningService.class));
}
void springContextCreatesBean() {
assertNotNull(service);
}
@BeforeEach
@@ -4,6 +4,7 @@ import com.baiyue.iam.entity.IamTenant;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.core.annotation.Order;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.ArrayList;
import java.util.List;
@@ -26,7 +27,7 @@ class TenantApprovalInitializationCoordinatorTest {
when(first.initialize(context)).thenReturn(firstResult);
when(second.initialize(context)).thenReturn(secondResult);
when(failing.initialize(context)).thenThrow(new RuntimeException("role initialization failed"));
var coordinator = new TenantApprovalInitializationCoordinator(List.of(first, second, failing));
var coordinator = coordinator(List.of(first, second, failing));
assertThrows(RuntimeException.class, () -> coordinator.initialize(context));
@@ -41,7 +42,7 @@ class TenantApprovalInitializationCoordinatorTest {
TestResult result = new TestResult("credential-result");
var context = context();
when(initializer.initialize(context)).thenReturn(result);
var coordinator = new TenantApprovalInitializationCoordinator(List.of(initializer));
var coordinator = coordinator(List.of(initializer));
var batch = coordinator.initialize(context);
@@ -51,8 +52,7 @@ class TenantApprovalInitializationCoordinatorTest {
@Test
void springOrderControlsInitializerExecutionSequence() {
List<String> calls = new ArrayList<>();
var coordinator = new TenantApprovalInitializationCoordinator(
List.of(new LateInitializer(calls), new EarlyInitializer(calls)));
var coordinator = coordinator(List.of(new LateInitializer(calls), new EarlyInitializer(calls)));
coordinator.initialize(context());
@@ -65,6 +65,18 @@ class TenantApprovalInitializationCoordinatorTest {
return initializer;
}
private TenantApprovalInitializationCoordinator coordinator(List<TenantApprovalInitializer> initializers) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
for (int index = 0; index < initializers.size(); index++) {
TenantApprovalInitializer initializer = initializers.get(index);
context.registerBean("initializer" + index, TenantApprovalInitializer.class, () -> initializer);
}
context.registerBean("initializers", List.class, () -> initializers);
context.registerBean(TenantApprovalInitializationCoordinator.class);
context.refresh();
return context.getBean(TenantApprovalInitializationCoordinator.class);
}
private TenantApprovalInitializer.ApprovalContext context() {
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
@@ -4,23 +4,26 @@ import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.repository.ProfileResourceRepository;
import com.baiyue.iam.repository.TenantRepository;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(TenantService.class)
class TenantCustomerExportTest {
@MockBean private TenantRepository repository;
@MockBean private ProfileResourceRepository profileRepository;
@MockBean private TenantApprovalInitializationCoordinator approvalInitialization;
@Resource private TenantService service;
@Test
void returnsUnmaskedCustomerRowsAndAdvancingCursor() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", mock(ProfileResourceRepository.class));
IamTenant tenant = new IamTenant();
tenant.setId(101L);
tenant.setTenantCode("TEN101");
@@ -9,8 +9,16 @@ import com.baiyue.iam.entity.IamTenantQualification;
import com.baiyue.iam.entity.IamTenantReview;
import com.baiyue.iam.repository.TenantRepository;
import com.baiyue.iam.repository.ProfileResourceRepository;
import com.baiyue.iam.repository.MemberRepository;
import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.client.AuthAccountClient;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -18,11 +26,11 @@ import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.doReturn;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
@@ -30,13 +38,20 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.common.core.api.ResultCode;
@SpringJUnitConfig(classes = {TenantService.class, TenantApprovalInitializationCoordinator.class,
TenantAdministratorProvisioningService.class})
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class TenantServiceTest {
@MockBean private TenantRepository repository;
@MockBean private ProfileResourceRepository profileRepository;
@MockBean private MemberRepository members;
@MockBean private IamRoleMapper roles;
@MockBean private AuthAccountClient authClient;
@SpyBean private TenantAdministratorProvisioningService provisioning;
@Resource private TenantService service;
@Test
void pageMerchantsMapsTenantEntitiesToApiResponses() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
IamTenant tenant = new IamTenant();
tenant.setId(10001L);
@@ -72,9 +87,6 @@ class TenantServiceTest {
@Test
void platformCanMaintainAndDisableOnlyMerchantTenant() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
IamTenant tenant = merchant(10001L, "ACTIVE");
when(repository.findTenant(10001L)).thenReturn(tenant);
@@ -102,9 +114,6 @@ class TenantServiceTest {
@Test
void platformCannotBypassReviewToActivatePendingTenant() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
when(repository.findTenant(10001L)).thenReturn(merchant(10001L, "PENDING"));
BizException exception = assertThrows(BizException.class,
@@ -115,9 +124,6 @@ class TenantServiceTest {
@Test
void platformRegistrationCreatesDraftWithoutCreatingReviewTicket() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
var created = service.register(new RegisterRequest(
"Example Merchant", "Example Merchant Ltd", "Bob", "Alice", "13800138000",
@@ -135,9 +141,6 @@ class TenantServiceTest {
@Test
void platformRegistrationAlwaysCreatesTheDraftWithoutACreditCode() {
TenantRepository repository = mock(TenantRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
var created = service.register(new RegisterRequest(
"Example Merchant", "Example Merchant Ltd", "Bob", "Alice", "13800138000",
@@ -150,11 +153,6 @@ class TenantServiceTest {
@Test
void explicitSubmissionRequiresOnlyBusinessLicenseAndLegalPersonIdAndCreatesReview() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
IamTenant tenant = merchant(10001L, "PROFILE_REQUIRED");
when(repository.findTenantForUpdate(10001L)).thenReturn(tenant);
when(profileRepository.findQualifications(10001L)).thenReturn(List.of(
@@ -169,11 +167,6 @@ class TenantServiceTest {
@Test
void explicitSubmissionRejectsAnIncompleteQualificationSet() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
when(repository.findTenantForUpdate(10001L)).thenReturn(merchant(10001L, "PROFILE_REQUIRED"));
when(profileRepository.findQualifications(10001L)).thenReturn(List.of(
qualification("BUSINESS_LICENSE")));
@@ -186,11 +179,6 @@ class TenantServiceTest {
@Test
void explicitSubmissionRejectsMissingUnifiedSocialCreditCodeBeforeCreatingReview() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
IamTenant tenant = merchant(10001L, "PROFILE_REQUIRED");
tenant.setUnifiedSocialCreditCode(null);
when(repository.findTenantForUpdate(10001L)).thenReturn(tenant);
@@ -204,25 +192,16 @@ class TenantServiceTest {
@Test
void approvalProvisionsMissingAdministratorAndReturnsCredentialsOnce() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantAdministratorProvisioningService provisioning = mock(TenantAdministratorProvisioningService.class);
when(provisioning.name()).thenReturn("tenant-administrator");
TenantApprovalInitializationCoordinator initialization =
new TenantApprovalInitializationCoordinator(List.of(provisioning));
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
ReflectionTestUtils.setField(service, "approvalInitialization", initialization);
IamTenantReview review = review(71L, 10001L);
IamTenant tenant = merchant(10001L, "PENDING");
when(repository.findReviewForUpdate(71L)).thenReturn(review);
when(repository.findTenant(10001L)).thenReturn(tenant);
when(profileRepository.findQualifications(10001L)).thenReturn(List.of(
qualification("BUSINESS_LICENSE"), qualification("LEGAL_PERSON_ID")));
when(provisioning.initialize(any())).thenReturn(
doReturn(
TenantAdministratorProvisioningService.ProvisioningResult.created(
81L, "merchant_10001", "Password1234"));
81L, "merchant_10001", "Password1234")).when(provisioning).initialize(any());
var result = service.review(71L, 9001L, true, "资料完整");
@@ -238,16 +217,7 @@ class TenantServiceTest {
@Test
void approvalKeepsClientRegisteredAccountAsAdministratorWithoutNewCredentials() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantAdministratorProvisioningService provisioning = mock(TenantAdministratorProvisioningService.class);
when(provisioning.name()).thenReturn("tenant-administrator");
TenantApprovalInitializationCoordinator initialization =
new TenantApprovalInitializationCoordinator(List.of(provisioning));
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
ReflectionTestUtils.setField(service, "approvalInitialization", initialization);
IamTenantReview review = review(71L, 10001L);
IamTenant tenant = merchant(10001L, "PENDING");
when(repository.findReviewForUpdate(71L)).thenReturn(review);
@@ -255,8 +225,8 @@ class TenantServiceTest {
when(profileRepository.findQualifications(10001L)).thenReturn(List.of(
qualification("BUSINESS_LICENSE"), qualification("LEGAL_PERSON_ID"),
qualification("FREIGHT_FORWARDER_CERTIFICATE"), qualification("BANK_ACCOUNT_LICENSE")));
when(provisioning.initialize(any())).thenReturn(
TenantAdministratorProvisioningService.ProvisioningResult.existing());
doReturn(TenantAdministratorProvisioningService.ProvisioningResult.existing())
.when(provisioning).initialize(any());
var result = service.review(71L, 9001L, true, "资料完整");
@@ -269,16 +239,7 @@ class TenantServiceTest {
@Test
void failureAfterProvisioningCompensatesAdministratorAndKeepsApprovalFailed() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantAdministratorProvisioningService provisioning = mock(TenantAdministratorProvisioningService.class);
when(provisioning.name()).thenReturn("tenant-administrator");
TenantApprovalInitializationCoordinator initialization =
new TenantApprovalInitializationCoordinator(List.of(provisioning));
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
ReflectionTestUtils.setField(service, "approvalInitialization", initialization);
IamTenantReview review = review(71L, 10001L);
IamTenant tenant = merchant(10001L, "PENDING");
var administrator = TenantAdministratorProvisioningService.ProvisioningResult.created(
@@ -288,7 +249,7 @@ class TenantServiceTest {
when(profileRepository.findQualifications(10001L)).thenReturn(List.of(
qualification("BUSINESS_LICENSE"), qualification("LEGAL_PERSON_ID"),
qualification("FREIGHT_FORWARDER_CERTIFICATE"), qualification("BANK_ACCOUNT_LICENSE")));
when(provisioning.initialize(any())).thenReturn(administrator);
doReturn(administrator).when(provisioning).initialize(any());
doThrow(new RuntimeException("review write failed")).when(repository).saveReview(review);
assertThrows(RuntimeException.class, () -> service.review(71L, 9001L, true, "资料完整"));
@@ -298,12 +259,7 @@ class TenantServiceTest {
}
@Test
void 企业激活后仅需两类必填资质审核通过即可下单() {
TenantRepository repository = mock(TenantRepository.class);
ProfileResourceRepository profileRepository = mock(ProfileResourceRepository.class);
TenantService service = new TenantService();
ReflectionTestUtils.setField(service, "repository", repository);
ReflectionTestUtils.setField(service, "profileRepository", profileRepository);
void shouldHandleCase01() {
when(repository.findTenant(10001L)).thenReturn(merchant(10001L, "ACTIVE"));
when(profileRepository.findQualifications(10001L)).thenReturn(
List.of(approvedQualification("BUSINESS_LICENSE")),