Commit 113a6389fa3cccab6418388d3f948b228fa1378e

Authored by Igor Kulikov
2 parents d110f5a0 f005f82f

Merge with master

Showing 75 changed files with 1916 additions and 915 deletions
... ... @@ -66,6 +66,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A
66 66 import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
67 67 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
68 68 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
  69 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
69 70
70 71 @RestController
71 72 @TbCoreComponent
... ... @@ -120,7 +121,7 @@ public class AlarmController extends BaseController {
120 121
121 122 @ApiOperation(value = "Create or update Alarm (saveAlarm)",
122 123 notes = "Creates or Updates the Alarm. " +
123   - "When creating alarm, platform generates Alarm Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  124 + "When creating alarm, platform generates Alarm Id as " + UUID_WIKI_LINK +
124 125 "The newly created Alarm id will be present in the response. Specify existing Alarm id to update the alarm. " +
125 126 "Referencing non-existing Alarm Id will cause 'Not Found' error. " +
126 127 "\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " +
... ...
... ... @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
84 84 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
85 85 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
86 86 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
  87 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
87 88 import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
88 89 import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
89 90
... ... @@ -136,7 +137,7 @@ public class AssetController extends BaseController {
136 137 }
137 138
138 139 @ApiOperation(value = "Create Or Update Asset (saveAsset)",
139   - notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " +
  140 + notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as " + UUID_WIKI_LINK +
140 141 "The newly created Asset id will be present in the response. " +
141 142 "Specify existing Asset id to update the asset. " +
142 143 "Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
... ... @@ -542,7 +543,7 @@ public class AssetController extends BaseController {
542 543 notes = "Creates assignment of an existing asset to an instance of The Edge. " +
543 544 EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
544 545 "Second, remote edge service will receive a copy of assignment asset " +
545   - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  546 + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
546 547 "Third, once asset will be delivered to edge service, it's going to be available for usage on remote edge instance.",
547 548 produces = MediaType.APPLICATION_JSON_VALUE)
548 549 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ... @@ -582,7 +583,7 @@ public class AssetController extends BaseController {
582 583 notes = "Clears assignment of the asset to the edge. " +
583 584 EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
584 585 "Second, remote edge service will receive an 'unassign' command to remove asset " +
585   - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  586 + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
586 587 "Third, once 'unassign' command will be delivered to edge service, it's going to remove asset locally.",
587 588 produces = MediaType.APPLICATION_JSON_VALUE)
588 589 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ...
... ... @@ -18,11 +18,13 @@ package org.thingsboard.server.controller;
18 18 public class ControllerConstants {
19 19
20 20 protected static final String NEW_LINE = "\n\n";
  21 + protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address%29) ";
21 22 protected static final int DEFAULT_PAGE_SIZE = 1000;
22 23 protected static final String ENTITY_TYPE = "entityType";
23 24 protected static final String CUSTOMER_ID = "customerId";
24 25 protected static final String TENANT_ID = "tenantId";
25 26 protected static final String DEVICE_ID = "deviceId";
  27 + protected static final String EDGE_ID = "edgeId";
26 28 protected static final String RPC_ID = "rpcId";
27 29 protected static final String ENTITY_ID = "entityId";
28 30 protected static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " +
... ... @@ -129,9 +131,9 @@ public class ControllerConstants {
129 131 protected static final String EVENT_END_TIME_DESCRIPTION = "Timestamp. Events with creation time after it won't be queried.";
130 132
131 133 protected static final String EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Unassignment works in async way - first, 'unassign' notification event pushed to edge queue on platform. ";
132   - protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)";
  134 + protected static final String EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform). ";
133 135 protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. ";
134   - protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform)";
  136 + protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform). ";
135 137
136 138 protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n";
137 139 protected static final String MARKDOWN_CODE_BLOCK_END = "\n```";
... ...
... ... @@ -51,7 +51,6 @@ import org.thingsboard.server.common.data.id.EdgeId;
51 51 import org.thingsboard.server.common.data.id.TenantId;
52 52 import org.thingsboard.server.common.data.page.PageData;
53 53 import org.thingsboard.server.common.data.page.PageLink;
54   -import org.thingsboard.server.common.data.page.TimePageLink;
55 54 import org.thingsboard.server.queue.util.TbCoreComponent;
56 55 import org.thingsboard.server.service.security.model.SecurityUser;
57 56 import org.thingsboard.server.service.security.permission.Operation;
... ... @@ -69,6 +68,8 @@ import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_SO
69 68 import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_TEXT_SEARCH_DESCRIPTION;
70 69 import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION;
71 70 import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION;
  71 +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID;
  72 +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION;
72 73 import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION;
73 74 import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION;
74 75 import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
... ... @@ -829,7 +830,7 @@ public class DashboardController extends BaseController {
829 830 notes = "Creates assignment of an existing dashboard to an instance of The Edge. " +
830 831 EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
831 832 "Second, remote edge service will receive a copy of assignment dashboard " +
832   - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  833 + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
833 834 "Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance." +
834 835 TENANT_AUTHORITY_PARAGRAPH,
835 836 produces = MediaType.APPLICATION_JSON_VALUE)
... ... @@ -870,7 +871,7 @@ public class DashboardController extends BaseController {
870 871 notes = "Clears assignment of the dashboard to the edge. " +
871 872 EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
872 873 "Second, remote edge service will receive an 'unassign' command to remove dashboard " +
873   - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  874 + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
874 875 "Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally." +
875 876 TENANT_AUTHORITY_PARAGRAPH,
876 877 produces = MediaType.APPLICATION_JSON_VALUE)
... ... @@ -906,24 +907,32 @@ public class DashboardController extends BaseController {
906 907 }
907 908 }
908 909
  910 + @ApiOperation(value = "Get Edge Dashboards (getEdgeDashboards)",
  911 + notes = "Returns a page of dashboard info objects assigned to the specified edge. "
  912 + + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
  913 + produces = MediaType.APPLICATION_JSON_VALUE)
909 914 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
910 915 @RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
911 916 @ResponseBody
912 917 public PageData<DashboardInfo> getEdgeDashboards(
913   - @PathVariable("edgeId") String strEdgeId,
  918 + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
  919 + @PathVariable(EDGE_ID) String strEdgeId,
  920 + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
914 921 @RequestParam int pageSize,
  922 + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
915 923 @RequestParam int page,
  924 + @ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
916 925 @RequestParam(required = false) String textSearch,
  926 + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES)
