!1413 场景联动优化 review 提到的逻辑

Merge pull request !1413 from puhui999/feature/iot
This commit is contained in:
芋道源码
2025-08-24 09:22:46 +00:00
committed by Gitee
21 changed files with 1243 additions and 1042 deletions

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.enums.rule; package cn.iocoder.yudao.module.iot.enums.rule;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable; import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -32,4 +33,8 @@ public enum IotSceneRuleConditionTypeEnum implements ArrayValuable<Integer> {
return ARRAYS; return ARRAYS;
} }
public static IotSceneRuleConditionTypeEnum typeOf(Integer type) {
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
}
} }

View File

@@ -55,9 +55,8 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
@Resource @Resource
private IotDeviceService deviceService; private IotDeviceService deviceService;
// TODO @puhui999sceneRuleMatcherManager 变量名
@Resource @Resource
private IotSceneRuleMatcherManager matcherManager; private IotSceneRuleMatcherManager sceneRuleMatcherManager;
@Resource @Resource
private List<IotSceneRuleAction> sceneRuleActions; private List<IotSceneRuleAction> sceneRuleActions;
@@ -275,7 +274,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
private boolean matchSingleTrigger(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger, IotSceneRuleDO sceneRule) { private boolean matchSingleTrigger(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger, IotSceneRuleDO sceneRule) {
try { try {
// 2. 检查触发器的条件分组 // 2. 检查触发器的条件分组
return matcherManager.isMatched(message, trigger) && isTriggerConditionGroupsMatched(message, trigger, sceneRule); return sceneRuleMatcherManager.isMatched(message, trigger) && isTriggerConditionGroupsMatched(message, trigger, sceneRule);
} catch (Exception e) { } catch (Exception e) {
log.error("[matchSingleTrigger][触发器匹配异常] sceneRuleId: {}, triggerType: {}, message: {}", log.error("[matchSingleTrigger][触发器匹配异常] sceneRuleId: {}, triggerType: {}, message: {}",
sceneRule.getId(), trigger.getType(), message, e); sceneRule.getId(), trigger.getType(), message, e);
@@ -334,7 +333,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition,
IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) {
try { try {
return matcherManager.isConditionMatched(message, condition); return sceneRuleMatcherManager.isConditionMatched(message, condition);
} catch (Exception e) { } catch (Exception e) {
log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]",
sceneRule.getId(), trigger, e); sceneRule.getId(), trigger, e);

View File

@@ -12,7 +12,6 @@ import org.springframework.stereotype.Component;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@@ -37,33 +36,26 @@ public class IotSceneRuleMatcherManager {
*/ */
private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleConditionMatcher> conditionMatchers; private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleConditionMatcher> conditionMatchers;
/**
* 所有匹配器列表(按优先级排序)
*/
// TODO @puhui999貌似 local variable 也可以
private final List<IotSceneRuleMatcher> allMatchers;
public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) { public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) {
if (CollUtil.isEmpty(matchers)) { if (CollUtil.isEmpty(matchers)) {
log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]"); log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]");
this.triggerMatchers = new HashMap<>(); this.triggerMatchers = new HashMap<>();
this.conditionMatchers = new HashMap<>(); this.conditionMatchers = new HashMap<>();
this.allMatchers = new ArrayList<>();
return; return;
} }
// 按优先级排序并过滤启用的匹配器 // 按优先级排序并过滤启用的匹配器
this.allMatchers = matchers.stream() List<IotSceneRuleMatcher> allMatchers = matchers.stream()
.filter(IotSceneRuleMatcher::isEnabled) .filter(IotSceneRuleMatcher::isEnabled)
.sorted(Comparator.comparing(IotSceneRuleMatcher::getPriority)) .sorted(Comparator.comparing(IotSceneRuleMatcher::getPriority))
.collect(Collectors.toList()); .toList();
// 分离触发器匹配器和条件匹配器 // 分离触发器匹配器和条件匹配器
List<IotSceneRuleTriggerMatcher> triggerMatchers = this.allMatchers.stream() List<IotSceneRuleTriggerMatcher> triggerMatchers = allMatchers.stream()
.filter(matcher -> matcher instanceof IotSceneRuleTriggerMatcher) .filter(matcher -> matcher instanceof IotSceneRuleTriggerMatcher)
.map(matcher -> (IotSceneRuleTriggerMatcher) matcher) .map(matcher -> (IotSceneRuleTriggerMatcher) matcher)
.toList(); .toList();
List<IotSceneRuleConditionMatcher> conditionMatchers = this.allMatchers.stream() List<IotSceneRuleConditionMatcher> conditionMatchers = allMatchers.stream()
.filter(matcher -> matcher instanceof IotSceneRuleConditionMatcher) .filter(matcher -> matcher instanceof IotSceneRuleConditionMatcher)
.map(matcher -> (IotSceneRuleConditionMatcher) matcher) .map(matcher -> (IotSceneRuleConditionMatcher) matcher)
.toList(); .toList();
@@ -92,7 +84,7 @@ public class IotSceneRuleMatcherManager {
// 日志输出初始化信息 // 日志输出初始化信息
log.info("[IotSceneRuleMatcherManager][初始化完成,共加载({})个匹配器,其中触发器匹配器({})个,条件匹配器({})个]", log.info("[IotSceneRuleMatcherManager][初始化完成,共加载({})个匹配器,其中触发器匹配器({})个,条件匹配器({})个]",
this.allMatchers.size(), this.triggerMatchers.size(), this.conditionMatchers.size()); allMatchers.size(), this.triggerMatchers.size(), this.conditionMatchers.size());
this.triggerMatchers.forEach((type, matcher) -> this.triggerMatchers.forEach((type, matcher) ->
log.info("[IotSceneRuleMatcherManager][触发器匹配器类型: ({}), 优先级: ({})] ", type, matcher.getPriority())); log.info("[IotSceneRuleMatcherManager][触发器匹配器类型: ({}), 优先级: ({})] ", type, matcher.getPriority()));
this.conditionMatchers.forEach((type, matcher) -> this.conditionMatchers.forEach((type, matcher) ->
@@ -123,7 +115,7 @@ public class IotSceneRuleMatcherManager {
} }
try { try {
return matcher.isMatched(message, trigger); return matcher.matches(message, trigger);
} catch (Exception e) { } catch (Exception e) {
log.error("[isMatched][触发器匹配异常] message: {}, trigger: {}", message, trigger, e); log.error("[isMatched][触发器匹配异常] message: {}, trigger: {}", message, trigger, e);
return false; return false;
@@ -144,7 +136,7 @@ public class IotSceneRuleMatcherManager {
} }
// 根据条件类型查找对应的匹配器 // 根据条件类型查找对应的匹配器
IotSceneRuleConditionTypeEnum conditionType = findConditionTypeEnum(condition.getType()); IotSceneRuleConditionTypeEnum conditionType = IotSceneRuleConditionTypeEnum.typeOf(condition.getType());
if (conditionType == null) { if (conditionType == null) {
log.warn("[isConditionMatched][conditionType({}) 未知的条件类型]", condition.getType()); log.warn("[isConditionMatched][conditionType({}) 未知的条件类型]", condition.getType());
return false; return false;
@@ -157,45 +149,11 @@ public class IotSceneRuleMatcherManager {
// 执行匹配逻辑 // 执行匹配逻辑
try { try {
return matcher.isMatched(message, condition); return matcher.matches(message, condition);
} catch (Exception e) { } catch (Exception e) {
log.error("[isConditionMatched][message({}) condition({}) 条件匹配异常]", message, condition, e); log.error("[isConditionMatched][message({}) condition({}) 条件匹配异常]", message, condition, e);
return false; return false;
} }
} }
/**
* 根据类型值查找条件类型枚举
*
* @param typeValue 类型值
* @return 条件类型枚举
*/
private IotSceneRuleConditionTypeEnum findConditionTypeEnum(Integer typeValue) {
// TODO @puhui999是不是搞到枚举类里
return Arrays.stream(IotSceneRuleConditionTypeEnum.values())
.filter(type -> type.getType().equals(typeValue))
.findFirst()
.orElse(null);
}
// TODO @puhui999下面两个方法是不是也可以删除哈
/**
* 获取所有支持的触发器类型
*
* @return 支持的触发器类型列表
*/
public Set<IotSceneRuleTriggerTypeEnum> getSupportedTriggerTypes() {
return new HashSet<>(triggerMatchers.keySet());
}
/**
* 获取所有支持的条件类型
*
* @return 支持的条件类型列表
*/
public Set<IotSceneRuleConditionTypeEnum> getSupportedConditionTypes() {
return new HashSet<>(conditionMatchers.keySet());
}
} }

View File

@@ -43,7 +43,7 @@ public class CurrentTimeConditionMatcher implements IotSceneRuleConditionMatcher
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效"); IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效");
@@ -123,7 +123,6 @@ public class CurrentTimeConditionMatcher implements IotSceneRuleConditionMatcher
isDateTimeOperator(operatorEnum); isDateTimeOperator(operatorEnum);
} }
// TODO @puhui999switch 兼容下 jdk8
/** /**
* 匹配日期时间(时间戳) * 匹配日期时间(时间戳)
* 直接实现时间戳比较逻辑 * 直接实现时间戳比较逻辑
@@ -131,15 +130,17 @@ public class CurrentTimeConditionMatcher implements IotSceneRuleConditionMatcher
private boolean matchDateTime(long currentTimestamp, IotSceneRuleConditionOperatorEnum operatorEnum, String param) { private boolean matchDateTime(long currentTimestamp, IotSceneRuleConditionOperatorEnum operatorEnum, String param) {
try { try {
long targetTimestamp = Long.parseLong(param); long targetTimestamp = Long.parseLong(param);
return switch (operatorEnum) { switch (operatorEnum) {
case DATE_TIME_GREATER_THAN -> currentTimestamp > targetTimestamp; case DATE_TIME_GREATER_THAN:
case DATE_TIME_LESS_THAN -> currentTimestamp < targetTimestamp; return currentTimestamp > targetTimestamp;
case DATE_TIME_BETWEEN -> matchDateTimeBetween(currentTimestamp, param); case DATE_TIME_LESS_THAN:
default -> { return currentTimestamp < targetTimestamp;
case DATE_TIME_BETWEEN:
return matchDateTimeBetween(currentTimestamp, param);
default:
log.warn("[matchDateTime][operatorEnum({}) 不支持的日期时间操作符]", operatorEnum); log.warn("[matchDateTime][operatorEnum({}) 不支持的日期时间操作符]", operatorEnum);
yield false; return false;
} }
};
} catch (Exception e) { } catch (Exception e) {
log.error("[matchDateTime][operatorEnum({}) param({}) 日期时间匹配异常]", operatorEnum, param, e); log.error("[matchDateTime][operatorEnum({}) param({}) 日期时间匹配异常]", operatorEnum, param, e);
return false; return false;
@@ -167,15 +168,17 @@ public class CurrentTimeConditionMatcher implements IotSceneRuleConditionMatcher
private boolean matchTime(LocalTime currentTime, IotSceneRuleConditionOperatorEnum operatorEnum, String param) { private boolean matchTime(LocalTime currentTime, IotSceneRuleConditionOperatorEnum operatorEnum, String param) {
try { try {
LocalTime targetTime = parseTime(param); LocalTime targetTime = parseTime(param);
return switch (operatorEnum) { switch (operatorEnum) {
case TIME_GREATER_THAN -> currentTime.isAfter(targetTime); case TIME_GREATER_THAN:
case TIME_LESS_THAN -> currentTime.isBefore(targetTime); return currentTime.isAfter(targetTime);
case TIME_BETWEEN -> matchTimeBetween(currentTime, param); case TIME_LESS_THAN:
default -> { return currentTime.isBefore(targetTime);
case TIME_BETWEEN:
return matchTimeBetween(currentTime, param);
default:
log.warn("[matchTime][operatorEnum({}) 不支持的时间操作符]", operatorEnum); log.warn("[matchTime][operatorEnum({}) 不支持的时间操作符]", operatorEnum);
yield false; return false;
} }
};
} catch (Exception e) { } catch (Exception e) {
log.error("[matchTime][][operatorEnum({}) param({}) 时间解析异常]", operatorEnum, param, e); log.error("[matchTime][][operatorEnum({}) param({}) 时间解析异常]", operatorEnum, param, e);
return false; return false;

View File

@@ -22,9 +22,8 @@ public class DevicePropertyConditionMatcher implements IotSceneRuleConditionMatc
return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY; return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY;
} }
// TODO @puhui999matches 会不会更好?参考的 org.hamcrest.Matcher jdk 接口
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效"); IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效");

View File

@@ -22,7 +22,7 @@ public class DeviceStateConditionMatcher implements IotSceneRuleConditionMatcher
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效"); IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "条件基础参数无效");

View File

@@ -33,6 +33,6 @@ public interface IotSceneRuleConditionMatcher extends IotSceneRuleMatcher {
* @param condition 触发条件 * @param condition 触发条件
* @return 是否匹配 * @return 是否匹配
*/ */
boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition); boolean matches(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition);
} }

