Merge remote-tracking branch 'base-version/main' into dev

This commit is contained in:
chenbowen
2025-12-22 13:47:15 +08:00
15 changed files with 538 additions and 22 deletions

View File

@@ -0,0 +1,141 @@
package com.zt.plat.module.system.service.integration.iwork.impl;
import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest;
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO;
import com.zt.plat.module.system.dal.mysql.dept.PostMapper;
import com.zt.plat.module.system.dal.mysql.user.AdminUserMapper;
import com.zt.plat.module.system.service.dept.DeptService;
import com.zt.plat.module.system.service.dept.PostService;
import com.zt.plat.module.system.service.integration.iwork.IWorkSyncProcessor;
import com.zt.plat.module.system.service.user.AdminUserService;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* Tests for cross-page pending handling and placeholder backfill in IWorkSyncProcessorImpl.
*/
class IWorkSyncProcessorImplTest extends BaseMockitoUnitTest {
@InjectMocks
private IWorkSyncProcessorImpl processor;
@Mock
private DeptService deptService;
@Mock
private PostService postService;
@Mock
private PostMapper postMapper;
@Mock
private AdminUserService adminUserService;
@Mock
private AdminUserMapper adminUserMapper;
@Test
void shouldProcessPendingChildWhenParentArrivesInLaterPage() {
IWorkSyncProcessor.DeptSyncContext context = new IWorkSyncProcessor.DeptSyncContext();
IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true);
IWorkHrDepartmentPageRespVO.Department child = new IWorkHrDepartmentPageRespVO.Department();
child.setId(200);
child.setDepartmentname("child");
child.setSupdepid(100); // parent comes later
IWorkHrDepartmentPageRespVO.Department parent = new IWorkHrDepartmentPageRespVO.Department();
parent.setId(100);
parent.setDepartmentname("parent");
parent.setSupdepid(0); // root
when(deptService.getDept(anyLong())).thenReturn(null);
when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(100L, 200L);
processor.syncDepartments(List.of(child), options, context);
verify(deptService, never()).createDept(any());
assertEquals(1, context.getPendingDepartments().size());
processor.syncDepartments(List.of(parent), options, context);
verify(deptService, times(2)).createDept(any());
assertTrue(context.getPendingDepartments().isEmpty(), "pending should be cleared after parent processed");
}
@Test
void shouldInsertPlaceholderWhenParentMissingAfterFlush() {
IWorkSyncProcessor.DeptSyncContext context = new IWorkSyncProcessor.DeptSyncContext();
IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true);
IWorkHrDepartmentPageRespVO.Department child = new IWorkHrDepartmentPageRespVO.Department();
child.setId(300);
child.setDepartmentname("orphan");
child.setSupdepid(9999); // never provided
when(deptService.getDept(anyLong())).thenReturn(null);
when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(300L);
processor.syncDepartments(List.of(child), options, context);
assertEquals(1, context.getPendingDepartments().size());
IWorkSyncProcessor.BatchResult flushResult = processor.flushDeptPending(context, options);
assertNotNull(flushResult);
ArgumentCaptor<DeptSaveReqVO> captor = ArgumentCaptor.forClass(DeptSaveReqVO.class);
verify(deptService, times(1)).createDept(captor.capture());
DeptSaveReqVO placeholderReq = captor.getValue();
assertTrue(Boolean.TRUE.equals(placeholderReq.getDelayCodeGeneration()));
assertNull(placeholderReq.getCode());
assertTrue(context.getPendingDepartments().isEmpty(), "pending should be cleared after placeholder insert");
assertTrue(context.getPlaceholderDeptIds().contains(300L));
}
@Test
void shouldKeepExternalCodeNullWhenDepartmentCodeBlank() {
IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true);
IWorkHrDepartmentPageRespVO.Department dept = new IWorkHrDepartmentPageRespVO.Department();
dept.setId(500);
dept.setDepartmentname("blank-code-dept");
dept.setDepartmentcode(" ");
dept.setSupdepid(0);
when(deptService.getDept(anyLong())).thenReturn(null);
when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(500L);
processor.syncDepartments(List.of(dept), options, null);
ArgumentCaptor<DeptSaveReqVO> captor = ArgumentCaptor.forClass(DeptSaveReqVO.class);
verify(deptService, times(1)).createDept(captor.capture());
DeptSaveReqVO req = captor.getValue();
assertNull(req.getExternalDeptCode(), "externalDeptCode should remain null when source code is blank");
}
@Test
void shouldKeepExternalCodeNullWhenSubcompanyCodeBlank() {
IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true);
IWorkHrSubcompanyPageRespVO.Subcompany subcompany = new IWorkHrSubcompanyPageRespVO.Subcompany();
subcompany.setId(600);
subcompany.setSubcompanyname("blank-code-sub");
subcompany.setSubcompanycode(null);
subcompany.setSupsubcomid(0);
when(deptService.getDept(anyLong())).thenReturn(null);
when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(600L);
processor.syncSubcompanies(List.of(subcompany), options, null);
ArgumentCaptor<DeptSaveReqVO> captor = ArgumentCaptor.forClass(DeptSaveReqVO.class);
verify(deptService, times(1)).createDept(captor.capture());
DeptSaveReqVO req = captor.getValue();
assertNull(req.getExternalDeptCode(), "externalDeptCode should remain null when source code is null or blank");
}
}

