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; | ... | ... |
... | ... | @@ -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", | ... | ... |