917 927 @RequestParam(required = false) String sortProperty,
918   - @RequestParam(required = false) String sortOrder,
919   - @RequestParam(required = false) Long startTime,
920   - @RequestParam(required = false) Long endTime) throws ThingsboardException {
  928 + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
  929 + @RequestParam(required = false) String sortOrder) throws ThingsboardException {
921 930 checkParameter("edgeId", strEdgeId);
922 931 try {
923 932 TenantId tenantId = getCurrentUser().getTenantId();
924 933 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
925 934 checkEdgeId(edgeId, Operation.READ);
926   - TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
  935 + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
927 936 PageData<DashboardInfo> nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
928 937 List<DashboardInfo> filteredDashboards = nonFilteredResult.getData().stream().filter(dashboardInfo -> {
929 938 try {
... ...
... ... @@ -112,6 +112,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT
112 112 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
113 113 import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION;
114 114 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
  115 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
115 116 import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
116 117
117 118 @RestController
... ... @@ -166,7 +167,7 @@ public class DeviceController extends BaseController {
166 167 }
167 168
168 169 @ApiOperation(value = "Create Or Update Device (saveDevice)",
169   - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  170 + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK +
170 171 "Device credentials are also generated if not provided in the 'accessToken' request parameter. " +
171 172 "The newly created device id will be present in the response. " +
172 173 "Specify existing Device id to update the device. " +
... ... @@ -203,7 +204,7 @@ public class DeviceController extends BaseController {
203 204 }
204 205
205 206 @ApiOperation(value = "Create Device (saveDevice) with credentials ",
206   - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  207 + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK +
207 208 "Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " +
208 209 "You may find the example of LwM2M device and RPK credentials below: \n\n" +
209 210 DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN +
... ... @@ -849,7 +850,7 @@ public class DeviceController extends BaseController {
849 850 notes = "Creates assignment of an existing device to an instance of The Edge. " +
850 851 EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
851 852 "Second, remote edge service will receive a copy of assignment device " +
852   - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  853 + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
853 854 "Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH,
854 855 produces = MediaType.APPLICATION_JSON_VALUE)
855 856 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ... @@ -892,7 +893,7 @@ public class DeviceController extends BaseController {
892 893 notes = "Clears assignment of the device to the edge. " +
893 894 EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
894 895 "Second, remote edge service will receive an 'unassign' command to remove device " +
895   - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  896 + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
896 897 "Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally." + TENANT_AUTHORITY_PARAGRAPH,
897 898 produces = MediaType.APPLICATION_JSON_VALUE)
898 899 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ...
... ... @@ -65,6 +65,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT
65 65 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
66 66 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
67 67 import static org.thingsboard.server.controller.ControllerConstants.TRANSPORT_TYPE_ALLOWABLE_VALUES;
  68 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
68 69
69 70 @RestController
70 71 @TbCoreComponent
... ... @@ -186,7 +187,7 @@ public class DeviceProfileController extends BaseController {
186 187 }
187 188
188 189 @ApiOperation(value = "Create Or Update Device Profile (saveDeviceProfile)",
189   - notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  190 + notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as " + UUID_WIKI_LINK +
190 191 "The newly created device profile id will be present in the response. " +
191 192 "Specify existing device profile id to update the device profile. " +
192 193 "Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE +
... ...
... ... @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
84 84 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
85 85 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
86 86 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
  87 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
87 88
88 89 @RestController
89 90 @TbCoreComponent
... ... @@ -149,7 +150,7 @@ public class EdgeController extends BaseController {
149 150 }
150 151
151 152 @ApiOperation(value = "Create Or Update Edge (saveEdge)",
152   - notes = "Create or update the Edge. When creating edge, platform generates Edge Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  153 + notes = "Create or update the Edge. When creating edge, platform generates Edge Id as " + UUID_WIKI_LINK +
153 154 "The newly created edge id will be present in the response. " +
154 155 "Specify existing Edge id to update the edge. " +
155 156 "Referencing non-existing Edge Id will cause 'Not Found' error." +
... ... @@ -452,17 +453,17 @@ public class EdgeController extends BaseController {
452 453 }
453 454 }
454 455
455   - @ApiOperation(value = "Set root rule chain for provided edge (setRootRuleChain)",
  456 + @ApiOperation(value = "Set root rule chain for provided edge (setEdgeRootRuleChain)",
456 457 notes = "Change root rule chain of the edge to the new provided rule chain. \n" +
457 458 "This operation will send a notification to update root rule chain on remote edge service." + TENANT_AUTHORITY_PARAGRAPH,
458 459 produces = MediaType.APPLICATION_JSON_VALUE)
459 460 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
460 461 @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST)
461 462 @ResponseBody
462   - public Edge setRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
463   - @PathVariable(EDGE_ID) String strEdgeId,
464   - @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true)
465   - @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException {
  463 + public Edge setEdgeRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
  464 + @PathVariable(EDGE_ID) String strEdgeId,
  465 + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true)
  466 + @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException {
466 467 checkParameter(EDGE_ID, strEdgeId);
467 468 checkParameter("ruleChainId", strRuleChainId);
468 469 try {
... ... @@ -736,6 +737,9 @@ public class EdgeController extends BaseController {
736 737 edge.setEdgeLicenseKey(null);
737 738 }
738 739
  740 + @ApiOperation(value = "Check edge license (checkInstance)",
  741 + notes = "Checks license request from edge service by forwarding request to license portal.",
  742 + produces = MediaType.APPLICATION_JSON_VALUE)
739 743 @RequestMapping(value = "/license/checkInstance", method = RequestMethod.POST)
740 744 @ResponseBody
741 745 public ResponseEntity<JsonNode> checkInstance(@RequestBody JsonNode request) throws ThingsboardException {
... ... @@ -748,6 +752,9 @@ public class EdgeController extends BaseController {
748 752 }
749 753 }
750 754
  755 + @ApiOperation(value = "Activate edge instance (activateInstance)",
  756 + notes = "Activates edge license on license portal.",
  757 + produces = MediaType.APPLICATION_JSON_VALUE)
751 758 @RequestMapping(value = "/license/activateInstance", params = {"licenseSecret", "releaseDate"}, method = RequestMethod.POST)
752 759 @ResponseBody
753 760 public ResponseEntity<JsonNode> activateInstance(@RequestParam String licenseSecret,
... ...
... ... @@ -728,7 +728,7 @@ public class EntityViewController extends BaseController {
728 728 notes = "Creates assignment of an existing entity view to an instance of The Edge. " +
729 729 EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
730 730 "Second, remote edge service will receive a copy of assignment entity view " +
731   - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  731 + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
732 732 "Third, once entity view will be delivered to edge service, it's going to be available for usage on remote edge instance.",
733 733 produces = MediaType.APPLICATION_JSON_VALUE)
734 734 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ... @@ -765,7 +765,7 @@ public class EntityViewController extends BaseController {
765 765 notes = "Clears assignment of the entity view to the edge. " +
766 766 EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
767 767 "Second, remote edge service will receive an 'unassign' command to remove entity view " +
768   - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  768 + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
769 769 "Third, once 'unassign' command will be delivered to edge service, it's going to remove entity view locally.",
770 770 produces = MediaType.APPLICATION_JSON_VALUE)
771 771 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ...
... ... @@ -64,6 +64,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
64 64 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
65 65 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
66 66 import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
  67 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
67 68
68 69 @Slf4j
69 70 @RestController
... ... @@ -138,7 +139,7 @@ public class OtaPackageController extends BaseController {
138 139 }
139 140
140 141 @ApiOperation(value = "Create Or Update OTA Package Info (saveOtaPackageInfo)",
141   - notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  142 + notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as " + UUID_WIKI_LINK +
142 143 "The newly created OTA Package id will be present in the response. " +
143 144 "Specify existing OTA Package id to update the OTA Package Info. " +
144 145 "Referencing non-existing OTA Package Id will cause 'Not Found' error. " +
... ...
... ... @@ -83,6 +83,8 @@ import java.util.stream.Collectors;
83 83
84 84 import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION;
85 85 import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION;
  86 +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID;
  87 +import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION;
86 88 import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION;
87 89 import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION;
88 90 import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
... ... @@ -100,6 +102,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A
100 102 import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
101 103 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
102 104 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
  105 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
103 106
104 107 @Slf4j
105 108 @RestController
... ... @@ -185,7 +188,7 @@ public class RuleChainController extends BaseController {
185 188 }
186 189
187 190 @ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)",
188   - notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  191 + notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as " + UUID_WIKI_LINK +
189 192 "The newly created Rule Chain Id will be present in the response. " +
190 193 "Specify existing Rule Chain id to update the rule chain. " +
191 194 "Referencing non-existing rule chain Id will cause 'Not Found' error." +
... ... @@ -601,7 +604,7 @@ public class RuleChainController extends BaseController {
601 604 notes = "Creates assignment of an existing rule chain to an instance of The Edge. " +
602 605 EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
603 606 "Second, remote edge service will receive a copy of assignment rule chain " +
604   - EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  607 + EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
605 608 "Third, once rule chain will be delivered to edge service, it's going to start processing messages locally. " +
606 609 "\n\nOnly rule chain with type 'EDGE' can be assigned to edge." + TENANT_AUTHORITY_PARAGRAPH,
607 610 produces = MediaType.APPLICATION_JSON_VALUE)
... ... @@ -642,7 +645,7 @@ public class RuleChainController extends BaseController {
642 645 notes = "Clears assignment of the rule chain to the edge. " +
643 646 EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
644 647 "Second, remote edge service will receive an 'unassign' command to remove rule chain " +
645   - EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION + ". " +
  648 + EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
646 649 "Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally." + TENANT_AUTHORITY_PARAGRAPH,
647 650 produces = MediaType.APPLICATION_JSON_VALUE)
648 651 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ... @@ -677,17 +680,25 @@ public class RuleChainController extends BaseController {
677 680 }
678 681 }
679 682
  683 + @ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)",
  684 + notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
680 685 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
681 686 @RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET)
682 687 @ResponseBody
683 688 public PageData<RuleChain> getEdgeRuleChains(
684   - @PathVariable("edgeId") String strEdgeId,
  689 + @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
  690 + @PathVariable(EDGE_ID) String strEdgeId,
  691 + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
685 692 @RequestParam int pageSize,
  693 + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
686 694 @RequestParam int page,
  695 + @ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
687 696 @RequestParam(required = false) String textSearch,
  697 + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES)
688 698 @RequestParam(required = false) String sortProperty,
  699 + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
689 700 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
690   - checkParameter("edgeId", strEdgeId);
  701 + checkParameter(EDGE_ID, strEdgeId);
691 702 try {
692 703 TenantId tenantId = getCurrentUser().getTenantId();
693 704 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
... ... @@ -699,10 +710,14 @@ public class RuleChainController extends BaseController {
699 710 }
700 711 }
701 712
  713 + @ApiOperation(value = "Set Edge Template Root Rule Chain (setEdgeTemplateRootRuleChain)",
  714 + notes = "Makes the rule chain to be root rule chain for any new edge that will be created. " +
  715 + "Does not update root rule chain for already created edges. " + TENANT_AUTHORITY_PARAGRAPH)
702 716 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
703 717 @RequestMapping(value = "/ruleChain/{ruleChainId}/edgeTemplateRoot", method = RequestMethod.POST)
704 718 @ResponseBody
705   - public RuleChain setEdgeTemplateRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
  719 + public RuleChain setEdgeTemplateRootRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
  720 + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
706 721 checkParameter(RULE_CHAIN_ID, strRuleChainId);
707 722 try {
708 723 RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
... ... @@ -718,10 +733,14 @@ public class RuleChainController extends BaseController {
718 733 }
719 734 }
720 735
  736 + @ApiOperation(value = "Set Auto Assign To Edge Rule Chain (setAutoAssignToEdgeRuleChain)",
  737 + notes = "Makes the rule chain to be automatically assigned for any new edge that will be created. " +
  738 + "Does not assign this rule chain for already created edges. " + TENANT_AUTHORITY_PARAGRAPH)
721 739 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
722 740 @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.POST)
723 741 @ResponseBody
724   - public RuleChain setAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
  742 + public RuleChain setAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
  743 + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
725 744 checkParameter(RULE_CHAIN_ID, strRuleChainId);
726 745 try {
727 746 RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
... ... @@ -737,10 +756,14 @@ public class RuleChainController extends BaseController {
737 756 }
738 757 }
739 758
  759 + @ApiOperation(value = "Unset Auto Assign To Edge Rule Chain (unsetAutoAssignToEdgeRuleChain)",
  760 + notes = "Removes the rule chain from the list of rule chains that are going to be automatically assigned for any new edge that will be created. " +
  761 + "Does not unassign this rule chain for already assigned edges. " + TENANT_AUTHORITY_PARAGRAPH)
740 762 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
741 763 @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.DELETE)
742 764 @ResponseBody
743   - public RuleChain unsetAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
  765 + public RuleChain unsetAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
  766 + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
744 767 checkParameter(RULE_CHAIN_ID, strRuleChainId);
745 768 try {
746 769 RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
... ... @@ -757,6 +780,8 @@ public class RuleChainController extends BaseController {
757 780 }
758 781
759 782 // TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign
  783 + @ApiOperation(value = "Get Auto Assign To Edge Rule Chains (getAutoAssignToEdgeRuleChains)",
  784 + notes = "Returns a list of Rule Chains that will be assigned to a newly created edge. " + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
760 785 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
761 786 @RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET)
762 787 @ResponseBody
... ...
... ... @@ -62,6 +62,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
62 62 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
63 63 import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
64 64 import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
  65 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
65 66
66 67 @Slf4j
67 68 @RestController
... ... @@ -131,7 +132,7 @@ public class TbResourceController extends BaseController {
131 132 }
132 133
133 134 @ApiOperation(value = "Create Or Update Resource (saveResource)",
134   - notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  135 + notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as " + UUID_WIKI_LINK +
135 136 "The newly created Resource id will be present in the response. " +
136 137 "Specify existing Resource id to update the Resource. " +
137 138 "Referencing non-existing Resource Id will cause 'Not Found' error. " +
... ...
... ... @@ -57,6 +57,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PA
57 57 import static org.thingsboard.server.controller.ControllerConstants.TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES;
58 58 import static org.thingsboard.server.controller.ControllerConstants.TENANT_SORT_PROPERTY_ALLOWABLE_VALUES;
59 59 import static org.thingsboard.server.controller.ControllerConstants.TENANT_TEXT_SEARCH_DESCRIPTION;
  60 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
60 61
61 62 @RestController
62 63 @TbCoreComponent
... ... @@ -111,7 +112,7 @@ public class TenantController extends BaseController {
111 112 }
112 113
113 114 @ApiOperation(value = "Create Or update Tenant (saveTenant)",
114   - notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  115 + notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as " + UUID_WIKI_LINK +
115 116 "Default Rule Chain and Device profile are also generated for the new tenants automatically. " +
116 117 "The newly created Tenant Id will be present in the response. " +
117 118 "Specify existing Tenant Id id to update the Tenant. " +
... ...
... ... @@ -53,6 +53,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFI
53 53 import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES;
54 54 import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES;
55 55 import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION;
  56 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
56 57
57 58 @RestController
58 59 @TbCoreComponent
... ... @@ -110,7 +111,7 @@ public class TenantProfileController extends BaseController {
110 111 }
111 112
112 113 @ApiOperation(value = "Create Or update Tenant Profile (saveTenantProfile)",
113   - notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  114 + notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as " + UUID_WIKI_LINK +
114 115 "The newly created Tenant Profile Id will be present in the response. " +
115 116 "Specify existing Tenant Profile Id id to update the Tenant Profile. " +
116 117 "Referencing non-existing Tenant Profile Id will cause 'Not Found' error. " +
... ...
... ... @@ -81,6 +81,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU
81 81 import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION;
82 82 import static org.thingsboard.server.controller.ControllerConstants.USER_SORT_PROPERTY_ALLOWABLE_VALUES;
83 83 import static org.thingsboard.server.controller.ControllerConstants.USER_TEXT_SEARCH_DESCRIPTION;
  84 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
84 85
85 86 @RequiredArgsConstructor
86 87 @RestController
... ... @@ -174,7 +175,7 @@ public class UserController extends BaseController {
174 175 }
175 176
176 177 @ApiOperation(value = "Save Or update User (saveUser)",
177   - notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  178 + notes = "Create or update the User. When creating user, platform generates User Id as " + UUID_WIKI_LINK +
178 179 "The newly created User Id will be present in the response. " +
179 180 "Specify existing User Id to update the device. " +
180 181 "Referencing non-existing User Id will cause 'Not Found' error." +
... ...
... ... @@ -45,6 +45,7 @@ import java.util.List;
45 45
46 46 import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER;
47 47 import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
  48 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
48 49 import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_ID_PARAM_DESCRIPTION;
49 50
50 51 @Slf4j
... ... @@ -78,7 +79,7 @@ public class WidgetTypeController extends BaseController {
78 79
79 80 @ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)",
80 81 notes = "Create or update the Widget Type. " + WIDGET_TYPE_DESCRIPTION + " " +
81   - "When creating the Widget Type, platform generates Widget Type Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  82 + "When creating the Widget Type, platform generates Widget Type Id as " + UUID_WIKI_LINK +
82 83 "The newly created Widget Type Id will be present in the response. " +
83 84 "Specify existing Widget Type id to update the Widget Type. " +
84 85 "Referencing non-existing Widget Type Id will cause 'Not Found' error." +
... ...
... ... @@ -49,6 +49,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A
49 49 import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
50 50 import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
51 51 import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
  52 +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
52 53 import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_ID_PARAM_DESCRIPTION;
53 54 import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES;
54 55 import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION;
... ... @@ -79,7 +80,7 @@ public class WidgetsBundleController extends BaseController {
79 80
80 81 @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)",
81 82 notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " +
82   - "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)). " +
  83 + "When creating the bundle, platform generates Widget Bundle Id as " + UUID_WIKI_LINK +
83 84 "The newly created Widget Bundle Id will be present in the response. " +
84 85 "Specify existing Widget Bundle id to update the Widget Bundle. " +
85 86 "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." +
... ...
... ... @@ -61,8 +61,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
61 61
62 62 protected DeviceProfile deviceProfile;
63 63
64   - protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
65   - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  64 + protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
  65 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
  66 + }
  67 +
  68 + protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic, boolean enableCompatibilityWithJsonPayloadFormat, boolean useJsonPayloadFormatForDefaultDownlinkTopics) throws Exception {
  69 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, enableCompatibilityWithJsonPayloadFormat, useJsonPayloadFormatForDefaultDownlinkTopics);
66 70 }
67 71
68 72 protected void processBeforeTest(String deviceName,
... ... @@ -76,8 +80,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
76 80 String rpcRequestProtoSchema,
77 81 String provisionKey,
78 82 String provisionSecret,
79   - DeviceProfileProvisionType provisionType
80   - ) throws Exception {
  83 + DeviceProfileProvisionType provisionType,
  84 + boolean enableCompatibilityWithJsonPayloadFormat,
  85 + boolean useJsonPayloadFormatForDefaultDownlinkTopics) throws Exception {
81 86 loginSysAdmin();
82 87
83 88 Tenant tenant = new Tenant();
... ... @@ -106,7 +111,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
106 111 gateway.setAdditionalInfo(additionalInfo);
107 112
108 113 if (payloadType != null) {
109   - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema, provisionKey, provisionSecret, provisionType);
  114 + DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema, provisionKey, provisionSecret, provisionType, enableCompatibilityWithJsonPayloadFormat, useJsonPayloadFormatForDefaultDownlinkTopics);
110 115 deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);
111 116 device.setType(deviceProfile.getName());
112 117 device.setDeviceProfileId(deviceProfile.getId());
... ... @@ -162,7 +167,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
162 167 String telemetryProtoSchema, String attributesProtoSchema,
163 168 String rpcResponseProtoSchema, String rpcRequestProtoSchema,
164 169 String provisionKey, String provisionSecret,
165   - DeviceProfileProvisionType provisionType) {
  170 + DeviceProfileProvisionType provisionType,
  171 + boolean enableCompatibilityWithJsonPayloadFormat,
  172 + boolean useJsonPayloadFormatForDefaultDownlinkTopics) {
166 173 DeviceProfile deviceProfile = new DeviceProfile();
167 174 deviceProfile.setName(transportPayloadType.name());
168 175 deviceProfile.setType(DeviceProfileType.DEFAULT);
... ... @@ -200,6 +207,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
200 207 protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
201 208 protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(rpcResponseProtoSchema);
202 209 protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(rpcRequestProtoSchema);
  210 + protoTransportPayloadConfiguration.setEnableCompatibilityWithJsonPayloadFormat(enableCompatibilityWithJsonPayloadFormat);
  211 + protoTransportPayloadConfiguration.setUseJsonPayloadFormatForDefaultDownlinkTopics(enableCompatibilityWithJsonPayloadFormat && useJsonPayloadFormatForDefaultDownlinkTopics);
203 212 transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
204 213 }
205 214 mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
... ...
... ... @@ -15,24 +15,72 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.attributes;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  23 +import io.netty.handler.codec.mqtt.MqttQoS;
18 24 import lombok.extern.slf4j.Slf4j;
19 25 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
  26 +import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 27 import org.eclipse.paho.client.mqttv3.MqttCallback;
  28 +import org.eclipse.paho.client.mqttv3.MqttException;
21 29 import org.eclipse.paho.client.mqttv3.MqttMessage;
  30 +import org.thingsboard.common.util.JacksonUtil;
  31 +import org.thingsboard.server.common.data.Device;
22 32 import org.thingsboard.server.common.data.TransportPayloadType;
  33 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  36 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  38 +import org.thingsboard.server.gen.transport.TransportApiProtos;
23 39 import org.thingsboard.server.gen.transport.TransportProtos;
24 40 import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
25 41
  42 +import java.nio.charset.StandardCharsets;
26 43 import java.util.ArrayList;
  44 +import java.util.Arrays;
27 45 import java.util.List;
28 46 import java.util.concurrent.CountDownLatch;
  47 +import java.util.concurrent.TimeUnit;
  48 +import java.util.stream.Collectors;
  49 +
  50 +import static org.junit.Assert.assertEquals;
  51 +import static org.junit.Assert.assertNotNull;
  52 +import static org.junit.Assert.assertTrue;
  53 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
29 54
30 55 @Slf4j
31 56 public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqttIntegrationTest {
32 57
  58 + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
  59 + "\n" +
  60 + "package test;\n" +
  61 + "\n" +
  62 + "message PostAttributes {\n" +
  63 + " string attribute1 = 1;\n" +
  64 + " bool attribute2 = 2;\n" +
  65 + " double attribute3 = 3;\n" +
  66 + " int32 attribute4 = 4;\n" +
  67 + " JsonObject attribute5 = 5;\n" +
  68 + "\n" +
  69 + " message JsonObject {\n" +
  70 + " int32 someNumber = 6;\n" +
  71 + " repeated int32 someArray = 7;\n" +
  72 + " NestedJsonObject someNestedObject = 8;\n" +
  73 + " message NestedJsonObject {\n" +
  74 + " string key = 9;\n" +
  75 + " }\n" +
  76 + " }\n" +
  77 + "}";
  78 +
33 79 protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," +
34 80 "\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}";
35 81
  82 + private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}";
  83 +
36 84 protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
37 85 super.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic);
38 86 }
... ... @@ -107,4 +155,544 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt
107 155 }
108 156 }
109 157
  158 + // subscribe to attributes updates from server methods
  159 +
  160 + protected void processJsonTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception {
  161 +
  162 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  163 +
  164 + TestMqttCallback onUpdateCallback = getTestMqttCallback();
  165 + client.setCallback(onUpdateCallback);
  166 +
  167 + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value());
  168 +
  169 + Thread.sleep(1000);
  170 +
  171 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  172 + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
  173 +
  174 + validateUpdateAttributesJsonResponse(onUpdateCallback);
  175 +
  176 + TestMqttCallback onDeleteCallback = getTestMqttCallback();
  177 + client.setCallback(onDeleteCallback);
  178 +
  179 + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
  180 + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
  181 +
  182 + validateDeleteAttributesJsonResponse(onDeleteCallback);
  183 + }
  184 +
  185 + protected void processProtoTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception {
  186 +
  187 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  188 +
  189 + TestMqttCallback onUpdateCallback = getTestMqttCallback();
  190 + client.setCallback(onUpdateCallback);
  191 +
  192 + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value());
  193 +
  194 + Thread.sleep(1000);
  195 +
  196 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  197 + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
  198 +
  199 + validateUpdateAttributesProtoResponse(onUpdateCallback);
  200 +
  201 + TestMqttCallback onDeleteCallback = getTestMqttCallback();
  202 + client.setCallback(onDeleteCallback);
  203 +
  204 + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
  205 + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
  206 +
  207 + validateDeleteAttributesProtoResponse(onDeleteCallback);
  208 + }
  209 +
  210 + protected void validateUpdateAttributesJsonResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  211 + assertNotNull(callback.getPayloadBytes());
  212 + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  213 + assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response));
  214 + }
  215 +
  216 + protected void validateDeleteAttributesJsonResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  217 + assertNotNull(callback.getPayloadBytes());
  218 + String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  219 + assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response));
  220 + }
  221 +
  222 + protected void validateUpdateAttributesProtoResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  223 + assertNotNull(callback.getPayloadBytes());
  224 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  225 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  226 + attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
  227 +
  228 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  229 + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  230 +
  231 + List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  232 + List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  233 +
  234 + assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
  235 + assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
  236 + }
  237 +
  238 + protected void validateDeleteAttributesProtoResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  239 + assertNotNull(callback.getPayloadBytes());
  240 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  241 + attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
  242 +
  243 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  244 + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  245 +
  246 + assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
  247 + assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
  248 + }
  249 +
  250 + protected void processJsonGatewayTestSubscribeToAttributesUpdates() throws Exception {
  251 +
  252 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  253 +
  254 + TestMqttCallback onUpdateCallback = getTestMqttCallback();
  255 + client.setCallback(onUpdateCallback);
  256 +
  257 + Device device = new Device();
  258 + device.setName("Gateway Device Subscribe to attribute updates");
  259 + device.setType("default");
  260 +
  261 + byte[] connectPayloadBytes = getJsonConnectPayloadBytes();
  262 +
  263 + publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC);
  264 +
  265 + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class),
  266 + 20,
  267 + 100);
  268 +
  269 + assertNotNull(savedDevice);
  270 +
  271 + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value());
  272 +
  273 + Thread.sleep(1000);
  274 +
  275 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  276 + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
  277 +
  278 + validateJsonGatewayUpdateAttributesResponse(onUpdateCallback);
  279 +
  280 + TestMqttCallback onDeleteCallback = getTestMqttCallback();
  281 + client.setCallback(onDeleteCallback);
  282 +
  283 + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
  284 + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
  285 +
  286 + validateJsonGatewayDeleteAttributesResponse(onDeleteCallback);
  287 +
  288 + }
  289 +
  290 + protected void processProtoGatewayTestSubscribeToAttributesUpdates() throws Exception {
  291 +
  292 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  293 +
  294 + TestMqttCallback onUpdateCallback = getTestMqttCallback();
  295 + client.setCallback(onUpdateCallback);
  296 +
  297 + Device device = new Device();
  298 + device.setName("Gateway Device Subscribe to attribute updates");
  299 + device.setType("default");
  300 +
  301 + byte[] connectPayloadBytes = getProtoConnectPayloadBytes();
  302 +
  303 + publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC);
  304 +
  305 + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class),
  306 + 20,
  307 + 100);
  308 +
  309 + assertNotNull(savedDevice);
  310 +
  311 + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value());
  312 +
  313 + Thread.sleep(1000);
  314 +
  315 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  316 + onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
  317 +
  318 + validateProtoGatewayUpdateAttributesResponse(onUpdateCallback);
  319 +
  320 + TestMqttCallback onDeleteCallback = getTestMqttCallback();
  321 + client.setCallback(onDeleteCallback);
  322 +
  323 + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
  324 + onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
  325 +
  326 + validateProtoGatewayDeleteAttributesResponse(onDeleteCallback);
  327 +
  328 + }
  329 +
  330 + protected void validateJsonGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  331 + assertNotNull(callback.getPayloadBytes());
  332 + String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  333 + assertEquals(getJsonResponseGatewayAttributesUpdatedPayload(), s);
  334 + }
  335 +
  336 + protected void validateJsonGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  337 + assertNotNull(callback.getPayloadBytes());
  338 + String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
  339 + assertEquals(s, getJsonResponseGatewayAttributesDeletedPayload());
  340 + }
  341 +
  342 + protected byte[] getJsonConnectPayloadBytes() {
  343 + String connectPayload = "{\"device\": \"Gateway Device Subscribe to attribute updates\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}";
  344 + return connectPayload.getBytes();
  345 + }
  346 +
  347 + private static String getJsonResponseGatewayAttributesUpdatedPayload() {
  348 + return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\"," +
  349 + "\"data\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  350 + }
  351 +
  352 + private static String getJsonResponseGatewayAttributesDeletedPayload() {
  353 + return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\",\"data\":{\"deleted\":[\"attribute5\"]}}";
  354 + }
  355 +
  356 + protected void validateProtoGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  357 + assertNotNull(callback.getPayloadBytes());
  358 +
  359 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  360 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  361 + attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
  362 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  363 +
  364 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder();
  365 + gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates");
  366 + gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(expectedAttributeUpdateNotificationMsg);
  367 +
  368 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build();
  369 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  370 +
  371 + assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName());
  372 +
  373 + List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  374 + List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  375 +
  376 + assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
  377 + assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
  378 +
  379 + }
  380 +
  381 + protected void validateProtoGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
  382 + assertNotNull(callback.getPayloadBytes());
  383 + TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
  384 + attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
  385 + TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
  386 +
  387 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder();
  388 + gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates");
  389 + gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(attributeUpdateNotificationMsg);
  390 +
  391 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build();
  392 + TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
  393 +
  394 + assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName());
  395 +
  396 + TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg();
  397 + TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg();
  398 +
  399 + assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
  400 + assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
  401 +
  402 + }
  403 +
  404 + protected byte[] getProtoConnectPayloadBytes() {
  405 + TransportApiProtos.ConnectMsg connectProto = getConnectProto();
  406 + return connectProto.toByteArray();
  407 + }
  408 +
  409 + private TransportApiProtos.ConnectMsg getConnectProto() {
  410 + TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder();
  411 + builder.setDeviceName("Gateway Device Subscribe to attribute updates");
  412 + builder.setDeviceType(TransportPayloadType.PROTOBUF.name());
  413 + return builder.build();
  414 + }
  415 +
  416 + // request attributes from server methods
  417 +
  418 + protected void processJsonTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception {
  419 +
  420 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  421 +
  422 + postJsonAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic);
  423 +
  424 + Thread.sleep(5000);
  425 +
  426 + TestMqttCallback callback = getTestMqttCallback();
  427 + client.setCallback(callback);
  428 +
  429 + validateJsonResponse(client, callback.getLatch(), callback, attrReqTopicPrefix);
  430 + }
  431 +
  432 + protected void processProtoTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception {
  433 +
  434 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  435 +
  436 + postProtoAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic);
  437 +
  438 + Thread.sleep(5000);
  439 +
  440 + TestMqttCallback callback = getTestMqttCallback();
  441 + client.setCallback(callback);
  442 +
  443 + validateProtoResponse(client, callback.getLatch(), callback, attrReqTopicPrefix);
  444 + }
  445 +
  446 + protected void processJsonTestGatewayRequestAttributesValuesFromTheServer() throws Exception {
  447 +
  448 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  449 +
  450 + postJsonGatewayDeviceClientAttributes(client);
  451 +
  452 + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class),
  453 + 20,
  454 + 100);
  455 +
  456 + assertNotNull(savedDevice);
  457 +
  458 + Thread.sleep(2000);
  459 +
  460 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  461 +
  462 + Thread.sleep(5000);
  463 +
  464 + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  465 +
  466 + TestMqttCallback clientAttributesCallback = getTestMqttCallback();
  467 + client.setCallback(clientAttributesCallback);
  468 + validateJsonClientResponseGateway(client, clientAttributesCallback);
  469 +
  470 + TestMqttCallback sharedAttributesCallback = getTestMqttCallback();
  471 + client.setCallback(sharedAttributesCallback);
  472 + validateJsonSharedResponseGateway(client, sharedAttributesCallback);
  473 + }
  474 +
  475 + protected void processProtoTestGatewayRequestAttributesValuesFromTheServer() throws Exception {
  476 +
  477 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  478 +
  479 + postProtoGatewayDeviceClientAttributes(client);
  480 +
  481 + Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class),
  482 + 20,
  483 + 100);
  484 +
  485 + assertNotNull(savedDevice);
  486 +
  487 + Thread.sleep(2000);
  488 +
  489 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  490 +
  491 + Thread.sleep(5000);
  492 +
  493 + client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  494 +
  495 + TestMqttCallback clientAttributesCallback = getTestMqttCallback();
  496 + client.setCallback(clientAttributesCallback);
  497 + validateProtoClientResponseGateway(client, clientAttributesCallback);
  498 +
  499 + TestMqttCallback sharedAttributesCallback = getTestMqttCallback();
  500 + client.setCallback(sharedAttributesCallback);
  501 + validateProtoSharedResponseGateway(client, sharedAttributesCallback);
  502 + }
  503 +
  504 + protected void postJsonAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception {
  505 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  506 + client.publish(attrPubTopic, new MqttMessage(POST_ATTRIBUTES_PAYLOAD.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  507 + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  508 + }
  509 +
  510 + protected void postProtoAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception {
  511 + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
  512 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  513 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  514 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  515 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  516 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  517 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  518 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
  519 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  520 +
  521 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  522 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  523 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  524 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  525 +
  526 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  527 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  528 + assertNotNull(jsonObjectBuilderDescriptor);
  529 + DynamicMessage jsonObject = jsonObjectBuilder
  530 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  531 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  532 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  533 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  534 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  535 + .build();
  536 +
  537 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  538 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  539 + assertNotNull(postAttributesMsgDescriptor);
  540 + DynamicMessage postAttributesMsg = postAttributesBuilder
  541 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
  542 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
  543 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
  544 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
  545 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
  546 + .build();
  547 + byte[] payload = postAttributesMsg.toByteArray();
  548 + client.publish(attrPubTopic, new MqttMessage(payload));
  549 + client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value());
  550 + }
  551 +
  552 + protected void postJsonGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception {
  553 + String postClientAttributes = "{\"" + "Gateway Device Request Attributes" + "\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  554 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(postClientAttributes.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  555 + }
  556 +
  557 + protected void postProtoGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception {
  558 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  559 + List<String> expectedKeys = Arrays.asList(keys.split(","));
  560 + TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys);
  561 + TransportApiProtos.AttributesMsg.Builder attributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder();
  562 + attributesMsgBuilder.setDeviceName("Gateway Device Request Attributes");
  563 + attributesMsgBuilder.setMsg(postAttributeMsg);
  564 + TransportApiProtos.AttributesMsg attributesMsg = attributesMsgBuilder.build();
  565 + TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributeMsgBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder();
  566 + gatewayAttributeMsgBuilder.addMsg(attributesMsg);
  567 + byte[] bytes = gatewayAttributeMsgBuilder.build().toByteArray();
  568 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes));
  569 + }
  570 +
  571 + protected void validateJsonResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopicPrefix) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  572 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  573 + String payloadStr = "{\"clientKeys\":\"" + keys + "\", \"sharedKeys\":\"" + keys + "\"}";
  574 + MqttMessage mqttMessage = new MqttMessage();
  575 + mqttMessage.setPayload(payloadStr.getBytes());
  576 + client.publish(attrReqTopicPrefix + "1", mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  577 + latch.await(1, TimeUnit.MINUTES);
  578 + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
  579 + String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  580 + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
  581 + }
  582 +
  583 + protected void validateProtoResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopic) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  584 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  585 + TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder();
  586 + attributesRequestBuilder.setClientKeys(keys);
  587 + attributesRequestBuilder.setSharedKeys(keys);
  588 + TransportApiProtos.AttributesRequest attributesRequest = attributesRequestBuilder.build();
  589 + MqttMessage mqttMessage = new MqttMessage();
  590 + mqttMessage.setPayload(attributesRequest.toByteArray());
  591 + client.publish(attrReqTopic + "1", mqttMessage);
  592 + latch.await(3, TimeUnit.SECONDS);
  593 + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
  594 + TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg();
  595 + TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
  596 + assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId());
  597 + List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  598 + List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  599 + List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  600 + List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  601 + assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
  602 + assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
  603 + }
  604 +
  605 + private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() {
  606 + TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder();
  607 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  608 + result.addAllClientAttributeList(tsKvProtoList);
  609 + result.addAllSharedAttributeList(tsKvProtoList);
  610 + result.setRequestId(1);
  611 + return result.build();
  612 + }
  613 +
  614 + protected void validateJsonClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  615 + String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": true, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}";
  616 + MqttMessage mqttMessage = new MqttMessage();
  617 + mqttMessage.setPayload(payloadStr.getBytes());
  618 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  619 + callback.getLatch().await(1, TimeUnit.MINUTES);
  620 + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
  621 + String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  622 + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
  623 + }
  624 +
  625 + protected void validateJsonSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  626 + String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": false, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}";
  627 + MqttMessage mqttMessage = new MqttMessage();
  628 + mqttMessage.setPayload(payloadStr.getBytes());
  629 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
  630 + callback.getLatch().await(1, TimeUnit.MINUTES);
  631 + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
  632 + String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
  633 + assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
  634 + }
  635 +
  636 + protected void validateProtoClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  637 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  638 + TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true);
  639 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
  640 + callback.getLatch().await(3, TimeUnit.SECONDS);
  641 + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
  642 + TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(true);
  643 + TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
  644 + assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName());
  645 +
  646 + TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg();
  647 + TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg();
  648 + assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId());
  649 +
  650 + List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  651 + List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  652 + assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
  653 + }
  654 +
  655 + protected void validateProtoSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
  656 + String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
  657 + TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false);
  658 + client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
  659 + callback.getLatch().await(3, TimeUnit.SECONDS);
  660 + assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
  661 + TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(false);
  662 + TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
  663 + assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName());
  664 +
  665 + TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg();
  666 + TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg();
  667 + assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId());
  668 +
  669 + List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  670 + List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
  671 +
  672 + assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
  673 + }
  674 +
  675 + private TransportApiProtos.GatewayAttributeResponseMsg getExpectedGatewayAttributeResponseMsg(boolean client) {
  676 + TransportApiProtos.GatewayAttributeResponseMsg.Builder gatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.newBuilder();
  677 + TransportProtos.GetAttributeResponseMsg.Builder getAttributeResponseMsgBuilder = TransportProtos.GetAttributeResponseMsg.newBuilder();
  678 + List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
  679 + if (client) {
  680 + getAttributeResponseMsgBuilder.addAllClientAttributeList(tsKvProtoList);
  681 + } else {
  682 + getAttributeResponseMsgBuilder.addAllSharedAttributeList(tsKvProtoList);
  683 + }
  684 + getAttributeResponseMsgBuilder.setRequestId(1);
  685 + TransportProtos.GetAttributeResponseMsg getAttributeResponseMsg = getAttributeResponseMsgBuilder.build();
  686 + gatewayAttributeResponseMsg.setDeviceName("Gateway Device Request Attributes");
  687 + gatewayAttributeResponseMsg.setResponseMsg(getAttributeResponseMsg);
  688 + return gatewayAttributeResponseMsg.build();
  689 + }
  690 +
  691 + private TransportApiProtos.GatewayAttributesRequestMsg getGatewayAttributesRequestMsg(String keys, boolean client) {
  692 + return TransportApiProtos.GatewayAttributesRequestMsg.newBuilder()
  693 + .setClient(client)
  694 + .addAllKeys(Arrays.asList(keys.split(",")))
  695 + .setDeviceName("Gateway Device Request Attributes")
  696 + .setId(1).build();
  697 + }
