| | |
| | | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.tcm.training.admin.common.PageResponse; |
| | | import com.tcm.training.admin.live.entity.Clinic; |
| | | import com.tcm.training.admin.live.mapper.ClinicMapper; |
| | | import com.tcm.training.admin.member.dto.UserBatchClinicUpdateRequest; |
| | | import com.tcm.training.admin.member.dto.UserUpdateRequest; |
| | | import com.tcm.training.admin.member.entity.AppUser; |
| | | import com.tcm.training.admin.member.mapper.UserMapper; |
| | | import com.tcm.training.admin.member.row.UserDetailRow; |
| | |
| | | import org.junit.jupiter.api.BeforeAll; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.junit.jupiter.api.extension.ExtendWith; |
| | | import org.junit.jupiter.params.ParameterizedTest; |
| | | import org.junit.jupiter.params.provider.CsvSource; |
| | | import org.junit.jupiter.params.provider.ValueSource; |
| | | import org.mockito.ArgumentCaptor; |
| | | import org.mockito.InjectMocks; |
| | | import org.mockito.Mock; |
| | |
| | | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertThrows; |
| | |
| | | assertTrue(wrapperCaptor.getValue().getParamNameValuePairs().values().stream().allMatch(value -> value == null)); |
| | | assertEquals(Long.valueOf(12L), result.getId()); |
| | | } |
| | | |
| | | @ParameterizedTest |
| | | @CsvSource({"10, 100", "20, 100", "20, "}) |
| | | void updateShouldSynchronizeClinicBindingIncludingStaleRelations(Long oldClinicId, Long oldDoctorId) { |
| | | AppUser user = prepareUserUpdate(0); |
| | | user.setClinicId(oldClinicId); |
| | | user.setSuperiorClinicUserId(oldDoctorId); |
| | | prepareClinicAccounts(1); |
| | | |
| | | userAppService.update(12L, updateRequest(20L)); |
| | | |
| | | verify(userMapper).updateById(user); |
| | | assertClinicBinding(Collections.singletonList(12L), 20L, 200L); |
| | | } |
| | | |
| | | @Test |
| | | void updateShouldExplicitlyClearBothClinicFields() { |
| | | AppUser user = prepareUserUpdate(0); |
| | | user.setClinicId(10L); |
| | | user.setSuperiorClinicUserId(100L); |
| | | |
| | | userAppService.update(12L, updateRequest(null)); |
| | | |
| | | assertClinicBinding(Collections.singletonList(12L), null, null); |
| | | verify(clinicMapper, never()).selectById(any()); |
| | | } |
| | | |
| | | @Test |
| | | void updateShouldPreserveDoctorAccountClinic() { |
| | | AppUser user = prepareUserUpdate(1); |
| | | user.setClinicId(10L); |
| | | |
| | | userAppService.update(12L, updateRequest(null)); |
| | | |
| | | assertEquals(Long.valueOf(10L), user.getClinicId()); |
| | | verify(userMapper).updateById(user); |
| | | verify(userMapper, never()).update(any(), any()); |
| | | } |
| | | |
| | | @Test |
| | | void batchUpdateShouldSynchronizeBothClinicFields() { |
| | | prepareClinicAccounts(1); |
| | | when(userMapper.selectCount(any())).thenReturn(2L); |
| | | |
| | | userAppService.batchUpdateClinic(batchRequest()); |
| | | |
| | | assertClinicBinding(Arrays.asList(12L, 13L), 20L, 200L); |
| | | } |
| | | |
| | | @ParameterizedTest |
| | | @ValueSource(ints = {0, 2}) |
| | | void updateShouldRejectMissingOrAmbiguousClinicAccount(int accountCount) { |
| | | AppUser user = new AppUser(); |
| | | user.setId(12L); |
| | | user.setType(0); |
| | | when(userMapper.selectOne(any())).thenReturn(user); |
| | | prepareClinicAccounts(accountCount); |
| | | |
| | | IllegalArgumentException error = assertThrows(IllegalArgumentException.class, |
| | | () -> userAppService.update(12L, updateRequest(20L))); |
| | | |
| | | assertEquals(accountCount == 0 ? "目标诊所尚未关联诊所账号,无法绑定患者" |
| | | : "目标诊所关联多个账号,请先确认患者归属", error.getMessage()); |
| | | assertNoUserWrite(); |
| | | } |
| | | |
| | | @ParameterizedTest |
| | | @ValueSource(ints = {0, 2}) |
| | | void batchUpdateShouldRejectMissingOrAmbiguousClinicAccount(int accountCount) { |
| | | prepareClinicAccounts(accountCount); |
| | | |
| | | assertThrows(IllegalArgumentException.class, |
| | | () -> userAppService.batchUpdateClinic(batchRequest())); |
| | | |
| | | assertNoUserWrite(); |
| | | } |
| | | |
| | | @ParameterizedTest |
| | | @ValueSource(booleans = {false, true}) |
| | | void batchUpdateShouldRejectMissingOrDeletedClinic(boolean deleted) { |
| | | if (deleted) { |
| | | Clinic clinic = new Clinic(); |
| | | clinic.setId(20L); |
| | | clinic.setDeleted(1); |
| | | when(clinicMapper.selectById(20L)).thenReturn(clinic); |
| | | } |
| | | |
| | | IllegalArgumentException error = assertThrows(IllegalArgumentException.class, |
| | | () -> userAppService.batchUpdateClinic(batchRequest())); |
| | | |
| | | assertEquals("绑定诊所不存在", error.getMessage()); |
| | | assertNoUserWrite(); |
| | | } |
| | | |
| | | @Test |
| | | void batchUpdateShouldRejectUsersOutsidePersonalUserScope() { |
| | | prepareClinicAccounts(1); |
| | | when(userMapper.selectCount(any())).thenAnswer(invocation -> { |
| | | com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AppUser> query = |
| | | invocation.getArgument(0); |
| | | assertTrue(query.getSqlSegment().contains("type =")); |
| | | assertTrue(query.getParamNameValuePairs().containsValue(0)); |
| | | return 1L; |
| | | }); |
| | | |
| | | IllegalArgumentException error = assertThrows(IllegalArgumentException.class, |
| | | () -> userAppService.batchUpdateClinic(batchRequest())); |
| | | |
| | | assertEquals("部分用户不存在或不是普通用户", error.getMessage()); |
| | | assertNoUserWrite(); |
| | | } |
| | | |
| | | private AppUser prepareUserUpdate(int type) { |
| | | AppUser user = new AppUser(); |
| | | user.setId(12L); |
| | | user.setType(type); |
| | | user.setDeleted(0); |
| | | // 第一次查询用户,第二次检查手机号冲突。 |
| | | when(userMapper.selectOne(any())).thenReturn(user, null); |
| | | UserDetailRow detail = new UserDetailRow(); |
| | | detail.setId(12L); |
| | | when(userMapper.selectUserDetail(12L)).thenReturn(detail); |
| | | return user; |
| | | } |
| | | |
| | | private void prepareClinicAccounts(int count) { |
| | | Clinic clinic = new Clinic(); |
| | | clinic.setId(20L); |
| | | clinic.setDeleted(0); |
| | | when(clinicMapper.selectById(20L)).thenReturn(clinic); |
| | | AppUser doctor = new AppUser(); |
| | | doctor.setId(200L); |
| | | doctor.setType(1); |
| | | doctor.setClinicId(20L); |
| | | when(userMapper.selectList(any())).thenAnswer(invocation -> { |
| | | com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AppUser> query = |
| | | invocation.getArgument(0); |
| | | String sql = query.getSqlSegment(); |
| | | assertTrue(sql.contains("clinic_id =") && sql.contains("type =") && sql.contains("deleted =")); |
| | | assertTrue(query.getParamNameValuePairs().values().containsAll(Arrays.asList(20L, 1, 0))); |
| | | return Collections.nCopies(count, doctor); |
| | | }); |
| | | } |
| | | |
| | | private UserUpdateRequest updateRequest(Long clinicId) { |
| | | UserUpdateRequest request = new UserUpdateRequest(); |
| | | request.setNickname("测试用户"); |
| | | request.setPhone("13800000000"); |
| | | request.setStatus(1); |
| | | request.setClinicId(clinicId); |
| | | return request; |
| | | } |
| | | |
| | | private UserBatchClinicUpdateRequest batchRequest() { |
| | | UserBatchClinicUpdateRequest request = new UserBatchClinicUpdateRequest(); |
| | | request.setUserIds(Arrays.asList(12L, 13L)); |
| | | request.setClinicId(20L); |
| | | return request; |
| | | } |
| | | |
| | | private void assertNoUserWrite() { |
| | | verify(userMapper, never()).updateById(any(AppUser.class)); |
| | | verify(userMapper, never()).update(any(), any()); |
| | | } |
| | | |
| | | private void assertClinicBinding(List<Long> userIds, Long clinicId, Long doctorId) { |
| | | ArgumentCaptor<LambdaUpdateWrapper<AppUser>> captor = ArgumentCaptor.forClass(LambdaUpdateWrapper.class); |
| | | verify(userMapper).update(isNull(), captor.capture()); |
| | | LambdaUpdateWrapper<AppUser> update = captor.getValue(); |
| | | // 按列名核对绑定参数,避免诊所 ID 和诊所账号 ID 被误用。 |
| | | String[] assignments = update.getSqlSet().split(","); |
| | | assertEquals(2, assignments.length); |
| | | assertAssignment(update, assignments[0], "clinic_id", clinicId); |
| | | assertAssignment(update, assignments[1], "superior_clinic_user_id", doctorId); |
| | | String sql = update.getSqlSegment(); |
| | | assertTrue(sql.contains("id IN") && sql.contains("type =") && sql.contains("deleted =")); |
| | | assertTrue(update.getParamNameValuePairs().values().containsAll(userIds)); |
| | | assertTrue(update.getParamNameValuePairs().containsValue(0)); |
| | | } |
| | | |
| | | private void assertAssignment(LambdaUpdateWrapper<AppUser> update, String assignment, |
| | | String column, Long expectedValue) { |
| | | assertTrue(assignment.startsWith(column + "=")); |
| | | String parameter = assignment.substring(assignment.lastIndexOf('.') + 1, assignment.length() - 1); |
| | | assertTrue(update.getParamNameValuePairs().containsKey(parameter)); |
| | | assertEquals(expectedValue, update.getParamNameValuePairs().get(parameter)); |
| | | } |
| | | } |