feat:【IoT 物联网】新版本同步

This commit is contained in:
YunaiV
2025-08-30 09:34:40 +08:00
parent d8fbd0f6c5
commit a89b6d14a8
500 changed files with 19983 additions and 13090 deletions

View File

@@ -0,0 +1,154 @@
package cn.iocoder.yudao.module.iot.service.rule.action.databridge;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.*;
import cn.iocoder.yudao.module.iot.service.rule.data.action.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
/**
* {@link IotDataRuleAction} 实现类的单元测试
*
* @author HUIHUI
*/
@Disabled // 默认禁用,需要手动启用测试
@Slf4j
public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest {
private IotDeviceMessage message;
@Mock
private RestTemplate restTemplate;
@InjectMocks
private IotHttpDataSinkAction httpDataBridgeExecute;
@BeforeEach
public void setUp() {
// TODO @芋艿:@puhui999需要调整下
// 创建共享的测试消息
//message = IotDeviceMessage.builder().messageId("TEST-001").reportTime(LocalDateTime.now())
// .productKey("testProduct").deviceName("testDevice")
// .type("property").identifier("temperature").data("{\"value\": 60}")
// .build();
}
@Test
public void testKafkaMQDataBridge() throws Exception {
// 1. 创建执行器实例
IotKafkaDataRuleAction action = new IotKafkaDataRuleAction();
// 2. 创建配置
IotDataSinkKafkaConfig config = new IotDataSinkKafkaConfig()
.setBootstrapServers("127.0.0.1:9092")
.setTopic("test-topic")
.setSsl(false)
.setUsername(null)
.setPassword(null);
// 3. 执行测试并验证缓存
executeAndVerifyCache(action, config, "KafkaMQ");
}
@Test
public void testRabbitMQDataBridge() throws Exception {
// 1. 创建执行器实例
IotRabbitMQDataRuleAction action = new IotRabbitMQDataRuleAction();
// 2. 创建配置
IotDataSinkRabbitMQConfig config = new IotDataSinkRabbitMQConfig()
.setHost("localhost")
.setPort(5672)
.setVirtualHost("/")
.setUsername("admin")
.setPassword("123456")
.setExchange("test-exchange")
.setRoutingKey("test-key")
.setQueue("test-queue");
// 3. 执行测试并验证缓存
executeAndVerifyCache(action, config, "RabbitMQ");
}
@Test
public void testRedisDataBridge() throws Exception {
// 1. 创建执行器实例
IotRedisRuleAction action = new IotRedisRuleAction();
// 2. 创建配置 - 测试 Stream 数据结构
IotDataSinkRedisConfig config = new IotDataSinkRedisConfig();
config.setHost("127.0.0.1");
config.setPort(6379);
config.setDatabase(0);
config.setPassword("123456");
config.setTopic("test-stream");
config.setDataStructure(1); // Stream 类型
// 3. 执行测试并验证缓存
executeAndVerifyCache(action, config, "Redis");
}
@Test
public void testRocketMQDataBridge() throws Exception {
// 1. 创建执行器实例
IotRocketMQDataRuleAction action = new IotRocketMQDataRuleAction();
// 2. 创建配置
IotDataSinkRocketMQConfig config = new IotDataSinkRocketMQConfig()
.setNameServer("127.0.0.1:9876")
.setGroup("test-group")
.setTopic("test-topic")
.setTags("test-tag");
// 3. 执行测试并验证缓存
executeAndVerifyCache(action, config, "RocketMQ");
}
@Test
public void testHttpDataBridge() throws Exception {
// 1. 配置 RestTemplate mock 返回成功响应
when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(), any(Class.class)))
.thenReturn(new ResponseEntity<>("Success", HttpStatus.OK));
// 2. 创建配置
IotDataSinkHttpConfig config = new IotDataSinkHttpConfig()
.setUrl("https://doc.iocoder.cn/").setMethod(HttpMethod.GET.name());
// 3. 执行测试
log.info("[testHttpDataBridge][执行HTTP数据桥接测试]");
httpDataBridgeExecute.execute(message, new IotDataSinkDO()
.setType(httpDataBridgeExecute.getType()).setConfig(config));
}
/**
* 执行测试并验证缓存的通用方法
*
* @param action 执行器实例
* @param config 配置对象
* @param type MQ 类型
* @throws Exception 如果执行过程中发生异常
*/
private void executeAndVerifyCache(IotDataRuleAction action, IotAbstractDataSinkConfig config, String type)
throws Exception {
log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type);
action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config));
log.info("[test{}DataBridge][第二次执行,应该会复用缓存的 producer]", type);
action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config));
}
}