110 698 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.attributes.request;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Test;
  21 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  22 +import org.thingsboard.server.common.data.TransportPayloadType;
  23 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  24 +import org.thingsboard.server.gen.transport.TransportProtos;
  25 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
  26 +
  27 +import java.util.ArrayList;
  28 +import java.util.List;
  29 +
  30 +@Slf4j
  31 +public abstract class AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesIntegrationTest {
  32 +
  33 + @After
  34 + public void afterTest() throws Exception {
  35 + processAfterTest();
  36 + }
  37 +
  38 + @Test
  39 + public void testRequestAttributesValuesFromTheServerWithEnabledJsonCompatibility() throws Exception {
  40 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  41 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, false);
  42 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
  43 + }
  44 +
  45 + @Test
  46 + public void testRequestAttributesValuesFromTheServerWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  47 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  48 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  49 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
  50 + }
  51 +
  52 + @Test
  53 + public void testRequestAttributesValuesFromTheServerOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  54 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  55 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  56 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
  57 + }
  58 +
  59 + @Test
  60 + public void testRequestAttributesValuesFromTheServerOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  61 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  62 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  63 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX);
  64 + }
  65 +
  66 + @Test
  67 + public void testRequestAttributesValuesFromTheServerGatewayWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  68 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null, true, true);
  69 + processProtoTestGatewayRequestAttributesValuesFromTheServer();
  70 + }
  71 +
  72 + @Test
  73 + public void testRequestAttributesValuesFromTheServerOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  74 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null, true, true);
  75 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
  76 + }
  77 +
  78 +
  79 + protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
  80 + List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
  81 + TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V);
  82 + TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V);
  83 + TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "42.0", TransportProtos.KeyValueType.DOUBLE_V);
  84 + TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "73", TransportProtos.KeyValueType.LONG_V);
  85 + TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V);
  86 + keyValueProtos.add(strKeyValueProto);
  87 + keyValueProtos.add(boolKeyValueProto);
  88 + keyValueProtos.add(dblKeyValueProto);
  89 + keyValueProtos.add(longKeyValueProto);
  90 + keyValueProtos.add(jsonKeyValueProto);
  91 + return keyValueProtos;
  92 + }
  93 +
  94 +}
... ...
... ... @@ -15,7 +15,11 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.attributes.request;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
18 21 import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 23 import io.netty.handler.codec.mqtt.MqttQoS;
20 24 import lombok.extern.slf4j.Slf4j;
21 25 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
... ... @@ -25,16 +29,26 @@ import org.junit.After;
25 29 import org.junit.Before;
26 30 import org.junit.Test;
27 31 import org.thingsboard.server.common.data.Device;
  32 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  33 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
28 34 import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 35 import org.thingsboard.common.util.JacksonUtil;
  36 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  37 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  38 +import org.thingsboard.server.gen.transport.TransportApiProtos;
  39 +import org.thingsboard.server.gen.transport.TransportProtos;
30 40 import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
31 41
32 42 import java.nio.charset.StandardCharsets;
  43 +import java.util.Arrays;
  44 +import java.util.List;
33 45 import java.util.concurrent.CountDownLatch;
34 46 import java.util.concurrent.TimeUnit;
  47 +import java.util.stream.Collectors;
35 48
36 49 import static org.junit.Assert.assertEquals;
37 50 import static org.junit.Assert.assertNotNull;
  51 +import static org.junit.Assert.assertTrue;
38 52 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
39 53
40 54 @Slf4j
... ... @@ -52,109 +66,21 @@ public abstract class AbstractMqttAttributesRequestIntegrationTest extends Abstr
52 66
53 67 @Test
54 68 public void testRequestAttributesValuesFromTheServer() throws Exception {
55   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
  69 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
56 70 }
57 71
58 72 @Test
59 73 public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception {
60   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
  74 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
61 75 }
62 76
63 77 @Test
64 78 public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception {
65   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
  79 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
66 80 }
67 81
68 82 @Test
69 83 public void testRequestAttributesValuesFromTheServerGateway() throws Exception {
70   - processTestGatewayRequestAttributesValuesFromTheServer();
71   - }
72   -
73   - protected void processTestRequestAttributesValuesFromTheServer(String attrPubTopic, String attrSubTopic, String attrReqTopicPrefix) throws Exception {
74   -
75   - MqttAsyncClient client = getMqttAsyncClient(accessToken);
76   -
77   - postAttributesAndSubscribeToTopic(savedDevice, client, attrPubTopic, attrSubTopic);
78   -
79   - Thread.sleep(5000);
80   -
81   - TestMqttCallback callback = getTestMqttCallback();
82   - client.setCallback(callback);
83   -
84   - validateResponse(client, callback.getLatch(), callback, attrReqTopicPrefix);
85   - }
86   -
87   - protected void processTestGatewayRequestAttributesValuesFromTheServer() throws Exception {
88   -
89   - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
90   -
91   - postGatewayDeviceClientAttributes(client);
92   -
93   - Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class),
94   - 20,
95   - 100);
96   -
97   - assertNotNull(savedDevice);
98   -
99   - Thread.sleep(2000);
100   -
101   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
102   -
103   - Thread.sleep(5000);
104   -
105   - client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
106   -
107   - TestMqttCallback clientAttributesCallback = getTestMqttCallback();
108   - client.setCallback(clientAttributesCallback);
109   - validateClientResponseGateway(client, clientAttributesCallback);
110   -
111   - TestMqttCallback sharedAttributesCallback = getTestMqttCallback();
112   - client.setCallback(sharedAttributesCallback);
113   - validateSharedResponseGateway(client, sharedAttributesCallback);
114   - }
115   -
116   - protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception {
117   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
118   - client.publish(attrPubTopic, new MqttMessage(POST_ATTRIBUTES_PAYLOAD.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
119   - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value()).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
120   - }
121   -
122   - protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception {
123   - String postClientAttributes = "{\"" + "Gateway Device Request Attributes" + "\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
124   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(postClientAttributes.getBytes())).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
125   - }
126   -
127   - protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopicPrefix) throws MqttException, InterruptedException, InvalidProtocolBufferException {
128   - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
129   - String payloadStr = "{\"clientKeys\":\"" + keys + "\", \"sharedKeys\":\"" + keys + "\"}";
130   - MqttMessage mqttMessage = new MqttMessage();
131   - mqttMessage.setPayload(payloadStr.getBytes());
132   - client.publish(attrReqTopicPrefix + "1", mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
133   - latch.await(1, TimeUnit.MINUTES);
134   - assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
135   - String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
136   - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
137   - }
138   -
139   - protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
140   - String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": true, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}";
141   - MqttMessage mqttMessage = new MqttMessage();
142   - mqttMessage.setPayload(payloadStr.getBytes());
143   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
144   - callback.getLatch().await(1, TimeUnit.MINUTES);
145   - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
146   - String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
147   - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
148   - }
149   -
150   - protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
151   - String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": false, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}";
152   - MqttMessage mqttMessage = new MqttMessage();
153   - mqttMessage.setPayload(payloadStr.getBytes());
154   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage).waitForCompletion(TimeUnit.MINUTES.toMillis(1));
155   - callback.getLatch().await(1, TimeUnit.MINUTES);
156   - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
157   - String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
158   - assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8)));
  84 + processJsonTestGatewayRequestAttributesValuesFromTheServer();
159 85 }
160 86 }
... ...
... ... @@ -21,9 +21,10 @@ import org.junit.Before;
21 21 import org.junit.Test;
22 22 import org.thingsboard.server.common.data.TransportPayloadType;
23 23 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  24 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
24 25
25 26 @Slf4j
26   -public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
  27 +public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesIntegrationTest {
27 28
28 29 @Before
29 30 public void beforeTest() throws Exception {
... ... @@ -37,21 +38,21 @@ public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends A
37 38
38 39 @Test
39 40 public void testRequestAttributesValuesFromTheServer() throws Exception {
40   - super.testRequestAttributesValuesFromTheServer();
  41 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
41 42 }
42 43
43 44 @Test
44 45 public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception {
45   - super.testRequestAttributesValuesFromTheServerOnShortTopic();
  46 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
46 47 }
47 48
48 49 @Test
49 50 public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception {
50   - super.testRequestAttributesValuesFromTheServerOnShortJsonTopic();
  51 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
51 52 }
52 53
53 54 @Test
54 55 public void testRequestAttributesValuesFromTheServerGateway() throws Exception {
55   - processTestGatewayRequestAttributesValuesFromTheServer();
  56 + processJsonTestGatewayRequestAttributesValuesFromTheServer();
56 57 }
57 58 }
... ...
... ... @@ -15,65 +15,20 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.attributes.request;
17 17
18   -import com.github.os72.protobuf.dynamic.DynamicSchema;
19   -import com.google.protobuf.Descriptors;
20   -import com.google.protobuf.DynamicMessage;
21   -import com.google.protobuf.InvalidProtocolBufferException;
22   -import com.squareup.wire.schema.internal.parser.ProtoFileElement;
23   -import io.netty.handler.codec.mqtt.MqttQoS;
24 18 import lombok.extern.slf4j.Slf4j;
25   -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
26   -import org.eclipse.paho.client.mqttv3.MqttException;
27   -import org.eclipse.paho.client.mqttv3.MqttMessage;
28 19 import org.junit.After;
29 20 import org.junit.Test;
30   -import org.thingsboard.server.common.data.Device;
31 21 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
32 22 import org.thingsboard.server.common.data.TransportPayloadType;
33   -import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
34   -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
35   -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
36 23 import org.thingsboard.server.common.data.device.profile.MqttTopics;
37   -import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
38   -import org.thingsboard.server.gen.transport.TransportApiProtos;
39 24 import org.thingsboard.server.gen.transport.TransportProtos;
40 25 import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
41 26
42 27 import java.util.ArrayList;
43   -import java.util.Arrays;
44 28 import java.util.List;
45   -import java.util.concurrent.CountDownLatch;
46   -import java.util.concurrent.TimeUnit;
47   -import java.util.stream.Collectors;
48   -
49   -import static org.junit.Assert.assertEquals;
50   -import static org.junit.Assert.assertNotNull;
51   -import static org.junit.Assert.assertTrue;
52   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
53 29
54 30 @Slf4j
55   -public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
56   -
57   - public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
58   - "\n" +
59   - "package test;\n" +
60   - "\n" +
61   - "message PostAttributes {\n" +
62   - " string attribute1 = 1;\n" +
63   - " bool attribute2 = 2;\n" +
64   - " double attribute3 = 3;\n" +
65   - " int32 attribute4 = 4;\n" +
66   - " JsonObject attribute5 = 5;\n" +
67   - "\n" +
68   - " message JsonObject {\n" +
69   - " int32 someNumber = 6;\n" +
70   - " repeated int32 someArray = 7;\n" +
71   - " NestedJsonObject someNestedObject = 8;\n" +
72   - " message NestedJsonObject {\n" +
73   - " string key = 9;\n" +
74   - " }\n" +
75   - " }\n" +
76   - "}";
  31 +public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesIntegrationTest {
77 32
78 33 @After
79 34 public void afterTest() throws Exception {
... ... @@ -83,182 +38,36 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
83 38 @Test
84 39 public void testRequestAttributesValuesFromTheServer() throws Exception {
85 40 super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
86   - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED);
87   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
  41 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
  42 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
88 43 }
89 44
90 45 @Test
91 46 public void testRequestAttributesValuesFromTheServerOnShortTopic() throws Exception {
92 47 super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
93   - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED);
94   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
  48 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
  49 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
95 50 }
96 51
97 52 @Test
98 53 public void testRequestAttributesValuesFromTheServerOnShortProtoTopic() throws Exception {
99 54 super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
100   - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED);
101   - processTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX);
  55 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
  56 + processProtoTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX);
