From 2bf8e9d5b499c89a8f62cf55e3d94ff1f2680ca6 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 21 Jun 2022 17:53:30 +0300 Subject: [PATCH] Add implementation and test for ota package contructor --- .../constructor/OtaPackageMsgConstructor.java | 71 +++++++-------- .../thingsboard/server/edge/BaseEdgeTest.java | 91 ++++++++++++++++++- common/edge-api/src/main/proto/edge.proto | 14 +-- 3 files changed, 126 insertions(+), 50 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java index 5da37aa46c..be38079d1e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java @@ -16,59 +16,54 @@ package org.thingsboard.server.service.edge.rpc.constructor; import com.google.protobuf.ByteString; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; -import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.queue.util.TbCoreComponent; -import java.nio.charset.StandardCharsets; - @Component @TbCoreComponent public class OtaPackageMsgConstructor { - @Autowired - private DataDecodingEncodingService dataDecodingEncodingService; - public OtaPackageUpdateMsg constructOtaPackageUpdatedMsg(UpdateMsgType msgType, OtaPackage otaPackage) { OtaPackageUpdateMsg.Builder builder = OtaPackageUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(otaPackage.getId().getId().getMostSignificantBits()) - .setIdLSB(otaPackage.getId().getId().getLeastSignificantBits()); -// .setName(deviceProfile.getName()) -// .setDefault(deviceProfile.isDefault()) -// .setType(deviceProfile.getType().name()) -// .setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile.getProfileData()))); - // TODO: @voba - add possibility to setup edge rule chain as device profile default -// if (deviceProfile.getDefaultRuleChainId() != null) { -// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits()) -// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits()); -// } -// if (deviceProfile.getDefaultQueueName() != null) { -// builder.setDefaultQueueName(deviceProfile.getDefaultQueueName()); -// } -// if (deviceProfile.getDescription() != null) { -// builder.setDescription(deviceProfile.getDescription()); -// } -// if (deviceProfile.getTransportType() != null) { -// builder.setTransportType(deviceProfile.getTransportType().name()); -// } -// if (deviceProfile.getProvisionType() != null) { -// builder.setProvisionType(deviceProfile.getProvisionType().name()); -// } -// if (deviceProfile.getProvisionDeviceKey() != null) { -// builder.setProvisionDeviceKey(deviceProfile.getProvisionDeviceKey()); -// } -// if (deviceProfile.getImage() != null) { -// builder.setImage(ByteString.copyFrom(deviceProfile.getImage().getBytes(StandardCharsets.UTF_8))); -// } + .setIdLSB(otaPackage.getId().getId().getLeastSignificantBits()) + .setDeviceProfileIdMSB(otaPackage.getDeviceProfileId().getId().getMostSignificantBits()) + .setDeviceProfileIdLSB(otaPackage.getDeviceProfileId().getId().getLeastSignificantBits()) + .setType(otaPackage.getType().name()) + .setTitle(otaPackage.getTitle()) + .setVersion(otaPackage.getVersion()) + .setTag(otaPackage.getTag()); + + if (otaPackage.getUrl() != null) { + builder.setUrl(otaPackage.getUrl()); + } + if (otaPackage.getAdditionalInfo() != null) { + builder.setAdditionalInfo(JacksonUtil.toString(otaPackage.getAdditionalInfo())); + } + if (otaPackage.getFileName() != null) { + builder.setFileName(otaPackage.getFileName()); + } + if (otaPackage.getContentType() != null) { + builder.setContentType(otaPackage.getContentType()); + } + if (otaPackage.getChecksumAlgorithm() != null) { + builder.setChecksumAlgorithm(otaPackage.getChecksumAlgorithm().name()); + } + if (otaPackage.getChecksum() != null) { + builder.setChecksum(otaPackage.getChecksum()); + } + if (otaPackage.getDataSize() != null) { + builder.setDataSize(otaPackage.getDataSize()); + } + if (otaPackage.getData() != null) { + builder.setData(ByteString.copyFrom(otaPackage.getData().array())); + } return builder.build(); } diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 3f554ad0bc..2b56af82cb 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.gson.JsonObject; import com.google.protobuf.AbstractMessage; +import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.MessageLite; import org.apache.commons.lang3.RandomStringUtils; @@ -32,7 +33,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Customer; @@ -72,6 +76,8 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.EntityKeyValueType; @@ -126,6 +132,7 @@ import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg; import org.thingsboard.server.gen.transport.TransportProtos; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -213,7 +220,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { thermostatDeviceProfile = this.createDeviceProfile(THERMOSTAT_DEVICE_PROFILE_NAME, transportConfiguration); extendDeviceProfileData(thermostatDeviceProfile); - doPost("/api/deviceProfile", thermostatDeviceProfile, DeviceProfile.class); + thermostatDeviceProfile = doPost("/api/deviceProfile", thermostatDeviceProfile, DeviceProfile.class); Device savedDevice = saveDevice("Edge Device 1", THERMOSTAT_DEVICE_PROFILE_NAME); doPost("/api/edge/" + edge.getUuidId() @@ -1650,15 +1657,16 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { } @Test - public void testOtaPackages() throws Exception { + public void testOtaPackages_usesUrl() throws Exception { // 1 SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); firmwareInfo.setDeviceProfileId(thermostatDeviceProfile.getId()); firmwareInfo.setType(FIRMWARE); - firmwareInfo.setTitle("My firmware"); + firmwareInfo.setTitle("My firmware #1"); firmwareInfo.setVersion("v1.0"); + firmwareInfo.setTag("My firmware #1 v1.0"); firmwareInfo.setUsesUrl(true); - firmwareInfo.setUrl("http://thingsboard.io/v1"); + firmwareInfo.setUrl("http://localhost:8080/v1/package"); firmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); edgeImitator.expectMessageAmount(1); @@ -1669,10 +1677,75 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { Assert.assertTrue(latestMessage instanceof OtaPackageUpdateMsg); OtaPackageUpdateMsg otaPackageUpdateMsg = (OtaPackageUpdateMsg) latestMessage; Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, otaPackageUpdateMsg.getMsgType()); + Assert.assertEquals(savedFirmwareInfo.getUuidId().getMostSignificantBits(), otaPackageUpdateMsg.getIdMSB()); + Assert.assertEquals(savedFirmwareInfo.getUuidId().getLeastSignificantBits(), otaPackageUpdateMsg.getIdLSB()); + Assert.assertEquals(thermostatDeviceProfile.getUuidId().getMostSignificantBits(), otaPackageUpdateMsg.getDeviceProfileIdMSB()); + Assert.assertEquals(thermostatDeviceProfile.getUuidId().getLeastSignificantBits(), otaPackageUpdateMsg.getDeviceProfileIdLSB()); + Assert.assertEquals(FIRMWARE, OtaPackageType.valueOf(otaPackageUpdateMsg.getType())); + Assert.assertEquals("My firmware #1", otaPackageUpdateMsg.getTitle()); + Assert.assertEquals("v1.0", otaPackageUpdateMsg.getVersion()); + Assert.assertEquals("My firmware #1 v1.0", otaPackageUpdateMsg.getTag()); + Assert.assertEquals("http://localhost:8080/v1/package", otaPackageUpdateMsg.getUrl()); + Assert.assertFalse(otaPackageUpdateMsg.hasData()); + Assert.assertFalse(otaPackageUpdateMsg.hasFileName()); + Assert.assertFalse(otaPackageUpdateMsg.hasContentType()); + Assert.assertFalse(otaPackageUpdateMsg.hasChecksumAlgorithm()); + Assert.assertFalse(otaPackageUpdateMsg.hasChecksum()); + Assert.assertFalse(otaPackageUpdateMsg.hasDataSize()); + + // 2 + edgeImitator.expectMessageAmount(1); + doDelete("/api/otaPackage/" + savedFirmwareInfo.getUuidId()) + .andExpect(status().isOk()); + Assert.assertTrue(edgeImitator.waitForMessages()); + latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof OtaPackageUpdateMsg); + otaPackageUpdateMsg = (OtaPackageUpdateMsg) latestMessage; + Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, otaPackageUpdateMsg.getMsgType()); Assert.assertEquals(otaPackageUpdateMsg.getIdMSB(), savedFirmwareInfo.getUuidId().getMostSignificantBits()); Assert.assertEquals(otaPackageUpdateMsg.getIdLSB(), savedFirmwareInfo.getUuidId().getLeastSignificantBits()); + } - // TODO - add check of content - constructor fix + @Test + public void testOtaPackages_hasData() throws Exception { + // 1 + SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); + firmwareInfo.setDeviceProfileId(thermostatDeviceProfile.getId()); + firmwareInfo.setType(FIRMWARE); + firmwareInfo.setTitle("My firmware #2"); + firmwareInfo.setVersion("v2.0"); + firmwareInfo.setTag("My firmware #2 v2.0"); + firmwareInfo.setUsesUrl(false); + firmwareInfo.setHasData(false); + firmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); + + edgeImitator.expectMessageAmount(1); + + OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class); + MockMultipartFile testData = new MockMultipartFile("file", "firmware.bin", "image/png", ByteBuffer.wrap(new byte[]{1, 3, 5}).array()); + savedFirmwareInfo = saveData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksumAlgorithm={checksumAlgorithm}", testData, ChecksumAlgorithm.SHA256.name()); + + Assert.assertTrue(edgeImitator.waitForMessages()); + + AbstractMessage latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof OtaPackageUpdateMsg); + OtaPackageUpdateMsg otaPackageUpdateMsg = (OtaPackageUpdateMsg) latestMessage; + Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, otaPackageUpdateMsg.getMsgType()); + Assert.assertEquals(savedFirmwareInfo.getUuidId().getMostSignificantBits(), otaPackageUpdateMsg.getIdMSB()); + Assert.assertEquals(savedFirmwareInfo.getUuidId().getLeastSignificantBits(), otaPackageUpdateMsg.getIdLSB()); + Assert.assertEquals(thermostatDeviceProfile.getUuidId().getMostSignificantBits(), otaPackageUpdateMsg.getDeviceProfileIdMSB()); + Assert.assertEquals(thermostatDeviceProfile.getUuidId().getLeastSignificantBits(), otaPackageUpdateMsg.getDeviceProfileIdLSB()); + Assert.assertEquals(FIRMWARE, OtaPackageType.valueOf(otaPackageUpdateMsg.getType())); + Assert.assertEquals("My firmware #2", otaPackageUpdateMsg.getTitle()); + Assert.assertEquals("v2.0", otaPackageUpdateMsg.getVersion()); + Assert.assertEquals("My firmware #2 v2.0", otaPackageUpdateMsg.getTag()); + Assert.assertFalse(otaPackageUpdateMsg.hasUrl()); + Assert.assertEquals("firmware.bin", otaPackageUpdateMsg.getFileName()); + Assert.assertEquals("image/png", otaPackageUpdateMsg.getContentType()); + Assert.assertEquals(ChecksumAlgorithm.SHA256.name(), otaPackageUpdateMsg.getChecksumAlgorithm()); + Assert.assertEquals("62467691cf583d4fa78b18fafaf9801f505e0ef03baf0603fd4b0cd004cd1e75", otaPackageUpdateMsg.getChecksum()); + Assert.assertEquals(3L, otaPackageUpdateMsg.getDataSize()); + Assert.assertEquals(ByteString.copyFrom(new byte[]{1, 3, 5}), otaPackageUpdateMsg.getData()); // 2 edgeImitator.expectMessageAmount(1); @@ -1767,4 +1840,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { Assert.assertEquals(source, target); Assert.assertEquals(source.hashCode(), target.hashCode()); } + + private OtaPackageInfo saveData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { + MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); + postRequest.file(content); + setJwtToken(postRequest); + return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackageInfo.class); + } + } diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index ce1e7bf4b1..218822bf84 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -432,13 +432,13 @@ message OtaPackageUpdateMsg { string version = 8; string tag = 9; optional string url = 10; - bool hasData = 11; - optional string fileName = 12; - optional string contentType = 13; - optional string checksumAlgorithm = 14; - optional string checksum = 15; - optional int64 dataSize = 16; - optional bytes data = 17; + optional string fileName = 11; + optional string contentType = 12; + optional string checksumAlgorithm = 13; + optional string checksum = 14; + optional int64 dataSize = 15; + optional bytes data = 16; + optional string additionalInfo = 17; } /**