View File

@@ -0,0 +1,211 @@
package cn.iocoder.yudao.module.iot.service.rule.scene;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper;
import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
/**
* {@link IotSceneRuleServiceImpl} 的简化单元测试类
* 使用 Mockito 进行纯单元测试,不依赖 Spring 容器
*
* @author 芋道源码
*/
public class IotSceneRuleServiceSimpleTest extends BaseMockitoUnitTest {
@InjectMocks
private IotSceneRuleServiceImpl sceneRuleService;
@Mock
private IotSceneRuleMapper sceneRuleMapper;
@Mock
private List<IotSceneRuleAction> sceneRuleActions;
@Mock
private IotSchedulerManager schedulerManager;
@Mock
private IotProductService productService;
@Mock
private IotDeviceService deviceService;
@Test
public void testCreateScene_Rule_success() {
// 准备参数
IotSceneRuleSaveReqVO createReqVO = randomPojo(IotSceneRuleSaveReqVO.class, o -> {
o.setId(null);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class)));
o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class)));
});
// Mock 行为
Long expectedId = randomLongId();
when(sceneRuleMapper.insert(any(IotSceneRuleDO.class))).thenAnswer(invocation -> {
IotSceneRuleDO sceneRule = invocation.getArgument(0);
sceneRule.setId(expectedId);
return 1;
});
// 调用
Long sceneRuleId = sceneRuleService.createSceneRule(createReqVO);
// 断言
assertEquals(expectedId, sceneRuleId);
verify(sceneRuleMapper, times(1)).insert(any(IotSceneRuleDO.class));
}
@Test
public void testUpdateScene_Rule_success() {
// 准备参数
Long id = randomLongId();
IotSceneRuleSaveReqVO updateReqVO = randomPojo(IotSceneRuleSaveReqVO.class, o -> {
o.setId(id);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class)));
o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class)));
});
// Mock 行为
IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule);
when(sceneRuleMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1);
// 调用
assertDoesNotThrow(() -> sceneRuleService.updateSceneRule(updateReqVO));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
verify(sceneRuleMapper, times(1)).updateById(any(IotSceneRuleDO.class));
}
@Test
public void testDeleteSceneRule_success() {
// 准备参数
Long id = randomLongId();
// Mock 行为
IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule);
when(sceneRuleMapper.deleteById(id)).thenReturn(1);
// 调用
assertDoesNotThrow(() -> sceneRuleService.deleteSceneRule(id));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
verify(sceneRuleMapper, times(1)).deleteById(id);
}
@Test
public void testGetSceneRule() {
// 准备参数
Long id = randomLongId();
IotSceneRuleDO expectedSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id));
// Mock 行为
when(sceneRuleMapper.selectById(id)).thenReturn(expectedSceneRule);
// 调用
IotSceneRuleDO result = sceneRuleService.getSceneRule(id);
// 断言
assertEquals(expectedSceneRule, result);
verify(sceneRuleMapper, times(1)).selectById(id);
}
@Test
public void testUpdateSceneRuleStatus_success() {
// 准备参数
Long id = randomLongId();
Integer status = CommonStatusEnum.DISABLE.getStatus();
// Mock 行为
IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> {
o.setId(id);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule);
when(sceneRuleMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1);
// 调用
assertDoesNotThrow(() -> sceneRuleService.updateSceneRuleStatus(id, status));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
verify(sceneRuleMapper, times(1)).updateById(any(IotSceneRuleDO.class));
}
@Test
public void testExecuteSceneRuleByTimer_success() {
// 准备参数
Long id = randomLongId();
// Mock 行为
IotSceneRuleDO sceneRule = randomPojo(IotSceneRuleDO.class, o -> {
o.setId(id);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(sceneRuleMapper.selectById(id)).thenReturn(sceneRule);
// 调用
assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
}
@Test
public void testExecuteSceneRuleByTimer_notExists() {
// 准备参数
Long id = randomLongId();
// Mock 行为
when(sceneRuleMapper.selectById(id)).thenReturn(null);
// 调用 - 不存在的场景规则应该不会抛异常,只是记录日志
assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
}
@Test
public void testExecuteSceneRuleByTimer_disabled() {
// 准备参数
Long id = randomLongId();
// Mock 行为
IotSceneRuleDO sceneRule = randomPojo(IotSceneRuleDO.class, o -> {
o.setId(id);
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
});
when(sceneRuleMapper.selectById(id)).thenReturn(sceneRule);
// 调用 - 禁用的场景规则应该不会执行,只是记录日志
assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id));
// 验证
verify(sceneRuleMapper, times(1)).selectById(id);
}
}

