package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotBaseConditionMatcherTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import static cn.hutool.core.util.RandomUtil.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static org.junit.jupiter.api.Assertions.*; /** * {@link IotDeviceServiceInvokeTriggerMatcher} 的单元测试 * * @author HUIHUI */ public class IotDeviceServiceInvokeTriggerMatcherTest extends IotBaseConditionMatcherTest { private IotDeviceServiceInvokeTriggerMatcher matcher; @BeforeEach public void setUp() { matcher = new IotDeviceServiceInvokeTriggerMatcher(); } @Test public void testGetSupportedTriggerType_success() { // 准备参数 // 无需准备参数 // 调用 IotSceneRuleTriggerTypeEnum result = matcher.getSupportedTriggerType(); // 断言 assertEquals(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE, result); } @Test public void testGetPriority_success() { // 准备参数 // 无需准备参数 // 调用 int result = matcher.getPriority(); // 断言 assertEquals(40, result); } @Test public void testIsEnabled_success() { // 准备参数 // 无需准备参数 // 调用 boolean result = matcher.isEnabled(); // 断言 assertTrue(result); } @Test public void testMatches_serviceInvokeSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_configServiceSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("interval", randomInt()) .put("enabled", randomBoolean()) .put("threshold", randomDouble()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_updateServiceSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("version", randomString()) .put("url", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_serviceIdentifierMismatch() { // 准备参数 String messageIdentifier = randomString(); String triggerIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", messageIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier); // 不匹配的服务标识符 // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_wrongMessageMethod() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = new IotDeviceMessage(); message.setDeviceId(randomLongId()); message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()); // 错误的方法 message.setParams(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_nullTriggerIdentifier() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(null); // 缺少标识符 // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_nullMessageParams() { // 准备参数 String serviceIdentifier = randomString(); IotDeviceMessage message = new IotDeviceMessage(); message.setDeviceId(randomLongId()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setParams(null); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_invalidMessageParams() { // 准备参数 String serviceIdentifier = randomString(); IotDeviceMessage message = new IotDeviceMessage(); message.setDeviceId(randomLongId()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setParams(randomString()); // 不是 Map 类型 IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_missingServiceIdentifierInParams() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) // 缺少 identifier 字段 .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_nullTrigger() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); // 调用 boolean result = matcher.matches(message, null); // 断言 assertFalse(result); } @Test public void testMatches_nullTriggerType() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(null); trigger.setIdentifier(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } @Test public void testMatches_emptyInputDataSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.ofEntries()) // 空的输入数据 .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_noInputDataSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) // 没有 inputData 字段 .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_complexInputDataSuccess() { // 准备参数 String serviceIdentifier = randomString(); Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("sensors", new String[]{randomString(), randomString(), randomString()}) .put("precision", randomDouble()) .put("duration", randomInt()) .put("autoSave", randomBoolean()) .put("config", MapUtil.builder(new HashMap()) .put("mode", randomString()) .put("level", randomString()) .build()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(serviceIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } @Test public void testMatches_caseSensitiveIdentifierMismatch() { // 准备参数 String serviceIdentifier = randomString().toUpperCase(); // 大写 String triggerIdentifier = serviceIdentifier.toLowerCase(); // 小写 Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", randomString()) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = createValidTrigger(triggerIdentifier); // 调用 boolean result = matcher.matches(message, trigger); // 断言 // 根据实际实现,这里可能需要调整期望结果 // 如果实现是大小写敏感的,则应该为 false assertFalse(result); } // ========== 参数条件匹配测试 ========== /** * 测试无参数条件时的匹配逻辑 - 只要标识符匹配就返回 true * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.2** */ @Test public void testMatches_noParameterCondition_success() { // 准备参数 String serviceIdentifier = "testService"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("level", 5) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(null); // 无参数条件 trigger.setValue(null); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } /** * 测试有参数条件时的匹配逻辑 - 参数条件匹配成功 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.1** */ @Test public void testMatches_withParameterCondition_greaterThan_success() { // 准备参数 String serviceIdentifier = "level"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("level", 5) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 大于操作符 trigger.setValue("3"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } /** * 测试有参数条件时的匹配逻辑 - 参数条件匹配失败 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.1** */ @Test public void testMatches_withParameterCondition_greaterThan_failure() { // 准备参数 String serviceIdentifier = "level"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("level", 2) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 大于操作符 trigger.setValue("3"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } /** * 测试有参数条件时的匹配逻辑 - 等于操作符 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.1** */ @Test public void testMatches_withParameterCondition_equals_success() { // 准备参数 String serviceIdentifier = "mode"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("mode", "auto") .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(IotSceneRuleConditionOperatorEnum.EQUALS.getOperator()); // 等于操作符 trigger.setValue("auto"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } /** * 测试参数缺失时的处理 - 消息中缺少 inputData * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.3** */ @Test public void testMatches_withParameterCondition_missingInputData() { // 准备参数 String serviceIdentifier = "testService"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) // 缺少 inputData 字段 .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 配置了参数条件 trigger.setValue("3"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } /** * 测试参数缺失时的处理 - inputData 中缺少指定参数 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.3** */ @Test public void testMatches_withParameterCondition_missingParam() { // 准备参数 String serviceIdentifier = "level"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("otherParam", 5) // 不是 level 参数 .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 配置了参数条件 trigger.setValue("3"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertFalse(result); } /** * 测试只有 operator 没有 value 时不触发参数条件匹配 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.2** */ @Test public void testMatches_onlyOperator_noValue() { // 准备参数 String serviceIdentifier = "testService"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("level", 5) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 只有 operator trigger.setValue(null); // 没有 value // 调用 boolean result = matcher.matches(message, trigger); // 断言:只有 operator 没有 value 时,不触发参数条件匹配,标识符匹配即成功 assertTrue(result); } /** * 测试只有 value 没有 operator 时不触发参数条件匹配 * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.2** */ @Test public void testMatches_onlyValue_noOperator() { // 准备参数 String serviceIdentifier = "testService"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputData", MapUtil.builder(new HashMap()) .put("level", 5) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(null); // 没有 operator trigger.setValue("3"); // 只有 value // 调用 boolean result = matcher.matches(message, trigger); // 断言:只有 value 没有 operator 时,不触发参数条件匹配,标识符匹配即成功 assertTrue(result); } /** * 测试使用 inputParams 字段(替代 inputData) * **Property 4: 服务调用触发器参数匹配逻辑** * **Validates: Requirements 5.1** */ @Test public void testMatches_withInputParams_success() { // 准备参数 String serviceIdentifier = "level"; Map serviceParams = MapUtil.builder(new HashMap()) .put("identifier", serviceIdentifier) .put("inputParams", MapUtil.builder(new HashMap()) // 使用 inputParams 而不是 inputData .put("level", 5) .build()) .build(); IotDeviceMessage message = createServiceInvokeMessage(serviceParams); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(serviceIdentifier); trigger.setOperator(">"); // 大于操作符 trigger.setValue("3"); // 调用 boolean result = matcher.matches(message, trigger); // 断言 assertTrue(result); } // ========== 辅助方法 ========== /** * 创建服务调用消息 */ private IotDeviceMessage createServiceInvokeMessage(Map serviceParams) { IotDeviceMessage message = new IotDeviceMessage(); message.setDeviceId(randomLongId()); message.setMethod(IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()); message.setParams(serviceParams); return message; } /** * 创建有效的触发器 */ private IotSceneRuleDO.Trigger createValidTrigger(String identifier) { IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE.getType()); trigger.setIdentifier(identifier); return trigger; } }