|
|
|
@ -15,12 +15,15 @@ |
|
|
|
*/ |
|
|
|
package org.thingsboard.rule.engine.mail; |
|
|
|
|
|
|
|
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|
|
|
import org.junit.Test; |
|
|
|
import org.junit.runner.RunWith; |
|
|
|
import lombok.Data; |
|
|
|
import lombok.RequiredArgsConstructor; |
|
|
|
import org.junit.jupiter.api.AfterEach; |
|
|
|
import org.junit.jupiter.api.Assertions; |
|
|
|
import org.junit.jupiter.api.BeforeEach; |
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
import org.junit.jupiter.params.ParameterizedTest; |
|
|
|
import org.junit.jupiter.params.provider.MethodSource; |
|
|
|
import org.mockito.ArgumentCaptor; |
|
|
|
import org.mockito.Mock; |
|
|
|
import org.mockito.junit.MockitoJUnitRunner; |
|
|
|
import org.thingsboard.common.util.JacksonUtil; |
|
|
|
import org.thingsboard.rule.engine.api.TbContext; |
|
|
|
import org.thingsboard.rule.engine.api.TbEmail; |
|
|
|
@ -28,85 +31,135 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|
|
|
import org.thingsboard.rule.engine.api.TbNodeException; |
|
|
|
import org.thingsboard.server.common.data.id.DeviceId; |
|
|
|
import org.thingsboard.server.common.data.id.EntityId; |
|
|
|
import org.thingsboard.server.common.data.id.RuleChainId; |
|
|
|
import org.thingsboard.server.common.data.id.RuleNodeId; |
|
|
|
import org.thingsboard.server.common.data.msg.TbMsgType; |
|
|
|
import org.thingsboard.server.common.msg.TbMsg; |
|
|
|
import org.thingsboard.server.common.msg.TbMsgDataType; |
|
|
|
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.util.UUID; |
|
|
|
import java.util.stream.Stream; |
|
|
|
|
|
|
|
import static org.junit.Assert.assertEquals; |
|
|
|
import static org.junit.Assert.assertNotSame; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
import static org.mockito.Mockito.never; |
|
|
|
import static org.mockito.Mockito.times; |
|
|
|
import static org.mockito.Mockito.verify; |
|
|
|
|
|
|
|
@RunWith(MockitoJUnitRunner.class) |
|
|
|
public class TbMsgToEmailNodeTest { |
|
|
|
|
|
|
|
private TbMsgToEmailNode emailNode; |
|
|
|
private static final int EXPECTED_TEMPERATURE = 30; |
|
|
|
private static final String EXPECTED_DEVICE_NAME = "TH-001"; |
|
|
|
private static final String EXPECTED_DEVICE_TYPE = "thermostat"; |
|
|
|
private static final String EXPECTED_SUBJECT = "Device " + EXPECTED_DEVICE_TYPE + " temperature high"; |
|
|
|
private static final String EXPECTED_BODY = "Device " + EXPECTED_DEVICE_NAME + " has high temperature " + EXPECTED_TEMPERATURE; |
|
|
|
private static final String EXPECTED_TO_EMAIL = "user@email.io"; |
|
|
|
private static final String DYNAMIC_MAIL_BODY_TYPE = "dynamic"; |
|
|
|
|
|
|
|
private EntityId originator; |
|
|
|
private TbMsgToEmailNode node; |
|
|
|
private TbMsgToEmailNodeConfiguration config; |
|
|
|
|
|
|
|
private TbContext ctxMock; |
|
|
|
|
|
|
|
@BeforeEach |
|
|
|
void setUp() throws TbNodeException { |
|
|
|
ctxMock = mock(TbContext.class); |
|
|
|
originator = new DeviceId(UUID.randomUUID()); |
|
|
|
config = new TbMsgToEmailNodeConfiguration().defaultConfiguration(); |
|
|
|
node = new TbMsgToEmailNode(); |
|
|
|
node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); |
|
|
|
} |
|
|
|
|
|
|
|
@Mock |
|
|
|
private TbContext ctx; |
|
|
|
@AfterEach |
|
|
|
void tearDown() { |
|
|
|
node.destroy(); |
|
|
|
} |
|
|
|
|
|
|
|
private EntityId originator = new DeviceId(Uuids.timeBased()); |
|
|
|
private TbMsgMetaData metaData = new TbMsgMetaData(); |
|
|
|
private String rawJson = "{\"name\": \"temp\", \"passed\": 5 , \"complex\": {\"val\":12, \"count\":100}}"; |
|
|
|
@Test |
|
|
|
void givenDefaultConfig_whenVerify_thenOK() { |
|
|
|
// GIVEN-WHEN-THEN
|
|
|
|
assertThat(config.getFromTemplate()).isEqualTo("info@testmail.org"); |
|
|
|
assertThat(config.getToTemplate()).isEqualTo("${userEmail}"); |
|
|
|
assertThat(config.getSubjectTemplate()).isEqualTo("Device ${deviceType} temperature high"); |
|
|
|
assertThat(config.getBodyTemplate()).isEqualTo("Device ${deviceName} has high temperature $[temperature]"); |
|
|
|
} |
|
|
|
|
|
|
|
private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); |
|
|
|
private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); |
|
|
|
static Stream<MailBodyTypeTestConfig> MailBodyTypeTestConfig() { |
|
|
|
return Stream.of( |
|
|
|
new MailBodyTypeTestConfig(false, "false", null), |
|
|
|
new MailBodyTypeTestConfig(false, null, null), |
|
|
|
new MailBodyTypeTestConfig(false, DYNAMIC_MAIL_BODY_TYPE, "false"), |
|
|
|
new MailBodyTypeTestConfig(true, DYNAMIC_MAIL_BODY_TYPE, "true"), |
|
|
|
new MailBodyTypeTestConfig(true, "true", null) |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
@Test |
|
|
|
public void msgCanBeConverted() { |
|
|
|
initWithScript(); |
|
|
|
metaData.putValue("username", "oreo"); |
|
|
|
metaData.putValue("userEmail", "user@email.io"); |
|
|
|
metaData.putValue("name", "temp"); |
|
|
|
metaData.putValue("passed", "5"); |
|
|
|
metaData.putValue("count", "100"); |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); |
|
|
|
|
|
|
|
emailNode.onMsg(ctx, msg); |
|
|
|
|
|
|
|
ArgumentCaptor<TbMsg> msgCaptor = ArgumentCaptor.forClass(TbMsg.class); |
|
|
|
ArgumentCaptor<TbMsgType> typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); |
|
|
|
ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); |
|
|
|
ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); |
|
|
|
ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); |
|
|
|
verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); |
|
|
|
|
|
|
|
|
|
|
|
assertEquals(TbMsgType.SEND_EMAIL, typeCaptor.getValue()); |
|
|
|
assertEquals(originator, originatorCaptor.getValue()); |
|
|
|
assertEquals("oreo", metadataCaptor.getValue().getValue("username")); |
|
|
|
assertNotSame(metaData, metadataCaptor.getValue()); |
|
|
|
|
|
|
|
TbEmail actual = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), TbEmail.class); |
|
|
|
|
|
|
|
TbEmail expected = TbEmail.builder() |
|
|
|
.from("test@mail.org") |
|
|
|
.to("user@email.io") |
|
|
|
.subject("Hi oreo there") |
|
|
|
.body("temp is to high. Current 5 and 100") |
|
|
|
@ParameterizedTest |
|
|
|
@MethodSource("MailBodyTypeTestConfig") |
|
|
|
public void givenMailBodyTypeTestConfig_whenOnMsg_thenVerify(MailBodyTypeTestConfig testConfig) throws TbNodeException { |
|
|
|
// GIVEN
|
|
|
|
String mailBodyType = testConfig.getMailBodyType(); |
|
|
|
config.setMailBodyType(mailBodyType); |
|
|
|
if (DYNAMIC_MAIL_BODY_TYPE.equals(mailBodyType)) { |
|
|
|
config.setIsHtmlTemplate("${html}"); |
|
|
|
} |
|
|
|
node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); |
|
|
|
|
|
|
|
var md = new TbMsgMetaData(); |
|
|
|
md.putValue("userEmail", EXPECTED_TO_EMAIL); |
|
|
|
md.putValue("deviceType", EXPECTED_DEVICE_TYPE); |
|
|
|
md.putValue("deviceName", EXPECTED_DEVICE_NAME); |
|
|
|
if (testConfig.getMdValue() != null) { |
|
|
|
md.putValue("html", testConfig.getMdValue()); |
|
|
|
} |
|
|
|
|
|
|
|
var msgDataStr = "{\"temperature\": " + EXPECTED_TEMPERATURE + "}"; |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, md, msgDataStr); |
|
|
|
|
|
|
|
// WHEN
|
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
|
|
|
|
// THEN
|
|
|
|
var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); |
|
|
|
var typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); |
|
|
|
var originatorCaptor = ArgumentCaptor.forClass(EntityId.class); |
|
|
|
var metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); |
|
|
|
var dataCaptor = ArgumentCaptor.forClass(String.class); |
|
|
|
verify(ctxMock, times(1)).transformMsg( |
|
|
|
msgCaptor.capture(), |
|
|
|
typeCaptor.capture(), |
|
|
|
originatorCaptor.capture(), |
|
|
|
metadataCaptor.capture(), |
|
|
|
dataCaptor.capture() |
|
|
|
); |
|
|
|
verify(ctxMock, never()).tellFailure(any(), any()); |
|
|
|
|
|
|
|
Assertions.assertEquals(TbMsgType.SEND_EMAIL, typeCaptor.getValue()); |
|
|
|
Assertions.assertEquals(originator, originatorCaptor.getValue()); |
|
|
|
Assertions.assertNotSame(md, metadataCaptor.getValue()); |
|
|
|
|
|
|
|
var actual = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), TbEmail.class); |
|
|
|
var expected = getExpectedTbEmail(testConfig.isExpectedHtmlValue()); |
|
|
|
|
|
|
|
Assertions.assertEquals(expected, actual); |
|
|
|
} |
|
|
|
|
|
|
|
private TbEmail getExpectedTbEmail(boolean html) { |
|
|
|
return TbEmail.builder() |
|
|
|
.from(config.getFromTemplate()) |
|
|
|
.to(EXPECTED_TO_EMAIL) |
|
|
|
.subject(EXPECTED_SUBJECT) |
|
|
|
.body(EXPECTED_BODY) |
|
|
|
.html(html) |
|
|
|
.build(); |
|
|
|
assertEquals(expected, actual); |
|
|
|
} |
|
|
|
|
|
|
|
private void initWithScript() { |
|
|
|
try { |
|
|
|
TbMsgToEmailNodeConfiguration config = new TbMsgToEmailNodeConfiguration(); |
|
|
|
config.setFromTemplate("test@mail.org"); |
|
|
|
config.setToTemplate("${userEmail}"); |
|
|
|
config.setSubjectTemplate("Hi ${username} there"); |
|
|
|
config.setBodyTemplate("${name} is to high. Current ${passed} and ${count}"); |
|
|
|
config.setMailBodyType("false"); |
|
|
|
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); |
|
|
|
|
|
|
|
emailNode = new TbMsgToEmailNode(); |
|
|
|
emailNode.init(ctx, nodeConfiguration); |
|
|
|
} catch (TbNodeException ex) { |
|
|
|
throw new IllegalStateException(ex); |
|
|
|
} |
|
|
|
@Data |
|
|
|
@RequiredArgsConstructor |
|
|
|
static class MailBodyTypeTestConfig { |
|
|
|
private final boolean expectedHtmlValue; |
|
|
|
private final String mailBodyType; |
|
|
|
private final String mdValue; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|