View File

@@ -0,0 +1,338 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link CurrentTimeConditionMatcher} 的单元测试
*
* @author HUIHUI
*/
public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private CurrentTimeConditionMatcher matcher;
@Test
public void testGetSupportedConditionType() {
// 调用
IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.CURRENT_TIME, result);
}
@Test
public void testGetPriority() {
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(40, result);
}
@Test
public void testIsEnabled() {
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
// ========== 时间戳条件测试 ==========
@Test
public void testMatches_DateTimeGreaterThan_success() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
long pastTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
String.valueOf(pastTimestamp)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_DateTimeGreaterThan_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
String.valueOf(futureTimestamp)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_DateTimeLessThan_success() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_LESS_THAN.getOperator(),
String.valueOf(futureTimestamp)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_DateTimeBetween_success() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
long startTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8"));
long endTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_BETWEEN.getOperator(),
startTimestamp + "," + endTimestamp
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_DateTimeBetween_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
long startTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
long endTimestamp = LocalDateTime.now().plusHours(2).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_BETWEEN.getOperator(),
startTimestamp + "," + endTimestamp
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
// ========== 当日时间条件测试 ==========
@Test
public void testMatches_TimeGreaterThan_earlyMorning() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(),
"06:00:00" // 早上6点
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
// 结果取决于当前时间如果当前时间大于6点则为true
assertNotNull(result);
}
@Test
public void testMatches_TimeLessThan_lateNight() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_LESS_THAN.getOperator(),
"23:59:59" // 晚上11点59分59秒
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
// 大部分情况下应该为true除非在午夜前1秒运行测试
assertNotNull(result);
}
@Test
public void testMatches_TimeBetween_allDay() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"00:00:00,23:59:59" // 全天
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result); // 全天范围应该总是匹配
}
@Test
public void testMatches_TimeBetween_workingHours() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"09:00:00,17:00:00" // 工作时间
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
// 结果取决于当前时间是否在工作时间内
assertNotNull(result);
}
// ========== 异常情况测试 ==========
@Test
public void testMatches_nullCondition() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullConditionType() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidOperator() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType());
condition.setOperator(randomString()); // 随机无效操作符
condition.setParam("12:00:00");
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidTimeFormat() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(),
randomString() // 随机无效时间格式
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidTimestampFormat() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
randomString() // 随机无效时间戳格式
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidBetweenFormat() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"09:00:00" // 缺少结束时间
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
// ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage() {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
return message;
}
/**
* 创建日期时间条件
*/
private IotSceneRuleDO.TriggerCondition createDateTimeCondition(String operator, String param) {
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType());
condition.setOperator(operator);
condition.setParam(param);
return condition;
}
/**
* 创建当日时间条件
*/
private IotSceneRuleDO.TriggerCondition createTimeCondition(String operator, String param) {
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType());
condition.setOperator(operator);
condition.setParam(param);
return condition;
}
}

View File