102 57 }
103 58
104 59 @Test
105 60 public void testRequestAttributesValuesFromTheServerGateway() throws Exception {
106 61 super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);
107   - processTestGatewayRequestAttributesValuesFromTheServer();
  62 + processProtoTestGatewayRequestAttributesValuesFromTheServer();
108 63 }
109 64
110 65 @Test
111   - public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception { }
112   -
113   - protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client, String attrPubTopic, String attrSubTopic) throws Exception {
114   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
115   - DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
116   - assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
117   - MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
118   - TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
119   - assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
120   - ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
121   - ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
122   - DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
123   -
124   - DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
125   - Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
126   - assertNotNull(nestedJsonObjectBuilderDescriptor);
127   - DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
128   -
129   - DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
130   - Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
131   - assertNotNull(jsonObjectBuilderDescriptor);
132   - DynamicMessage jsonObject = jsonObjectBuilder
133   - .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
134   - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
135   - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
136   - .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
137   - .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
138   - .build();
139   -
140   - DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
141   - Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
142   - assertNotNull(postAttributesMsgDescriptor);
143   - DynamicMessage postAttributesMsg = postAttributesBuilder
144   - .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
145   - .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
146   - .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
147   - .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
148   - .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
149   - .build();
150   - byte[] payload = postAttributesMsg.toByteArray();
151   - client.publish(attrPubTopic, new MqttMessage(payload));
152   - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value());
153   - }
154   -
155   - protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception {
156   - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
157   - List<String> expectedKeys = Arrays.asList(keys.split(","));
158   - TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys);
159   - TransportApiProtos.AttributesMsg.Builder attributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder();
160   - attributesMsgBuilder.setDeviceName("Gateway Device Request Attributes");
161   - attributesMsgBuilder.setMsg(postAttributeMsg);
162   - TransportApiProtos.AttributesMsg attributesMsg = attributesMsgBuilder.build();
163   - TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributeMsgBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder();
164   - gatewayAttributeMsgBuilder.addMsg(attributesMsg);
165   - byte[] bytes = gatewayAttributeMsgBuilder.build().toByteArray();
166   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes));
167   - }
168   -
169   - protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback, String attrReqTopic) throws MqttException, InterruptedException, InvalidProtocolBufferException {
170   - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
171   - TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder();
172   - attributesRequestBuilder.setClientKeys(keys);
173   - attributesRequestBuilder.setSharedKeys(keys);
174   - TransportApiProtos.AttributesRequest attributesRequest = attributesRequestBuilder.build();
175   - MqttMessage mqttMessage = new MqttMessage();
176   - mqttMessage.setPayload(attributesRequest.toByteArray());
177   - client.publish(attrReqTopic + "1", mqttMessage);
178   - latch.await(3, TimeUnit.SECONDS);
179   - assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
180   - TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg();
181   - TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
182   - assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId());
183   - List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
184   - List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
185   - List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
186   - List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
187   - assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
188   - assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
189   - }
190   -
191   - protected void validateClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
192   - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
193   - TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true);
194   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
195   - callback.getLatch().await(3, TimeUnit.SECONDS);
196   - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
197   - TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(true);
198   - TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
199   - assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName());
200   -
201   - TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg();
202   - TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg();
203   - assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId());
204   -
205   - List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
206   - List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
207   - assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
208   - }
209   -
210   - protected void validateSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
211   - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
212   - TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false);
213   - client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
214   - callback.getLatch().await(3, TimeUnit.SECONDS);
215   - assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS());
216   - TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(false);
217   - TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes());
218   - assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName());
219   -
220   - TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg();
221   - TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg();
222   - assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId());
223   -
224   - List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
225   - List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
226   -
227   - assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
228   - }
229   -
230   - private TransportApiProtos.GatewayAttributesRequestMsg getGatewayAttributesRequestMsg(String keys, boolean client) {
231   - return TransportApiProtos.GatewayAttributesRequestMsg.newBuilder()
232   - .setClient(client)
233   - .addAllKeys(Arrays.asList(keys.split(",")))
234   - .setDeviceName("Gateway Device Request Attributes")
235   - .setId(1).build();
236   - }
237   -
238   - private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() {
239   - TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder();
240   - List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
241   - result.addAllClientAttributeList(tsKvProtoList);
242   - result.addAllSharedAttributeList(tsKvProtoList);
243   - result.setRequestId(1);
244   - return result.build();
  66 + public void testRequestAttributesValuesFromTheServerOnShortJsonTopic() throws Exception {
  67 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);
  68 + processJsonTestRequestAttributesValuesFromTheServer(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
245 69 }
246 70
247   - private TransportApiProtos.GatewayAttributeResponseMsg getExpectedGatewayAttributeResponseMsg(boolean client) {
248   - TransportApiProtos.GatewayAttributeResponseMsg.Builder gatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.newBuilder();
249   - TransportProtos.GetAttributeResponseMsg.Builder getAttributeResponseMsgBuilder = TransportProtos.GetAttributeResponseMsg.newBuilder();
250   - List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
251   - if (client) {
252   - getAttributeResponseMsgBuilder.addAllClientAttributeList(tsKvProtoList);
253   - } else {
254   - getAttributeResponseMsgBuilder.addAllSharedAttributeList(tsKvProtoList);
255   - }
256   - getAttributeResponseMsgBuilder.setRequestId(1);
257   - TransportProtos.GetAttributeResponseMsg getAttributeResponseMsg = getAttributeResponseMsgBuilder.build();
258   - gatewayAttributeResponseMsg.setDeviceName("Gateway Device Request Attributes");
259   - gatewayAttributeResponseMsg.setResponseMsg(getAttributeResponseMsg);
260   - return gatewayAttributeResponseMsg.build();
261   - }
262 71
263 72 protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
264 73 List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.attributes.request.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.DaoSqlTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest;
  20 +
  21 +@DaoSqlTest
  22 +public class MqttAttributesRequestBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesRequestBackwardCompatibilityIntegrationTest {
  23 +}
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesRequestSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
  22 +public class MqttAttributesRequestIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestJsonSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesRequestJsonSqlIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest {
  22 +public class MqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/sql/MqttAttributesRequestProtoSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesRequestProtoSqlIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest {
  22 +public class MqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest {
23 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Test;
  21 +import org.thingsboard.server.common.data.TransportPayloadType;
  22 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  23 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
  24 +
  25 +@Slf4j
  26 +public abstract class AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesIntegrationTest {
  27 +
  28 + @After
  29 + public void afterTest() throws Exception {
  30 + processAfterTest();
  31 + }
  32 +
  33 + @Test
  34 + public void testSubscribeToAttributesUpdatesFromServerWithEnabledJsonCompatibility() throws Exception {
  35 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, false);
  36 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
  37 + }
  38 +
  39 + @Test
  40 + public void testSubscribeToAttributesUpdatesFromServerWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  41 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true);
  42 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
  43 + }
  44 +
  45 + @Test
  46 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  47 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true);
  48 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC);
  49 + }
  50 +
  51 + @Test
  52 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  53 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true);
  54 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC);
  55 + }
  56 +
  57 + @Test
  58 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  59 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, true);
  60 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC);
  61 + }
  62 +
  63 + @Test
  64 + public void testProtoSubscribeToAttributesUpdatesFromTheServerGatewayWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  65 + super.processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null, true, false);
  66 + processProtoGatewayTestSubscribeToAttributesUpdates();
  67 + }
  68 +
  69 +}
... ...
... ... @@ -15,40 +15,17 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.attributes.updates;
17 17
18   -import com.google.protobuf.InvalidProtocolBufferException;
19   -import io.netty.handler.codec.mqtt.MqttQoS;
20 18 import lombok.extern.slf4j.Slf4j;
21   -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
22 19 import org.junit.After;
23 20 import org.junit.Before;
24 21 import org.junit.Test;
25   -import org.thingsboard.server.common.data.Device;
26 22 import org.thingsboard.server.common.data.TransportPayloadType;
27 23 import org.thingsboard.server.common.data.device.profile.MqttTopics;
28   -import org.thingsboard.common.util.JacksonUtil;
29 24 import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
30 25
31   -import java.nio.charset.StandardCharsets;
32   -import java.util.concurrent.TimeUnit;
33   -
34   -import static org.junit.Assert.assertEquals;
35   -import static org.junit.Assert.assertNotNull;
36   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
37   -
38 26 @Slf4j
39 27 public abstract class AbstractMqttAttributesUpdatesIntegrationTest extends AbstractMqttAttributesIntegrationTest {
40 28
41   - private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}";
42   -
43   - private static String getResponseGatewayAttributesUpdatedPayload() {
44   - return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\"," +
45   - "\"data\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}";
46   - }
47   -
48   - private static String getResponseGatewayAttributesDeletedPayload() {
49   - return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\",\"data\":{\"deleted\":[\"attribute5\"]}}";
50   - }
51   -
52 29 @Before
53 30 public void beforeTest() throws Exception {
54 31 processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.JSON, null, null);
... ... @@ -60,116 +37,23 @@ public abstract class AbstractMqttAttributesUpdatesIntegrationTest extends Abstr
60 37 }
61 38
62 39 @Test
63   - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
64   - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
  40 + public void testJsonSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  41 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
65 42 }
66 43
67 44 @Test
68   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
69   - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC);
  45 + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
  46 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC);
70 47 }
71 48
72 49 @Test
73   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {
74   - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC);
  50 + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {
  51 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC);
75 52 }
76 53
77 54 @Test
78   - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
79   - processGatewayTestSubscribeToAttributesUpdates();
80   - }
81   -
82   - protected void processTestSubscribeToAttributesUpdates(String attrSubTopic) throws Exception {
83   -
84   - MqttAsyncClient client = getMqttAsyncClient(accessToken);
85   -
86   - TestMqttCallback onUpdateCallback = getTestMqttCallback();
87   - client.setCallback(onUpdateCallback);
88   -
89   - client.subscribe(attrSubTopic, MqttQoS.AT_MOST_ONCE.value());
90   -
91   - Thread.sleep(1000);
92   -
93   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
94   - onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
95   -
96   - validateUpdateAttributesResponse(onUpdateCallback);
97   -
98   - TestMqttCallback onDeleteCallback = getTestMqttCallback();
99   - client.setCallback(onDeleteCallback);
100   -
101   - doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
102   - onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
103   -
104   - validateDeleteAttributesResponse(onDeleteCallback);
105   - }
106   -
107   - protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
108   - assertNotNull(callback.getPayloadBytes());
109   - String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
110   - assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response));
111   - }
112   -
113   - protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
114   - assertNotNull(callback.getPayloadBytes());
115   - String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
116   - assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response));
  55 + public void testJsonSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
  56 + processJsonGatewayTestSubscribeToAttributesUpdates();
117 57 }
118 58
119   - protected void processGatewayTestSubscribeToAttributesUpdates() throws Exception {
120   -
121   - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
122   -
123   - TestMqttCallback onUpdateCallback = getTestMqttCallback();
124   - client.setCallback(onUpdateCallback);
125   -
126   - Device device = new Device();
127   - device.setName("Gateway Device Subscribe to attribute updates");
128   - device.setType("default");
129   -
130   - byte[] connectPayloadBytes = getConnectPayloadBytes();
131   -
132   - publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC);
133   -
134   - Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class),
135   - 20,
136   - 100);
137   -
138   - assertNotNull(savedDevice);
139   -
140   - client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value());
141   -
142   - Thread.sleep(1000);
143   -
144   - doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
145   - onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS);
146   -
147   - validateGatewayUpdateAttributesResponse(onUpdateCallback);
148   -
149   - TestMqttCallback onDeleteCallback = getTestMqttCallback();
150   - client.setCallback(onDeleteCallback);
151   -
152   - doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
153   - onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS);
154   -
155   - validateGatewayDeleteAttributesResponse(onDeleteCallback);
156   -
157   - }
158   -
159   - protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
160   - assertNotNull(callback.getPayloadBytes());
161   - String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
162   - assertEquals(getResponseGatewayAttributesUpdatedPayload(), s);
163   - }
164   -
165   - protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
166   - assertNotNull(callback.getPayloadBytes());
167   - String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
168   - assertEquals(s, getResponseGatewayAttributesDeletedPayload());
169   - }
170   -
171   - protected byte[] getConnectPayloadBytes() {
172   - String connectPayload = "{\"device\": \"Gateway Device Subscribe to attribute updates\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}";
173   - return connectPayload.getBytes();
174   - }
175 59 }
... ...
... ... @@ -20,9 +20,11 @@ import org.junit.After;
20 20 import org.junit.Before;
21 21 import org.junit.Test;
22 22 import org.thingsboard.server.common.data.TransportPayloadType;
  23 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  24 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
23 25
24 26 @Slf4j
25   -public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
  27 +public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesIntegrationTest {
26 28
27 29 @Before
28 30 public void beforeTest() throws Exception {
... ... @@ -35,22 +37,22 @@ public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends A
35 37 }
36 38
37 39 @Test
38   - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
39   - super.testSubscribeToAttributesUpdatesFromTheServer();
  40 + public void testJsonSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  41 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
40 42 }
41 43
42 44 @Test
43   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
44   - super.testSubscribeToAttributesUpdatesFromTheServerOnShortTopic();
  45 + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
  46 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC);
45 47 }
46 48
47 49 @Test
48   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {
49   - super.testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic();
  50 + public void testJsonSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {
  51 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC);
50 52 }
51 53
52 54 @Test
53   - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
54   - processGatewayTestSubscribeToAttributesUpdates();
  55 + public void testJsonSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
  56 + processJsonGatewayTestSubscribeToAttributesUpdates();
55 57 }
56 58 }
... ...
... ... @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.TransportPayloadType;
24 24 import org.thingsboard.server.common.data.device.profile.MqttTopics;
25 25 import org.thingsboard.server.gen.transport.TransportApiProtos;
26 26 import org.thingsboard.server.gen.transport.TransportProtos;
  27 +import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
27 28
28 29 import java.util.List;
29 30 import java.util.stream.Collectors;
... ... @@ -33,7 +34,7 @@ import static org.junit.Assert.assertNotNull;
33 34 import static org.junit.Assert.assertTrue;
34 35
35 36 @Slf4j
36   -public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
  37 +public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesIntegrationTest {
37 38
38 39 @Before
39 40 public void beforeTest() throws Exception {
... ... @@ -46,116 +47,28 @@ public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends
46 47 }
47 48
48 49 @Test
49   - public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
50   - super.testSubscribeToAttributesUpdatesFromTheServer();
  50 + public void testProtoSubscribeToAttributesUpdatesFromTheServer() throws Exception {
  51 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
51 52 }
52 53
53 54 @Test
54   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
55   - super.testSubscribeToAttributesUpdatesFromTheServerOnShortTopic();
  55 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortTopic() throws Exception {
  56 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC);
56 57 }
57 58
58 59 @Test
59   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {}
60   -
61   - @Test
62   - public void testSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopic() throws Exception {
63   - processTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC);
  60 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortJsonTopic() throws Exception {
  61 + processJsonTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC);