View File

@@ -25,7 +25,7 @@ public class DeviceEventPostTriggerMatcher implements IotSceneRuleTriggerMatcher
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");

View File

@@ -24,7 +24,7 @@ public class DevicePropertyPostTriggerMatcher implements IotSceneRuleTriggerMatc
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");

View File

@@ -24,7 +24,7 @@ public class DeviceServiceInvokeTriggerMatcher implements IotSceneRuleTriggerMat
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");

View File

@@ -23,7 +23,7 @@ public class DeviceStateUpdateTriggerMatcher implements IotSceneRuleTriggerMatch
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");

View File

@@ -33,6 +33,6 @@ public interface IotSceneRuleTriggerMatcher extends IotSceneRuleMatcher {
* @param trigger 触发器配置 * @param trigger 触发器配置
* @return 是否匹配 * @return 是否匹配
*/ */
boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger); boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger);
} }

View File

@@ -25,7 +25,7 @@ public class TimerTriggerMatcher implements IotSceneRuleTriggerMatcher {
} }
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean matches(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// 1.1 基础参数校验 // 1.1 基础参数校验
if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");

View File

@@ -5,103 +5,110 @@ 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.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link CurrentTimeConditionMatcher} 的单元测试 * {@link CurrentTimeConditionMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest { public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private CurrentTimeConditionMatcher matcher; private CurrentTimeConditionMatcher matcher;
@BeforeEach
public void setUp() {
matcher = new CurrentTimeConditionMatcher();
}
@Test @Test
public void testGetSupportedConditionType() { public void testGetSupportedConditionType() {
// when & then // 调用
assertEquals(IotSceneRuleConditionTypeEnum.CURRENT_TIME, matcher.getSupportedConditionType()); IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.CURRENT_TIME, result);
} }
@Test @Test
public void testGetPriority() { public void testGetPriority() {
// when & then // 调用
assertEquals(40, matcher.getPriority()); int result = matcher.getPriority();
// 断言
assertEquals(40, result);
} }
@Test @Test
public void testIsEnabled() { public void testIsEnabled() {
// when & then // 调用
assertTrue(matcher.isEnabled()); boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
} }
// ========== 时间戳条件测试 ========== // ========== 时间戳条件测试 ==========
@Test @Test
public void testIsMatched_DateTimeGreaterThan_Success() { public void testMatches_DateTimeGreaterThan_success() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
long pastTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8")); long pastTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
String.valueOf(pastTimestamp) String.valueOf(pastTimestamp)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_DateTimeGreaterThan_Failure() { public void testMatches_DateTimeGreaterThan_fail() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8")); long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
String.valueOf(futureTimestamp) String.valueOf(futureTimestamp)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_DateTimeLessThan_Success() { public void testMatches_DateTimeLessThan_success() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8")); long futureTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_LESS_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.DATE_TIME_LESS_THAN.getOperator(),
String.valueOf(futureTimestamp) String.valueOf(futureTimestamp)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_DateTimeBetween_Success() { public void testMatches_DateTimeBetween_success() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
long startTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8")); long startTimestamp = LocalDateTime.now().minusHours(1).toEpochSecond(ZoneOffset.of("+8"));
long endTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8")); long endTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
@@ -109,17 +116,17 @@ public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
startTimestamp + "," + endTimestamp startTimestamp + "," + endTimestamp
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_DateTimeBetween_Failure() { public void testMatches_DateTimeBetween_fail() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
long startTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8")); long startTimestamp = LocalDateTime.now().plusHours(1).toEpochSecond(ZoneOffset.of("+8"));
long endTimestamp = LocalDateTime.now().plusHours(2).toEpochSecond(ZoneOffset.of("+8")); long endTimestamp = LocalDateTime.now().plusHours(2).toEpochSecond(ZoneOffset.of("+8"));
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
@@ -127,78 +134,78 @@ public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
startTimestamp + "," + endTimestamp startTimestamp + "," + endTimestamp
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
// ========== 当日时间条件测试 ========== // ========== 当日时间条件测试 ==========
@Test @Test
public void testIsMatched_TimeGreaterThan_EarlyMorning() { public void testMatches_TimeGreaterThan_earlyMorning() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(),
"06:00:00" // 早上6点 "06:00:00" // 早上6点
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
// 结果取决于当前时间如果当前时间大于6点则为true // 结果取决于当前时间如果当前时间大于6点则为true
assertNotNull(result); assertNotNull(result);
} }
@Test @Test
public void testIsMatched_TimeLessThan_LateNight() { public void testMatches_TimeLessThan_lateNight() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_LESS_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_LESS_THAN.getOperator(),
"23:59:59" // 晚上11点59分59秒 "23:59:59" // 晚上11点59分59秒
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
// 大部分情况下应该为true除非在午夜前1秒运行测试 // 大部分情况下应该为true除非在午夜前1秒运行测试
assertNotNull(result); assertNotNull(result);
} }
@Test @Test
public void testIsMatched_TimeBetween_AllDay() { public void testMatches_TimeBetween_allDay() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"00:00:00,23:59:59" // 全天 "00:00:00,23:59:59" // 全天
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); // 全天范围应该总是匹配 assertTrue(result); // 全天范围应该总是匹配
} }
@Test @Test
public void testIsMatched_TimeBetween_WorkingHours() { public void testMatches_TimeBetween_workingHours() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"09:00:00,17:00:00" // 工作时间 "09:00:00,17:00:00" // 工作时间
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
// 结果取决于当前时间是否在工作时间内 // 结果取决于当前时间是否在工作时间内
assertNotNull(result); assertNotNull(result);
} }
@@ -206,97 +213,106 @@ public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
// ========== 异常情况测试 ========== // ========== 异常情况测试 ==========
@Test @Test
public void testIsMatched_NullCondition() { public void testMatches_nullCondition() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_NullConditionType() { public void testMatches_nullConditionType() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null); condition.setType(null);
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_InvalidOperator() { public void testMatches_invalidOperator() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType()); condition.setType(IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType());
condition.setOperator("invalid_operator"); condition.setOperator(randomString()); // 随机无效操作符
condition.setParam("12:00:00"); condition.setParam("12:00:00");
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_InvalidTimeFormat() { public void testMatches_invalidTimeFormat() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN.getOperator(),
"invalid-time-format" randomString() // 随机无效时间格式
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_InvalidTimestampFormat() { public void testMatches_invalidTimestampFormat() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition( IotSceneRuleDO.TriggerCondition condition = createDateTimeCondition(
IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN.getOperator(),
"invalid-timestamp" randomString() // 随机无效时间戳格式
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_InvalidBetweenFormat() { public void testMatches_invalidBetweenFormat() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.TriggerCondition condition = createTimeCondition( IotSceneRuleDO.TriggerCondition condition = createTimeCondition(
IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(), IotSceneRuleConditionOperatorEnum.TIME_BETWEEN.getOperator(),
"09:00:00" // 缺少结束时间 "09:00:00" // 缺少结束时间
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
// ========== 辅助方法 ========== // ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage() {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
return message;
}
/** /**
* 创建日期时间条件 * 创建日期时间条件
*/ */
@@ -318,4 +334,5 @@ public class CurrentTimeConditionMatcherTest extends BaseMockitoUnitTest {
condition.setParam(param); condition.setParam(param);
return condition; return condition;
} }
} }

View File

@@ -6,185 +6,206 @@ 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.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DevicePropertyConditionMatcher} 的单元测试 * {@link DevicePropertyConditionMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest { public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DevicePropertyConditionMatcher matcher; private DevicePropertyConditionMatcher matcher;
@BeforeEach
public void setUp() {
matcher = new DevicePropertyConditionMatcher();
}
@Test @Test
public void testGetSupportedConditionType() { public void testGetSupportedConditionType() {
// when & then // 调用
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY, matcher.getSupportedConditionType()); IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY, result);
} }
@Test @Test
public void testGetPriority() { public void testGetPriority() {
// when & then // 调用
assertEquals(20, matcher.getPriority()); int result = matcher.getPriority();
// 断言
assertEquals(20, result);
} }
@Test @Test
public void testIsEnabled() { public void testIsEnabled() {
// when & then // 调用
assertTrue(matcher.isEnabled()); boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_TemperatureEquals() { public void testMatches_temperatureEquals_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); String propertyName = "temperature";
Double propertyValue = 25.5;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"25.5" String.valueOf(propertyValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_HumidityGreaterThan() { public void testMatches_humidityGreaterThan_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("humidity", 75); String propertyName = "humidity";
Integer propertyValue = 75;
Integer compareValue = 70;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"humidity", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"70" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_PressureLessThan() { public void testMatches_pressureLessThan_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("pressure", 1010.5); String propertyName = "pressure";
Double propertyValue = 1010.5;
Integer compareValue = 1020;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"pressure", propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
"1020" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_StatusNotEquals() { public void testMatches_statusNotEquals_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("status", "active"); String propertyName = "status";
String propertyValue = "active";
String compareValue = "inactive";
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"status", propertyName,
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
"inactive" compareValue
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_PropertyMismatch() { public void testMatches_propertyMismatch_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 15.0); String propertyName = "temperature";
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_PropertyNotFound() { public void testMatches_propertyNotFound_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"humidity", // 不存在的属性 randomString(), // 随机不存在的属性
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"50" "50"
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullCondition() { public void testMatches_nullCondition_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullConditionType() { public void testMatches_nullConditionType_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null); condition.setType(null);
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingIdentifier() { public void testMatches_missingIdentifier_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
@@ -193,16 +214,16 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator()); condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
condition.setParam("20"); condition.setParam("20");
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingOperator() { public void testMatches_missingOperator_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
@@ -211,16 +232,16 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
condition.setOperator(null); // 缺少操作符 condition.setOperator(null); // 缺少操作符
condition.setParam("20"); condition.setParam("20");
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingParam() { public void testMatches_missingParam_fail() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("temperature", 25.5); Map<String, Object> properties = MapUtil.of("temperature", 25.5);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
@@ -229,123 +250,131 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator()); condition.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
condition.setParam(null); // 缺少参数 condition.setParam(null); // 缺少参数
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessage() { public void testMatches_nullMessage_fail() {
// given // 准备参数
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature", "temperature",
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" "20"
); );
// when // 调用
boolean result = matcher.isMatched(null, condition); boolean result = matcher.matches(null, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullDeviceProperties() { public void testMatches_nullDeviceProperties_fail() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setParams(null); message.setParams(null);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"temperature", "temperature",
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" "20"
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_GreaterThanOrEquals() { public void testMatches_voltageGreaterThanOrEquals_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("voltage", 12.0); String propertyName = "voltage";
Double propertyValue = 12.0;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"voltage", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(),
"12.0" String.valueOf(propertyValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_LessThanOrEquals() { public void testMatches_currentLessThanOrEquals_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("current", 2.5); String propertyName = "current";
Double propertyValue = 2.5;
Double compareValue = 3.0;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"current", propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(),
"3.0" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_StringProperty() { public void testMatches_stringProperty_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("mode", "auto"); String propertyName = "mode";
String propertyValue = "auto";
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"mode", propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"auto" propertyValue
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_BooleanProperty() { public void testMatches_booleanProperty_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.of("enabled", true); String propertyName = "enabled";
Boolean propertyValue = true;
Map<String, Object> properties = MapUtil.of(propertyName, propertyValue);
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"enabled", propertyName,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"true" String.valueOf(propertyValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_MultipleProperties() { public void testMatches_multipleProperties_success() {
// given // 准备参数
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5) .put("temperature", 25.5)
.put("humidity", 60) .put("humidity", 60)
@@ -353,16 +382,18 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
.put("enabled", true) .put("enabled", true)
.build(); .build();
IotDeviceMessage message = createDeviceMessage(properties); IotDeviceMessage message = createDeviceMessage(properties);
String targetProperty = "humidity";
Integer targetValue = 60;
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
"humidity", targetProperty,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"60" String.valueOf(targetValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@@ -373,6 +404,7 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createDeviceMessage(Map<String, Object> properties) { private IotDeviceMessage createDeviceMessage(Map<String, Object> properties) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setParams(properties); message.setParams(properties);
return message; return message;
} }
@@ -388,4 +420,5 @@ public class DevicePropertyConditionMatcherTest extends BaseMockitoUnitTest {
condition.setParam(param); condition.setParam(param);
return condition; return condition;
} }
} }

View File

@@ -6,307 +6,327 @@ 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.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DeviceStateConditionMatcher} 的单元测试 * {@link DeviceStateConditionMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DeviceStateConditionMatcherTest extends BaseMockitoUnitTest { public class DeviceStateConditionMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceStateConditionMatcher matcher; private DeviceStateConditionMatcher matcher;
@BeforeEach
public void setUp() {
matcher = new DeviceStateConditionMatcher();
}
@Test @Test
public void testGetSupportedConditionType() { public void testGetSupportedConditionType() {
// when & then // 调用
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_STATE, matcher.getSupportedConditionType()); IotSceneRuleConditionTypeEnum result = matcher.getSupportedConditionType();
// 断言
assertEquals(IotSceneRuleConditionTypeEnum.DEVICE_STATE, result);
} }
@Test @Test
public void testGetPriority() { public void testGetPriority() {
// when & then // 调用
assertEquals(30, matcher.getPriority()); int result = matcher.getPriority();
// 断言
assertEquals(30, result);
} }
@Test @Test
public void testIsEnabled() { public void testIsEnabled() {
// when & then // 调用
assertTrue(matcher.isEnabled()); boolean result = matcher.isEnabled();
}
@Test // 断言
public void testIsMatched_Success_OnlineState() {
// given
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString()
);
// when
boolean result = matcher.isMatched(message, condition);
// then
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_OfflineState() { public void testMatches_onlineState_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.OFFLINE.getState()); IotDeviceStateEnum deviceState = IotDeviceStateEnum.ONLINE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() deviceState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_InactiveState() { public void testMatches_offlineState_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.INACTIVE.getState()); IotDeviceStateEnum deviceState = IotDeviceStateEnum.OFFLINE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.INACTIVE.getState().toString() deviceState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_StateMismatch() { public void testMatches_inactiveState_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceStateEnum deviceState = IotDeviceStateEnum.INACTIVE;
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() deviceState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
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); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_NotEqualsOperator() { public void testMatches_notEqualsOperator_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceStateEnum actualState = IotDeviceStateEnum.ONLINE;
IotDeviceStateEnum compareState = IotDeviceStateEnum.OFFLINE;
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() compareState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_GreaterThanOperator() { public void testMatches_greaterThanOperator_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.OFFLINE.getState()); // 2 IotDeviceStateEnum actualState = IotDeviceStateEnum.OFFLINE; // 状态值为 2
IotDeviceStateEnum compareState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() // 1 compareState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_LessThanOperator() { public void testMatches_lessThanOperator_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.INACTIVE.getState()); // 0 IotDeviceStateEnum actualState = IotDeviceStateEnum.INACTIVE; // 状态值为 0
IotDeviceStateEnum compareState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() // 1 compareState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_NullCondition() { public void testMatches_nullCondition_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullConditionType() { public void testMatches_nullConditionType_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(null); condition.setType(null);
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingOperator() { public void testMatches_missingOperator_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType()); condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(null); condition.setOperator(null);
condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString()); condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString());
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingParam() { public void testMatches_missingParam_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType()); condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator()); condition.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator());
condition.setParam(null); condition.setParam(null);
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessage() { public void testMatches_nullMessage_fail() {
// given // 准备参数
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() IotDeviceStateEnum.ONLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(null, condition); boolean result = matcher.matches(null, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullDeviceState() { public void testMatches_nullDeviceState_fail() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setParams(null); message.setParams(null);
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() IotDeviceStateEnum.ONLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_GreaterThanOrEqualsOperator() { public void testMatches_greaterThanOrEqualsOperator_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); // 1 IotDeviceStateEnum deviceState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceMessage message = createDeviceMessage(deviceState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() // 1 deviceState.getState().toString() // 比较值也为 1
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_LessThanOrEqualsOperator() { public void testMatches_lessThanOrEqualsOperator_success() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); // 1 IotDeviceStateEnum actualState = IotDeviceStateEnum.ONLINE; // 状态值为 1
IotDeviceStateEnum compareState = IotDeviceStateEnum.OFFLINE; // 状态值为 2
IotDeviceMessage message = createDeviceMessage(actualState.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() // 2 compareState.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidOperator() { public void testMatches_invalidOperator_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition(); IotSceneRuleDO.TriggerCondition condition = new IotSceneRuleDO.TriggerCondition();
condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType()); condition.setType(IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType());
condition.setOperator("invalid_operator"); condition.setOperator(randomString()); // 随机无效操作符
condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString()); condition.setParam(IotDeviceStateEnum.ONLINE.getState().toString());
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidParamFormat() { public void testMatches_invalidParamFormat_fail() {
// given // 准备参数
IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createDeviceMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.TriggerCondition condition = createValidCondition( IotSceneRuleDO.TriggerCondition condition = createValidCondition(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"invalid_state_value" randomString() // 随机无效状态值
); );
// when // 调用
boolean result = matcher.isMatched(message, condition); boolean result = matcher.matches(message, condition);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@@ -317,6 +337,7 @@ public class DeviceStateConditionMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createDeviceMessage(Integer deviceState) { private IotDeviceMessage createDeviceMessage(Integer deviceState) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setParams(deviceState); message.setParams(deviceState);
return message; return message;
} }
@@ -331,4 +352,5 @@ public class DeviceStateConditionMatcherTest extends BaseMockitoUnitTest {
condition.setParam(param); condition.setParam(param);
return condition; return condition;
} }
} }

View File

@@ -6,154 +6,178 @@ 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.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DeviceEventPostTriggerMatcher} 的单元测试 * {@link DeviceEventPostTriggerMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest { public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceEventPostTriggerMatcher matcher; private DeviceEventPostTriggerMatcher matcher;
@BeforeEach @Test
public void setUp() { public void testGetSupportedTriggerType_success() {
matcher = new DeviceEventPostTriggerMatcher(); // 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST, result);
} }
@Test @Test
public void testGetSupportedTriggerType() { public void testGetPriority_success() {
// when & then // 准备参数
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST, matcher.getSupportedTriggerType()); // 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(30, result);
} }
@Test @Test
public void testGetPriority() { public void testIsEnabled_success() {
// when & then // 准备参数
assertEquals(30, matcher.getPriority()); // 无需准备参数
}
@Test // 调用
public void testIsEnabled() { boolean result = matcher.isEnabled();
// when & then
assertTrue(matcher.isEnabled());
}
@Test // 断言
public void testIsMatched_Success_AlarmEvent() {
// given
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm")
.put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high")
.put("message", "Temperature too high")
.build())
.build();
IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm");
// when
boolean result = matcher.isMatched(message, trigger);
// then
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_ErrorEvent() { public void testMatches_alarmEventSuccess() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "error") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("code", 500) .put("level", randomString())
.put("description", "System error") .put("message", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("error"); IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_InfoEvent() { public void testMatches_errorEventSuccess() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "info") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("status", "normal") .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()) .put("timestamp", System.currentTimeMillis())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("info"); IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_EventIdentifierMismatch() { public void testMatches_eventIdentifierMismatch() {
// given // 准备参数
String messageIdentifier = randomString();
String triggerIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm") .put("identifier", messageIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("error"); // 不匹配的事件标识符 IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_WrongMessageMethod() { public void testMatches_wrongMessageMethod() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法 message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法
message.setParams(eventParams); message.setParams(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingIdentifier() { public void testMatches_nullTriggerIdentifier() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
@@ -161,157 +185,166 @@ public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST.getType());
trigger.setIdentifier(null); // 缺少标识符 trigger.setIdentifier(null); // 缺少标识符
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessageParams() { public void testMatches_nullMessageParams() {
// given // 准备参数
String eventIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams(null); message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidMessageParams() { public void testMatches_invalidMessageParams() {
// given // 准备参数
String eventIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams("invalid-params"); // 不是 Map 类型 message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingEventIdentifierInParams() { public void testMatches_missingEventIdentifierInParams() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) // 缺少 identifier 字段 .build()) // 缺少 identifier 字段
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm"); IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTrigger() { public void testMatches_nullTrigger() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTriggerType() { public void testMatches_nullTriggerType() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "alarm") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null); trigger.setType(null);
trigger.setIdentifier("alarm"); trigger.setIdentifier(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_ComplexEventValue() { public void testMatches_complexEventValueSuccess() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "maintenance") .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("type", "scheduled") .put("type", randomString())
.put("duration", 120) .put("duration", randomInt())
.put("components", new String[]{"motor", "sensor"}) .put("components", new String[]{randomString(), randomString()})
.put("priority", "medium") .put("priority", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("maintenance"); IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_EmptyEventValue() { public void testMatches_emptyEventValueSuccess() {
// given // 准备参数
String eventIdentifier = randomString();
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "heartbeat") .put("identifier", eventIdentifier)
.put("value", MapUtil.of()) // 空的事件值 .put("value", MapUtil.ofEntries()) // 空的事件值
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("heartbeat"); IotSceneRuleDO.Trigger trigger = createValidTrigger(eventIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_CaseInsensitiveIdentifier() { public void testMatches_caseSensitiveIdentifierMismatch() {
// given // 准备参数
String eventIdentifier = randomString().toUpperCase(); // 大写
String triggerIdentifier = eventIdentifier.toLowerCase(); // 小写
Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> eventParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "ALARM") // 大写 .put("identifier", eventIdentifier)
.put("value", MapUtil.builder(new HashMap<String, Object>()) .put("value", MapUtil.builder(new HashMap<String, Object>())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createEventPostMessage(eventParams); IotDeviceMessage message = createEventPostMessage(eventParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("alarm"); // 小写 IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
// 根据实际实现,这里可能需要调整期望结果 // 根据实际实现,这里可能需要调整期望结果
// 如果实现是大小写敏感的,则应该为 false // 如果实现是大小写敏感的,则应该为 false
assertFalse(result); assertFalse(result);
@@ -324,6 +357,7 @@ public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createEventPostMessage(Map<String, Object> eventParams) { private IotDeviceMessage createEventPostMessage(Map<String, Object> eventParams) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.EVENT_POST.getMethod());
message.setParams(eventParams); message.setParams(eventParams);
return message; return message;
@@ -338,4 +372,5 @@ public class DeviceEventPostTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setIdentifier(identifier); trigger.setIdentifier(identifier);
return trigger; return trigger;
} }
} }

View File

@@ -7,268 +7,308 @@ 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.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DevicePropertyPostTriggerMatcher} 的单元测试 * {@link DevicePropertyPostTriggerMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DevicePropertyPostTriggerMatcherTest extends BaseMockitoUnitTest { public class DevicePropertyPostTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DevicePropertyPostTriggerMatcher matcher; private DevicePropertyPostTriggerMatcher matcher;
@BeforeEach @Test
public void setUp() { public void testGetSupportedTriggerType_success() {
matcher = new DevicePropertyPostTriggerMatcher(); // 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST, result);
} }
@Test @Test
public void testGetSupportedTriggerType() { public void testGetPriority_success() {
// when & then // 准备参数
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST, matcher.getSupportedTriggerType()); // 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(20, result);
} }
@Test @Test
public void testGetPriority() { public void testIsEnabled_success() {
// when & then // 准备参数
assertEquals(20, matcher.getPriority()); // 无需准备参数
}
@Test // 调用
public void testIsEnabled() { boolean result = matcher.isEnabled();
// when & then
assertTrue(matcher.isEnabled());
}
@Test // 断言
public void testIsMatched_Success_TemperatureProperty() {
// given
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5)
.build();
IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature",
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20"
);
// when
boolean result = matcher.isMatched(message, trigger);
// then
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_HumidityProperty() { public void testMatches_numericPropertyGreaterThanSuccess() {
// given // 准备参数
String propertyName = randomString();
Double propertyValue = 25.5;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("humidity", 60) .put(propertyName, propertyValue)
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"humidity", 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(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"60" String.valueOf(propertyValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_PropertyMismatch() { public void testMatches_propertyValueNotMeetCondition() {
// given // 准备参数
String propertyName = randomString();
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 15.0) .put(propertyName, propertyValue)
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_PropertyNotFound() { public void testMatches_propertyNotFound() {
// given // 准备参数
String existingProperty = randomString();
String missingProperty = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5) .put(existingProperty, randomDouble())
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"humidity", // 不存在的属性 missingProperty, // 不存在的属性
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"50" String.valueOf(randomInt())
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_WrongMessageMethod() { public void testMatches_wrongMessageMethod() {
// given // 准备参数
String propertyName = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5) .put(propertyName, randomDouble())
.build(); .build();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(properties); message.setParams(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" String.valueOf(randomInt())
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingIdentifier() { public void testMatches_nullTriggerIdentifier() {
// given // 准备参数
String propertyName = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5) .put(propertyName, randomDouble())
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST.getType());
trigger.setIdentifier(null); // 缺少标识符 trigger.setIdentifier(null); // 缺少标识符
trigger.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator()); trigger.setOperator(IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator());
trigger.setValue("20"); trigger.setValue(String.valueOf(randomInt()));
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessageParams() { public void testMatches_nullMessageParams() {
// given // 准备参数
String propertyName = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(null); message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" String.valueOf(randomInt())
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidMessageParams() { public void testMatches_invalidMessageParams() {
// given // 准备参数
String propertyName = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams("invalid-params"); // 不是 Map 类型 message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
"20" String.valueOf(randomInt())
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_LessThanOperator() { public void testMatches_lessThanOperatorSuccess() {
// given // 准备参数
String propertyName = randomString();
Double propertyValue = 15.0;
Integer compareValue = 20;
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 15.0) .put(propertyName, propertyValue)
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"temperature", propertyName,
IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.LESS_THAN.getOperator(),
"20" String.valueOf(compareValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_NotEqualsOperator() { public void testMatches_notEqualsOperatorSuccess() {
// given // 准备参数
String propertyName = randomString();
String propertyValue = randomString();
String compareValue = randomString();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("status", "active") .put(propertyName, propertyValue)
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"status", propertyName,
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
"inactive" compareValue
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_MultipleProperties() { public void testMatches_multiplePropertiesTargetPropertySuccess() {
// given // 准备参数
String targetProperty = randomString();
Integer targetValue = randomInt();
Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> properties = MapUtil.builder(new HashMap<String, Object>())
.put("temperature", 25.5) .put(randomString(), randomDouble())
.put("humidity", 60) .put(targetProperty, targetValue)
.put("status", "active") .put(randomString(), randomString())
.build(); .build();
IotDeviceMessage message = createPropertyPostMessage(properties); IotDeviceMessage message = createPropertyPostMessage(properties);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
"humidity", targetProperty,
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
"60" String.valueOf(targetValue)
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@@ -279,6 +319,7 @@ public class DevicePropertyPostTriggerMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createPropertyPostMessage(Map<String, Object> properties) { private IotDeviceMessage createPropertyPostMessage(Map<String, Object> properties) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(properties); message.setParams(properties);
return message; return message;
@@ -295,4 +336,5 @@ public class DevicePropertyPostTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setValue(value); trigger.setValue(value);
return trigger; return trigger;
} }
} }

View File

@@ -6,155 +6,178 @@ 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.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DeviceServiceInvokeTriggerMatcher} 的单元测试 * {@link DeviceServiceInvokeTriggerMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest { public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceServiceInvokeTriggerMatcher matcher; private DeviceServiceInvokeTriggerMatcher matcher;
@BeforeEach @Test
public void setUp() { public void testGetSupportedTriggerType_success() {
matcher = new DeviceServiceInvokeTriggerMatcher(); // 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE, result);
} }
@Test @Test
public void testGetSupportedTriggerType() { public void testGetPriority_success() {
// when & then // 准备参数
// TODO @puhui999单测按照现有项目的注释风格哈类似 // 调用;// 断言 // 无需准备参数
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE, matcher.getSupportedTriggerType());
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(40, result);
} }
@Test @Test
public void testGetPriority() { public void testIsEnabled_success() {
// when & then // 准备参数
assertEquals(40, matcher.getPriority()); // 无需准备参数
}
@Test // 调用
public void testIsEnabled() { boolean result = matcher.isEnabled();
// when & then
assertTrue(matcher.isEnabled());
}
@Test // 断言
public void testIsMatched_Success_RestartService() {
// given
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart")
.put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft")
.build())
.build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart");
// when
boolean result = matcher.isMatched(message, trigger);
// then
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_ConfigService() { public void testMatches_serviceInvokeSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "config") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("interval", 30) .put("mode", randomString())
.put("enabled", true)
.put("threshold", 75.5)
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("config"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_UpdateService() { public void testMatches_configServiceSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "update") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("version", "1.2.3") .put("interval", randomInt())
.put("url", "http://example.com/firmware.bin") .put("enabled", randomBoolean())
.put("threshold", randomDouble())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("update"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_ServiceIdentifierMismatch() { public void testMatches_updateServiceSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("version", randomString())
.put("url", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("config"); // 不匹配的服务标识符 IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
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); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_WrongMessageMethod() { public void testMatches_wrongMessageMethod() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法 message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法
message.setParams(serviceParams); message.setParams(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingIdentifier() { public void testMatches_nullTriggerIdentifier() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
@@ -162,178 +185,188 @@ public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType());
trigger.setIdentifier(null); // 缺少标识符 trigger.setIdentifier(null); // 缺少标识符
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessageParams() { public void testMatches_nullMessageParams() {
// given // 准备参数
String serviceIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams(null); message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidMessageParams() { public void testMatches_invalidMessageParams() {
// given // 准备参数
String serviceIdentifier = randomString();
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams("invalid-params"); // 不是 Map 类型 message.setParams(randomString()); // 不是 Map 类型
IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart"); // 调用
boolean result = matcher.matches(message, trigger);
// when // 断言
boolean result = matcher.isMatched(message, trigger);
// then
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingServiceIdentifierInParams() { public void testMatches_missingServiceIdentifierInParams() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) // 缺少 identifier 字段 .build()) // 缺少 identifier 字段
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTrigger() { public void testMatches_nullTrigger() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTriggerType() { public void testMatches_nullTriggerType() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "restart") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null); trigger.setType(null);
trigger.setIdentifier("restart"); trigger.setIdentifier(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_EmptyInputData() { public void testMatches_emptyInputDataSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "ping") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.of()) // 空的输入数据 .put("inputData", MapUtil.ofEntries()) // 空的输入数据
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("ping"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_NoInputData() { public void testMatches_noInputDataSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "status") .put("identifier", serviceIdentifier)
// 没有 inputData 字段 // 没有 inputData 字段
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("status"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_ComplexInputData() { public void testMatches_complexInputDataSuccess() {
// given // 准备参数
String serviceIdentifier = randomString();
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "calibrate") .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("sensors", new String[]{"temperature", "humidity", "pressure"}) .put("sensors", new String[]{randomString(), randomString(), randomString()})
.put("precision", 0.01) .put("precision", randomDouble())
.put("duration", 300) .put("duration", randomInt())
.put("autoSave", true) .put("autoSave", randomBoolean())
.put("config", MapUtil.builder(new HashMap<String, Object>()) .put("config", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "auto") .put("mode", randomString())
.put("level", "high") .put("level", randomString())
.build()) .build())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("calibrate"); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_CaseInsensitiveIdentifier() { public void testMatches_caseSensitiveIdentifierMismatch() {
// given // 准备参数
String serviceIdentifier = randomString().toUpperCase(); // 大写
String triggerIdentifier = serviceIdentifier.toLowerCase(); // 小写
Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>()) Map<String, Object> serviceParams = MapUtil.builder(new HashMap<String, Object>())
.put("identifier", "RESTART") // 大写 .put("identifier", serviceIdentifier)
.put("inputData", MapUtil.builder(new HashMap<String, Object>()) .put("inputData", MapUtil.builder(new HashMap<String, Object>())
.put("mode", "soft") .put("mode", randomString())
.build()) .build())
.build(); .build();
IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotDeviceMessage message = createServiceInvokeMessage(serviceParams);
IotSceneRuleDO.Trigger trigger = createValidTrigger("restart"); // 小写 IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
// 根据实际实现,这里可能需要调整期望结果 // 根据实际实现,这里可能需要调整期望结果
// 如果实现是大小写敏感的,则应该为 false // 如果实现是大小写敏感的,则应该为 false
assertFalse(result); assertFalse(result);
@@ -346,6 +379,7 @@ public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createServiceInvokeMessage(Map<String, Object> serviceParams) { private IotDeviceMessage createServiceInvokeMessage(Map<String, Object> serviceParams) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod());
message.setParams(serviceParams); message.setParams(serviceParams);
return message; return message;
@@ -360,4 +394,5 @@ public class DeviceServiceInvokeTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setIdentifier(identifier); trigger.setIdentifier(identifier);
return trigger; return trigger;
} }
} }

View File

@@ -7,216 +7,231 @@ 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.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link DeviceStateUpdateTriggerMatcher} 的单元测试 * {@link DeviceStateUpdateTriggerMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class DeviceStateUpdateTriggerMatcherTest extends BaseMockitoUnitTest { public class DeviceStateUpdateTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private DeviceStateUpdateTriggerMatcher matcher; private DeviceStateUpdateTriggerMatcher matcher;
@BeforeEach @Test
public void setUp() { public void testGetSupportedTriggerType_success() {
matcher = new DeviceStateUpdateTriggerMatcher(); // 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE, result);
} }
@Test @Test
public void testGetSupportedTriggerType() { public void testGetPriority_success() {
// when & then // 准备参数
assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE, matcher.getSupportedTriggerType()); // 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(10, result);
} }
@Test @Test
public void testGetPriority() { public void testIsEnabled_success() {
// when & then // 准备参数
assertEquals(10, matcher.getPriority()); // 无需准备参数
// 调用
boolean result = matcher.isEnabled();
// 断言
assertTrue(result);
} }
@Test @Test
public void testIsEnabled() { public void testMatches_onlineStateSuccess() {
// when & then // 准备参数
assertTrue(matcher.isEnabled());
}
@Test
public void testIsMatched_Success_OnlineState() {
// given
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() IotDeviceStateEnum.ONLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_OfflineState() { public void testMatches_offlineStateSuccess() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.OFFLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.OFFLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() IotDeviceStateEnum.OFFLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_StateMismatch() { public void testMatches_stateMismatch() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() IotDeviceStateEnum.OFFLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTrigger() { public void testMatches_nullTrigger() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTriggerType() { public void testMatches_nullTriggerType() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null); trigger.setType(null);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_WrongMessageMethod() { public void testMatches_wrongMessageMethod() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(IotDeviceStateEnum.ONLINE.getState()); message.setParams(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() IotDeviceStateEnum.ONLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingOperator() { public void testMatches_nullTriggerOperator() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator(null); trigger.setOperator(null);
trigger.setValue(IotDeviceStateEnum.ONLINE.getState().toString()); trigger.setValue(IotDeviceStateEnum.ONLINE.getState().toString());
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_MissingValue() { public void testMatches_nullTriggerValue() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator()); trigger.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator());
trigger.setValue(null); trigger.setValue(null);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullMessageParams() { public void testMatches_nullMessageParams() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(null); message.setParams(null);
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.EQUALS.getOperator(),
IotDeviceStateEnum.ONLINE.getState().toString() IotDeviceStateEnum.ONLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_GreaterThanOperator() { public void testMatches_greaterThanOperatorSuccess() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(), IotSceneRuleConditionOperatorEnum.GREATER_THAN.getOperator(),
IotDeviceStateEnum.INACTIVE.getState().toString() IotDeviceStateEnum.INACTIVE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_NotEqualsOperator() { public void testMatches_notEqualsOperatorSuccess() {
// given // 准备参数
IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState()); IotDeviceMessage message = createStateUpdateMessage(IotDeviceStateEnum.ONLINE.getState());
IotSceneRuleDO.Trigger trigger = createValidTrigger( IotSceneRuleDO.Trigger trigger = createValidTrigger(
IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(), IotSceneRuleConditionOperatorEnum.NOT_EQUALS.getOperator(),
IotDeviceStateEnum.OFFLINE.getState().toString() IotDeviceStateEnum.OFFLINE.getState().toString()
); );
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@@ -227,6 +242,7 @@ public class DeviceStateUpdateTriggerMatcherTest extends BaseMockitoUnitTest {
*/ */
private IotDeviceMessage createStateUpdateMessage(Integer state) { private IotDeviceMessage createStateUpdateMessage(Integer state) {
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod()); message.setMethod(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod());
message.setParams(state); message.setParams(state);
return message; return message;
@@ -242,4 +258,5 @@ public class DeviceStateUpdateTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setValue(value); trigger.setValue(value);
return trigger; return trigger;
} }
} }

View File

@@ -4,230 +4,265 @@ 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.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; 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.*; import static org.junit.jupiter.api.Assertions.*;
/** /**
* {@link TimerTriggerMatcher} 的单元测试 * {@link TimerTriggerMatcher} 的单元测试
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class TimerTriggerMatcherTest extends BaseMockitoUnitTest { public class TimerTriggerMatcherTest extends BaseMockitoUnitTest {
@InjectMocks
private TimerTriggerMatcher matcher; private TimerTriggerMatcher matcher;
@BeforeEach @Test
public void setUp() { public void testGetSupportedTriggerType_success() {
matcher = new TimerTriggerMatcher(); // 准备参数
// 无需准备参数
// 调用
IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType();
// 断言
assertEquals(IotSceneRuleTriggerTypeEnum.TIMER, result);
} }
@Test @Test
public void testGetSupportedTriggerType() { public void testGetPriority_success() {
// when & then // 准备参数
assertEquals(IotSceneRuleTriggerTypeEnum.TIMER, matcher.getSupportedTriggerType()); // 无需准备参数
// 调用
int result = matcher.getPriority();
// 断言
assertEquals(50, result);
} }
@Test @Test
public void testGetPriority() { public void testIsEnabled_success() {
// when & then // 准备参数
assertEquals(50, matcher.getPriority()); // 无需准备参数
}
@Test // 调用
public void testIsEnabled() { boolean result = matcher.isEnabled();
// when & then
assertTrue(matcher.isEnabled());
}
@Test // 断言
public void testIsMatched_Success_ValidCronExpression() {
// given
IotDeviceMessage message = new IotDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 12 * * ?"); // 每天中午12点
// when
boolean result = matcher.isMatched(message, trigger);
// then
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_EveryMinuteCron() { public void testMatches_validCronExpressionSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 * * * * ?"); // 每分钟 String cronExpression = "0 0 12 * * ?"; // 每天中午12点
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_WeekdaysCron() { public void testMatches_everyMinuteCronSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 9 ? * MON-FRI"); // 工作日上午9点 String cronExpression = "0 * * * * ?"; // 每分钟
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidCronExpression() { public void testMatches_weekdaysCronSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("invalid-cron-expression"); String cronExpression = "0 0 9 ? * MON-FRI"; // 工作日上午9点
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
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); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_EmptyCronExpression() { public void testMatches_emptyCronExpression() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger(""); String cronExpression = ""; // 空的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullCronExpression() { public void testMatches_nullCronExpression() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.TIMER.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.TIMER.getType());
trigger.setCronExpression(null); trigger.setCronExpression(null);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTrigger() { public void testMatches_nullTrigger() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
// when // 调用
boolean result = matcher.isMatched(message, null); boolean result = matcher.matches(message, null);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Failure_NullTriggerType() { public void testMatches_nullTriggerType() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(null); trigger.setType(null);
trigger.setCronExpression("0 0 12 * * ?"); trigger.setCronExpression("0 0 12 * * ?");
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_ComplexCronExpression() { public void testMatches_complexCronExpressionSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 15 10 ? * 6#3"); // 每月第三个星期五上午10:15 String cronExpression = "0 15 10 ? * 6#3"; // 每月第三个星期五上午10:15
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_IncorrectCronFormat() { public void testMatches_incorrectCronFormat() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 12 * *"); // 缺少字段 String cronExpression = "0 0 12 * *"; // 缺少字段的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_SpecificDateCron() { public void testMatches_specificDateCronSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 0 1 1 ? 2025"); // 2025年1月1日午夜 String cronExpression = "0 0 0 1 1 ? 2025"; // 2025年1月1日午夜
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Success_EverySecondCron() { public void testMatches_everySecondCronSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("* * * * * ?"); // 每秒 String cronExpression = "* * * * * ?"; // 每秒执行
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
@Test @Test
public void testIsMatched_Failure_InvalidCharactersCron() { public void testMatches_invalidCharactersCron() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 12 * * @ #"); // 包含无效字符 String cronExpression = "0 0 12 * * @ #"; // 包含无效字符的 cron 表达式
IotSceneRuleDO.Trigger trigger = createValidTrigger(cronExpression);
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertFalse(result); assertFalse(result);
} }
@Test @Test
public void testIsMatched_Success_RangeCron() { public void testMatches_rangeCronSuccess() {
// given // 准备参数
IotDeviceMessage message = new IotDeviceMessage(); IotDeviceMessage message = createDeviceMessage();
IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 9-17 * * MON-FRI"); // 工作日9-17点 IotSceneRuleDO.Trigger trigger = createValidTrigger("0 0 9-17 * * MON-FRI"); // 工作日9-17点
// when // 调用
boolean result = matcher.isMatched(message, trigger); boolean result = matcher.matches(message, trigger);
// then // 断言
assertTrue(result); assertTrue(result);
} }
// ========== 辅助方法 ========== // ========== 辅助方法 ==========
/**
* 创建设备消息
*/
private IotDeviceMessage createDeviceMessage() {
IotDeviceMessage message = new IotDeviceMessage();
message.setDeviceId(randomLongId());
return message;
}
/** /**
* 创建有效的定时触发器 * 创建有效的定时触发器
*/ */
@@ -237,4 +272,5 @@ public class TimerTriggerMatcherTest extends BaseMockitoUnitTest {
trigger.setCronExpression(cronExpression); trigger.setCronExpression(cronExpression);
return trigger; return trigger;
} }
} }