@@ -0,0 +1,424 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap;
import java.util.Map;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DevicePropertyConditionMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DevicePropertyConditionMatcher matcher;
@Test
public void testGetSupportedConditionType() {
// 调用
IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY, result);
}
@Test
public void testGetPriority() {
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(20, result);
}
@Test
public void testIsEnabled() {
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_temperatureEquals_success() {
// 准备参数
String propertyName = "temperature";
Double propertyValue = 25.5;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
String.valueOf(propertyValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_humidityGreaterThan_success() {
// 准备参数
String propertyName = "humidity";
Integer propertyValue = 75;
Integer compareValue = 70;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_pressureLessThan_success() {
// 准备参数
String propertyName = "pressure";
Double propertyValue = 1010.5;
Integer compareValue = 1020;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_statusNotEquals_success() {
// 准备参数
String propertyName = "status";
String propertyValue = "active";
String compareValue = "inactive";
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
compareValue
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_propertyMismatch_fail() {
// 准备参数
String propertyName = "temperature";
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_propertyNotFound_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
randomString(), // 随机不存在的属性名
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"50"
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullCondition_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullConditionType_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingIdentifier_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY.getType());
condition.setIdentifier(null); // 缺少标识符
condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
condition.setParam("20");
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingOperator_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY.getType());
condition.setIdentifier("temperature");
condition.setOperator(null); // 缺少操作符
condition.setParam("20");
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingParam_fail() {
// 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY.getType());
condition.setIdentifier("temperature");
condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
condition.setParam(null); // 缺少参数
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessage_fail() {
// 准备参数
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature",
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20"
);
// 调用
boolean result = matcher.matches(null, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullDeviceProperties_fail() {
// 准备参数
IotDeviceMessage message = new IotDeviceMessage();
message.setParams(null);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature",
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20"
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_voltageGreaterThanOrEquals_success() {
// 准备参数
String propertyName = "voltage";
Double propertyValue = 12.0;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(),
String.valueOf(propertyValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_currentLessThanOrEquals_success() {
// 准备参数
String propertyName = "current";
Double propertyValue = 2.5;
Double compareValue = 3.0;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_stringProperty_success() {
// 准备参数
String propertyName = "mode";
String propertyValue = "auto";
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
propertyValue
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_booleanProperty_success() {
// 准备参数
String propertyName = "enabled";
Boolean propertyValue = true;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
String.valueOf(propertyValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_multipleProperties_success() {
// 准备参数
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5)
.put("humidity", 60)
.put("status", "active")
.put("enabled", true)
.build();
IotDeviceMessage message = createDeviceMessage(properties);
String targetProperty = "humidity";
Integer targetValue = 60;
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
targetProperty,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
String.valueOf(targetValue)
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
// ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage(Map<String, Object> properties) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setParams(properties);
return message;
}
/**
* 创建有效的条件
*/
private IotSceneRuleDO.TriggerCondition createValidCondition(String identifier, String operator, String param) {
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY.getType());
condition.setIdentifier(identifier);
condition.setOperator(operator);
condition.setParam(param);
return condition;
}
}

View File

@@ -0,0 +1,356 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DeviceStateConditionMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DeviceStateConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceStateConditionMatcher matcher;
@Test
public void testGetSupportedConditionType() {
// 调用
IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_STATE, result);
}
@Test
public void testGetPriority() {
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(30, result);
}
@Test
public void testIsEnabled() {
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_onlineState_success() {
// 准备参数
IotDeviceStateEnum deviceState = IotDeviceStateEnum.ONLINE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
deviceState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_offlineState_success() {
// 准备参数
IotDeviceStateEnum deviceState = IotDeviceStateEnum.OFFLINE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
deviceState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_inactiveState_success() {
// 准备参数
IotDeviceStateEnum deviceState = IotDeviceStateEnum.INACTIVE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
deviceState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_stateMismatch_fail() {
// 准备参数
IotDeviceStateEnum actualState = IotDeviceStateEnum.ONLINE;
IotDeviceStateEnum expectedState = IotDeviceStateEnum.OFFLINE;
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
expectedState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_notEqualsOperator_success() {
// 准备参数
IotDeviceStateEnum actualState = IotDeviceStateEnum.ONLINE;
IotDeviceStateEnum compareState = IotDeviceStateEnum.OFFLINE;
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
compareState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_greaterThanOperator_success() {
// 准备参数
IotDeviceStateEnum actualState = IotDeviceStateEnum.OFFLINE; // 状态值为 2
IotDeviceStateEnum compareState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
compareState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_lessThanOperator_success() {
// 准备参数
IotDeviceStateEnum actualState = IotDeviceStateEnum.INACTIVE; // 状态值为 0
IotDeviceStateEnum compareState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
compareState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_nullCondition_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullConditionType_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingOperator_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(null);
condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString());
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingParam_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator());
condition.setParam(null);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessage_fail() {
// 准备参数
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(null, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullDeviceState_fail() {
// 准备参数
IotDeviceMessage message = new IotDeviceMessage();
message.setParams(null);
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_greaterThanOrEqualsOperator_success() {
// 准备参数
IotDeviceStateEnum deviceState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(),
deviceState.getState().toString() // 比较值也为 1
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_lessThanOrEqualsOperator_success() {
// 准备参数
IotDeviceStateEnum actualState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceStateEnum compareState = IotDeviceStateEnum.OFFLINE; // 状态值为 2
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(),
compareState.getState().toString()
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertTrue(result);
}
@Test
public void testMatches_invalidOperator_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(randomString()); // 随机无效操作符
condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString());
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidParamFormat_fail() {
// 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
randomString() // 随机无效状态值
);
// 调用
boolean result = matcher.matches(message, condition);
// 断言
assertFalse(result);
}
// ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage(Integer deviceState) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setParams(deviceState);
return message;
}
/**
* 创建有效的条件
*/
private IotSceneRuleDO.TriggerCondition createValidCondition(String operator, String param) {
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(operator);
condition.setParam(param);
return condition;
}
}

View File

@@ -0,0 +1,376 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomInt;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DeviceEventPostTriggerMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceEventPostTriggerMatcher matcher;
@Test
public void testGetSupportedTriggerType_success() {
// 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST, result);
}
@Test
public void testGetPriority_success() {
// 准备参数
// 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(30, result);
}
@Test
public void testIsEnabled_success() {
// 准备参数
// 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_alarmEventSuccess() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.put("message", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_errorEventSuccess() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("code", randomInt())
.put("description", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_infoEventSuccess() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("status", randomString())
.put("timestamp", System.currentTimeMillis())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_eventIdentifierMismatch() {
// 准备参数
String messageIdentifier = randomString();
String triggerIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", messageIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_wrongMessageMethod() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法
message.setParams(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerIdentifier() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST.getType());
trigger.setIdentifier(null); // 缺少标识符
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessageParams() {
// 准备参数
String eventIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidMessageParams() {
// 准备参数
String eventIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingEventIdentifierInParams() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build()) // 缺少 identifier 字段
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTrigger() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerType() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null);
trigger.setIdentifier(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_complexEventValueSuccess() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("type", randomString())
.put("duration", randomInt())
.put("components", new String[]{randomString(), randomString()})
.put("priority", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_emptyEventValueSuccess() {
// 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.ofEntries()) // 空的事件值
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_caseSensitiveIdentifierMismatch() {
// 准备参数
String eventIdentifier = randomString().toUpperCase(); // 大写
String triggerIdentifier = eventIdentifier.toLowerCase(); // 小写
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", randomString())
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
// 根据实际实现,这里可能需要调整期望结果
// 如果实现是大小写敏感的,则应该为 false
assertFalse(result);
}
// ========== 辅助方法 ==========
/**
* 创建事件上报消息
*/
private IotDeviceMessage createEventPostMessage(Map<String, Object> eventParams) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams(eventParams);
return message;
}
/**
* 创建有效的触发器
*/
private IotSceneRuleDO.Trigger createValidTrigger(String identifier) {
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST.getType());
trigger.setIdentifier(identifier);
return trigger;
}
}

View File

@@ -0,0 +1,340 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomDouble;
import static cn.hutool.core.util.RandomUtil.randomInt;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DevicePropertyPostTriggerMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DevicePropertyPostTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DevicePropertyPostTriggerMatcher matcher;
@Test
public void testGetSupportedTriggerType_success() {
// 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST, result);
}
@Test
public void testGetPriority_success() {
// 准备参数
// 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(20, result);
}
@Test
public void testIsEnabled_success() {
// 准备参数
// 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_numericPropertyGreaterThanSuccess() {
// 准备参数
String propertyName = randomString();
Double propertyValue = 25.5;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, propertyValue)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_integerPropertyEqualsSuccess() {
// 准备参数
String propertyName = randomString();
Integer propertyValue = randomInt();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, propertyValue)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
String.valueOf(propertyValue)
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_propertyValueNotMeetCondition() {
// 准备参数
String propertyName = randomString();
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, propertyValue)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_propertyNotFound() {
// 准备参数
String existingProperty = randomString();
String missingProperty = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(existingProperty, randomDouble())
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
missingProperty, // 不存在的属性
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(randomInt())
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_wrongMessageMethod() {
// 准备参数
String propertyName = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, randomDouble())
.build();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(randomInt())
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerIdentifier() {
// 准备参数
String propertyName = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, randomDouble())
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
trigger.setIdentifier(null); // 缺少标识符
trigger.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
trigger.setValue(String.valueOf(randomInt()));
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessageParams() {
// 准备参数
String propertyName = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(randomInt())
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidMessageParams() {
// 准备参数
String propertyName = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
String.valueOf(randomInt())
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_lessThanOperatorSuccess() {
// 准备参数
String propertyName = randomString();
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, propertyValue)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
String.valueOf(compareValue)
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_notEqualsOperatorSuccess() {
// 准备参数
String propertyName = randomString();
String propertyValue = randomString();
String compareValue = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(propertyName, propertyValue)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
propertyName,
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
compareValue
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_multiplePropertiesTargetPropertySuccess() {
// 准备参数
String targetProperty = randomString();
Integer targetValue = randomInt();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put(randomString(), randomDouble())
.put(targetProperty, targetValue)
.put(randomString(), randomString())
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
targetProperty,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
String.valueOf(targetValue)
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
// ========== 辅助方法 ==========
/**
* 创建属性上报消息
*/
private IotDeviceMessage createPropertyPostMessage(Map<String, Object> properties) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(properties);
return message;
}
/**
* 创建有效的触发器
*/
private IotSceneRuleDO.Trigger createValidTrigger(String identifier, String operator, String value) {
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
trigger.setIdentifier(identifier);
trigger.setOperator(operator);
trigger.setValue(value);
return trigger;
}
}

View File

@@ -0,0 +1,398 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DeviceServiceInvokeTriggerMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceServiceInvokeTriggerMatcher matcher;
@Test
public void testGetSupportedTriggerType_success() {
// 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE, result);
}
@Test
public void testGetPriority_success() {
// 准备参数
// 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(40, result);
}
@Test
public void testIsEnabled_success() {
// 准备参数
// 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_serviceInvokeSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_configServiceSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("interval", randomInt())
.put("enabled", randomBoolean())
.put("threshold", randomDouble())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_updateServiceSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("version", randomString())
.put("url", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_serviceIdentifierMismatch() {
// 准备参数
String messageIdentifier = randomString();
String triggerIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", messageIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier); // 不匹配的服务标识符
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_wrongMessageMethod() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法
message.setParams(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerIdentifier() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType());
trigger.setIdentifier(null); // 缺少标识符
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessageParams() {
// 准备参数
String serviceIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_invalidMessageParams() {
// 准备参数
String serviceIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_missingServiceIdentifierInParams() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build()) // 缺少 identifier 字段
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTrigger() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerType() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null);
trigger.setIdentifier(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_emptyInputDataSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.ofEntries()) // 空的输入数据
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_noInputDataSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
// 没有 inputData 字段
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_complexInputDataSuccess() {
// 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("sensors", new String[]{randomString(), randomString(), randomString()})
.put("precision", randomDouble())
.put("duration", randomInt())
.put("autoSave", randomBoolean())
.put("config", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.put("level", randomString())
.build())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_caseSensitiveIdentifierMismatch() {
// 准备参数
String serviceIdentifier = randomString().toUpperCase(); // 大写
String triggerIdentifier = serviceIdentifier.toLowerCase(); // 小写
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", randomString())
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
// 根据实际实现,这里可能需要调整期望结果
// 如果实现是大小写敏感的,则应该为 false
assertFalse(result);
}
// ========== 辅助方法 ==========
/**
* 创建服务调用消息
*/
private IotDeviceMessage createServiceInvokeMessage(Map<String, Object> serviceParams) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams(serviceParams);
return message;
}
/**
* 创建有效的触发器
*/
private IotSceneRuleDO.Trigger createValidTrigger(String identifier) {
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType());
trigger.setIdentifier(identifier);
return trigger;
}
}

View File

@@ -0,0 +1,262 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link DeviceStateUpdateTriggerMatcher} 的单元测试
*
* @author HUIHUI
*/
public class DeviceStateUpdateTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceStateUpdateTriggerMatcher matcher;
@Test
public void testGetSupportedTriggerType_success() {
// 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE, result);
}
@Test
public void testGetPriority_success() {
// 准备参数
// 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(10, result);
}
@Test
public void testIsEnabled_success() {
// 准备参数
// 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_onlineStateSuccess() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_offlineStateSuccess() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.OFFLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_stateMismatch() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTrigger() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerType() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_wrongMessageMethod() {
// 准备参数
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerOperator() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator(null);
trigger.setValue(IotDeviceStateEnum.ONLINE.getState().toString());
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerValue() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator());
trigger.setValue(null);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullMessageParams() {
// 准备参数
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_greaterThanOperatorSuccess() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
IotDeviceStateEnum.INACTIVE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_notEqualsOperatorSuccess() {
// 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString()
);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
// ========== 辅助方法 ==========
/**
* 创建设备状态更新消息
*/
private IotDeviceMessage createStateUpdateMessage(Integer state) {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(state);
return message;
}
/**
* 创建有效的触发器
*/
private IotSceneRuleDO.Trigger createValidTrigger(String operator, String value) {
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator(operator);
trigger.setValue(value);
return trigger;
}
}

View File

@@ -0,0 +1,276 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link TimerTriggerMatcher} 的单元测试
*
* @author HUIHUI
*/
public class TimerTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private TimerTriggerMatcher matcher;
@Test
public void testGetSupportedTriggerType_success() {
// 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.TIMER, result);
}
@Test
public void testGetPriority_success() {
// 准备参数
// 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(50, result);
}
@Test
public void testIsEnabled_success() {
// 准备参数
// 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
}
@Test
public void testMatches_validCronExpressionSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 0 12 * * ?"; // 每天中午12点
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_everyMinuteCronSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 * * * * ?"; // 每分钟
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_weekdaysCronSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 0 9 ? * MON-FRI"; // 工作日上午9点
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_invalidCronExpression() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = randomString(); // 随机无效的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_emptyCronExpression() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = ""; // 空的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullCronExpression() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.TIMER.getType());
trigger.setCronExpression(null);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTrigger() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
// 调用
boolean result = matcher.matches(message, null);
// 断言
assertFalse(result);
}
@Test
public void testMatches_nullTriggerType() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null);
trigger.setCronExpression("0 0 12 * * ?");
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_complexCronExpressionSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 15 10 ? * 6#3"; // 每月第三个星期五上午10:15
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_incorrectCronFormat() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 0 12 * *"; // 缺少字段的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_specificDateCronSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 0 0 1 1 ? 2025"; // 2025年1月1日午夜
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_everySecondCronSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "* * * * * ?"; // 每秒执行
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
@Test
public void testMatches_invalidCharactersCron() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
String cronExpression = "0 0 12 * * @ #"; // 包含无效字符的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertFalse(result);
}
@Test
public void testMatches_rangeCronSuccess() {
// 准备参数
IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 9-17 * * MON-FRI"); // 工作日9-17点
// 调用
boolean result = matcher.matches(message, trigger);
// 断言
assertTrue(result);
}
// ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage() {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
return message;
}
/**
* 创建有效的定时触发器
*/
private IotSceneRuleDO.Trigger createValidTrigger(String cronExpression) {
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.TIMER.getType());
trigger.setCronExpression(cronExpression);
return trigger;
}
}

View File

@@ -0,0 +1,52 @@
spring:
main:
lazy-initialization: true # 开启懒加载,加快速度
banner-mode: off # 单元测试,禁用 Banner
# 数据源配置项
datasource:
name: ruoyi-vue-pro
url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式DATABASE_TO_UPPER 配置表和字段使用小写
driver-class-name: org.h2.Driver
username: sa
password:
druid:
async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
initial-size: 1 # 单元测试,配置为 1提升启动速度
sql:
init:
schema-locations: classpath:/sql/create_tables.sql
mybatis-plus:
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
# 日志配置
logging:
level:
cn.iocoder.yudao.module.iot.service.rule.scene.matcher: DEBUG
cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherManager: INFO
cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition: DEBUG
cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger: DEBUG
root: WARN
--- #################### 定时任务相关配置 ####################
--- #################### 配置中心相关配置 ####################
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项(单元测试,禁用 Lock4j
--- #################### 监控相关配置 ####################
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
info:
base-package: cn.iocoder.yudao
tenant: # 多租户相关配置项
enable: true
xss:
enable: false
demo: false # 关闭演示模式

View File

@@ -0,0 +1,37 @@
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 设置特定包的日志级别 -->
<logger name="cn.iocoder.yudao.module.iot.service.rule.scene.matcher" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<!-- 设置 IotSceneRuleMatcherManager 的日志级别 -->
<logger name="cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherManager" level="INFO"
additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<!-- 设置所有匹配器的日志级别 -->
<logger name="cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<!-- 根日志级别 -->
<root level="WARN">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

View File

@@ -0,0 +1,10 @@
DELETE FROM "iot_scene_rule";
DELETE FROM "iot_product";
DELETE FROM "iot_device";
DELETE FROM "iot_thing_model";
DELETE FROM "iot_device_data";
DELETE FROM "iot_alert_config";
DELETE FROM "iot_alert_record";
DELETE FROM "iot_ota_firmware";
DELETE FROM "iot_ota_task";
DELETE FROM "iot_ota_record";

View File

@@ -0,0 +1,182 @@
CREATE TABLE IF NOT EXISTS "iot_scene_rule" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(255) NOT NULL DEFAULT '',
"description" varchar(500) DEFAULT NULL,
"status" tinyint NOT NULL DEFAULT '0',
"triggers" text,
"actions" text,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 场景联动规则表';
CREATE TABLE IF NOT EXISTS "iot_product" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(255) NOT NULL DEFAULT '',
"product_key" varchar(100) NOT NULL DEFAULT '',
"protocol_type" tinyint NOT NULL DEFAULT '0',
"category_id" bigint DEFAULT NULL,
"description" varchar(500) DEFAULT NULL,
"data_format" tinyint NOT NULL DEFAULT '0',
"device_type" tinyint NOT NULL DEFAULT '0',
"net_type" tinyint NOT NULL DEFAULT '0',
"validate_type" tinyint NOT NULL DEFAULT '0',
"status" tinyint NOT NULL DEFAULT '0',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 产品表';
CREATE TABLE IF NOT EXISTS "iot_device" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"device_name" varchar(255) NOT NULL DEFAULT '',
"product_id" bigint NOT NULL,
"device_key" varchar(100) NOT NULL DEFAULT '',
"device_secret" varchar(100) NOT NULL DEFAULT '',
"nickname" varchar(255) DEFAULT NULL,
"status" tinyint NOT NULL DEFAULT '0',
"status_last_update_time" timestamp DEFAULT NULL,
"last_online_time" timestamp DEFAULT NULL,
"last_offline_time" timestamp DEFAULT NULL,
"active_time" timestamp DEFAULT NULL,
"ip" varchar(50) DEFAULT NULL,
"firmware_version" varchar(50) DEFAULT NULL,
"device_type" tinyint NOT NULL DEFAULT '0',
"gateway_id" bigint DEFAULT NULL,
"sub_device_count" int NOT NULL DEFAULT '0',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 设备表';
CREATE TABLE IF NOT EXISTS "iot_thing_model" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"product_id" bigint NOT NULL,
"identifier" varchar(100) NOT NULL DEFAULT '',
"name" varchar(255) NOT NULL DEFAULT '',
"description" varchar(500) DEFAULT NULL,
"type" tinyint NOT NULL DEFAULT '1',
"property" text,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 物模型表';
CREATE TABLE IF NOT EXISTS "iot_device_data" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"device_id" bigint NOT NULL,
"product_id" bigint NOT NULL,
"identifier" varchar(100) NOT NULL DEFAULT '',
"type" tinyint NOT NULL DEFAULT '1',
"data" text,
"ts" bigint NOT NULL DEFAULT '0',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("id")
) COMMENT 'IoT 设备数据表';
CREATE TABLE IF NOT EXISTS "iot_alert_config" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(255) NOT NULL DEFAULT '',
"product_id" bigint NOT NULL,
"device_id" bigint DEFAULT NULL,
"rule_id" bigint DEFAULT NULL,
"status" tinyint NOT NULL DEFAULT '0',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 告警配置表';
CREATE TABLE IF NOT EXISTS "iot_alert_record" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"alert_config_id" bigint NOT NULL,
"alert_name" varchar(255) NOT NULL DEFAULT '',
"product_id" bigint NOT NULL,
"device_id" bigint DEFAULT NULL,
"rule_id" bigint DEFAULT NULL,
"alert_data" text,
"alert_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deal_status" tinyint NOT NULL DEFAULT '0',
"deal_time" timestamp DEFAULT NULL,
"deal_user_id" bigint DEFAULT NULL,
"deal_remark" varchar(500) DEFAULT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT 告警记录表';
CREATE TABLE IF NOT EXISTS "iot_ota_firmware" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(255) NOT NULL DEFAULT '',
"product_id" bigint NOT NULL,
"version" varchar(50) NOT NULL DEFAULT '',
"description" varchar(500) DEFAULT NULL,
"file_url" varchar(500) DEFAULT NULL,
"file_size" bigint NOT NULL DEFAULT '0',
"status" tinyint NOT NULL DEFAULT '0',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT OTA 固件表';
CREATE TABLE IF NOT EXISTS "iot_ota_task" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(255) NOT NULL DEFAULT '',
"firmware_id" bigint NOT NULL,
"product_id" bigint NOT NULL,
"upgrade_type" tinyint NOT NULL DEFAULT '0',
"status" tinyint NOT NULL DEFAULT '0',
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT OTA 升级任务表';
CREATE TABLE IF NOT EXISTS "iot_ota_record" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"task_id" bigint NOT NULL,
"firmware_id" bigint NOT NULL,
"device_id" bigint NOT NULL,
"status" tinyint NOT NULL DEFAULT '0',
"progress" int NOT NULL DEFAULT '0',
"error_msg" varchar(500) DEFAULT NULL,
"start_time" timestamp DEFAULT NULL,
"end_time" timestamp DEFAULT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT 'IoT OTA 升级记录表';