64 62 }
65 63
66 64 @Test
67   - public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
68   - processGatewayTestSubscribeToAttributesUpdates();
  65 + public void testProtoSubscribeToAttributesUpdatesFromTheServerOnShortProtoTopic() throws Exception {
  66 + processProtoTestSubscribeToAttributesUpdates(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC);
69 67 }
70 68
71   - protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
72   - assertNotNull(callback.getPayloadBytes());
73   - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
74   - List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
75   - attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
76   -
77   - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
78   - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
79   -
80   - List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
81   - List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
82   -
83   - assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
84   - assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
85   -
86   - }
87   -
88   - protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
89   - assertNotNull(callback.getPayloadBytes());
90   - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
91   - attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
92   -
93   - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
94   - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
95   -
96   - assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
97   - assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
98   -
99   - }
100   -
101   - protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
102   - assertNotNull(callback.getPayloadBytes());
103   -
104   - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
105   - List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
106   - attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
107   - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
108   -
109   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder();
110   - gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates");
111   - gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(expectedAttributeUpdateNotificationMsg);
112   -
113   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build();
114   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
115   -
116   - assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName());
117   -
118   - List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
119   - List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
120   -
121   - assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
122   - assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
123   -
124   - }
125   -
126   - protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException {
127   - assertNotNull(callback.getPayloadBytes());
128   - TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
129   - attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
130   - TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
131   -
132   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder();
133   - gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates");
134   - gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(attributeUpdateNotificationMsg);
135   -
136   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build();
137   - TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
138   -
139   - assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName());
140   -
141   - TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg();
142   - TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg();
143   -
144   - assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
145   - assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
146   -
147   - }
148   -
149   - protected byte[] getConnectPayloadBytes() {
150   - TransportApiProtos.ConnectMsg connectProto = getConnectProto();
151   - return connectProto.toByteArray();
152   - }
153   -
154   - private TransportApiProtos.ConnectMsg getConnectProto() {
155   - TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder();
156   - builder.setDeviceName("Gateway Device Subscribe to attribute updates");
157   - builder.setDeviceType(TransportPayloadType.PROTOBUF.name());
158   - return builder.build();
  69 + @Test
  70 + public void testProtoSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception {
  71 + processProtoGatewayTestSubscribeToAttributesUpdates();
159 72 }
160 73
161 74 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.DaoSqlTest;
  19 +import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest;
  20 +
  21 +@DaoSqlTest
  22 +public class MqttAttributesUpdatesBackwardCompatibilityIntegrationTest extends AbstractMqttAttributesUpdatesBackwardCompatibilityIntegrationTest {
  23 +}
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesUpdatesSqlIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
  22 +public class MqttAttributesUpdatesIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlJsonIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesUpdatesSqlJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
  22 +public class MqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/sql/MqttAttributesUpdatesSqlProtoIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesUpdatesSqlProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest {
  22 +public class MqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest {
23 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.claim;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.TransportPayloadType;
  23 +
  24 +@Slf4j
  25 +public abstract class AbstractMqttClaimBackwardCompatibilityDeviceTest extends AbstractMqttClaimDeviceTest {
  26 +
  27 + @Before
  28 + public void beforeTest() throws Exception {
  29 + processBeforeTest("Test Claim device", "Test Claim gateway", TransportPayloadType.PROTOBUF, null, null, true, true);
  30 + createCustomerAndUser();
  31 + }
  32 +
  33 + @After
  34 + public void afterTest() throws Exception { super.afterTest(); }
  35 +
  36 + @Test
  37 + public void testGatewayClaimingDevice() throws Exception {
  38 + processTestGatewayClaimingDevice("Test claiming gateway device Proto", false);
  39 + }
  40 +
  41 + @Test
  42 + public void testGatewayClaimingDeviceWithoutSecretAndDuration() throws Exception {
  43 + processTestGatewayClaimingDevice("Test claiming gateway device empty payload Proto", true);
  44 + }
  45 +
  46 + protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception {
  47 + processProtoTestGatewayClaimDevice(deviceName, emptyPayload);
  48 + }
  49 +
  50 +}
... ...
... ... @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 29 import org.thingsboard.server.common.data.security.Authority;
30 30 import org.thingsboard.server.dao.device.claim.ClaimResponse;
31 31 import org.thingsboard.server.dao.device.claim.ClaimResult;
  32 +import org.thingsboard.server.gen.transport.TransportApiProtos;
32 33 import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
33 34
34 35 import static org.junit.Assert.assertEquals;
... ... @@ -202,4 +203,36 @@ public abstract class AbstractMqttClaimDeviceTest extends AbstractMqttIntegratio
202 203 validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes);
203 204 }
204 205
  206 + protected void processProtoTestGatewayClaimDevice(String deviceName, boolean emptyPayload) throws Exception {
  207 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  208 + byte[] failurePayloadBytes;
  209 + byte[] payloadBytes;
  210 + if (emptyPayload) {
  211 + payloadBytes = getGatewayClaimMsg(deviceName, 0, emptyPayload).toByteArray();
  212 + } else {
  213 + payloadBytes = getGatewayClaimMsg(deviceName, 60000, emptyPayload).toByteArray();
  214 + }
  215 + failurePayloadBytes = getGatewayClaimMsg(deviceName, 1, emptyPayload).toByteArray();
  216 +
  217 + validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes);
  218 + }
  219 +
  220 + private TransportApiProtos.GatewayClaimMsg getGatewayClaimMsg(String deviceName, long duration, boolean emptyPayload) {
  221 + TransportApiProtos.GatewayClaimMsg.Builder gatewayClaimMsgBuilder = TransportApiProtos.GatewayClaimMsg.newBuilder();
  222 + TransportApiProtos.ClaimDeviceMsg.Builder claimDeviceMsgBuilder = TransportApiProtos.ClaimDeviceMsg.newBuilder();
  223 + TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder();
  224 + if (!emptyPayload) {
  225 + claimDeviceBuilder.setSecretKey("value");
  226 + }
  227 + if (duration > 0) {
  228 + claimDeviceBuilder.setDurationMs(duration);
  229 + }
  230 + TransportApiProtos.ClaimDevice claimDevice = claimDeviceBuilder.build();
  231 + claimDeviceMsgBuilder.setClaimRequest(claimDevice);
  232 + claimDeviceMsgBuilder.setDeviceName(deviceName);
  233 + TransportApiProtos.ClaimDeviceMsg claimDeviceMsg = claimDeviceMsgBuilder.build();
  234 + gatewayClaimMsgBuilder.addMsg(claimDeviceMsg);
  235 + return gatewayClaimMsgBuilder.build();
  236 + }
  237 +
205 238 }
... ...
... ... @@ -68,35 +68,7 @@ public abstract class AbstractMqttClaimProtoDeviceTest extends AbstractMqttClaim
68 68 }
69 69
70 70 protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception {
71   - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
72   - byte[] failurePayloadBytes;
73   - byte[] payloadBytes;
74   - if (emptyPayload) {
75   - payloadBytes = getGatewayClaimMsg(deviceName, 0, emptyPayload).toByteArray();
76   - } else {
77   - payloadBytes = getGatewayClaimMsg(deviceName, 60000, emptyPayload).toByteArray();
78   - }
79   - failurePayloadBytes = getGatewayClaimMsg(deviceName, 1, emptyPayload).toByteArray();
80   -
81   - validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes);
82   - }
83   -
84   - private TransportApiProtos.GatewayClaimMsg getGatewayClaimMsg(String deviceName, long duration, boolean emptyPayload) {
85   - TransportApiProtos.GatewayClaimMsg.Builder gatewayClaimMsgBuilder = TransportApiProtos.GatewayClaimMsg.newBuilder();
86   - TransportApiProtos.ClaimDeviceMsg.Builder claimDeviceMsgBuilder = TransportApiProtos.ClaimDeviceMsg.newBuilder();
87   - TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder();
88   - if (!emptyPayload) {
89   - claimDeviceBuilder.setSecretKey("value");
90   - }
91   - if (duration > 0) {
92   - claimDeviceBuilder.setDurationMs(duration);
93   - }
94   - TransportApiProtos.ClaimDevice claimDevice = claimDeviceBuilder.build();
95   - claimDeviceMsgBuilder.setClaimRequest(claimDevice);
96   - claimDeviceMsgBuilder.setDeviceName(deviceName);
97   - TransportApiProtos.ClaimDeviceMsg claimDeviceMsg = claimDeviceMsgBuilder.build();
98   - gatewayClaimMsgBuilder.addMsg(claimDeviceMsg);
99   - return gatewayClaimMsgBuilder.build();
  71 + processProtoTestGatewayClaimDevice(deviceName, emptyPayload);
100 72 }
101 73
102 74 private TransportApiProtos.ClaimDevice getClaimDevice(long duration, boolean emptyPayload) {
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.claim.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.DaoSqlTest;
  19 +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimBackwardCompatibilityDeviceTest;
  20 +import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest;
  21 +
  22 +@DaoSqlTest
  23 +public class MqttClaimDeviceBackwardCompatibilityTest extends AbstractMqttClaimBackwardCompatibilityDeviceTest {
  24 +}
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceJsonSqlTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttClaimDeviceJsonSqlTest extends AbstractMqttClaimJsonDeviceTest {
  22 +public class MqttClaimDeviceJsonTest extends AbstractMqttClaimJsonDeviceTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceProtoSqlTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttClaimDeviceProtoSqlTest extends AbstractMqttClaimProtoDeviceTest {
  22 +public class MqttClaimDeviceProtoTest extends AbstractMqttClaimProtoDeviceTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/sql/MqttClaimDeviceSqlTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttClaimDeviceSqlTest extends AbstractMqttClaimDeviceTest {
  22 +public class MqttClaimDeviceTest extends AbstractMqttClaimDeviceTest {
23 23 }
... ...
... ... @@ -94,7 +94,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
94 94
95 95
96 96 protected void processTestProvisioningDisabledDevice() throws Exception {
97   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  97 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
98 98 byte[] result = createMqttClientAndPublish().getPayloadBytes();
99 99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
100 100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ... @@ -103,7 +103,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
103 103
104 104
105 105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
106   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  106 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
107 107 byte[] result = createMqttClientAndPublish().getPayloadBytes();
108 108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
109 109
... ... @@ -119,7 +119,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
119 119
120 120
121 121 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
122   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  122 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
123 123 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
124 124 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
125 125 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -138,7 +138,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
138 138
139 139
140 140 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
141   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  141 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
142 142 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
143 143 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
144 144 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -163,7 +163,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
163 163
164 164
165 165 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
166   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  166 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
167 167 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\"";
168 168 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
169 169 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -188,7 +188,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
188 188 }
189 189
190 190 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
191   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
  191 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false);
192 192 byte[] result = createMqttClientAndPublish().getPayloadBytes();
193 193 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
194 194
... ... @@ -199,7 +199,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
199 199 }
200 200
201 201 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
202   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
  202 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false);
203 203 byte[] result = createMqttClientAndPublish().getPayloadBytes();
204 204 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
205 205 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ...
... ... @@ -101,14 +101,14 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
101 101
102 102
103 103 protected void processTestProvisioningDisabledDevice() throws Exception {
104   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  104 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
105 105 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
106 106 Assert.assertNotNull(result);
107 107 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
108 108 }
109 109
110 110 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
111   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  111 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
112 112 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
113 113
114 114 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
... ... @@ -122,7 +122,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
122 122 }
123 123
124 124 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
125   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  125 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
126 126 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
127 127
128 128 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes());
... ... @@ -140,7 +140,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
140 140 }
141 141
142 142 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
143   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  143 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
144 144 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
145 145
146 146 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes());
... ... @@ -164,7 +164,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
164 164 }
165 165
166 166 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
167   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
  167 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, false, false);
168 168 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg(
169 169 ValidateBasicMqttCredRequestMsg.newBuilder()
170 170 .setClientId("test_clientId")
... ... @@ -195,7 +195,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
195 195 }
196 196
197 197 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
198   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
  198 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false);
199 199 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
200 200
201 201 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
... ... @@ -205,7 +205,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
205 205 }
206 206
207 207 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
208   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
  208 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, false, false);
209 209 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
210 210 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
211 211 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceJsonSqlTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionJsonDeviceTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttProvisionDeviceJsonSqlTest extends AbstractMqttProvisionJsonDeviceTest {
  22 +public class MqttProvisionDeviceJsonTest extends AbstractMqttProvisionJsonDeviceTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/sql/MqttProvisionDeviceProtoSqlTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.provision.AbstractMqttProvisionProtoDeviceTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttProvisionDeviceProtoSqlTest extends AbstractMqttProvisionProtoDeviceTest {
  22 +public class MqttProvisionDeviceProtoTest extends AbstractMqttProvisionProtoDeviceTest {
23 23 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.rpc;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Before;
  21 +import org.junit.Test;
  22 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  23 +import org.thingsboard.server.common.data.TransportPayloadType;
  24 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  25 +
  26 +@Slf4j
  27 +public abstract class AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest {
  28 +
  29 + @After
  30 + public void afterTest() throws Exception {
  31 + super.processAfterTest();
  32 + }
  33 +
  34 + @Test
  35 + public void testServerMqttOneWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  36 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  37 + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  38 + }
  39 +
  40 + @Test
  41 + public void testServerMqttOneWayRpcOnShortTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  42 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  43 + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
  44 + }
  45 +
  46 + @Test
  47 + public void testServerMqttOneWayRpcOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  48 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  49 + processOneWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC);
  50 + }
  51 +
  52 + @Test
  53 + public void testServerMqttTwoWayRpcWithEnabledJsonCompatibility() throws Exception {
  54 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, false);
  55 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  56 + }
  57 +
  58 + @Test
  59 + public void testServerMqttTwoWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  60 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  61 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  62 + }
  63 +
  64 + @Test
  65 + public void testServerMqttTwoWayRpcOnShortTopic() throws Exception {
  66 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  67 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
  68 + }
  69 +
  70 + @Test
  71 + public void testServerMqttTwoWayRpcOnShortProtoTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  72 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  73 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC);
  74 + }
  75 +
  76 + @Test
  77 + public void testServerMqttTwoWayRpcOnShortJsonTopicWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  78 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  79 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC);
  80 + }
  81 +
  82 + @Test
  83 + public void testGatewayServerMqttOneWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  84 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  85 + processProtoOneWayRpcTestGateway("Gateway Device OneWay RPC Proto");
  86 + }
  87 +
  88 + @Test
  89 + public void testGatewayServerMqttTwoWayRpcWithEnabledJsonCompatibilityAndJsonDownlinks() throws Exception {
  90 + super.processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, true, true);
  91 + processProtoTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto");
  92 + }
  93 +
  94 +}
... ...
... ... @@ -97,17 +97,17 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
97 97
98 98 @Test
99 99 public void testServerMqttTwoWayRpc() throws Exception {
100   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  100 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
101 101 }
102 102
103 103 @Test
104 104 public void testServerMqttTwoWayRpcOnShortTopic() throws Exception {
105   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
  105 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
106 106 }
107 107
108 108 @Test
109 109 public void testServerMqttTwoWayRpcOnShortJsonTopic() throws Exception {
110   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC);
  110 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC);
111 111 }
112 112
113 113 @Test
... ... @@ -117,12 +117,12 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
117 117
118 118 @Test
119 119 public void testGatewayServerMqttOneWayRpc() throws Exception {
120   - processOneWayRpcTestGateway("Gateway Device OneWay RPC");
  120 + processJsonOneWayRpcTestGateway("Gateway Device OneWay RPC");
121 121 }
122 122
123 123 @Test
124 124 public void testGatewayServerMqttTwoWayRpc() throws Exception {
125   - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC");
  125 + processJsonTwoWayRpcTestGateway("Gateway Device TwoWay RPC");
126 126 }
127 127
128 128 }
... ...
... ... @@ -17,8 +17,12 @@ package org.thingsboard.server.transport.mqtt.rpc;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
19 19 import com.fasterxml.jackson.databind.node.ObjectNode;
  20 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  21 +import com.google.protobuf.Descriptors;
  22 +import com.google.protobuf.DynamicMessage;
20 23 import com.google.protobuf.InvalidProtocolBufferException;
21 24 import com.nimbusds.jose.util.StandardCharset;
  25 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
22 26 import io.netty.handler.codec.mqtt.MqttQoS;
23 27 import lombok.extern.slf4j.Slf4j;
24 28 import org.apache.commons.lang3.StringUtils;
... ... @@ -31,18 +35,23 @@ import org.junit.Assert;
31 35 import org.thingsboard.common.util.JacksonUtil;
32 36 import org.thingsboard.server.common.data.Device;
33 37 import org.thingsboard.server.common.data.TransportPayloadType;
  38 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
34 40 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  41 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  42 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  43 +import org.thingsboard.server.gen.transport.TransportApiProtos;
35 44 import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
36 45
37 46 import java.util.ArrayList;
38 47 import java.util.Arrays;
39 48 import java.util.List;
40   -import java.util.concurrent.CopyOnWriteArrayList;
41 49 import java.util.concurrent.CountDownLatch;
42 50 import java.util.concurrent.TimeUnit;
43 51
44 52 import static org.junit.Assert.assertEquals;
45 53 import static org.junit.Assert.assertNotNull;
  54 +import static org.junit.Assert.assertTrue;
