Commit dd0c1a00f32d08809f3ee5944141de5f304155e4

Authored by puhui999
1 parent cf3ecd3e

feat:【IoT 物联网】新增场景联动单元测试,抽离出测试代码

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java
@@ -14,7 +14,6 @@ import io.swagger.v3.oas.annotations.Operation; @@ -14,7 +14,6 @@ import io.swagger.v3.oas.annotations.Operation;
14 import io.swagger.v3.oas.annotations.Parameter; 14 import io.swagger.v3.oas.annotations.Parameter;
15 import io.swagger.v3.oas.annotations.tags.Tag; 15 import io.swagger.v3.oas.annotations.tags.Tag;
16 import jakarta.annotation.Resource; 16 import jakarta.annotation.Resource;
17 -import jakarta.annotation.security.PermitAll;  
18 import jakarta.validation.Valid; 17 import jakarta.validation.Valid;
19 import org.springframework.security.access.prepost.PreAuthorize; 18 import org.springframework.security.access.prepost.PreAuthorize;
20 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
@@ -91,10 +90,4 @@ public class IotRuleSceneController { @@ -91,10 +90,4 @@ public class IotRuleSceneController {
91 new IotRuleSceneRespVO().setId(scene.getId()).setName(scene.getName()))); 90 new IotRuleSceneRespVO().setId(scene.getId()).setName(scene.getName())));
92 } 91 }
93 92
94 - @GetMapping("/test")  
95 - @PermitAll  
96 - public void test() {  
97 - ruleSceneService.test();  
98 - }  
99 -  
100 } 93 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java
@@ -103,9 +103,4 @@ public interface IotRuleSceneService { @@ -103,9 +103,4 @@ public interface IotRuleSceneService {
103 */ 103 */
104 void executeRuleSceneByTimer(Long id); 104 void executeRuleSceneByTimer(Long id);
105 105
106 - /**  
107 - * TODO 芋艿:测试方法,需要删除  
108 - */  
109 - void test();  
110 -  
111 } 106 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java
@@ -27,18 +27,11 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; @@ -27,18 +27,11 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum;
27 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; 27 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum;
28 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; 28 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
29 import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; 29 import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
30 -import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob;  
31 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 30 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
32 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 31 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
33 import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; 32 import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
34 import jakarta.annotation.Resource; 33 import jakarta.annotation.Resource;
35 -import lombok.SneakyThrows;  
36 import lombok.extern.slf4j.Slf4j; 34 import lombok.extern.slf4j.Slf4j;
37 -import org.quartz.JobKey;  
38 -import org.quartz.Scheduler;  
39 -import org.quartz.SchedulerException;  
40 -import org.quartz.TriggerKey;  
41 -import org.quartz.impl.StdSchedulerFactory;  
42 import org.springframework.stereotype.Service; 35 import org.springframework.stereotype.Service;
43 import org.springframework.validation.annotation.Validated; 36 import org.springframework.validation.annotation.Validated;
44 37
@@ -556,50 +549,4 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -556,50 +549,4 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
556 }); 549 });
557 } 550 }
558 551
559 - @Override  
560 - @SneakyThrows  
561 - public void test() {  
562 - // TODO @芋艿:测试思路代码,记得删除!!!  
563 - // 1. Job 类:IotRuleSceneJob DONE  
564 - // 2. 参数:id DONE  
565 - // 3. jobHandlerName:IotRuleSceneJob + id DONE  
566 -  
567 - // 新增:addJob  
568 - // 修改:不存在 addJob、存在 updateJob  
569 - // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以)pauseJob  
570 - // 有 + 开启:1)存在,更新;2)不存在,新增;结论:使用 save(addOrUpdateJob)  
571 - // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以)deleteJob  
572 -  
573 - //  
574 - if (false) {  
575 - Long id = 1L;  
576 - Map<String, Object> jobDataMap = IotRuleSceneJob.buildJobDataMap(id);  
577 - schedulerManager.addOrUpdateJob(IotRuleSceneJob.class,  
578 - IotRuleSceneJob.buildJobName(id),  
579 - "0/10 * * * * ?",  
580 - jobDataMap);  
581 - }  
582 - if (false) {  
583 - Long id = 1L;  
584 - schedulerManager.pauseJob(IotRuleSceneJob.buildJobName(id));  
585 - }  
586 - if (true) {  
587 - Long id = 1L;  
588 - schedulerManager.deleteJob(IotRuleSceneJob.buildJobName(id));  
589 - }  
590 - }  
591 -  
592 - public static void main2(String[] args) throws SchedulerException {  
593 -// System.out.println(QuartzJobBean.class);  
594 - Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();  
595 - scheduler.start();  
596 -  
597 - String jobHandlerName = "123";  
598 - // 暂停 Trigger 对象  
599 - scheduler.pauseTrigger(new TriggerKey(jobHandlerName));  
600 - // 取消并删除 Job 调度  
601 - scheduler.unscheduleJob(new TriggerKey(jobHandlerName));  
602 - scheduler.deleteJob(new JobKey(jobHandlerName));  
603 - }  
604 -  
605 } 552 }
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.rule.scene;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
  6 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
  7 +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper;
  8 +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
  9 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  10 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
  11 +import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
  12 +import org.junit.jupiter.api.Test;
  13 +import org.mockito.InjectMocks;
  14 +import org.mockito.Mock;
  15 +
  16 +import java.util.Collections;
  17 +import java.util.List;
  18 +
  19 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  21 +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
  22 +import static org.junit.jupiter.api.Assertions.assertEquals;
  23 +import static org.mockito.ArgumentMatchers.any;
  24 +import static org.mockito.Mockito.*;
  25 +
  26 +/**
  27 + * {@link IotRuleSceneServiceImpl} 的简化单元测试类
  28 + * 使用 Mockito 进行纯单元测试,不依赖 Spring 容器
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +public class IotRuleSceneServiceSimpleTest extends BaseMockitoUnitTest {
  33 +
  34 + @InjectMocks
  35 + private IotRuleSceneServiceImpl ruleSceneService;
  36 +
  37 + @Mock
  38 + private IotRuleSceneMapper ruleSceneMapper;
  39 +
  40 + @Mock
  41 + private List<IotSceneRuleAction> ruleSceneActions;
  42 +
  43 + @Mock
  44 + private IotSchedulerManager schedulerManager;
  45 +
  46 + @Mock
  47 + private IotProductService productService;
  48 +
  49 + @Mock
  50 + private IotDeviceService deviceService;
  51 +
  52 + @Test
  53 + public void testCreateRuleScene_success() {
  54 + // 准备参数
  55 + IotRuleSceneSaveReqVO createReqVO = randomPojo(IotRuleSceneSaveReqVO.class, o -> {
  56 + o.setId(null);
  57 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  58 + o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class)));
  59 + o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class)));
  60 + });
  61 +
  62 + // Mock 行为
  63 + Long expectedId = randomLongId();
  64 + when(ruleSceneMapper.insert(any(IotSceneRuleDO.class))).thenAnswer(invocation -> {
  65 + IotSceneRuleDO ruleScene = invocation.getArgument(0);
  66 + ruleScene.setId(expectedId);
  67 + return 1;
  68 + });
  69 +
  70 + // 调用
  71 + Long ruleSceneId = ruleSceneService.createRuleScene(createReqVO);
  72 +
  73 + // 断言
  74 + assertEquals(expectedId, ruleSceneId);
  75 + verify(ruleSceneMapper, times(1)).insert(any(IotSceneRuleDO.class));
  76 + }
  77 +
  78 + @Test
  79 + public void testUpdateRuleScene_success() {
  80 + // 准备参数
  81 + Long id = randomLongId();
  82 + IotRuleSceneSaveReqVO updateReqVO = randomPojo(IotRuleSceneSaveReqVO.class, o -> {
  83 + o.setId(id);
  84 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  85 + o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class)));
  86 + o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class)));
  87 + });
  88 +
  89 + // Mock 行为
  90 + IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
  91 + when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene);
  92 + when(ruleSceneMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1);
  93 +
  94 + // 调用
  95 + assertDoesNotThrow(() -> ruleSceneService.updateRuleScene(updateReqVO));
  96 +
  97 + // 验证
  98 + verify(ruleSceneMapper, times(1)).selectById(id);
  99 + verify(ruleSceneMapper, times(1)).updateById(any(IotSceneRuleDO.class));
  100 + }
  101 +
  102 + @Test
  103 + public void testDeleteRuleScene_success() {
  104 + // 准备参数
  105 + Long id = randomLongId();
  106 +
  107 + // Mock 行为
  108 + IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
  109 + when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene);
  110 + when(ruleSceneMapper.deleteById(id)).thenReturn(1);
  111 +
  112 + // 调用
  113 + assertDoesNotThrow(() -> ruleSceneService.deleteRuleScene(id));
  114 +
  115 + // 验证
  116 + verify(ruleSceneMapper, times(1)).selectById(id);
  117 + verify(ruleSceneMapper, times(1)).deleteById(id);
  118 + }
  119 +
  120 + @Test
  121 + public void testGetRuleScene() {
  122 + // 准备参数
  123 + Long id = randomLongId();
  124 + IotSceneRuleDO expectedRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
  125 +
  126 + // Mock 行为
  127 + when(ruleSceneMapper.selectById(id)).thenReturn(expectedRuleScene);
  128 +
  129 + // 调用
  130 + IotSceneRuleDO result = ruleSceneService.getRuleScene(id);
  131 +
  132 + // 断言
  133 + assertEquals(expectedRuleScene, result);
  134 + verify(ruleSceneMapper, times(1)).selectById(id);
  135 + }
  136 +
  137 + @Test
  138 + public void testUpdateRuleSceneStatus_success() {
  139 + // 准备参数
  140 + Long id = randomLongId();
  141 + Integer status = CommonStatusEnum.DISABLE.getStatus();
  142 +
  143 + // Mock 行为
  144 + IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> {
  145 + o.setId(id);
  146 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  147 + });
  148 + when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene);
  149 + when(ruleSceneMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1);
  150 +
  151 + // 调用
  152 + assertDoesNotThrow(() -> ruleSceneService.updateRuleSceneStatus(id, status));
  153 +
  154 + // 验证
  155 + verify(ruleSceneMapper, times(1)).selectById(id);
  156 + verify(ruleSceneMapper, times(1)).updateById(any(IotSceneRuleDO.class));
  157 + }
  158 +
  159 + @Test
  160 + public void testExecuteRuleSceneByTimer_success() {
  161 + // 准备参数
  162 + Long id = randomLongId();
  163 +
  164 + // Mock 行为
  165 + IotSceneRuleDO ruleScene = randomPojo(IotSceneRuleDO.class, o -> {
  166 + o.setId(id);
  167 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  168 + });
  169 + when(ruleSceneMapper.selectById(id)).thenReturn(ruleScene);
  170 +
  171 + // 调用
  172 + assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id));
  173 +
  174 + // 验证
  175 + verify(ruleSceneMapper, times(1)).selectById(id);
  176 + }
  177 +
  178 + @Test
  179 + public void testExecuteRuleSceneByTimer_notExists() {
  180 + // 准备参数
  181 + Long id = randomLongId();
  182 +
  183 + // Mock 行为
  184 + when(ruleSceneMapper.selectById(id)).thenReturn(null);
  185 +
  186 + // 调用 - 不存在的场景规则应该不会抛异常,只是记录日志
  187 + assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id));
  188 +
  189 + // 验证
  190 + verify(ruleSceneMapper, times(1)).selectById(id);
  191 + }
  192 +
  193 + @Test
  194 + public void testExecuteRuleSceneByTimer_disabled() {
  195 + // 准备参数
  196 + Long id = randomLongId();
  197 +
  198 + // Mock 行为
  199 + IotSceneRuleDO ruleScene = randomPojo(IotSceneRuleDO.class, o -> {
  200 + o.setId(id);
  201 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  202 + });
  203 + when(ruleSceneMapper.selectById(id)).thenReturn(ruleScene);
  204 +
  205 + // 调用 - 禁用的场景规则应该不会执行,只是记录日志
  206 + assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id));
  207 +
  208 + // 验证
  209 + verify(ruleSceneMapper, times(1)).selectById(id);
  210 + }
  211 +}
yudao-module-iot/yudao-module-iot-biz/src/test/resources/application-unit-test.yaml 0 → 100644
  1 +spring:
  2 + main:
  3 + lazy-initialization: true # 开启懒加载,加快速度
  4 + banner-mode: off # 单元测试,禁用 Banner
  5 + # 数据源配置项
  6 + datasource:
  7 + name: ruoyi-vue-pro
  8 + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
  9 + driver-class-name: org.h2.Driver
  10 + username: sa
  11 + password:
  12 + druid:
  13 + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
  14 + initial-size: 1 # 单元测试,配置为 1,提升启动速度
  15 + sql:
  16 + init:
  17 + schema-locations: classpath:/sql/create_tables.sql
  18 +
  19 +mybatis-plus:
  20 + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
  21 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
  22 +
  23 +--- #################### 定时任务相关配置 ####################
  24 +
  25 +--- #################### 配置中心相关配置 ####################
  26 +
  27 +--- #################### 服务保障相关配置 ####################
  28 +
  29 +# Lock4j 配置项(单元测试,禁用 Lock4j)
  30 +
  31 +--- #################### 监控相关配置 ####################
  32 +
  33 +--- #################### 芋道相关配置 ####################
  34 +
  35 +# 芋道配置项,设置当前项目所有自定义的配置
  36 +yudao:
  37 + info:
  38 + base-package: cn.iocoder.yudao
  39 + tenant: # 多租户相关配置项
  40 + enable: true
  41 + xss:
  42 + enable: false
  43 + demo: false # 关闭演示模式
yudao-module-iot/yudao-module-iot-biz/src/test/resources/logback.xml 0 → 100644
  1 +<configuration>
  2 + <!-- 引用 Spring Boot 的 logback 基础配置 -->
  3 + <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
  4 +</configuration>
yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/clean.sql 0 → 100644
  1 +-- IoT 模块测试数据清理脚本
  2 +DELETE
  3 +FROM "iot_scene_rule";
  4 +DELETE
  5 +FROM "iot_product";
  6 +DELETE
  7 +FROM "iot_device";
  8 +DELETE
  9 +FROM "iot_thing_model";
  10 +DELETE
  11 +FROM "iot_device_data";
  12 +DELETE
  13 +FROM "iot_alert_config";
  14 +DELETE
  15 +FROM "iot_alert_record";
  16 +DELETE
  17 +FROM "iot_ota_firmware";
  18 +DELETE
  19 +FROM "iot_ota_task";
  20 +DELETE
  21 +FROM "iot_ota_record";
yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/create_tables.sql 0 → 100644
  1 +-- IoT 模块测试数据库表结构
  2 +-- 基于 H2 数据库语法,兼容 MySQL 模式
  3 +
  4 +-- IoT 场景联动规则表
  5 +CREATE TABLE IF NOT EXISTS "iot_scene_rule"
  6 +(
  7 + "id"
  8 + bigint
  9 + NOT
  10 + NULL
  11 + GENERATED
  12 + BY
  13 + DEFAULT AS
  14 + IDENTITY,
  15 + "name"
  16 + varchar
  17 +(
  18 + 255
  19 +) NOT NULL DEFAULT '',
  20 + "description" varchar
  21 +(
  22 + 500
  23 +) DEFAULT NULL,
  24 + "status" tinyint NOT NULL DEFAULT '0',
  25 + "triggers" text,
  26 + "actions" text,
  27 + "creator" varchar
  28 +(
  29 + 64
  30 +) DEFAULT '',
  31 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  32 + "updater" varchar
  33 +(
  34 + 64
  35 +) DEFAULT '',
  36 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  37 + "deleted" bit NOT NULL DEFAULT FALSE,
  38 + "tenant_id" bigint NOT NULL DEFAULT '0',
  39 + PRIMARY KEY
  40 +(
  41 + "id"
  42 +)
  43 + ) COMMENT 'IoT 场景联动规则表';
  44 +
  45 +-- IoT 产品表
  46 +CREATE TABLE IF NOT EXISTS "iot_product"
  47 +(
  48 + "id"
  49 + bigint
  50 + NOT
  51 + NULL
  52 + GENERATED
  53 + BY
  54 + DEFAULT AS
  55 + IDENTITY,
  56 + "name"
  57 + varchar
  58 +(
  59 + 255
  60 +) NOT NULL DEFAULT '',
  61 + "product_key" varchar
  62 +(
  63 + 100
  64 +) NOT NULL DEFAULT '',
  65 + "protocol_type" tinyint NOT NULL DEFAULT '0',
  66 + "category_id" bigint DEFAULT NULL,
  67 + "description" varchar
  68 +(
  69 + 500
  70 +) DEFAULT NULL,
  71 + "data_format" tinyint NOT NULL DEFAULT '0',
  72 + "device_type" tinyint NOT NULL DEFAULT '0',
  73 + "net_type" tinyint NOT NULL DEFAULT '0',
  74 + "validate_type" tinyint NOT NULL DEFAULT '0',
  75 + "status" tinyint NOT NULL DEFAULT '0',
  76 + "creator" varchar
  77 +(
  78 + 64
  79 +) DEFAULT '',
  80 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  81 + "updater" varchar
  82 +(
  83 + 64
  84 +) DEFAULT '',
  85 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  86 + "deleted" bit NOT NULL DEFAULT FALSE,
  87 + "tenant_id" bigint NOT NULL DEFAULT '0',
  88 + PRIMARY KEY
  89 +(
  90 + "id"
  91 +)
  92 + ) COMMENT 'IoT 产品表';
  93 +
  94 +-- IoT 设备表
  95 +CREATE TABLE IF NOT EXISTS "iot_device"
  96 +(
  97 + "id"
  98 + bigint
  99 + NOT
  100 + NULL
  101 + GENERATED
  102 + BY
  103 + DEFAULT AS
  104 + IDENTITY,
  105 + "device_name"
  106 + varchar
  107 +(
  108 + 255
  109 +) NOT NULL DEFAULT '',
  110 + "product_id" bigint NOT NULL,
  111 + "device_key" varchar
  112 +(
  113 + 100
  114 +) NOT NULL DEFAULT '',
  115 + "device_secret" varchar
  116 +(
  117 + 100
  118 +) NOT NULL DEFAULT '',
  119 + "nickname" varchar
  120 +(
  121 + 255
  122 +) DEFAULT NULL,
  123 + "status" tinyint NOT NULL DEFAULT '0',
  124 + "status_last_update_time" timestamp DEFAULT NULL,
  125 + "last_online_time" timestamp DEFAULT NULL,
  126 + "last_offline_time" timestamp DEFAULT NULL,
  127 + "active_time" timestamp DEFAULT NULL,
  128 + "ip" varchar
  129 +(
  130 + 50
  131 +) DEFAULT NULL,
  132 + "firmware_version" varchar
  133 +(
  134 + 50
  135 +) DEFAULT NULL,
  136 + "device_type" tinyint NOT NULL DEFAULT '0',
  137 + "gateway_id" bigint DEFAULT NULL,
  138 + "sub_device_count" int NOT NULL DEFAULT '0',
  139 + "creator" varchar
  140 +(
  141 + 64
  142 +) DEFAULT '',
  143 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  144 + "updater" varchar
  145 +(
  146 + 64
  147 +) DEFAULT '',
  148 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  149 + "deleted" bit NOT NULL DEFAULT FALSE,
  150 + "tenant_id" bigint NOT NULL DEFAULT '0',
  151 + PRIMARY KEY
  152 +(
  153 + "id"
  154 +)
  155 + ) COMMENT 'IoT 设备表';
  156 +
  157 +-- IoT 物模型表
  158 +CREATE TABLE IF NOT EXISTS "iot_thing_model"
  159 +(
  160 + "id"
  161 + bigint
  162 + NOT
  163 + NULL
  164 + GENERATED
  165 + BY
  166 + DEFAULT AS
  167 + IDENTITY,
  168 + "product_id"
  169 + bigint
  170 + NOT
  171 + NULL,
  172 + "identifier"
  173 + varchar
  174 +(
  175 + 100
  176 +) NOT NULL DEFAULT '',
  177 + "name" varchar
  178 +(
  179 + 255
  180 +) NOT NULL DEFAULT '',
  181 + "description" varchar
  182 +(
  183 + 500
  184 +) DEFAULT NULL,
  185 + "type" tinyint NOT NULL DEFAULT '1',
  186 + "property" text,
  187 + "creator" varchar
  188 +(
  189 + 64
  190 +) DEFAULT '',
  191 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  192 + "updater" varchar
  193 +(
  194 + 64
  195 +) DEFAULT '',
  196 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  197 + "deleted" bit NOT NULL DEFAULT FALSE,
  198 + "tenant_id" bigint NOT NULL DEFAULT '0',
  199 + PRIMARY KEY
  200 +(
  201 + "id"
  202 +)
  203 + ) COMMENT 'IoT 物模型表';
  204 +
  205 +-- IoT 设备数据表
  206 +CREATE TABLE IF NOT EXISTS "iot_device_data"
  207 +(
  208 + "id"
  209 + bigint
  210 + NOT
  211 + NULL
  212 + GENERATED
  213 + BY
  214 + DEFAULT AS
  215 + IDENTITY,
  216 + "device_id"
  217 + bigint
  218 + NOT
  219 + NULL,
  220 + "product_id"
  221 + bigint
  222 + NOT
  223 + NULL,
  224 + "identifier"
  225 + varchar
  226 +(
  227 + 100
  228 +) NOT NULL DEFAULT '',
  229 + "type" tinyint NOT NULL DEFAULT '1',
  230 + "data" text,
  231 + "ts" bigint NOT NULL DEFAULT '0',
  232 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  233 + PRIMARY KEY
  234 +(
  235 + "id"
  236 +)
  237 + ) COMMENT 'IoT 设备数据表';
  238 +
  239 +-- IoT 告警配置表
  240 +CREATE TABLE IF NOT EXISTS "iot_alert_config"
  241 +(
  242 + "id"
  243 + bigint
  244 + NOT
  245 + NULL
  246 + GENERATED
  247 + BY
  248 + DEFAULT AS
  249 + IDENTITY,
  250 + "name"
  251 + varchar
  252 +(
  253 + 255
  254 +) NOT NULL DEFAULT '',
  255 + "product_id" bigint NOT NULL,
  256 + "device_id" bigint DEFAULT NULL,
  257 + "rule_id" bigint DEFAULT NULL,
  258 + "status" tinyint NOT NULL DEFAULT '0',
  259 + "creator" varchar
  260 +(
  261 + 64
  262 +) DEFAULT '',
  263 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  264 + "updater" varchar
  265 +(
  266 + 64
  267 +) DEFAULT '',
  268 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  269 + "deleted" bit NOT NULL DEFAULT FALSE,
  270 + "tenant_id" bigint NOT NULL DEFAULT '0',
  271 + PRIMARY KEY
  272 +(
  273 + "id"
  274 +)
  275 + ) COMMENT 'IoT 告警配置表';
  276 +
  277 +-- IoT 告警记录表
  278 +CREATE TABLE IF NOT EXISTS "iot_alert_record"
  279 +(
  280 + "id"
  281 + bigint
  282 + NOT
  283 + NULL
  284 + GENERATED
  285 + BY
  286 + DEFAULT AS
  287 + IDENTITY,
  288 + "alert_config_id"
  289 + bigint
  290 + NOT
  291 + NULL,
  292 + "alert_name"
  293 + varchar
  294 +(
  295 + 255
  296 +) NOT NULL DEFAULT '',
  297 + "product_id" bigint NOT NULL,
  298 + "device_id" bigint DEFAULT NULL,
  299 + "rule_id" bigint DEFAULT NULL,
  300 + "alert_data" text,
  301 + "alert_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  302 + "deal_status" tinyint NOT NULL DEFAULT '0',
  303 + "deal_time" timestamp DEFAULT NULL,
  304 + "deal_user_id" bigint DEFAULT NULL,
  305 + "deal_remark" varchar
  306 +(
  307 + 500
  308 +) DEFAULT NULL,
  309 + "creator" varchar
  310 +(
  311 + 64
  312 +) DEFAULT '',
  313 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  314 + "updater" varchar
  315 +(
  316 + 64
  317 +) DEFAULT '',
  318 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  319 + "deleted" bit NOT NULL DEFAULT FALSE,
  320 + "tenant_id" bigint NOT NULL DEFAULT '0',
  321 + PRIMARY KEY
  322 +(
  323 + "id"
  324 +)
  325 + ) COMMENT 'IoT 告警记录表';
  326 +
  327 +-- IoT OTA 固件表
  328 +CREATE TABLE IF NOT EXISTS "iot_ota_firmware"
  329 +(
  330 + "id"
  331 + bigint
  332 + NOT
  333 + NULL
  334 + GENERATED
  335 + BY
  336 + DEFAULT AS
  337 + IDENTITY,
  338 + "name"
  339 + varchar
  340 +(
  341 + 255
  342 +) NOT NULL DEFAULT '',
  343 + "product_id" bigint NOT NULL,
  344 + "version" varchar
  345 +(
  346 + 50
  347 +) NOT NULL DEFAULT '',
  348 + "description" varchar
  349 +(
  350 + 500
  351 +) DEFAULT NULL,
  352 + "file_url" varchar
  353 +(
  354 + 500
  355 +) DEFAULT NULL,
  356 + "file_size" bigint NOT NULL DEFAULT '0',
  357 + "status" tinyint NOT NULL DEFAULT '0',
  358 + "creator" varchar
  359 +(
  360 + 64
  361 +) DEFAULT '',
  362 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  363 + "updater" varchar
  364 +(
  365 + 64
  366 +) DEFAULT '',
  367 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  368 + "deleted" bit NOT NULL DEFAULT FALSE,
  369 + "tenant_id" bigint NOT NULL DEFAULT '0',
  370 + PRIMARY KEY
  371 +(
  372 + "id"
  373 +)
  374 + ) COMMENT 'IoT OTA 固件表';
  375 +
  376 +-- IoT OTA 升级任务表
  377 +CREATE TABLE IF NOT EXISTS "iot_ota_task"
  378 +(
  379 + "id"
  380 + bigint
  381 + NOT
  382 + NULL
  383 + GENERATED
  384 + BY
  385 + DEFAULT AS
  386 + IDENTITY,
  387 + "name"
  388 + varchar
  389 +(
  390 + 255
  391 +) NOT NULL DEFAULT '',
  392 + "firmware_id" bigint NOT NULL,
  393 + "product_id" bigint NOT NULL,
  394 + "upgrade_type" tinyint NOT NULL DEFAULT '0',
  395 + "status" tinyint NOT NULL DEFAULT '0',
  396 + "creator" varchar
  397 +(
  398 + 64
  399 +) DEFAULT '',
  400 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  401 + "updater" varchar
  402 +(
  403 + 64
  404 +) DEFAULT '',
  405 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  406 + "deleted" bit NOT NULL DEFAULT FALSE,
  407 + "tenant_id" bigint NOT NULL DEFAULT '0',
  408 + PRIMARY KEY
  409 +(
  410 + "id"
  411 +)
  412 + ) COMMENT 'IoT OTA 升级任务表';
  413 +
  414 +-- IoT OTA 升级记录表
  415 +CREATE TABLE IF NOT EXISTS "iot_ota_record"
  416 +(
  417 + "id"
  418 + bigint
  419 + NOT
  420 + NULL
  421 + GENERATED
  422 + BY
  423 + DEFAULT AS
  424 + IDENTITY,
  425 + "task_id"
  426 + bigint
  427 + NOT
  428 + NULL,
  429 + "firmware_id"
  430 + bigint
  431 + NOT
  432 + NULL,
  433 + "device_id"
  434 + bigint
  435 + NOT
  436 + NULL,
  437 + "status"
  438 + tinyint
  439 + NOT
  440 + NULL
  441 + DEFAULT
  442 + '0',
  443 + "progress"
  444 + int
  445 + NOT
  446 + NULL
  447 + DEFAULT
  448 + '0',
  449 + "error_msg"
  450 + varchar
  451 +(
  452 + 500
  453 +) DEFAULT NULL,
  454 + "start_time" timestamp DEFAULT NULL,
  455 + "end_time" timestamp DEFAULT NULL,
  456 + "creator" varchar
  457 +(
  458 + 64
  459 +) DEFAULT '',
  460 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  461 + "updater" varchar
  462 +(
  463 + 64
  464 +) DEFAULT '',
  465 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  466 + "deleted" bit NOT NULL DEFAULT FALSE,
  467 + "tenant_id" bigint NOT NULL DEFAULT '0',
  468 + PRIMARY KEY
  469 +(
  470 + "id"
  471 +)
  472 + ) COMMENT 'IoT OTA 升级记录表';