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() {