View File

@@ -0,0 +1,62 @@
package com.zt.plat.module.system.service.integration.iwork.impl;
import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO;
import com.zt.plat.module.system.enums.integration.IWorkSyncEntityTypeEnum;
import com.zt.plat.module.system.service.dept.DeptService;
import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService;
import com.zt.plat.module.system.service.integration.iwork.IWorkSyncProcessor;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class IWorkSyncServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private IWorkSyncServiceImpl syncService;
@Mock
private IWorkOrgRestService orgRestService;
@Mock
private IWorkSyncProcessor syncProcessor;
@Mock
private DeptService deptService;
@Test
void shouldBackfillCodesWhenPlaceholdersExistAfterFullSync() {
IWorkFullSyncReqVO reqVO = new IWorkFullSyncReqVO();
reqVO.setPageSize(1);
reqVO.setMaxPages(1);
IWorkHrDepartmentPageRespVO pageResp = new IWorkHrDepartmentPageRespVO();
pageResp.setSuccess(true);
IWorkHrDepartmentPageRespVO.Department dept = new IWorkHrDepartmentPageRespVO.Department();
dept.setId(1);
pageResp.setDataList(List.of(dept));
when(orgRestService.listDepartments(any())).thenReturn(pageResp);
// 在部门同步时标记占位 ID
doAnswer((Answer<IWorkSyncProcessor.BatchResult>) invocation -> {
IWorkSyncProcessor.DeptSyncContext context = invocation.getArgument(2);
if (context != null) {
context.getPlaceholderDeptIds().add(500L);
}
return IWorkSyncProcessor.BatchResult.empty();
}).when(syncProcessor).syncDepartments(any(), any(), any(IWorkSyncProcessor.DeptSyncContext.class));
when(syncProcessor.flushDeptPending(any(), any())).thenReturn(IWorkSyncProcessor.BatchResult.empty());
syncService.fullSyncDepartments(reqVO);
verify(deptService, times(1)).backfillMissingCodesWithoutEvent(argThat(set -> set.contains(500L)));
}
}

View File

@@ -1,7 +1,9 @@
package com.zt.plat.module.system.service.permission;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.framework.test.core.ut.BaseDbUnitTest;
import com.zt.plat.framework.common.util.json.JsonUtils;
import com.zt.plat.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
@@ -11,6 +13,7 @@ import com.zt.plat.module.system.dal.mysql.permission.RoleMapper;
import com.zt.plat.module.system.dal.mysql.permission.RoleMenuMapper;
import com.zt.plat.module.system.dal.mysql.permission.UserRoleMapper;
import com.zt.plat.module.system.dal.mysql.rolemenuexclusion.RoleMenuExclusionMapper;
import com.zt.plat.module.system.enums.permission.DataScopeEnum;
import com.zt.plat.module.system.enums.permission.RoleTypeEnum;
import com.zt.plat.module.system.service.dept.DeptService;
import com.zt.plat.module.system.service.user.AdminUserService;
@@ -408,4 +411,54 @@ public class PermissionServiceTest extends BaseDbUnitTest {
assertEquals(1, exclusionDOS.size());
assertEquals(101L, exclusionDOS.get(0).getMenuId());
}
@Test
public void testGetUserDataPermissionLevel_noRolesReturnSelf() {
Long userId = 1000L;
DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId);
assertEquals(DataScopeEnum.SELF, result);
}
@Test
public void testGetUserDataPermissionLevel_pickHighestPriority() {
Long userId = 2000L;
RoleDO roleCustom = randomPojo(RoleDO.class, o -> o
.setStatus(CommonStatusEnum.ENABLE.getStatus())
.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope())
.setId(110L)
.setTenantId(0L));
roleMapper.insert(roleCustom);
RoleDO roleCompany = randomPojo(RoleDO.class, o -> o
.setStatus(CommonStatusEnum.ENABLE.getStatus())
.setDataScope(DataScopeEnum.COMPANY_AND_DEPT.getScope())
.setId(120L)
.setTenantId(0L));
roleMapper.insert(roleCompany);
userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleCustom.getId())));
userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleCompany.getId())));
DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId);
assertEquals(DataScopeEnum.COMPANY_AND_DEPT, result);
}
@Test
public void testGetUserDataPermissionLevel_serializeAsNumber() {
Long userId = 3000L;
RoleDO roleAll = randomPojo(RoleDO.class, o -> o
.setStatus(CommonStatusEnum.ENABLE.getStatus())
.setDataScope(DataScopeEnum.ALL.getScope())
.setId(210L)
.setTenantId(0L));
roleMapper.insert(roleAll);
userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleAll.getId())));
DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId);
assertEquals(DataScopeEnum.ALL, result);
assertEquals("1", JsonUtils.toJsonString(result));
}
}