package com.malk.benteler.service; import com.alibaba.fastjson.JSON; import com.malk.benteler.config.BentelerYidaConf; import com.malk.benteler.dto.EiamBatchItemResult; import com.malk.benteler.dto.EiamBatchOperation; import com.malk.benteler.dto.EiamBatchResult; import com.malk.benteler.dto.EiamBatchStage; import com.malk.benteler.dto.EiamFormSyncResult; import com.malk.benteler.dto.EiamUpdateUserItem; import com.malk.server.aliwork.YDAuth; import com.malk.server.aliwork.YDConf; import com.malk.server.aliwork.YDParam; import com.malk.service.aliwork.YDClient_Form; import com.malk.service.aliwork.YDService; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * {@link BentelerYidaSyncService} 单实例同步闭环测试。 */ public class BentelerYidaSyncServiceTest { private YDClient_Form ydClientForm; private YDService ydService; private EiamLocalService eiamLocalService; private BentelerYidaConf conf; private BentelerYidaSyncService service; @Before public void setUp() { ydClientForm = mock(YDClient_Form.class); ydService = mock(YDService.class); eiamLocalService = mock(EiamLocalService.class); conf = TestBentelerYidaConf.create(); YDConf ydConf = new YDConf(); ydConf.setAppType("APP_TEST"); ydConf.setSystemToken("TOKEN_TEST"); service = new BentelerYidaSyncService(ydClientForm, ydService, ydConf, conf, new BentelerYidaFormMapper(conf), eiamLocalService); } @Test public void syncCreate_queriesInstanceAndWritesBackFullRowsAndStatistics() { Map formData = new HashMap<>(); formData.put(conf.getOnboardingOrganizationalUnitIdFieldId(), "ou_technical"); formData.put(conf.getOnboardingTableFieldId(), Arrays.asList( createRow("人员一", "13800000001"), createRow("人员二", "13800000002"))); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(eiamLocalService.batchCreate(any())).thenReturn(batchResult( EiamBatchOperation.CREATE, true, false)); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenReturn(Collections.emptyMap()); EiamFormSyncResult result = service.syncCreate("form_test"); assertTrue(result.isWritebackSuccess()); assertEquals(2, result.getTotal()); assertEquals(1, result.getSuccessCount()); ArgumentCaptor jsonCaptor = ArgumentCaptor.forClass(String.class); verify(ydClientForm).updateForm(any(YDAuth.class), anyString(), jsonCaptor.capture(), anyMap()); Map update = JSON.parseObject(jsonCaptor.getValue(), Map.class); List> rows = (List>) update.get( conf.getOnboardingTableFieldId()); assertEquals(2, rows.size()); assertEquals("成功", rows.get(0).get(conf.getDetailStatusFieldId())); assertEquals("失败", rows.get(1).get(conf.getDetailStatusFieldId())); assertEquals(2, ((Number) update.get(conf.getTotalFieldId())).intValue()); assertEquals("人员二 - 执行失败", update.get(conf.getFailureMessageFieldId())); } @Test public void syncCreate_writebackFailureReturnsExecutionResultWithoutRetryingEiam() { Map formData = new HashMap<>(); formData.put(conf.getOnboardingOrganizationalUnitIdFieldId(), "ou_technical"); formData.put(conf.getOnboardingTableFieldId(), Collections.singletonList( createRow("人员一", "13800000001"))); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(eiamLocalService.batchCreate(any())).thenReturn(batchResult( EiamBatchOperation.CREATE, true)); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenThrow(new IllegalStateException("writeback failed")); EiamFormSyncResult result = service.syncCreate("form_test"); assertFalse(result.isWritebackSuccess()); assertEquals(1, result.getSuccessCount()); verify(eiamLocalService).batchCreate(any()); } @Test @SuppressWarnings("unchecked") public void syncUpdate_readsEiamOrganizationalUnitIdDirectly() { Map row = new HashMap<>(); row.put(conf.getUpdateEmployeeFieldId() + "_id", Collections.singletonList("user_1")); Map formData = new HashMap<>(); formData.put(conf.getUpdateContentFieldId(), Collections.singletonList(BentelerYidaFormMapper.UPDATE_PRIMARY_ORG)); formData.put(conf.getUpdateOrganizationalUnitIdFieldId(), "ou_target"); formData.put(conf.getUpdateTableFieldId(), Collections.singletonList(row)); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(eiamLocalService.batchUpdate(any())).thenReturn(batchResult( EiamBatchOperation.UPDATE, true)); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenReturn(Collections.emptyMap()); EiamFormSyncResult result = service.syncUpdate("form_update"); assertEquals(1, result.getSuccessCount()); ArgumentCaptor itemsCaptor = ArgumentCaptor.forClass(List.class); verify(eiamLocalService).batchUpdate(itemsCaptor.capture()); List items = (List) itemsCaptor.getValue(); assertEquals("user_1", items.get(0).getUserId()); assertEquals("ou_target", items.get(0).getPrimaryOrganizationalUnitId()); } @Test @SuppressWarnings("unchecked") public void syncUpdate_phoneOnly_doesNotRequireOrganizationalUnit() { Map row = new HashMap<>(); row.put(conf.getUpdateEmployeeFieldId() + "_id", Collections.singletonList("user_1")); row.put(conf.getUpdatePhoneFieldId(), "17612168216"); Map formData = new HashMap<>(); formData.put(conf.getUpdateContentFieldId(), Collections.singletonList(BentelerYidaFormMapper.UPDATE_PHONE)); formData.put(conf.getUpdateTableFieldId(), Collections.singletonList(row)); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(eiamLocalService.batchUpdate(any())).thenReturn(batchResult( EiamBatchOperation.UPDATE, true)); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenReturn(Collections.emptyMap()); EiamFormSyncResult result = service.syncUpdate("form_update_phone"); assertEquals(1, result.getSuccessCount()); ArgumentCaptor itemsCaptor = ArgumentCaptor.forClass(List.class); verify(eiamLocalService).batchUpdate(itemsCaptor.capture()); List items = (List) itemsCaptor.getValue(); assertEquals("17612168216", items.get(0).getUsername()); assertEquals(null, items.get(0).getPrimaryOrganizationalUnitId()); } @Test public void syncDelete_exactlyFiftyRowsFallsBackWhenDetailQueryThrowsNpe() { List> inlineRows = new ArrayList<>(); for (int index = 0; index < 50; index++) { Map row = new HashMap<>(); row.put(conf.getOffboardingEmployeeFieldId() + "_id", Collections.singletonList("user_" + index)); inlineRows.add(row); } Map formData = new HashMap<>(); formData.put(conf.getOffboardingTableFieldId(), inlineRows); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(ydService.queryDetails(any(YDParam.class))).thenThrow(new NullPointerException()); when(eiamLocalService.batchDelete(any())).thenReturn(batchResult( EiamBatchOperation.DELETE, successFlags(50))); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenReturn(Collections.emptyMap()); EiamFormSyncResult result = service.syncDelete("form_delete"); assertEquals(50, result.getTotal()); verify(ydService).queryDetails(any(YDParam.class)); } @Test public void syncDelete_lessThanFiftyRowsUsesInlineDetails() { List> inlineRows = new ArrayList<>(); for (int index = 0; index < 49; index++) { Map row = new HashMap<>(); row.put(conf.getOffboardingEmployeeFieldId() + "_id", Collections.singletonList("user_" + index)); inlineRows.add(row); } Map formData = new HashMap<>(); formData.put(conf.getOffboardingTableFieldId(), inlineRows); when(ydClientForm.getForm(any(YDAuth.class), anyString(), isNull())) .thenReturn(instance(formData)); when(eiamLocalService.batchDelete(any())).thenReturn(batchResult( EiamBatchOperation.DELETE, successFlags(49))); when(ydClientForm.updateForm(any(YDAuth.class), anyString(), anyString(), anyMap())) .thenReturn(Collections.emptyMap()); EiamFormSyncResult result = service.syncDelete("form_delete_49"); assertEquals(49, result.getTotal()); verify(ydService, never()).queryDetails(any(YDParam.class)); } private Map createRow(String name, String phone) { Map row = new HashMap<>(); row.put(conf.getOnboardingNameFieldId(), name); row.put(conf.getOnboardingPhoneFieldId(), phone); return row; } private Map instance(Map formData) { Map instance = new HashMap<>(); instance.put("formData", formData); return instance; } private boolean[] successFlags(int size) { boolean[] flags = new boolean[size]; Arrays.fill(flags, true); return flags; } private EiamBatchResult batchResult(EiamBatchOperation operation, boolean... successFlags) { List items = new ArrayList<>(); for (int index = 0; index < successFlags.length; index++) { items.add(EiamBatchItemResult.builder().index(index).success(successFlags[index]) .stage(EiamBatchStage.COMPLETED).build()); } return EiamBatchResult.of(operation, items); } }