46 55 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
47 56
48 57 /**
... ... @@ -51,7 +60,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
51 60 @Slf4j
52 61 public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractMqttIntegrationTest {
53 62
54   - protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
  63 + protected static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  64 + "package rpc;\n" +
  65 + "\n" +
  66 + "message RpcRequestMsg {\n" +
  67 + " optional string method = 1;\n" +
  68 + " optional int32 requestId = 2;\n" +
  69 + " Params params = 3;\n" +
  70 + "\n" +
  71 + " message Params {\n" +
  72 + " optional string pin = 1;\n" +
  73 + " optional int32 value = 2;\n" +
  74 + " }\n" +
  75 + "}";
  76 +
  77 + private static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
55 78
56 79 protected Long asyncContextTimeoutToUseRpcPlugin;
57 80
... ... @@ -64,7 +87,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
64 87 MqttAsyncClient client = getMqttAsyncClient(accessToken);
65 88
66 89 CountDownLatch latch = new CountDownLatch(1);
67   - TestMqttCallback callback = new TestMqttCallback(client, latch);
  90 + TestOneWayMqttCallback callback = new TestOneWayMqttCallback(client, latch);
68 91 client.setCallback(callback);
69 92
70 93 client.subscribe(rpcSubTopic, MqttQoS.AT_MOST_ONCE.value());
... ... @@ -79,19 +102,19 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
79 102 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
80 103 }
81 104
82   - protected void processOneWayRpcTestGateway(String deviceName) throws Exception {
  105 + protected void processJsonOneWayRpcTestGateway(String deviceName) throws Exception {
83 106 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
84 107 String payload = "{\"device\":\"" + deviceName + "\"}";
85 108 byte[] payloadBytes = payload.getBytes();
86 109 validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes);
87 110 }
88 111
89   - protected void processTwoWayRpcTest(String rpcSubTopic) throws Exception {
  112 + protected void processJsonTwoWayRpcTest(String rpcSubTopic) throws Exception {
90 113 MqttAsyncClient client = getMqttAsyncClient(accessToken);
91 114 client.subscribe(rpcSubTopic, 1);
92 115
93 116 CountDownLatch latch = new CountDownLatch(1);
94   - TestMqttCallback callback = new TestMqttCallback(client, latch);
  117 + TestJsonMqttCallback callback = new TestJsonMqttCallback(client, latch);
95 118 client.setCallback(callback);
96 119
97 120 Thread.sleep(1000);
... ... @@ -105,6 +128,46 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
105 128 Assert.assertEquals(expected, result);
106 129 }
107 130
  131 + protected void processProtoTwoWayRpcTest(String rpcSubTopic) throws Exception {
  132 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  133 + client.subscribe(rpcSubTopic, 1);
  134 +
  135 + CountDownLatch latch = new CountDownLatch(1);
  136 + TestProtoMqttCallback callback = new TestProtoMqttCallback(client, latch);
  137 + client.setCallback(callback);
  138 +
  139 + Thread.sleep(1000);
  140 +
  141 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
  142 + String deviceId = savedDevice.getId().getId().toString();
  143 +
  144 + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  145 + String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}";
  146 + latch.await(3, TimeUnit.SECONDS);
  147 + Assert.assertEquals(expected, result);
  148 + }
  149 +
  150 + protected void processProtoTwoWayRpcTestGateway(String deviceName) throws Exception {
  151 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  152 + TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
  153 + byte[] payloadBytes = connectMsgProto.toByteArray();
  154 + validateProtoTwoWayRpcGatewayResponse(deviceName, client, payloadBytes);
  155 + }
  156 +
  157 + protected void processProtoOneWayRpcTestGateway(String deviceName) throws Exception {
  158 + MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
  159 + TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
  160 + byte[] payloadBytes = connectMsgProto.toByteArray();
  161 + validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes);
  162 + }
  163 +
  164 + private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) {
  165 + TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder();
  166 + builder.setDeviceName(deviceName);
  167 + builder.setDeviceType(TransportPayloadType.PROTOBUF.name());
  168 + return builder.build();
  169 + }
  170 +
108 171 protected void processSequenceTwoWayRpcTest() throws Exception {
109 172 List<String> expected = new ArrayList<>();
110 173 List<String> result = new ArrayList<>();
... ... @@ -131,13 +194,13 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
131 194 Assert.assertEquals(expected, result);
132 195 }
133 196
134   - protected void processTwoWayRpcTestGateway(String deviceName) throws Exception {
  197 + protected void processJsonTwoWayRpcTestGateway(String deviceName) throws Exception {
135 198 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
136 199
137 200 String payload = "{\"device\":\"" + deviceName + "\"}";
138 201 byte[] payloadBytes = payload.getBytes();
139 202
140   - validateTwoWayRpcGateway(deviceName, client, payloadBytes);
  203 + validateJsonTwoWayRpcGatewayResponse(deviceName, client, payloadBytes);
141 204 }
142 205
143 206 protected void validateOneWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception {
... ... @@ -151,7 +214,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
151 214 assertNotNull(savedDevice);
152 215
153 216 CountDownLatch latch = new CountDownLatch(1);
154   - TestMqttCallback callback = new TestMqttCallback(client, latch);
  217 + TestOneWayMqttCallback callback = new TestOneWayMqttCallback(client, latch);
155 218 client.setCallback(callback);
156 219
157 220 client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value());
... ... @@ -166,7 +229,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
166 229 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
167 230 }
168 231
169   - protected void validateTwoWayRpcGateway(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception {
  232 + protected void validateJsonTwoWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception {
170 233 publishMqttMsg(client, payloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC);
171 234
172 235 Device savedDevice = doExecuteWithRetriesAndInterval(
... ... @@ -177,7 +240,34 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
177 240 assertNotNull(savedDevice);
178 241
179 242 CountDownLatch latch = new CountDownLatch(1);
180   - TestMqttCallback callback = new TestMqttCallback(client, latch);
  243 + TestJsonMqttCallback callback = new TestJsonMqttCallback(client, latch);
  244 + client.setCallback(callback);
  245 +
  246 + client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value());
  247 +
  248 + Thread.sleep(1000);
  249 +
  250 + String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}";
  251 + String deviceId = savedDevice.getId().getId().toString();
  252 + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  253 + latch.await(3, TimeUnit.SECONDS);
  254 + String expected = "{\"success\":true}";
  255 + assertEquals(expected, result);
  256 + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
  257 + }
  258 +
  259 + protected void validateProtoTwoWayRpcGatewayResponse(String deviceName, MqttAsyncClient client, byte[] payloadBytes) throws Exception {
  260 + publishMqttMsg(client, payloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC);
  261 +
  262 + Device savedDevice = doExecuteWithRetriesAndInterval(
  263 + () -> getDeviceByName(deviceName),
  264 + 20,
  265 + 100
  266 + );
  267 + assertNotNull(savedDevice);
  268 +
  269 + CountDownLatch latch = new CountDownLatch(1);
  270 + TestProtoMqttCallback callback = new TestProtoMqttCallback(client, latch);
181 271 client.setCallback(callback);
182 272
183 273 client.subscribe(MqttTopics.GATEWAY_RPC_TOPIC, MqttQoS.AT_MOST_ONCE.value());
... ... @@ -197,7 +287,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
197 287 return doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class);
198 288 }
199 289
200   - protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException {
  290 + protected MqttMessage processJsonMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException {
201 291 MqttMessage message = new MqttMessage();
202 292 if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) {
203 293 message.setPayload(DEVICE_RESPONSE.getBytes(StandardCharset.UTF_8));
... ... @@ -210,13 +300,45 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
210 300 return message;
211 301 }
212 302
213   - protected class TestMqttCallback implements MqttCallback {
  303 + protected class TestOneWayMqttCallback implements MqttCallback {
  304 +
  305 + private final MqttAsyncClient client;
  306 + private final CountDownLatch latch;
  307 + private Integer qoS;
  308 +
  309 + TestOneWayMqttCallback(MqttAsyncClient client, CountDownLatch latch) {
  310 + this.client = client;
  311 + this.latch = latch;
  312 + }
  313 +
  314 + int getQoS() {
  315 + return qoS;
  316 + }
  317 +
  318 + @Override
  319 + public void connectionLost(Throwable throwable) {
  320 + }
  321 +
  322 + @Override
  323 + public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception {
  324 + log.info("Message Arrived: " + Arrays.toString(mqttMessage.getPayload()));
  325 + qoS = mqttMessage.getQos();
  326 + latch.countDown();
  327 + }
  328 +
  329 + @Override
  330 + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
  331 +
  332 + }
  333 + }
  334 +
  335 + protected class TestJsonMqttCallback implements MqttCallback {
214 336
215 337 private final MqttAsyncClient client;
216 338 private final CountDownLatch latch;
217 339 private Integer qoS;
218 340
219   - TestMqttCallback(MqttAsyncClient client, CountDownLatch latch) {
  341 + TestJsonMqttCallback(MqttAsyncClient client, CountDownLatch latch) {
220 342 this.client = client;
221 343 this.latch = latch;
222 344 }
... ... @@ -239,7 +361,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
239 361 responseTopic = requestTopic.replace("request", "response");
240 362 }
241 363 qoS = mqttMessage.getQos();
242   - client.publish(responseTopic, processMessageArrived(requestTopic, mqttMessage));
  364 + client.publish(responseTopic, processJsonMessageArrived(requestTopic, mqttMessage));
243 365 latch.countDown();
244 366 }
245 367
... ... @@ -249,6 +371,98 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
249 371 }
250 372 }
251 373
  374 + protected class TestProtoMqttCallback implements MqttCallback {
  375 +
  376 + private final MqttAsyncClient client;
  377 + private final CountDownLatch latch;
  378 + private Integer qoS;
  379 +
  380 + TestProtoMqttCallback(MqttAsyncClient client, CountDownLatch latch) {
  381 + this.client = client;
  382 + this.latch = latch;
  383 + }
  384 +
  385 + int getQoS() {
  386 + return qoS;
  387 + }
  388 +
  389 + @Override
  390 + public void connectionLost(Throwable throwable) {
  391 + }
  392 +
  393 + @Override
  394 + public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception {
  395 + log.info("Message Arrived: " + Arrays.toString(mqttMessage.getPayload()));
  396 + String responseTopic;
  397 + if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) {
  398 + responseTopic = requestTopic.replace("req", "res");
  399 + } else {
  400 + responseTopic = requestTopic.replace("request", "response");
  401 + }
  402 + qoS = mqttMessage.getQos();
  403 + client.publish(responseTopic, processProtoMessageArrived(requestTopic, mqttMessage));
  404 + latch.countDown();
  405 + }
  406 +
  407 + @Override
  408 + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
  409 +
  410 + }
  411 + }
  412 +
  413 + protected MqttMessage processProtoMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException {
  414 + MqttMessage message = new MqttMessage();
  415 + if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) {
  416 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration();
  417 + ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA);
  418 + DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA);
  419 +
  420 + byte[] requestPayload = mqttMessage.getPayload();
  421 + DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg");
  422 + Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType();
  423 + assertNotNull(rpcRequestMsgDescriptor);
  424 + try {
  425 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload);
  426 + List<Descriptors.FieldDescriptor> fields = rpcRequestMsgDescriptor.getFields();
  427 + for (Descriptors.FieldDescriptor fieldDescriptor: fields) {
  428 + assertTrue(dynamicMessage.hasField(fieldDescriptor));
  429 + }
  430 + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA);
  431 + DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA);
  432 +
  433 + DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg");
  434 + Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType();
  435 + assertNotNull(rpcResponseMsgDescriptor);
  436 + DynamicMessage rpcResponseMsg = rpcResponseBuilder
  437 + .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE)
  438 + .build();
  439 + message.setPayload(rpcResponseMsg.toByteArray());
  440 + } catch (InvalidProtocolBufferException e) {
  441 + log.warn("Command Response Ack Error, Invalid response received: ", e);
  442 + }
  443 + } else {
  444 + TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload());
  445 + String deviceName = msg.getDeviceName();
  446 + int requestId = msg.getRpcRequestMsg().getRequestId();
  447 + TransportApiProtos.GatewayRpcResponseMsg gatewayRpcResponseMsg = TransportApiProtos.GatewayRpcResponseMsg.newBuilder()
  448 + .setDeviceName(deviceName)
  449 + .setId(requestId)
  450 + .setData("{\"success\": true}")
  451 + .build();
  452 + message.setPayload(gatewayRpcResponseMsg.toByteArray());
  453 + }
  454 + return message;
  455 + }
  456 +
  457 + private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() {
  458 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  459 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  460 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  461 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  462 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  463 + return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  464 + }
  465 +
252 466 protected class TestSequenceMqttCallback implements MqttCallback {
253 467
254 468 private final MqttAsyncClient client;
... ... @@ -273,7 +487,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
273 487 var qoS = mqttMessage.getQos();
274 488
275 489 client.messageArrivedComplete(mqttMessage.getId(), qoS);
276   - client.publish(responseTopic, processMessageArrived(requestTopic, mqttMessage));
  490 + client.publish(responseTopic, processJsonMessageArrived(requestTopic, mqttMessage));
277 491 latch.countDown();
278 492 }
279 493
... ...
... ... @@ -53,30 +53,30 @@ public abstract class AbstractMqttServerSideRpcJsonIntegrationTest extends Abstr
53 53
54 54 @Test
55 55 public void testServerMqttTwoWayRpc() throws Exception {
56   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  56 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
57 57 }
58 58
59 59 @Test
60 60 public void testServerMqttTwoWayRpcOnShortTopic() throws Exception {
61   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
  61 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
62 62 }
63 63
64 64 @Test
65 65 public void testServerMqttTwoWayRpcOnShortJsonTopic() throws Exception {
66   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC);
  66 + processJsonTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC);
67 67 }
68 68
69 69 @Test
70 70 public void testGatewayServerMqttOneWayRpc() throws Exception {
71   - processOneWayRpcTestGateway("Gateway Device OneWay RPC Json");
  71 + processJsonOneWayRpcTestGateway("Gateway Device OneWay RPC Json");
72 72 }
73 73
74 74 @Test
75 75 public void testGatewayServerMqttTwoWayRpc() throws Exception {
76   - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Json");
  76 + processJsonTwoWayRpcTestGateway("Gateway Device TwoWay RPC Json");
77 77 }
78 78
79   - protected void processOneWayRpcTestGateway(String deviceName) throws Exception {
  79 + protected void processJsonOneWayRpcTestGateway(String deviceName) throws Exception {
80 80 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
81 81 String payload = "{\"device\": \"" + deviceName + "\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}";
82 82 byte[] payloadBytes = payload.getBytes();
... ...
... ... @@ -15,60 +15,20 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.rpc;
17 17
18   -import com.github.os72.protobuf.dynamic.DynamicSchema;
19   -import com.google.protobuf.Descriptors;
20   -import com.google.protobuf.DynamicMessage;
21   -import com.google.protobuf.InvalidProtocolBufferException;
22   -import com.squareup.wire.schema.internal.parser.ProtoFileElement;
23 18 import lombok.extern.slf4j.Slf4j;
24   -import org.eclipse.californium.core.CoapHandler;
25   -import org.eclipse.californium.core.CoapResponse;
26   -import org.eclipse.californium.core.coap.MediaTypeRegistry;
27   -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
28   -import org.eclipse.paho.client.mqttv3.MqttException;
29   -import org.eclipse.paho.client.mqttv3.MqttMessage;
30   -import org.jetbrains.annotations.NotNull;
31 19 import org.junit.After;
32   -import org.junit.Assert;
33 20 import org.junit.Before;
34 21 import org.junit.Test;
35 22 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
36 23 import org.thingsboard.server.common.data.TransportPayloadType;
37   -import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
38   -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
39 24 import org.thingsboard.server.common.data.device.profile.MqttTopics;
40   -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
41   -import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
42   -import org.thingsboard.server.gen.transport.TransportApiProtos;
43   -
44   -import java.util.List;
45   -import java.util.concurrent.CountDownLatch;
46   -import java.util.concurrent.TimeUnit;
47   -
48   -import static org.junit.Assert.assertNotNull;
49   -import static org.junit.Assert.assertTrue;
50   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
51 25
52 26 @Slf4j
53 27 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest {
54 28
55   - private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
56   - "package rpc;\n" +
57   - "\n" +
58   - "message RpcRequestMsg {\n" +
59   - " optional string method = 1;\n" +
60   - " optional int32 requestId = 2;\n" +
61   - " Params params = 3;\n" +
62   - "\n" +
63   - " message Params {\n" +
64   - " optional string pin = 1;\n" +
65   - " optional int32 value = 2;\n" +
66   - " }\n" +
67   - "}";
68   -
69 29 @Before
70 30 public void beforeTest() throws Exception {
71   - processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED);
  31 + processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED, false, false);
72 32 }
73 33
74 34 @After
... ... @@ -93,122 +53,27 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst
93 53
94 54 @Test
95 55 public void testServerMqttTwoWayRpc() throws Exception {
96   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
  56 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC);
97 57 }
98 58
99 59 @Test
100 60 public void testServerMqttTwoWayRpcOnShortTopic() throws Exception {
101   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
  61 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC);
102 62 }
103 63
104 64 @Test
105 65 public void testServerMqttTwoWayRpcOnShortProtoTopic() throws Exception {
106   - processTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC);
  66 + processProtoTwoWayRpcTest(MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC);
107 67 }
108 68
109 69 @Test
110 70 public void testGatewayServerMqttOneWayRpc() throws Exception {
111   - processOneWayRpcTestGateway("Gateway Device OneWay RPC Proto");
  71 + processProtoOneWayRpcTestGateway("Gateway Device OneWay RPC Proto");
112 72 }
113 73
114 74 @Test
115 75 public void testGatewayServerMqttTwoWayRpc() throws Exception {
116   - processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto");
117   - }
118   -
119   - protected void processTwoWayRpcTestGateway(String deviceName) throws Exception {
120   - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
121   - TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
122   - byte[] payloadBytes = connectMsgProto.toByteArray();
123   - validateTwoWayRpcGateway(deviceName, client, payloadBytes);
124   - }
125   -
126   - protected void processOneWayRpcTestGateway(String deviceName) throws Exception {
127   - MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
128   - TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
129   - byte[] payloadBytes = connectMsgProto.toByteArray();
130   - validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes);
131   - }
132   -
133   -
134   - private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) {
135   - TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder();
136   - builder.setDeviceName(deviceName);
137   - builder.setDeviceType(TransportPayloadType.PROTOBUF.name());
138   - return builder.build();
  76 + processProtoTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto");
139 77 }
140 78
141   - protected void processTwoWayRpcTest(String rpcSubTopic) throws Exception {
142   - MqttAsyncClient client = getMqttAsyncClient(accessToken);
143   - client.subscribe(rpcSubTopic, 1);
144   -
145   - CountDownLatch latch = new CountDownLatch(1);
146   - TestMqttCallback callback = new TestMqttCallback(client, latch);
147   - client.setCallback(callback);
148   -
149   - Thread.sleep(1000);
150   -
151   - String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
152   - String deviceId = savedDevice.getId().getId().toString();
153   -
154   - String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
155   - String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}";
156   - latch.await(3, TimeUnit.SECONDS);
157   - Assert.assertEquals(expected, result);
158   - }
159   -
160   - protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException {
161   - MqttMessage message = new MqttMessage();
162   - if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC) || requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC_V2)) {
163   - ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration();
164   - ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA);
165   - DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA);
166   -
167   - byte[] requestPayload = mqttMessage.getPayload();
168   - DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg");
169   - Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType();
170   - assertNotNull(rpcRequestMsgDescriptor);
171   - try {
172   - DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload);
173   - List<Descriptors.FieldDescriptor> fields = rpcRequestMsgDescriptor.getFields();
174   - for (Descriptors.FieldDescriptor fieldDescriptor: fields) {
175   - assertTrue(dynamicMessage.hasField(fieldDescriptor));
176   - }
177   - ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA);
178   - DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA);
179   -
180   - DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg");
181   - Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType();
182   - assertNotNull(rpcResponseMsgDescriptor);
183   - DynamicMessage rpcResponseMsg = rpcResponseBuilder
184   - .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE)
185   - .build();
186   - message.setPayload(rpcResponseMsg.toByteArray());
187   - } catch (InvalidProtocolBufferException e) {
188   - log.warn("Command Response Ack Error, Invalid response received: ", e);
189   - }
190   - } else {
191   - TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload());
192   - String deviceName = msg.getDeviceName();
193   - int requestId = msg.getRpcRequestMsg().getRequestId();
194   - TransportApiProtos.GatewayRpcResponseMsg gatewayRpcResponseMsg = TransportApiProtos.GatewayRpcResponseMsg.newBuilder()
195   - .setDeviceName(deviceName)
196   - .setId(requestId)
197   - .setData("{\"success\": true}")
198   - .build();
199   - message.setPayload(gatewayRpcResponseMsg.toByteArray());
200   - }
201   - return message;
202   - }
203   -
204   - private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() {
205   - DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
206   - assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
207   - MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
208   - TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
209   - assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
210   - return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
211   - }
212   -
213   -
214 79 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.rpc.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.DaoSqlTest;
  19 +import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest;
  20 +
  21 +
  22 +@DaoSqlTest
  23 +public class MqttServerSideRpcBackwardCompatibilityIntegrationTest extends AbstractMqttServerSideRpcBackwardCompatibilityIntegrationTest {
  24 +}
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java
... ... @@ -22,5 +22,5 @@ import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcDefaul
22 22 * Created by Valerii Sosliuk on 8/22/2017.
23 23 */
24 24 @DaoSqlTest
25   -public class MqttServerSideRpcSqlIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest {
  25 +public class MqttServerSideRpcIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest {
26 26 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcJsonSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttServerSideRpcJsonSqlIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest {
  22 +public class MqttServerSideRpcJsonIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoSqlIntegrationTest.java
... ... @@ -20,5 +20,5 @@ import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcProtoI
20 20
21 21
22 22 @DaoSqlTest
23   -public class MqttServerSideRpcProtoSqlIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest {
  23 +public class MqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest {
24 24 }
... ...
... ... @@ -55,6 +55,12 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac
55 55 }
56 56
57 57 @Test
  58 + public void testPushAttributesWithEnabledJsonBackwardCompatibility() throws Exception {
  59 + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC, true, false);
  60 + processJsonPayloadAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes());
  61 + }
  62 +
  63 + @Test
58 64 public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception {
59 65 super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC);
60 66 DynamicSchema attributesSchema = getDynamicSchema();
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest {
  22 +public class MqttAttributesIntegrationTest extends AbstractMqttAttributesIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesJsonIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlJsonIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest {
  22 +public class MqttAttributesJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest {
23 23 }
... ...
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesProtoIntegrationTest.java renamed from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/sql/MqttAttributesSqlProtoIntegrationTest.java
... ... @@ -19,5 +19,5 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
19 19 import org.thingsboard.server.transport.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
20 20
21 21 @DaoSqlTest
22   -public class MqttAttributesSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest {
  22 +public class MqttAttributesProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest {
23 23 }
... ...
... ... @@ -21,9 +21,7 @@ import com.google.protobuf.DynamicMessage;
21 21 import com.squareup.wire.schema.internal.parser.ProtoFileElement;
22 22 import lombok.extern.slf4j.Slf4j;
23 23 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
24   -import org.jetbrains.annotations.NotNull;
25 24 import org.junit.After;
26   -import org.junit.Ignore;
27 25 import org.junit.Test;
28 26 import org.thingsboard.server.common.data.Device;
29 27 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
... ... @@ -37,7 +35,6 @@ import org.thingsboard.server.gen.transport.TransportApiProtos;
37 35 import org.thingsboard.server.gen.transport.TransportProtos;
38 36
39 37 import java.util.Arrays;
40   -import java.util.Collections;
41 38 import java.util.List;
42 39
43 40 import static org.junit.Assert.assertNotNull;
... ... @@ -61,6 +58,12 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
61 58 }
62 59
63 60 @Test
  61 + public void testPushTelemetryWithEnabledJsonBackwardCompatibility() throws Exception {
  62 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, true, false);
  63 + processJsonPayloadTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes(), false);
  64 + }
  65 +
  66 + @Test
64 67 public void testPushTelemetryWithTs() throws Exception {
65 68 String schemaStr = "syntax =\"proto3\";\n" +
66 69 "\n" +
... ... @@ -87,7 +90,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
87 90 " }\n" +
88 91 " }\n" +
89 92 "}";
90   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  93 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
91 94 DynamicSchema telemetrySchema = getDynamicSchema(schemaStr);
92 95
93 96 DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
... ... @@ -189,7 +192,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
189 192 " }\n" +
190 193 " }\n" +
191 194 "}";
192   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  195 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
193 196 DynamicSchema telemetrySchema = getDynamicSchema(schemaStr);
194 197
195 198 DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
... ... @@ -249,7 +252,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
249 252
250 253 @Test
251 254 public void testPushTelemetryGateway() throws Exception {
252   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  255 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
253 256 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder();
254 257 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
255 258 String deviceName1 = "Device A";
... ... @@ -263,7 +266,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
263 266
264 267 @Test
265 268 public void testGatewayConnect() throws Exception {
266   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
  269 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false);
267 270 String deviceName = "Device A";
268 271 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
269 272 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
... ...
... ... @@ -54,6 +54,9 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC
54 54 private String deviceRpcRequestProtoSchema;
55 55 private String deviceRpcResponseProtoSchema;
56 56
  57 + private boolean enableCompatibilityWithJsonPayloadFormat;
  58 + private boolean useJsonPayloadFormatForDefaultDownlinkTopics;
  59 +
57 60 @Override
58 61 public TransportPayloadType getTransportPayloadType() {
59 62 return TransportPayloadType.PROTOBUF;
... ...
... ... @@ -15,8 +15,9 @@
15 15 */
16 16 package org.thingsboard.server.common.data.edge;
17 17
  18 +import io.swagger.annotations.ApiModel;
  19 +import io.swagger.annotations.ApiModelProperty;
18 20 import lombok.EqualsAndHashCode;
19   -import lombok.Getter;
20 21 import lombok.Setter;
21 22 import lombok.ToString;
22 23 import org.thingsboard.server.common.data.HasCustomerId;
... ... @@ -28,9 +29,9 @@ import org.thingsboard.server.common.data.id.EdgeId;
28 29 import org.thingsboard.server.common.data.id.RuleChainId;
29 30 import org.thingsboard.server.common.data.id.TenantId;
30 31
  32 +@ApiModel
31 33 @EqualsAndHashCode(callSuper = true)
32 34 @ToString
33   -@Getter
34 35 @Setter
35 36 public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements HasName, HasTenantId, HasCustomerId {
36 37
... ... @@ -82,8 +83,77 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
82 83 this.cloudEndpoint = edge.getCloudEndpoint();
83 84 }
84 85
  86 + @ApiModelProperty(position = 1, value = "JSON object with the Edge Id. " +
  87 + "Specify this field to update the Edge. " +
  88 + "Referencing non-existing Edge Id will cause error. " +
  89 + "Omit this field to create new Edge." )
  90 + @Override
  91 + public EdgeId getId() {
  92 + return super.getId();
  93 + }
  94 +
  95 + @ApiModelProperty(position = 2, value = "Timestamp of the edge creation, in milliseconds", example = "1609459200000", readOnly = true)
  96 + @Override
  97 + public long getCreatedTime() {
  98 + return super.getCreatedTime();
  99 + }
  100 +
  101 + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Use 'assignDeviceToTenant' to change the Tenant Id.", readOnly = true)
  102 + @Override
  103 + public TenantId getTenantId() {
  104 + return this.tenantId;
  105 + }
  106 +
  107 + @ApiModelProperty(position = 4, value = "JSON object with Customer Id. Use 'assignEdgeToCustomer' to change the Customer Id.", readOnly = true)
  108 + @Override
  109 + public CustomerId getCustomerId() {
  110 + return this.customerId;
  111 + }
  112 +
  113 + @ApiModelProperty(position = 5, value = "JSON object with Root Rule Chain Id. Use 'setEdgeRootRuleChain' to change the Root Rule Chain Id.", readOnly = true)
  114 + public RuleChainId getRootRuleChainId() {
  115 + return this.rootRuleChainId;
  116 + }
  117 +
  118 + @ApiModelProperty(position = 6, required = true, value = "Unique Edge Name in scope of Tenant", example = "Silo_A_Edge")
  119 + @Override
  120 + public String getName() {
  121 + return this.name;
  122 + }
  123 +
  124 + @ApiModelProperty(position = 7, required = true, value = "Edge type", example = "Silos")
  125 + public String getType() {
  126 + return this.type;
  127 + }
  128 +
  129 + @ApiModelProperty(position = 8, value = "Label that may be used in widgets", example = "Silo Edge on far field")
  130 + public String getLabel() {
  131 + return this.label;
  132 + }
  133 +
85 134 @Override
86 135 public String getSearchText() {
87 136 return getName();
88 137 }
  138 +
  139 + @ApiModelProperty(position = 9, required = true, value = "Edge routing key ('username') to authorize on cloud")
  140 + public String getRoutingKey() {
  141 + return this.routingKey;
  142 + }
  143 +
  144 + @ApiModelProperty(position = 10, required = true, value = "Edge secret ('password') to authorize on cloud")
  145 + public String getSecret() {
  146 + return this.secret;
  147 + }
  148 +
  149 + @ApiModelProperty(position = 11, required = true, value = "Edge license key obtained from license portal", example = "AgcnI24Z06XC&m6Sxsdgf")
  150 + public String getEdgeLicenseKey() {
  151 + return this.edgeLicenseKey;
  152 + }
  153 +
  154 + @ApiModelProperty(position = 12, required = true, value = "Edge uses this cloud URL to activate and periodically check it's license", example = "https://thingsboard.cloud")
  155 + public String getCloudEndpoint() {
  156 + return this.cloudEndpoint;
  157 + }
  158 +
89 159 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.common.data.edge;
17 17
  18 +import io.swagger.annotations.ApiModelProperty;
18 19 import lombok.Data;
19 20 import org.thingsboard.server.common.data.EntityType;
20 21 import org.thingsboard.server.common.data.relation.EntityRelation;
... ... @@ -28,8 +29,11 @@ import java.util.List;
28 29 @Data
29 30 public class EdgeSearchQuery {
30 31
  32 + @ApiModelProperty(position = 3, value = "Main search parameters.")
31 33 private RelationsSearchParameters parameters;
  34 + @ApiModelProperty(position = 1, value = "Type of the relation between root entity and edge (e.g. 'Contains' or 'Manages').")
32 35 private String relationType;
  36 + @ApiModelProperty(position = 2, value = "Array of edge types to filter the related entities (e.g. 'Silos', 'Stores').")
33 37 private List<String> edgeTypes;
34 38
35 39 public EntityRelationsQuery toEntitySearchQuery() {
... ...
... ... @@ -965,26 +965,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
965 965 @Override
966 966 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) {
967 967 log.trace("[{}] Received get attributes response", sessionId);
968   - String topicBase;
969   - MqttTransportAdaptor adaptor;
970   - switch (attrReqTopicType) {
971   - case V2:
972   - adaptor = deviceSessionCtx.getPayloadAdaptor();
973   - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_TOPIC_PREFIX;
974   - break;
975   - case V2_JSON:
976   - adaptor = context.getJsonMqttAdaptor();
977   - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_JSON_TOPIC_PREFIX;
978   - break;
979   - case V2_PROTO:
980   - adaptor = context.getProtoMqttAdaptor();
981   - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_PROTO_TOPIC_PREFIX;
982   - break;
983   - default:
984   - adaptor = deviceSessionCtx.getPayloadAdaptor();
985   - topicBase = MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX;
986   - break;
987   - }
  968 + String topicBase = attrReqTopicType.getAttributesResponseTopicBase();
  969 + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrReqTopicType);
988 970 try {
989 971 adaptor.convertToPublish(deviceSessionCtx, response, topicBase).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
990 972 } catch (Exception e) {
... ... @@ -995,26 +977,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
995 977 @Override
996 978 public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) {
997 979 log.trace("[{}] Received attributes update notification to device", sessionId);
998   - String topic;
999   - MqttTransportAdaptor adaptor;
1000   - switch (attrSubTopicType) {
1001   - case V2:
1002   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1003   - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC;
1004   - break;
1005   - case V2_JSON:
1006   - adaptor = context.getJsonMqttAdaptor();
1007   - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC;
1008   - break;
1009   - case V2_PROTO:
1010   - adaptor = context.getProtoMqttAdaptor();
1011   - topic = MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC;
1012   - break;
1013   - default:
1014   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1015   - topic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC;
1016   - break;
1017   - }
  980 + String topic = attrSubTopicType.getAttributesSubTopic();
  981 + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(attrSubTopicType);
1018 982 try {
1019 983 adaptor.convertToPublish(deviceSessionCtx, notification, topic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
1020 984 } catch (Exception e) {
... ... @@ -1031,26 +995,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
1031 995 @Override
1032 996 public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
1033 997 log.trace("[{}] Received RPC command to device", sessionId);
1034   - String baseTopic;
1035   - MqttTransportAdaptor adaptor;
1036   - switch (rpcSubTopicType) {
1037   - case V2:
1038   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1039   - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC;
1040   - break;
1041   - case V2_JSON:
1042   - adaptor = context.getJsonMqttAdaptor();
1043   - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC;
1044   - break;
1045   - case V2_PROTO:
1046   - adaptor = context.getProtoMqttAdaptor();
1047   - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC;
1048   - break;
1049   - default:
1050   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1051   - baseTopic = MqttTopics.DEVICE_RPC_REQUESTS_TOPIC;
1052   - break;
1053   - }
  998 + String baseTopic = rpcSubTopicType.getRpcRequestTopicBase();
  999 + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(rpcSubTopicType);
1054 1000 try {
1055 1001 adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic).ifPresent(payload -> {
1056 1002 int msgId = ((MqttPublishMessage) payload).variableHeader().packetId();
... ... @@ -1087,26 +1033,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
1087 1033 @Override
1088 1034 public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) {
1089 1035 log.trace("[{}] Received RPC response from server", sessionId);
1090   - String baseTopic;
1091   - MqttTransportAdaptor adaptor;
1092   - switch (toServerRpcSubTopicType) {
1093   - case V2:
1094   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1095   - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC;
1096   - break;
1097   - case V2_JSON:
1098   - adaptor = context.getJsonMqttAdaptor();
1099   - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC;
1100   - break;
1101   - case V2_PROTO:
1102   - adaptor = context.getProtoMqttAdaptor();
1103   - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC;
1104   - break;
1105   - default:
1106   - adaptor = deviceSessionCtx.getPayloadAdaptor();
1107   - baseTopic = MqttTopics.DEVICE_RPC_RESPONSE_TOPIC;
1108   - break;
1109   - }
  1036 + String baseTopic = toServerRpcSubTopicType.getRpcResponseTopicBase();
  1037 + MqttTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(toServerRpcSubTopicType);
1110 1038 try {
1111 1039 adaptor.convertToPublish(deviceSessionCtx, rpcResponse, baseTopic).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
1112 1040 } catch (Exception e) {
... ... @@ -1132,8 +1060,4 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
1132 1060 deviceSessionCtx.onDeviceUpdate(sessionInfo, device, deviceProfileOpt);
1133 1061 }
1134 1062
1135   - private enum TopicType {
1136   - V1, V2, V2_JSON, V2_PROTO
1137   - }
1138   -
1139 1063 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt;
  17 +
  18 +import lombok.Getter;
  19 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  20 +
  21 +public enum TopicType {
  22 +
  23 + V1(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC),
  24 + V2(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC),
  25 + V2_JSON(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_JSON_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC),
  26 + V2_PROTO(MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_SHORT_PROTO_TOPIC_PREFIX, MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC);
  27 +
  28 + @Getter
  29 + private final String attributesResponseTopicBase;
  30 +
  31 + @Getter
  32 + private final String attributesSubTopic;
  33 +
  34 + @Getter
  35 + private final String rpcRequestTopicBase;
  36 +
  37 + @Getter
  38 + private final String rpcResponseTopicBase;
  39 +
  40 + TopicType(String attributesRequestTopicBase, String attributesSubTopic, String rpcRequestTopicBase, String rpcResponseTopicBase) {
  41 + this.attributesResponseTopicBase = attributesRequestTopicBase;
  42 + this.attributesSubTopic = attributesSubTopic;
  43 + this.rpcRequestTopicBase = rpcRequestTopicBase;
  44 + this.rpcResponseTopicBase = rpcResponseTopicBase;
  45 + }
  46 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.mqtt.adaptors;
  17 +
  18 +import io.netty.handler.codec.mqtt.MqttMessage;
  19 +import io.netty.handler.codec.mqtt.MqttPublishMessage;
  20 +import lombok.AllArgsConstructor;
  21 +import lombok.Data;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.thingsboard.server.common.data.ota.OtaPackageType;
  24 +import org.thingsboard.server.common.transport.adaptor.AdaptorException;
  25 +import org.thingsboard.server.gen.transport.TransportProtos;
  26 +import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext;
  27 +
  28 +import java.util.Optional;
  29 +
  30 +@Data
  31 +@AllArgsConstructor
  32 +@Slf4j
  33 +public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor {
  34 +
  35 + private MqttTransportAdaptor protoAdaptor;
  36 + private MqttTransportAdaptor jsonAdaptor;
  37 +
  38 + @Override
  39 + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  40 + try {
  41 + return protoAdaptor.convertToPostTelemetry(ctx, inbound);
  42 + } catch (AdaptorException e) {
  43 + log.trace("[{}] failed to process post telemetry request msg: {} due to: ", ctx.getSessionId(), inbound, e);
  44 + return jsonAdaptor.convertToPostTelemetry(ctx, inbound);
  45 + }
  46 + }
  47 +
  48 + @Override
  49 + public TransportProtos.PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  50 + try {
  51 + return protoAdaptor.convertToPostAttributes(ctx, inbound);
  52 + } catch (AdaptorException e) {
  53 + log.trace("[{}] failed to process post attributes request msg: {} due to: ", ctx.getSessionId(), inbound, e);
  54 + return jsonAdaptor.convertToPostAttributes(ctx, inbound);
  55 + }
  56 + }
  57 +
  58 + @Override
  59 + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException {
  60 + try {
  61 + return protoAdaptor.convertToGetAttributes(ctx, inbound, topicBase);
  62 + } catch (AdaptorException e) {
  63 + log.trace("[{}] failed to process get attributes request msg: {} due to: ", ctx.getSessionId(), inbound, e);
  64 + return jsonAdaptor.convertToGetAttributes(ctx, inbound, topicBase);
  65 + }
  66 + }
  67 +
  68 + @Override
  69 + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException {
  70 + try {
  71 + return protoAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase);
  72 + } catch (AdaptorException e) {
  73 + log.trace("[{}] failed to process to device rpc response msg: {} due to: ", ctx.getSessionId(), mqttMsg, e);
  74 + return jsonAdaptor.convertToDeviceRpcResponse(ctx, mqttMsg, topicBase);
  75 + }
  76 + }
  77 +
  78 + @Override
  79 + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(MqttDeviceAwareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException {
  80 + try {
  81 + return protoAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase);
  82 + } catch (AdaptorException e) {
  83 + log.trace("[{}] failed to process to server rpc request msg: {} due to: ", ctx.getSessionId(), mqttMsg, e);
  84 + return jsonAdaptor.convertToServerRpcRequest(ctx, mqttMsg, topicBase);
  85 + }
  86 + }
  87 +
  88 + @Override
  89 + public TransportProtos.ClaimDeviceMsg convertToClaimDevice(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  90 + try {
  91 + return protoAdaptor.convertToClaimDevice(ctx, inbound);
  92 + } catch (AdaptorException e) {
  93 + log.trace("[{}] failed to process claim device request msg: {} due to: ", ctx.getSessionId(), inbound, e);
  94 + return jsonAdaptor.convertToClaimDevice(ctx, inbound);
  95 + }
  96 + }
  97 +
  98 + @Override
  99 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException {
  100 + log.warn("[{}] invoked not implemented adaptor method! GetAttributeResponseMsg: {} TopicBase: {}", ctx.getSessionId(), responseMsg, topicBase);
  101 + return Optional.empty();
  102 + }
  103 +
  104 + @Override
  105 + public Optional<MqttMessage> convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
  106 + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, responseMsg);
  107 + }
  108 +
  109 + @Override
  110 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException {
  111 + log.warn("[{}] invoked not implemented adaptor method! AttributeUpdateNotificationMsg: {} Topic: {}", ctx.getSessionId(), notificationMsg, topic);
  112 + return Optional.empty();
  113 + }
  114 +
  115 + @Override
  116 + public Optional<MqttMessage> convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException {
  117 + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, notificationMsg);
  118 + }
  119 +
  120 + @Override
  121 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException {
  122 + log.warn("[{}] invoked not implemented adaptor method! ToDeviceRpcRequestMsg: {} TopicBase: {}", ctx.getSessionId(), rpcRequest, topicBase);
  123 + return Optional.empty();
  124 + }
  125 +
  126 + @Override
  127 + public Optional<MqttMessage> convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException {
  128 + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, rpcRequest);
  129 + }
  130 +
  131 + @Override
  132 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException {
  133 + log.warn("[{}] invoked not implemented adaptor method! ToServerRpcResponseMsg: {} TopicBase: {}", ctx.getSessionId(), rpcResponse, topicBase);
  134 + return Optional.empty();
  135 + }
  136 +
  137 + @Override
  138 + public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
  139 + log.warn("[{}] invoked not implemented adaptor method! MqttPublishMessage: {}", ctx.getSessionId(), inbound);
  140 + return null;
  141 + }
  142 +
  143 + @Override
  144 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException {
  145 + log.warn("[{}] invoked not implemented adaptor method! ProvisionDeviceResponseMsg: {}", ctx.getSessionId(), provisionResponse);
  146 + return Optional.empty();
  147 + }
  148 +
  149 + @Override
  150 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException {
  151 + return protoAdaptor.convertToPublish(ctx, firmwareChunk, requestId, chunk, firmwareType);
  152 + }
  153 +}
... ...
... ... @@ -32,13 +32,14 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
32 32 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
33 33 import org.thingsboard.server.gen.transport.TransportProtos;
34 34 import org.thingsboard.server.transport.mqtt.MqttTransportContext;
  35 +import org.thingsboard.server.transport.mqtt.TopicType;
  36 +import org.thingsboard.server.transport.mqtt.adaptors.BackwardCompatibilityAdaptor;
35 37 import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
36 38 import org.thingsboard.server.transport.mqtt.util.MqttTopicFilter;
37 39 import org.thingsboard.server.transport.mqtt.util.MqttTopicFilterFactory;
38 40
39 41 import java.util.Collection;
40 42 import java.util.Collections;
41   -import java.util.Queue;
42 43 import java.util.UUID;
43 44 import java.util.concurrent.ConcurrentLinkedQueue;
44 45 import java.util.concurrent.ConcurrentMap;
... ... @@ -80,6 +81,9 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
80 81 private volatile Descriptors.Descriptor telemetryDynamicMessageDescriptor;
81 82 private volatile Descriptors.Descriptor rpcResponseDynamicMessageDescriptor;
82 83 private volatile DynamicMessage.Builder rpcRequestDynamicMessageBuilder;
  84 + private volatile MqttTransportAdaptor adaptor;
  85 + private volatile boolean jsonPayloadFormatCompatibilityEnabled;
  86 + private volatile boolean useJsonPayloadFormatForDefaultDownlinkTopics;
83 87
84 88 @Getter
85 89 @Setter
... ... @@ -88,6 +92,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
88 92 public DeviceSessionCtx(UUID sessionId, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap, MqttTransportContext context) {
89 93 super(sessionId, mqttQoSMap);
90 94 this.context = context;
  95 + this.adaptor = context.getJsonMqttAdaptor();
91 96 }
92 97
93 98 public int nextMsgId() {
... ... @@ -103,7 +108,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
103 108 }
104 109
105 110 public MqttTransportAdaptor getPayloadAdaptor() {
106   - return payloadType.equals(TransportPayloadType.JSON) ? context.getJsonMqttAdaptor() : context.getProtoMqttAdaptor();
  111 + return adaptor;
107 112 }
108 113
109 114 public boolean isJsonPayloadType() {
... ... @@ -129,16 +134,16 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
129 134 @Override
130 135 public void setDeviceProfile(DeviceProfile deviceProfile) {
131 136 super.setDeviceProfile(deviceProfile);
132   - updateTopicFilters(deviceProfile);
  137 + updateDeviceSessionConfiguration(deviceProfile);
133 138 }
134 139
135 140 @Override
136 141 public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
137 142 super.onDeviceProfileUpdate(sessionInfo, deviceProfile);
138   - updateTopicFilters(deviceProfile);
  143 + updateDeviceSessionConfiguration(deviceProfile);
139 144 }
140 145
141   - private void updateTopicFilters(DeviceProfile deviceProfile) {
  146 + private void updateDeviceSessionConfiguration(DeviceProfile deviceProfile) {
142 147 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
143 148 if (transportConfiguration.getType().equals(DeviceTransportType.MQTT) &&
144 149 transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) {
... ... @@ -148,22 +153,57 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
148 153 telemetryTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceTelemetryTopic());
149 154 attributesTopicFilter = MqttTopicFilterFactory.toFilter(mqttConfig.getDeviceAttributesTopic());
150 155 if (TransportPayloadType.PROTOBUF.equals(payloadType)) {
151   - updateDynamicMessageDescriptors(transportPayloadTypeConfiguration);
  156 + ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  157 + updateDynamicMessageDescriptors(protoTransportPayloadConfig);
  158 + jsonPayloadFormatCompatibilityEnabled = protoTransportPayloadConfig.isEnableCompatibilityWithJsonPayloadFormat();
  159 + useJsonPayloadFormatForDefaultDownlinkTopics = jsonPayloadFormatCompatibilityEnabled && protoTransportPayloadConfig.isUseJsonPayloadFormatForDefaultDownlinkTopics();
152 160 }
153 161 } else {
154 162 telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter();
155 163 attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter();
  164 + payloadType = TransportPayloadType.JSON;
156 165 }
  166 + updateAdaptor();
157 167 }
158 168
159   - private void updateDynamicMessageDescriptors(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) {
160   - ProtoTransportPayloadConfiguration protoTransportPayloadConfig = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  169 + private void updateDynamicMessageDescriptors(ProtoTransportPayloadConfiguration protoTransportPayloadConfig) {
161 170 telemetryDynamicMessageDescriptor = protoTransportPayloadConfig.getTelemetryDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceTelemetryProtoSchema());
162 171 attributesDynamicMessageDescriptor = protoTransportPayloadConfig.getAttributesDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceAttributesProtoSchema());
163 172 rpcResponseDynamicMessageDescriptor = protoTransportPayloadConfig.getRpcResponseDynamicMessageDescriptor(protoTransportPayloadConfig.getDeviceRpcResponseProtoSchema());
164 173 rpcRequestDynamicMessageBuilder = protoTransportPayloadConfig.getRpcRequestDynamicMessageBuilder(protoTransportPayloadConfig.getDeviceRpcRequestProtoSchema());
165 174 }
166 175
  176 + public MqttTransportAdaptor getAdaptor(TopicType topicType) {
  177 + switch (topicType) {
  178 + case V2:
  179 + return getDefaultAdaptor();
  180 + case V2_JSON:
  181 + return context.getJsonMqttAdaptor();
  182 + case V2_PROTO:
  183 + return context.getProtoMqttAdaptor();
  184 + default:
  185 + return useJsonPayloadFormatForDefaultDownlinkTopics ? context.getJsonMqttAdaptor() : getDefaultAdaptor();
  186 + }
  187 + }
  188 +
  189 + private MqttTransportAdaptor getDefaultAdaptor() {
  190 + return isJsonPayloadType() ? context.getJsonMqttAdaptor() : context.getProtoMqttAdaptor();
  191 + }
  192 +
  193 + private void updateAdaptor() {
  194 + if (isJsonPayloadType()) {
  195 + adaptor = context.getJsonMqttAdaptor();
  196 + jsonPayloadFormatCompatibilityEnabled = false;
  197 + useJsonPayloadFormatForDefaultDownlinkTopics = false;
  198 + } else {
  199 + if (jsonPayloadFormatCompatibilityEnabled) {
  200 + adaptor = new BackwardCompatibilityAdaptor(context.getProtoMqttAdaptor(), context.getJsonMqttAdaptor());
  201 + } else {
  202 + adaptor = context.getProtoMqttAdaptor();
  203 + }
  204 + }
  205 + }
  206 +
167 207 public void addToQueue(MqttMessage msg) {
168 208 msgQueueSize.incrementAndGet();
169 209 ReferenceCountUtil.retain(msg);
... ...
... ... @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.apache.commons.lang3.StringUtils;
21 21 import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.beans.factory.annotation.Value;
22 23 import org.springframework.stereotype.Service;
23 24 import org.thingsboard.server.common.data.Tenant;
24 25 import org.thingsboard.server.common.data.TenantInfo;
... ... @@ -55,6 +56,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
55 56 private static final String DEFAULT_TENANT_REGION = "Global";
56 57 public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
57 58
  59 + @Value("${zk.enabled}")
  60 + private Boolean zkEnabled;
  61 +
58 62 @Autowired
59 63 private TenantDao tenantDao;
60 64
... ... @@ -190,6 +194,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
190 194 if (!StringUtils.isEmpty(tenant.getEmail())) {
191 195 validateEmail(tenant.getEmail());
192 196 }
  197 + validateTenantProfile(tenantId, tenant);
193 198 }
194 199
195 200 @Override
... ... @@ -198,6 +203,14 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
198 203 if (old == null) {
199 204 throw new DataValidationException("Can't update non existing tenant!");
200 205 }
  206 + validateTenantProfile(tenantId, tenant);
  207 + }
  208 +
  209 + private void validateTenantProfile(TenantId tenantId, Tenant tenant) {
  210 + TenantProfile tenantProfileById = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId());
  211 + if (!zkEnabled && (tenantProfileById.isIsolatedTbCore() || tenantProfileById.isIsolatedTbRuleEngine())) {
  212 + throw new DataValidationException("Can't use isolated tenant profiles in monolith setup!");
  213 + }
201 214 }
202 215 };
203 216
... ...
... ... @@ -20,8 +20,12 @@ import org.junit.Assert;
20 20 import org.junit.Test;
21 21 import org.thingsboard.server.common.data.Tenant;
22 22 import org.thingsboard.server.common.data.TenantInfo;
  23 +import org.thingsboard.server.common.data.TenantProfile;
  24 +import org.thingsboard.server.common.data.id.TenantId;
