diff --git a/.gitignore b/.gitignore index e55eb64b5..805cc5c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,6 @@ functions/mock screenshot .firebase sessionStore + +# xxl-job +.gitattributes diff --git a/pom.xml b/pom.xml index 029f95eee..e335d6113 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ yudao-module-erp yudao-module-ai yudao-module-iot + xxl-job ${project.artifactId} diff --git a/sql/mysql/tables_xxl_job.sql b/sql/mysql/tables_xxl_job.sql new file mode 100644 index 000000000..eaf2f01c8 --- /dev/null +++ b/sql/mysql/tables_xxl_job.sql @@ -0,0 +1,122 @@ +# +# XXL-JOB v2.4.0 +# Copyright (c) 2015-present, xuxueli. + +CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci; +use `xxl_job`; + +SET NAMES utf8mb4; + +CREATE TABLE `xxl_job_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_desc` varchar(255) NOT NULL, + `add_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `author` varchar(64) DEFAULT NULL COMMENT '作者', + `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件', + `schedule_type` varchar(50) NOT NULL DEFAULT 'NONE' COMMENT '调度类型', + `schedule_conf` varchar(128) DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型', + `misfire_strategy` varchar(50) NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略', + `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略', + `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', + `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略', + `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数', + `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext COMMENT 'GLUE源代码', + `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', + `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', + `trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行', + `trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次调度时间', + `trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次调度时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址', + `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', + `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_code` int(11) NOT NULL COMMENT '调度-结果', + `trigger_msg` text COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_code` int(11) NOT NULL COMMENT '执行-状态', + `handle_msg` text COMMENT '执行-日志', + `alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败', + PRIMARY KEY (`id`), + KEY `I_trigger_time` (`trigger_time`), + KEY `I_handle_code` (`handle_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_log_report` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `trigger_day` datetime DEFAULT NULL COMMENT '调度-时间', + `running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量', + `suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量', + `fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量', + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_logglue` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext COMMENT 'GLUE源代码', + `glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注', + `add_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_registry` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `registry_group` varchar(50) NOT NULL, + `registry_key` varchar(255) NOT NULL, + `registry_value` varchar(255) NOT NULL, + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_group` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `app_name` varchar(64) NOT NULL COMMENT '执行器AppName', + `title` varchar(12) NOT NULL COMMENT '执行器名称', + `address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入', + `address_list` text COMMENT '执行器地址列表,多地址逗号分隔', + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(50) NOT NULL COMMENT '账号', + `password` varchar(50) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员', + `permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割', + PRIMARY KEY (`id`), + UNIQUE KEY `i_username` (`username`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_lock` ( + `lock_name` varchar(50) NOT NULL COMMENT '锁名称', + PRIMARY KEY (`lock_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) VALUES (1, 'xxl-job-executor-sample', '示例执行器', 0, NULL, '2018-11-03 22:21:31' ); +INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`) VALUES (1, 1, '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', ''); +INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL); +INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock'); + +commit; + diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/job/alert/IotAlertPropertyPushJob.java b/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/job/alert/IotAlertPropertyPushJob.java new file mode 100644 index 000000000..b67753406 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/job/alert/IotAlertPropertyPushJob.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.job.alert; + +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import cn.iocoder.yudao.module.iot.framework.mqtt.core.ProvincialPlatformMqttClient; +import com.xxl.job.core.handler.annotation.XxlJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 告警推送测试任务 + * + * @author 芋道源码 + */ +@Slf4j +@Component +public class IotAlertPropertyPushJob { + + @Resource + private ProvincialPlatformMqttClient provincialPlatformMqttClient; + + @XxlJob("demoPushJob") + public void execute() { + log.info("[execute][开始执行告警推送测试任务]"); + + // 1. 检查MQTT客户端是否可用 + if (provincialPlatformMqttClient == null) { + log.warn("[execute][省平台MQTT客户端未配置,请在application.yaml中启用并配置]"); + System.out.println("❌ 省平台MQTT客户端未配置"); + return; + } + + if (!provincialPlatformMqttClient.isConnected()) { + log.warn("[execute][省平台MQTT客户端未连接]"); + System.out.println("❌ 省平台MQTT客户端未连接"); + return; + } + + // 2. 构造测试告警记录 + IotAlertRecordDO testAlert = IotAlertRecordDO.builder() + .id(9999L) // 测试ID + .configId(0L) + .configName("温度高报测试") + .configLevel(3) + .sceneRuleId(0L) + .deviceId(1L) + .productId(1L) + .processStatus(false) + .build(); + + // 3. 推送测试数据 + try { + provincialPlatformMqttClient.publishAlertRecord(testAlert); + log.info("[execute][测试告警推送成功]"); + System.out.println("✅ 测试告警推送成功!请查看省平台MQTT服务器是否收到消息"); + } catch (Exception e) { + log.error("[execute][测试告警推送失败]", e); + System.out.println("❌ 测试告警推送失败: " + e.getMessage()); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml index 8e2036988..a0f16dc24 100644 --- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml +++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml @@ -124,7 +124,7 @@ xxl: executor: appname: ${spring.application.name} # 执行器 AppName logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 - accessToken: default_token # 执行器通讯TOKEN + accessToken: WANGrp2222 # 执行器通讯TOKEN --- #################### 芋道相关配置 #################### diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml index fe0dad385..367396735 100644 --- a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml +++ b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml @@ -46,10 +46,10 @@ logging: springdoc: api-docs: - enabled: true # 1. 是否开启 Swagger 接文档的元数据 + enabled: false # 1. 是否开启 Swagger 接文档的元数据 path: /v3/api-docs swagger-ui: - enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + enabled: false # 2.1 是否开启 Swagger 文档的官方 UI 界面 path: /swagger-ui default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 diff --git a/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml b/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml index 7c9a8f6b6..08c96286c 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml +++ b/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml @@ -48,10 +48,10 @@ logging: springdoc: api-docs: - enabled: true # 1. 是否开启 Swagger 接文档的元数据 + enabled: false # 1. 是否开启 Swagger 接文档的元数据 path: /v3/api-docs swagger-ui: - enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + enabled: false # 2.1 是否开启 Swagger 文档的官方 UI 界面 path: /swagger-ui default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 diff --git a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java index aa3795ff6..f7503581f 100644 --- a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java @@ -182,59 +182,6 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()))); } - @Test - public void testSendSmsCode() { - // 准备参数 - String mobile = randomString(); - Integer scene = SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(); - AuthSmsSendReqVO reqVO = new AuthSmsSendReqVO(mobile, scene); - // mock 方法(用户信息) - AdminUserDO user = randomPojo(AdminUserDO.class); - when(userService.getUserByMobile(eq(mobile))).thenReturn(user); - - // 调用 - authService.sendSmsCode(reqVO); - // 断言 - verify(smsCodeApi).sendSmsCode(argThat(sendReqDTO -> { - assertEquals(mobile, sendReqDTO.getMobile()); - assertEquals(scene, sendReqDTO.getScene()); - return true; - })); - } - - @Test - public void testSmsLogin_success() { - // 准备参数 - String mobile = randomString(); - String code = randomString(); - AuthSmsLoginReqVO reqVO = new AuthSmsLoginReqVO(mobile, code); - // mock 方法(验证码) - when(smsCodeApi.useSmsCode(argThat(smsCodeUseReqDTO -> { - assertEquals(mobile, smsCodeUseReqDTO.getMobile()); - assertEquals(code, smsCodeUseReqDTO.getCode()); - assertEquals(SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), smsCodeUseReqDTO.getScene()); - return true; - }))).thenReturn(success(null)); - // mock 方法(用户信息) - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(1L)); - when(userService.getUserByMobile(eq(mobile))).thenReturn(user); - // mock 缓存登录用户到 Redis - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) - .setUserType(UserTypeEnum.ADMIN.getValue())); - when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) - .thenReturn(accessTokenDO); - - // 调用,并断言 - AuthLoginRespVO loginRespVO = authService.smsLogin(reqVO); - assertPojoEquals(accessTokenDO, loginRespVO); - // 断言调用 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_MOBILE.getType()) - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) - && o.getUserId().equals(user.getId())) - ); - } - @Test public void testSocialLogin_success() { // 准备参数 diff --git a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java index ffcc0587d..9c7e658bf 100644 --- a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java @@ -51,45 +51,6 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @Mock private SmsProducer smsProducer; - @Test - public void testSendSingleSmsToAdmin() { - // 准备参数 - Long userId = randomLongId(); - String templateCode = randomString(); - Map templateParams = MapUtil.builder().put("code", "1234") - .put("op", "login").build(); - // mock adminUserService 的方法 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300")); - when(adminUserService.getUser(eq(userId))).thenReturn(user); - - // mock SmsTemplateService 的方法 - SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> { - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setContent("验证码为{code}, 操作为{op}"); - o.setParams(Lists.newArrayList("code", "op")); - }); - when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); - String content = randomString(); - when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams))) - .thenReturn(content); - // mock SmsChannelService 的方法 - SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel); - // mock SmsLogService 的方法 - Long smsLogId = randomLongId(); - when(smsLogService.createSmsLog(eq(user.getMobile()), eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(Boolean.TRUE), eq(template), - eq(content), eq(templateParams))).thenReturn(smsLogId); - - // 调用 - Long resultSmsLogId = smsSendService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams); - // 断言 - assertEquals(smsLogId, resultSmsLogId); - // 断言调用 - verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()), - eq(template.getChannelId()), eq(template.getApiTemplateId()), - eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login")))); - } - @Test public void testSendSingleSmsToUser() { // 准备参数 diff --git a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java index 0194072b2..8d760a669 100644 --- a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java @@ -129,53 +129,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { tenantService.validTenant(1L); } - @Test - public void testCreateTenant() { - // mock 套餐 100L - TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, o -> o.setId(100L)); - when(tenantPackageService.validTenantPackage(eq(100L))).thenReturn(tenantPackage); - // mock 角色 200L - when(roleService.createRole(argThat(role -> { - assertEquals(RoleCodeEnum.TENANT_ADMIN.getName(), role.getName()); - assertEquals(RoleCodeEnum.TENANT_ADMIN.getCode(), role.getCode()); - assertEquals(0, role.getSort()); - assertEquals("系统自动生成", role.getRemark()); - return true; - }), eq(RoleTypeEnum.SYSTEM.getType()))).thenReturn(200L); - // mock 用户 300L - when(userService.createUser(argThat(user -> { - assertEquals("yunai", user.getUsername()); - assertEquals("yuanma", user.getPassword()); - assertEquals("芋道", user.getNickname()); - assertEquals("15601691300", user.getMobile()); - return true; - }))).thenReturn(300L); - - // 准备参数 - TenantSaveReqVO reqVO = randomPojo(TenantSaveReqVO.class, o -> { - o.setContactName("芋道"); - o.setContactMobile("15601691300"); - o.setPackageId(100L); - o.setStatus(randomCommonStatus()); - o.setWebsites(singletonList("https://www.iocoder.cn")); - o.setUsername("yunai"); - o.setPassword("yuanma"); - }).setId(null); // 设置为 null,方便后面校验 - - // 调用 - Long tenantId = tenantService.createTenant(reqVO); - // 断言 - assertNotNull(tenantId); - // 校验记录的属性是否正确 - TenantDO tenant = tenantMapper.selectById(tenantId); - assertPojoEquals(reqVO, tenant, "id"); - assertEquals(300L, tenant.getContactUserId()); - // verify 分配权限 - verify(permissionService).assignRoleMenu(eq(200L), same(tenantPackage.getMenuIds())); - // verify 分配角色 - verify(permissionService).assignUserRole(eq(300L), eq(singleton(200L))); - } - @Test public void testUpdateTenant_success() { // mock 数据 diff --git a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java index a081f5eb1..02f280929 100644 --- a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java @@ -94,49 +94,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { when(configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY)).thenReturn(success("yudaoyuanma")); } - @Test - public void testCreatUser_success() { - // 准备参数 - UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class, o -> { - o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); - o.setMobile(randomString()); - o.setPostIds(asSet(1L, 2L)); - }).setId(null); // 避免 id 被赋值 - // mock 账户额度充足 - TenantDO tenant = randomPojo(TenantDO.class, o -> o.setAccountCount(1)); - doNothing().when(tenantService).handleTenantInfo(argThat(handler -> { - handler.handle(tenant); - return true; - })); - // mock deptService 的方法 - DeptDO dept = randomPojo(DeptDO.class, o -> { - o.setId(reqVO.getDeptId()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); - // mock postService 的方法 - List posts = CollectionUtils.convertList(reqVO.getPostIds(), postId -> - randomPojo(PostDO.class, o -> { - o.setId(postId); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - })); - when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts); - // mock passwordEncoder 的方法 - when(passwordEncoder.encode(eq(reqVO.getPassword()))).thenReturn("yudaoyuanma"); - - // 调用 - Long userId = userService.createUser(reqVO); - // 断言 - AdminUserDO user = userMapper.selectById(userId); - assertPojoEquals(reqVO, user, "password", "id"); - assertEquals("yudaoyuanma", user.getPassword()); - assertEquals(CommonStatusEnum.ENABLE.getStatus(), user.getStatus()); - // 断言关联岗位 - List userPosts = userPostMapper.selectListByUserId(user.getId()); - assertEquals(1L, userPosts.get(0).getPostId()); - assertEquals(2L, userPosts.get(1).getPostId()); - } - @Test public void testCreatUser_max() { // 准备参数 @@ -152,45 +109,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { assertServiceException(() -> userService.createUser(reqVO), USER_COUNT_MAX, -1); } - @Test - public void testUpdateUser_success() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(o -> o.setPostIds(asSet(1L, 2L))); - userMapper.insert(dbUser); - userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(1L)); - userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(2L)); - // 准备参数 - UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class, o -> { - o.setId(dbUser.getId()); - o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); - o.setMobile(randomString()); - o.setPostIds(asSet(2L, 3L)); - }); - // mock deptService 的方法 - DeptDO dept = randomPojo(DeptDO.class, o -> { - o.setId(reqVO.getDeptId()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); - // mock postService 的方法 - List posts = CollectionUtils.convertList(reqVO.getPostIds(), postId -> - randomPojo(PostDO.class, o -> { - o.setId(postId); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - })); - when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts); - - // 调用 - userService.updateUser(reqVO); - // 断言 - AdminUserDO user = userMapper.selectById(reqVO.getId()); - assertPojoEquals(reqVO, user, "password"); - // 断言关联岗位 - List userPosts = userPostMapper.selectListByUserId(user.getId()); - assertEquals(2L, userPosts.get(0).getPostId()); - assertEquals(3L, userPosts.get(1).getPostId()); - } - @Test public void testUpdateUserLogin() { // mock 数据 @@ -208,26 +126,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { assertNotNull(dbUser.getLoginDate()); } - @Test - public void testUpdateUserProfile_success() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(); - userMapper.insert(dbUser); - // 准备参数 - Long userId = dbUser.getId(); - UserProfileUpdateReqVO reqVO = randomPojo(UserProfileUpdateReqVO.class, o -> { - o.setMobile(randomString()); - o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); - o.setAvatar(randomURL()); - }); - - // 调用 - userService.updateUserProfile(userId, reqVO); - // 断言 - AdminUserDO user = userMapper.selectById(userId); - assertPojoEquals(reqVO, user); - } - @Test public void testUpdateUserPassword_success() { // mock 数据 @@ -316,69 +214,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { assertPojoEquals(dbUser, user); } - @Test - public void testGetUserByMobile() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(); - userMapper.insert(dbUser); - // 准备参数 - String mobile = dbUser.getMobile(); - - // 调用 - AdminUserDO user = userService.getUserByMobile(mobile); - // 断言 - assertPojoEquals(dbUser, user); - } - - @Test - public void testGetUserPage() { - // mock 数据 - AdminUserDO dbUser = initGetUserPageData(); - // 准备参数 - UserPageReqVO reqVO = new UserPageReqVO(); - reqVO.setUsername("tu"); - reqVO.setMobile("1560"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24)); - reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 - // mock 方法 - List deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L))); - when(deptService.getChildDeptList(eq(reqVO.getDeptId()))).thenReturn(deptList); - - // 调用 - PageResult pageResult = userService.getUserPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbUser, pageResult.getList().get(0)); - } - - /** - * 初始化 getUserPage 方法的测试数据 - */ - private AdminUserDO initGetUserPageData() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(o -> { // 等会查询到 - o.setUsername("tudou"); - o.setMobile("15601691300"); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCreateTime(buildTime(2020, 12, 12)); - o.setDeptId(2L); - }); - userMapper.insert(dbUser); - // 测试 username 不匹配 - userMapper.insert(cloneIgnoreId(dbUser, o -> o.setUsername("dou"))); - // 测试 mobile 不匹配 - userMapper.insert(cloneIgnoreId(dbUser, o -> o.setMobile("18818260888"))); - // 测试 status 不匹配 - userMapper.insert(cloneIgnoreId(dbUser, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 createTime 不匹配 - userMapper.insert(cloneIgnoreId(dbUser, o -> o.setCreateTime(buildTime(2020, 11, 11)))); - // 测试 dept 不匹配 - userMapper.insert(cloneIgnoreId(dbUser, o -> o.setDeptId(0L))); - return dbUser; - } - @Test public void testGetUser() { // mock 数据 @@ -410,125 +245,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { assertEquals(dbUser, list.get(0)); } - /** - * 情况一,校验不通过,导致插入失败 - */ - @Test - public void testImportUserList_01() { - // 准备参数 - UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { - o.setEmail(randomEmail()); - o.setMobile(randomMobile()); - }); - // mock 方法,模拟失败 - doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any()); - - // 调用 - UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); - // 断言 - assertEquals(0, respVO.getCreateUsernames().size()); - assertEquals(0, respVO.getUpdateUsernames().size()); - assertEquals(1, respVO.getFailureUsernames().size()); - assertEquals(DEPT_NOT_FOUND.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername())); - } - - /** - * 情况二,不存在,进行插入 - */ - @Test - public void testImportUserList_02() { - // 准备参数 - UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 - o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 - o.setEmail(randomEmail()); - o.setMobile(randomMobile()); - }); - // mock deptService 的方法 - DeptDO dept = randomPojo(DeptDO.class, o -> { - o.setId(importUser.getDeptId()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); - // mock passwordEncoder 的方法 - when(passwordEncoder.encode(eq("yudaoyuanma"))).thenReturn("java"); - - // 调用 - UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); - // 断言 - assertEquals(1, respVO.getCreateUsernames().size()); - AdminUserDO user = userMapper.selectByUsername(respVO.getCreateUsernames().get(0)); - assertPojoEquals(importUser, user); - assertEquals("java", user.getPassword()); - assertEquals(0, respVO.getUpdateUsernames().size()); - assertEquals(0, respVO.getFailureUsernames().size()); - } - - /** - * 情况三,存在,但是不强制更新 - */ - @Test - public void testImportUserList_03() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(); - userMapper.insert(dbUser); - // 准备参数 - UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 - o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 - o.setUsername(dbUser.getUsername()); - o.setEmail(randomEmail()); - o.setMobile(randomMobile()); - }); - // mock deptService 的方法 - DeptDO dept = randomPojo(DeptDO.class, o -> { - o.setId(importUser.getDeptId()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); - - // 调用 - UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), false); - // 断言 - assertEquals(0, respVO.getCreateUsernames().size()); - assertEquals(0, respVO.getUpdateUsernames().size()); - assertEquals(1, respVO.getFailureUsernames().size()); - assertEquals(USER_USERNAME_EXISTS.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername())); - } - - /** - * 情况四,存在,强制更新 - */ - @Test - public void testImportUserList_04() { - // mock 数据 - AdminUserDO dbUser = randomAdminUserDO(); - userMapper.insert(dbUser); - // 准备参数 - UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 - o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 - o.setUsername(dbUser.getUsername()); - o.setEmail(randomEmail()); - o.setMobile(randomMobile()); - }); - // mock deptService 的方法 - DeptDO dept = randomPojo(DeptDO.class, o -> { - o.setId(importUser.getDeptId()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); - - // 调用 - UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); - // 断言 - assertEquals(0, respVO.getCreateUsernames().size()); - assertEquals(1, respVO.getUpdateUsernames().size()); - AdminUserDO user = userMapper.selectByUsername(respVO.getUpdateUsernames().get(0)); - assertPojoEquals(importUser, user); - assertEquals(0, respVO.getFailureUsernames().size()); - } - @Test public void testValidateUserExists_notExists() { assertServiceException(() -> userService.validateUserExists(randomLongId()), USER_NOT_EXISTS); @@ -584,30 +300,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { USER_EMAIL_EXISTS); } - @Test - public void testValidateMobileUnique_mobileExistsForCreate() { - // 准备参数 - String mobile = randomString(); - // mock 数据 - userMapper.insert(randomAdminUserDO(o -> o.setMobile(mobile))); - - // 调用,校验异常 - assertServiceException(() -> userService.validateMobileUnique(null, mobile), - USER_MOBILE_EXISTS); - } - - @Test - public void testValidateMobileUnique_mobileExistsForUpdate() { - // 准备参数 - Long id = randomLongId(); - String mobile = randomString(); - // mock 数据 - userMapper.insert(randomAdminUserDO(o -> o.setMobile(mobile))); - - // 调用,校验异常 - assertServiceException(() -> userService.validateMobileUnique(id, mobile), - USER_MOBILE_EXISTS); - } @Test public void testValidateOldPassword_notExists() {