23 25 import org.thingsboard.server.common.data.page.PageData;
24 26 import org.thingsboard.server.common.data.page.PageLink;
  27 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
  28 +import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
25 29 import org.thingsboard.server.dao.exception.DataValidationException;
26 30
27 31 import java.util.ArrayList;
... ... @@ -253,4 +257,22 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
253 257 Assert.assertTrue(pageData.getData().isEmpty());
254 258
255 259 }
  260 +
  261 + @Test(expected = DataValidationException.class)
  262 + public void testSaveTenantWithIsolatedProfileInMonolithSetup() {
  263 + TenantProfile tenantProfile = new TenantProfile();
  264 + tenantProfile.setName("Isolated Tenant Profile");
  265 + TenantProfileData profileData = new TenantProfileData();
  266 + profileData.setConfiguration(new DefaultTenantProfileConfiguration());
  267 + tenantProfile.setProfileData(profileData);
  268 + tenantProfile.setDefault(false);
  269 + tenantProfile.setIsolatedTbCore(true);
  270 + tenantProfile.setIsolatedTbRuleEngine(true);
  271 + TenantProfile isolatedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
  272 +
  273 + Tenant tenant = new Tenant();
  274 + tenant.setTitle("Tenant");
  275 + tenant.setTenantProfileId(isolatedTenantProfile.getId());
  276 + tenantService.saveTenant(tenant);
  277 + }
256 278 }
... ...
... ... @@ -71,7 +71,7 @@ public class RestJsonConverter {
71 71 }
72 72
73 73 private static KvEntry parseValue(String key, JsonNode value) {
74   - if (!value.isObject()) {
  74 + if (!value.isContainerNode()) {
75 75 if (value.isBoolean()) {
76 76 return new BooleanDataEntry(key, value.asBoolean());
77 77 } else if (value.isNumber()) {
... ...
... ... @@ -138,7 +138,11 @@ public class TbSendRPCRequestNode implements TbNode {
138 138 }
139 139
140 140 private String parseJsonData(JsonElement paramsEl) {
141   - return paramsEl.isJsonPrimitive() ? paramsEl.getAsString() : gson.toJson(paramsEl);
  141 + if (paramsEl != null) {
  142 + return paramsEl.isJsonPrimitive() ? paramsEl.getAsString() : gson.toJson(paramsEl);
  143 + } else {
  144 + return null;
  145 + }
142 146 }
143 147
144 148 }
... ...
... ... @@ -73,6 +73,18 @@
73 73 {{ 'device-profile.mqtt-payload-type-required' | translate }}
74 74 </mat-error>
75 75 </mat-form-field>
  76 + <div *ngIf="protoPayloadType" style="padding-bottom: 20px">
  77 + <mat-checkbox formControlName="enableCompatibilityWithJsonPayloadFormat">
  78 + {{ 'device-profile.mqtt-enable-compatibility-with-json-payload-format' | translate }}
  79 + </mat-checkbox>
  80 + <div class="tb-hint" innerHTML="{{ 'device-profile.mqtt-enable-compatibility-with-json-payload-format-hint' | translate }}"></div>
  81 + <div *ngIf="compatibilityWithJsonPayloadFormatEnabled">
  82 + <mat-checkbox formControlName="useJsonPayloadFormatForDefaultDownlinkTopics">
  83 + {{ 'device-profile.mqtt-use-json-format-for-default-downlink-topics' | translate }}
  84 + </mat-checkbox>
  85 + <div class="tb-hint" innerHTML="{{ 'device-profile.mqtt-use-json-format-for-default-downlink-topics-hint' | translate }}"></div>
  86 + </div>
  87 + </div>
76 88 <div *ngIf="protoPayloadType" fxLayout="column">
77 89 <mat-form-field fxFlex>
78 90 <mat-label translate>device-profile.telemetry-proto-schema</mat-label>
... ...
... ... @@ -97,7 +97,9 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
97 97 deviceTelemetryProtoSchema: [defaultTelemetrySchema, Validators.required],
98 98 deviceAttributesProtoSchema: [defaultAttributesSchema, Validators.required],
99 99 deviceRpcRequestProtoSchema: [defaultRpcRequestSchema, Validators.required],
100   - deviceRpcResponseProtoSchema: [defaultRpcResponseSchema, Validators.required]
  100 + deviceRpcResponseProtoSchema: [defaultRpcResponseSchema, Validators.required],
  101 + enableCompatibilityWithJsonPayloadFormat: [false, Validators.required],
  102 + useJsonPayloadFormatForDefaultDownlinkTopics: [false, Validators.required]
101 103 })
102 104 }, {validator: this.uniqueDeviceTopicValidator}
103 105 );
... ... @@ -106,6 +108,14 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
106 108 ).subscribe(payloadType => {
107 109 this.updateTransportPayloadBasedControls(payloadType, true);
108 110 });
  111 + this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.enableCompatibilityWithJsonPayloadFormat')
  112 + .valueChanges.pipe(takeUntil(this.destroy$)
  113 + ).subscribe(compatibilityWithJsonPayloadFormatEnabled => {
  114 + if (!compatibilityWithJsonPayloadFormatEnabled) {
  115 + this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.useJsonPayloadFormatForDefaultDownlinkTopics')
  116 + .patchValue(false, {emitEvent: false});
  117 + }
  118 + });
109 119 this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe(
110 120 takeUntil(this.destroy$)
111 121 ).subscribe(() => {
... ... @@ -132,6 +142,10 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
132 142 return transportPayloadType === TransportPayloadType.PROTOBUF;
133 143 }
134 144
  145 + get compatibilityWithJsonPayloadFormatEnabled(): boolean {
  146 + return this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.enableCompatibilityWithJsonPayloadFormat').value;
  147 + }
  148 +
135 149 writeValue(value: MqttDeviceProfileTransportConfiguration | null): void {
136 150 if (isDefinedAndNotNull(value)) {
137 151 this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
... ... @@ -156,7 +170,9 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
156 170 deviceTelemetryProtoSchema: defaultTelemetrySchema,
157 171 deviceAttributesProtoSchema: defaultAttributesSchema,
158 172 deviceRpcRequestProtoSchema: defaultRpcRequestSchema,
159   - deviceRpcResponseProtoSchema: defaultRpcResponseSchema
  173 + deviceRpcResponseProtoSchema: defaultRpcResponseSchema,
  174 + enableCompatibilityWithJsonPayloadFormat: false,
  175 + useJsonPayloadFormatForDefaultDownlinkTopics: false
160 176 }, {emitEvent: false});
161 177 }
162 178 if (type === TransportPayloadType.PROTOBUF && !this.disabled) {
... ... @@ -164,11 +180,15 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
164 180 transportPayloadTypeForm.get('deviceAttributesProtoSchema').enable({emitEvent: false});
165 181 transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').enable({emitEvent: false});
166 182 transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').enable({emitEvent: false});
  183 + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').enable({emitEvent: false});
  184 + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').enable({emitEvent: false});
167 185 } else {
168 186 transportPayloadTypeForm.get('deviceTelemetryProtoSchema').disable({emitEvent: false});
169 187 transportPayloadTypeForm.get('deviceAttributesProtoSchema').disable({emitEvent: false});
170 188 transportPayloadTypeForm.get('deviceRpcRequestProtoSchema').disable({emitEvent: false});
171 189 transportPayloadTypeForm.get('deviceRpcResponseProtoSchema').disable({emitEvent: false});
  190 + transportPayloadTypeForm.get('enableCompatibilityWithJsonPayloadFormat').disable({emitEvent: false});
  191 + transportPayloadTypeForm.get('useJsonPayloadFormatForDefaultDownlinkTopics').disable({emitEvent: false});
172 192 }
173 193 }
174 194
... ...
... ... @@ -247,6 +247,8 @@ export interface MqttDeviceProfileTransportConfiguration {
247 247 deviceAttributesTopic?: string;
248 248 transportPayloadTypeConfiguration?: {
249 249 transportPayloadType?: TransportPayloadType;
  250 + enableCompatibilityWithJsonPayloadFormat?: boolean;
  251 + useJsonPayloadFormatForDefaultDownlinkTopics?: boolean;
250 252 };
251 253 [key: string]: any;
252 254 }
... ... @@ -359,7 +361,11 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
359 361 const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {
360 362 deviceTelemetryTopic: 'v1/devices/me/telemetry',
361 363 deviceAttributesTopic: 'v1/devices/me/attributes',
362   - transportPayloadTypeConfiguration: {transportPayloadType: TransportPayloadType.JSON}
  364 + transportPayloadTypeConfiguration: {
  365 + transportPayloadType: TransportPayloadType.JSON,
  366 + enableCompatibilityWithJsonPayloadFormat: false,
  367 + useJsonPayloadFormatForDefaultDownlinkTopics: false,
  368 + }
363 369 };
364 370 transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT};
365 371 break;
... ...
... ... @@ -737,7 +737,7 @@
737 737 "close": "Dialog schließen"
738 738 },
739 739 "edge": {
740   - "edge": "Rand",
  740 + "edge": "Edge",
741 741 "edge-instances": "Kanteninstanzen",
742 742 "edge-file": "Edge-Datei",
743 743 "management": "Rand verwalten",
... ...
... ... @@ -1096,6 +1096,10 @@
1096 1096 "mqtt-device-payload-type": "MQTT device payload",
1097 1097 "mqtt-device-payload-type-json": "JSON",
1098 1098 "mqtt-device-payload-type-proto": "Protobuf",
  1099 + "mqtt-enable-compatibility-with-json-payload-format": "Enable compatibility with other payload formats.",
  1100 + "mqtt-enable-compatibility-with-json-payload-format-hint": "When enabled, the platform will use a Protobuf payload format by default. If parsing fails, the platform will attempt to use JSON payload format. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses Json, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.",
  1101 + "mqtt-use-json-format-for-default-downlink-topics": "Use Json format for default downlink topics",
  1102 + "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: <b>v1/devices/me/attributes/response/$request_id</b>, <b>v1/devices/me/attributes</b>, <b>v1/devices/me/rpc/request/$request_id</b>, <b>v1/devices/me/rpc/response/$request_id</b>. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: <b>v2/a/res/$request_id</b>, <b>v2/a</b>, <b>v2/r/req/$request_id</b>, <b>v2/r/res/$request_id</b>. Where <b>$request_id</b> is an integer request identifier.",
1099 1103 "snmp-add-mapping": "Add SNMP mapping",
1100 1104 "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured",
1101 1105 "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping",
... ...