Merge branch 'master' of https://github.com/thingsboard/thingsboard
[Issue 3544] dashboard logo feature added
This commit is contained in:
commit
86263cbff5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,14 +3,14 @@
|
||||
"alias": "date",
|
||||
"title": "Date",
|
||||
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAAAAABslHx1AAAAAmJLR0QA/4ePzL8AAAh0SURBVHja7d3/UxNnHsBx/7L7oXc/3NzM3dycvdajnavtUYXOVM/zsJ0eharIN5EgGLIEEWj40ihEEMSAhCU0CCoB0qAYhBKIfI+JBBJCstn3/UC9KtjT3g2apc/nh0x299nJvvLs83ye2X1mdx/xwB6IGPviARXNhxqI79sLDlAD+wLsiQjsC+4NSFBABERABERABERAdkKCblgf31bI3Xc79D//wuPJNwIZT5vFZ9xWqHRgoGB666vlZx9W0PvMQvXKa4MU5Ss+I7MGyTdxl6sriUagdJmlEial8qnxry6EFiTD98BY/YVog9TCiMVQpSiNerMTubw+BjS2ljqYqyh3B9pZ6pzqx1Ha1IxLMiwMf1GZGLtQ4aPB5NhtSH1Hh8/I2fVQcag8lt01fXkLQjb2jWUdZg+6YKQwHo72mxK+B+gXbU3UPRhopq3LV4ld3gjHc33xk9wORHMoiHeMulqD+cq0jpsJTw3SUvzM5mouuTO7XiP1ify7xujxiop8dKMOqfP+FiSRjdP4TT5mj3q8ouKUx9Td381qdd0pr83BtdHmMQa6+nIqSq+1mWZyFU4zbjRncsOti7taH5gJ6bBX1kpIS75aKIrkKrsPYfZzo3oqQYS2M2t1xfEtiMPMKTWUj9nD6RgRoL+bNifGLYjNjr3L1YSyCeQqnOZMNJbNY109rtbFcvy6WC6zEtLS6jkSObwWCC1GBosvdjBdxJgBoLS0pDbK1yVSJrcKgiNFVS1bkIlThpMum4Nro+FCY/5N9WJlmfcppPWsPiNB0UNcrZj0eh1lZeUFXNfFOvW6gdcAeRqJ+M510R8+ftymPD2e6GLM4oTN7aW3YibmMf24ezyexAkxUi+ZEz+5tdNYGXjdeUQMUQREQAREQAREQAREQATklwNZ7Otf3Vkq5gYIyRqC3OqeuhAgsUG0NIYSA2KJDRI+iBBoZENlAzUW1QDkDg9uzEm1dteXY1O1VRPQfqm2M1wTu9RkCjQOW6LVlqv+rGuagDxqjjmtBvQYuzq+hnYvZeEat4PJQG65OlzZd8rfiCYg8h2HfdWAHsOkdwXavZSGa1wOfAGdcXGw3ev1f6MFSHHtZfX+eZMOyTVhNLuh/WKNHK6JVV5uCjSuX1iTmts0AdmKuAoJBVUB2r1bVz2eXvuIa6PX2hnj2kg0IrMLiIAIyC8DEo8mO2SjswXYbMlTAJbzPq1UmMj8uxXAnZWVleUHwFr2Q/nJrKPN4PlXxh24dizTA6sWexJAFlIz84AvLj5SAY7cUk63JA7MRFJnANvpUCiUeA6ipExF0kaU97wrKWt3jkc87zKSfqwuCSAK/Xkwnrm0dR+5CS5XK9OQ6QRsBQAzx9MvYj169KNbQPgGnB149CnkON0PUN5RFRrrkqKN9OdBy4HM1OatxcihBbDmnEwAtkN1dQ4OTaifuaxHlcW3t4ZdCx9H730GJd2ARYLdhQxnZ2Vl5S29IqTKSPhPvtRUD0qmDZiTP5oDbEdl+d7ab7KyPrhiLYNPZgHC6Q+4fwJKZHB+Gt9tCLdPZGTNvmqNNNfAfgWgqAE2hsDQ/vTU2vzj3NzcmrUMPlwCYse/hcVDkO3i4eEguw5h8EWOn4CsvO9uOQFQfcLjmVRSBh+mfv+fNvJl7bQ0Y31ntONvKvBVicfj42P7SEps4YDd43my6xDCr9ZGvDIwcb46DPCNJEkm5g3FLoDJXoBN8zmbOtFbdWEZSEiSJLXhl8q8eCRJkjwwOiwyu4AIiIAIyM+E3NRQiFNLQAREQAREQAREQLQGmfwOAN/2cnVPNAYZ7gs+GgrOnZnC50oEpr9/SHAl4nykRciw9F1ZsGhlvGnw6lD5bGXMstQ0fn5Vi5AB9OhpqDTphwa5M1rFSFPBrHYhbZMEhgaJFfego0F7kMnvHt7nGrI9Ym4cnxiH6yGsNQ3e7nXR/QqIgAiIgAjILxyy7NEgxNCNsn8Z18ln1tkLNQixFeH63XVMDTDzBFj3KtgLiS5pDbLyARWmbE6MKRk56V0MHM5Pj9oLN470JMsBr/h8Pp8v9PI2khJKC6cqbys3Slh/n5QABqs9LyN5ZizPZWdkZJSEXw7Jv/4PznUcw/Dn1NSU6FupqR802X/9h3mSSfICx07Ijb9e5tuDNVy5CAr7wyjYMwfSkmiSrM8YeZXud+5Xs4TfGmHtw0vGHCxHrxyZsBdSUaa9PDIMuOMQGXApMG1fJuBFcSqag4ghioAIiIBoCSImDIhTS0AEREAEREAERAOQxIuemK1qD2KrqnUysG3l+rfag5xNIDsyJzba2mLD3Y3LoN6sn12/6zGZHGpPU1A7kBFdT5RyGv0um+VeUIL52o0evxkapvpHgtWagair6kgV5RSZvnZY5tGDKlcP+c3cvklDlemqdmqkbMGrpzTW6PF5LYPeKpi94T/vNy+WLAf7uwNj2oGEerpC3J2M9coxS491HRi+vrQxPm21DqpDnU+0A3kmLPMkc4jMLiACIiACkoyQR0OugHYhzzwS3XisLC0Z77qtvApE/sT/I+QKic9lFPnKPD1rzI4kh8P/ifxySN/hXp6F0JvDyaruA+Fz7RRbX/9BP5FlWZbdz690pPW8DNJ3+Fms8QqMfMbCnPPjcfc/1b+E38DfL2dkZBRsH5/ukOyYwpGuZxuk4xwFha0H76kpt798IyeSvNMB+vSV/14jzvT25yGPD44lfq8oH41RdaD3zTSJFzyosDPt9svayHMS4/7Uw72gez/9oMzMbzeTpdfa4XhRr3X3iH/HjpEE4M5LFof/yN1XySM/MXu85T1v0uSR9f9niBIMk8QhBo0C8kYg88l1Y31e1IiACIiACIiA7Bpkz7wgeM+8sjm2N16irewjHgisajwCAYV/A1HeMsl2Bkj/AAAAAElFTkSuQmCC",
|
||||
"description": null
|
||||
"description": "Contains widgets to change the data range for other widgets on the dashboard."
|
||||
},
|
||||
"widgetTypes": [
|
||||
{
|
||||
"alias": "date_range_navigator",
|
||||
"name": "Date-range-navigator",
|
||||
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAAAAABslHx1AAAAAmJLR0QA/4ePzL8AAAfbSURBVHja7d3tUxNJHsBx/jLcs+64rWVx9di9xYdSuUWL3boVo0b3BDwJCuFZkVWEEy8adYVEEZWFE42gPAgXNAQisCIPMUAYCI95fvjeC/R8AC2oYg2D3W8mM91JzSfdv+meVE86Av/Y0IDM09CYjwi/dTqAzFNg2uqPGJtmDaTpsYihwFqABIYiBlgTaUBABERABERABERA1jbEJ0n+95Qen9+0+mQB6U4vz2uYf+mvfDvrxrww1ykPiJZgjoSp3EjVwRb6ytsAf0Nd5Rz3QsH68n5yneP3Ga5oCNmbrwVWNYTbzdaKiXzrSPq0vWD8Yge49/e1/MyxYM2tseyZ3OEsuzNrtOq+RdUTWt2Q6qZQwxW1yavm/kl9iR7c2aDiWLDAxZw/N6WNDrX+QqlFt8qbFvnDzZX+6yavmvoqSZoDdzahoxwLFk4y6s5tzvSYL0rS9CqHZFYX3saUV3u4JZTSNZvZcLkP3HvvXNZzLPik+H6BP9fZfs6Xc+96++qGOC29M8Bg98Q4tn5c5lHAnT3UHeJ5CHunh4EAfT5fp5U5u+w6RHf2GunZQ24xRBEQAREQARGQ3wXSObVqIV35JgBLZsr8/ouULUkd0Htg8+EXABxJSEhIuPWydHzrq/dNHN/6fSPMZW7d2w3PDm5W9gK9p5rCBNmeuKEJaNpYOZ8X2FLpvfuFy7OxwVueOF/ips1mm10A2VPqMUaNkpPlrN/kd/3lrvdabIgfvvv61zBBrCQ0QfBb46s79Z+APw9O6WBsfQhgeyMAwwXp9RBfmZdpAQjsd8H2NjYMwLaOwWPgiZxmiP2/hi1GEppgOOb0LtX4qyPmbwLgcZw6wmvIZGyVcetD4uMf6j8fe1luJHo2sM4JSXcBHn4HrBjkN4PBYDAYhpYJaV93U8rfy31DEzC71QhoY7/onodERUdv40o6VKcQ3wypV1/+ApNYiyvSBQdqAOmb3pWEeIuVSqXynH+ZkMZdMLvOU1J8ETw/auczHn3le10jeV/GxcWlEN8KxacACB4pAP+6WUgywFz8bVYSgrdYqSzzL7dp9W0K4vzMCxBILgLGqiC0fuw1pCz3/8GePg8tOBoENj2DzWa8e17qVy5GvMWawLJjJJR43lGkBAhlH7DZbFNTMQ1z17e9EexD0c1Tuiri9w22fT4I8O+EQZttgpNpkzWxgUBKms1mm1lRCN7A8oI9rxNwpO9UTwL4FQqFQlFB18HtaTYAsjoB6FBuz5wk50ZSogGAVIVCoSjBfeJvh/qZVCgUCkU1UNwmhigCIiACIiCfEOSaLJJoWgIiIAIiIAIiIAIiIAKyEhD/zPuL+x/JCDJUOr819Sws7syRF8TQUT5oyz9lD97T27nXaqqDulC/3hCUGyTtYb/KU1nru24YVgcz7kyW2CfOeM5JVxrlBlGBijtNpOv0qVKGH1N1XTumK6dvyhVyfFiS/Bl+AieL/LYzbqM8IS1nHY1nH2pCGX64qkVS3VGXywrifkEf9BE0zzLc6aI/BNNTIJmnbMEBGUFEzy4gAiIgAiIgAvKBNNIvM0j5JRhJ9EFm81vHtWqZQQyJULnOSCDqhbwhjvVufjpwhqexYMnI6gT/pSMaL1o1UwVWOcXItnZfTE88FWk8jW2o3/CCfx43Z6ajVTt3nQ/nuS57vlaOpk1JnHSkEtVlKNSMRPlw/sGvVf29KKxf+rLna/1HWaQnvzq2n8SNcXFxpcb1cXFxcZL2sz/WEHbJcuZr2b/aOUzj/pgQyZUAAzEBAG2S5cvBcEuWN1/r2x3g+lMKPPhrj3TaFEw8M/UkM6RVo98R5sdIljlf64IeKLwL3Nmz86wPR9aOfSbqfoHCajFEERABERABEZAPQ8R8LdG0BERABERABERABERAPmmI3b74fx35puUFOX9Jn+exNi/MsLXICuI9CvVPSjJ+o63iGcbHOgtAz9UHIbtZ0uv1A7To+mVRI2XFPaFAs8bV+ouUO6W5YTtuB6dq9HJnl84z0JMy3qiXsmdlESPPNXluSwVlGn3WE80AdY0QLLzcS5cO/mXi7EX9/BPtqxwy2gj6dksFZU8kyaMZ4HYruB2jxW1dOup1UNwlSV4ZQHy5t+szJqxq67O8xnNOTckDlRNmsut/NnXpRvcbGvq7CxrPueXQtIL9HU7olXCYp9F0dcwAzJmHmbPPWSyWMcbNM/LrEDWrswddPsQbFEMUAREQAREQAfk0IaUJuw9Xh2QJcdS+uacqsj36IWO1nHKtY+kQR3LS+JsQDThjOglUphUMc+kxXGsLm2M8KdmxVIgjOek570A4epG81KearVxIIRD9/Hc/4WCTwWAwGO4vuD8YVPxDWhpk4h3HPOREEf1O10Tk9EiUy7jzY7T6VKVSeei/CzMWlSwCcR1OfOf7VmmAVC2P4/elRk7yY90JLR9HspgDnicedi2lRmp2lwYXQKajLWwxEoicpCr565GPEg7Wo8ZFG9353TeXFiM1u0vekqjyegzxebDtkvVU5AizUd9/pMB2LeooW8TxnqtW7dsSrUKRdi8EPYoEXUovKPVhvPoGy3bfWno/Un3I8f6Pmot1hBHiOFS9nJ79A4sO1G05E9YO0blSYy2bWQwaBURA1iakLfyzs9pEjQiIgAiIgAiIgHxikDWzQPDaWLJ5aizCtzYW0Q5ErI1lzQP8DwJX9hDY3Q8ZAAAAAElFTkSuQmCC",
|
||||
"description": null,
|
||||
"description": "Allows to change the data range for other widgets on the dashboard.",
|
||||
"descriptor": {
|
||||
"type": "static",
|
||||
"sizeX": 5,
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,87 @@
|
||||
--
|
||||
-- Copyright © 2016-2021 The Thingsboard Authors
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid uuid,
|
||||
IN system_ttl bigint, INOUT deleted bigint)
|
||||
LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
tenant_cursor CURSOR FOR select tenant.id as tenant_id
|
||||
from tenant;
|
||||
tenant_id_record uuid;
|
||||
customer_id_record uuid;
|
||||
tenant_ttl bigint;
|
||||
customer_ttl bigint;
|
||||
deleted_for_entities bigint;
|
||||
tenant_ttl_ts bigint;
|
||||
customer_ttl_ts bigint;
|
||||
BEGIN
|
||||
OPEN tenant_cursor;
|
||||
FETCH tenant_cursor INTO tenant_id_record;
|
||||
WHILE FOUND
|
||||
LOOP
|
||||
EXECUTE format(
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L',
|
||||
tenant_id_record, 'TTL') INTO tenant_ttl;
|
||||
if tenant_ttl IS NULL THEN
|
||||
tenant_ttl := system_ttl;
|
||||
END IF;
|
||||
IF tenant_ttl > 0 THEN
|
||||
tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint;
|
||||
deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts);
|
||||
deleted := deleted + deleted_for_entities;
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record;
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts);
|
||||
deleted := deleted + deleted_for_entities;
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record;
|
||||
END IF;
|
||||
FOR customer_id_record IN
|
||||
SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record
|
||||
LOOP
|
||||
EXECUTE format(
|
||||
'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L',
|
||||
customer_id_record, 'TTL') INTO customer_ttl;
|
||||
IF customer_ttl IS NULL THEN
|
||||
customer_ttl_ts := tenant_ttl_ts;
|
||||
ELSE
|
||||
IF customer_ttl > 0 THEN
|
||||
customer_ttl_ts :=
|
||||
(EXTRACT(EPOCH FROM current_timestamp) * 1000 -
|
||||
customer_ttl::bigint * 1000)::bigint;
|
||||
END IF;
|
||||
END IF;
|
||||
IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN
|
||||
deleted_for_entities :=
|
||||
delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record,
|
||||
customer_ttl_ts);
|
||||
deleted := deleted + deleted_for_entities;
|
||||
RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record;
|
||||
deleted_for_entities :=
|
||||
delete_device_records_from_ts_kv(tenant_id_record, customer_id_record,
|
||||
customer_ttl_ts);
|
||||
deleted := deleted + deleted_for_entities;
|
||||
RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record;
|
||||
deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record,
|
||||
customer_id_record,
|
||||
customer_ttl_ts);
|
||||
deleted := deleted + deleted_for_entities;
|
||||
RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record;
|
||||
END IF;
|
||||
END LOOP;
|
||||
FETCH tenant_cursor INTO tenant_id_record;
|
||||
END LOOP;
|
||||
END
|
||||
$$;
|
||||
@ -18,6 +18,7 @@ package org.thingsboard.server.controller;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -422,6 +423,25 @@ public class RuleChainController extends BaseController {
|
||||
}
|
||||
|
||||
private String msgToOutput(TbMsg msg) throws Exception {
|
||||
JsonNode resultNode = convertMsgToOut(msg);
|
||||
return objectMapper.writeValueAsString(resultNode);
|
||||
}
|
||||
|
||||
private String msgToOutput(List<TbMsg> msgs) throws Exception {
|
||||
JsonNode resultNode;
|
||||
if (msgs.size() > 1) {
|
||||
resultNode = objectMapper.createArrayNode();
|
||||
for (TbMsg msg : msgs) {
|
||||
JsonNode convertedData = convertMsgToOut(msg);
|
||||
((ArrayNode) resultNode).add(convertedData);
|
||||
}
|
||||
} else {
|
||||
resultNode = convertMsgToOut(msgs.get(0));
|
||||
}
|
||||
return objectMapper.writeValueAsString(resultNode);
|
||||
}
|
||||
|
||||
private JsonNode convertMsgToOut(TbMsg msg) throws Exception{
|
||||
ObjectNode msgData = objectMapper.createObjectNode();
|
||||
if (!StringUtils.isEmpty(msg.getData())) {
|
||||
msgData.set("msg", objectMapper.readTree(msg.getData()));
|
||||
@ -429,7 +449,8 @@ public class RuleChainController extends BaseController {
|
||||
Map<String, String> metadata = msg.getMetaData().getData();
|
||||
msgData.set("metadata", objectMapper.valueToTree(metadata));
|
||||
msgData.put("msgType", msg.getType());
|
||||
return objectMapper.writeValueAsString(msgData);
|
||||
return msgData;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@ -421,20 +422,33 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
|
||||
private void initStatesFromDataBase() {
|
||||
try {
|
||||
log.info("Initializing tenant states.");
|
||||
PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024);
|
||||
for (Tenant tenant : tenantIterator) {
|
||||
if (!myTenantStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) {
|
||||
log.debug("[{}] Initializing tenant state.", tenant.getId());
|
||||
updateLock.lock();
|
||||
try {
|
||||
updateTenantState(getOrFetchState(tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId()));
|
||||
log.debug("[{}] Initialized tenant state.", tenant.getId());
|
||||
} catch (Exception e) {
|
||||
log.warn("[{}] Failed to initialize tenant API state", tenant.getId(), e);
|
||||
} finally {
|
||||
updateLock.unlock();
|
||||
updateLock.lock();
|
||||
try {
|
||||
ExecutorService tmpInitExecutor = Executors.newWorkStealingPool(20);
|
||||
try {
|
||||
PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024);
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
for (Tenant tenant : tenantIterator) {
|
||||
if (!myTenantStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) {
|
||||
log.debug("[{}] Initializing tenant state.", tenant.getId());
|
||||
futures.add(tmpInitExecutor.submit(() -> {
|
||||
try {
|
||||
updateTenantState(getOrFetchState(tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId()));
|
||||
log.debug("[{}] Initialized tenant state.", tenant.getId());
|
||||
} catch (Exception e) {
|
||||
log.warn("[{}] Failed to initialize tenant API state", tenant.getId(), e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
for (Future<?> future : futures) {
|
||||
future.get();
|
||||
}
|
||||
} finally {
|
||||
tmpInitExecutor.shutdownNow();
|
||||
}
|
||||
} finally {
|
||||
updateLock.unlock();
|
||||
}
|
||||
log.info("Initialized tenant states.");
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -437,6 +437,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
|
||||
case "3.2.1":
|
||||
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
||||
log.info("Updating schema ...");
|
||||
conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time);");
|
||||
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.2.1", SCHEMA_UPDATE_SQL);
|
||||
loadSql(schemaUpdateFile, conn);
|
||||
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3002002;");
|
||||
|
||||
@ -178,7 +178,11 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
|
||||
}
|
||||
break;
|
||||
case "3.1.1":
|
||||
break;
|
||||
case "3.2.1":
|
||||
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
||||
loadSql(conn, LOAD_TTL_FUNCTIONS_SQL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
|
||||
|
||||
@ -283,10 +283,12 @@ public class DefaultTbClusterService implements TbClusterService {
|
||||
byte[] msgBytes = encodingService.encode(msg);
|
||||
TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> toRuleEngineProducer = producerProvider.getRuleEngineNotificationsMsgProducer();
|
||||
Set<String> tbRuleEngineServices = new HashSet<>(partitionService.getAllServiceIds(ServiceType.TB_RULE_ENGINE));
|
||||
if (msg.getEntityId().getEntityType().equals(EntityType.TENANT)
|
||||
|| msg.getEntityId().getEntityType().equals(EntityType.TENANT_PROFILE)
|
||||
|| msg.getEntityId().getEntityType().equals(EntityType.DEVICE_PROFILE)
|
||||
|| msg.getEntityId().getEntityType().equals(EntityType.API_USAGE_STATE)) {
|
||||
EntityType entityType = msg.getEntityId().getEntityType();
|
||||
if (entityType.equals(EntityType.TENANT)
|
||||
|| entityType.equals(EntityType.TENANT_PROFILE)
|
||||
|| entityType.equals(EntityType.DEVICE_PROFILE)
|
||||
|| entityType.equals(EntityType.API_USAGE_STATE)
|
||||
|| (entityType.equals(EntityType.DEVICE) && msg.getEvent() == ComponentLifecycleEvent.UPDATED)) {
|
||||
TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer();
|
||||
Set<String> tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE);
|
||||
for (String serviceId : tbCoreServices) {
|
||||
|
||||
@ -108,13 +108,18 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbMsg executeUpdate(TbMsg msg) throws ScriptException {
|
||||
public List<TbMsg> executeUpdate(TbMsg msg) throws ScriptException {
|
||||
JsonNode result = executeScript(msg);
|
||||
if (!result.isObject()) {
|
||||
if (result.isObject()) {
|
||||
return Collections.singletonList(unbindMsg(result, msg));
|
||||
} else if (result.isArray()){
|
||||
List<TbMsg> res = new ArrayList<>(result.size());
|
||||
result.forEach(jsonObject -> res.add(unbindMsg(jsonObject, msg)));
|
||||
return res;
|
||||
} else {
|
||||
log.warn("Wrong result type: {}", result.getNodeType());
|
||||
throw new ScriptException("Wrong result type: " + result.getNodeType());
|
||||
}
|
||||
return unbindMsg(result, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -44,7 +44,8 @@ public class CustomerUserPermissions extends AbstractPermissions {
|
||||
|
||||
private static final PermissionChecker customerEntityPermissionChecker =
|
||||
new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_CREDENTIALS,
|
||||
Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES) {
|
||||
Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES,
|
||||
Operation.WRITE, Operation.WRITE_ATTRIBUTES, Operation.WRITE_TELEMETRY) {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@ -213,7 +213,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
|
||||
}, s -> true, s -> {
|
||||
List<TsKvEntry> subscriptionUpdate = null;
|
||||
for (TsKvEntry kv : ts) {
|
||||
if (isInTimeRange(s, kv.getTs()) && (s.isAllKeys() || s.getKeyStates().containsKey((kv.getKey())))) {
|
||||
if ((s.isAllKeys() || s.getKeyStates().containsKey((kv.getKey())))) {
|
||||
if (subscriptionUpdate == null) {
|
||||
subscriptionUpdate = new ArrayList<>();
|
||||
}
|
||||
@ -375,11 +375,6 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInTimeRange(TbTimeseriesSubscription subscription, long kvTime) {
|
||||
return (subscription.getStartTime() == 0 || subscription.getStartTime() <= kvTime)
|
||||
&& (subscription.getEndTime() == 0 || subscription.getEndTime() >= kvTime);
|
||||
}
|
||||
|
||||
private void removeSubscriptionFromEntityMap(TbSubscription sub) {
|
||||
Set<TbSubscription> entitySubSet = subscriptionsByEntityId.get(sub.getEntityId());
|
||||
if (entitySubSet != null) {
|
||||
@ -429,16 +424,9 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
|
||||
serviceId, subscription.getSessionId(), subscription.getSubscriptionId(), subscription.getEntityId());
|
||||
|
||||
long curTs = System.currentTimeMillis();
|
||||
List<ReadTsKvQuery> queries = new ArrayList<>();
|
||||
subscription.getKeyStates().forEach((key, value) -> {
|
||||
if (curTs > value) {
|
||||
long startTs = subscription.getStartTime() > 0 ? Math.max(subscription.getStartTime(), value + 1L) : (value + 1L);
|
||||
long endTs = subscription.getEndTime() > 0 ? Math.min(subscription.getEndTime(), curTs) : curTs;
|
||||
queries.add(new BaseReadTsKvQuery(key, startTs, endTs, 0, 1000, Aggregation.NONE));
|
||||
}
|
||||
});
|
||||
if (!queries.isEmpty()) {
|
||||
DonAsynchron.withCallback(tsService.findAll(subscription.getTenantId(), subscription.getEntityId(), queries),
|
||||
|
||||
if (subscription.isLatestValues()) {
|
||||
DonAsynchron.withCallback(tsService.findLatest(subscription.getTenantId(), subscription.getEntityId(), subscription.getKeyStates().keySet()),
|
||||
missedUpdates -> {
|
||||
if (missedUpdates != null && !missedUpdates.isEmpty()) {
|
||||
TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId());
|
||||
@ -447,6 +435,26 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
|
||||
},
|
||||
e -> log.error("Failed to fetch missed updates.", e),
|
||||
tsCallBackExecutor);
|
||||
} else {
|
||||
List<ReadTsKvQuery> queries = new ArrayList<>();
|
||||
subscription.getKeyStates().forEach((key, value) -> {
|
||||
if (curTs > value) {
|
||||
long startTs = subscription.getStartTime() > 0 ? Math.max(subscription.getStartTime(), value + 1L) : (value + 1L);
|
||||
long endTs = subscription.getEndTime() > 0 ? Math.min(subscription.getEndTime(), curTs) : curTs;
|
||||
queries.add(new BaseReadTsKvQuery(key, startTs, endTs, 0, 1000, Aggregation.NONE));
|
||||
}
|
||||
});
|
||||
if (!queries.isEmpty()) {
|
||||
DonAsynchron.withCallback(tsService.findAll(subscription.getTenantId(), subscription.getEntityId(), queries),
|
||||
missedUpdates -> {
|
||||
if (missedUpdates != null && !missedUpdates.isEmpty()) {
|
||||
TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId());
|
||||
toCoreNotificationsProducer.send(tpi, toProto(subscription, missedUpdates), null);
|
||||
}
|
||||
},
|
||||
e -> log.error("Failed to fetch missed updates.", e),
|
||||
tsCallBackExecutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,12 +476,19 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
|
||||
data.forEach((key, value) -> {
|
||||
TbSubscriptionUpdateValueListProto.Builder dataBuilder = TbSubscriptionUpdateValueListProto.newBuilder();
|
||||
dataBuilder.setKey(key);
|
||||
value.forEach(v -> {
|
||||
boolean hasData = false;
|
||||
for (Object v : value) {
|
||||
Object[] array = (Object[]) v;
|
||||
dataBuilder.addTs((long) array[0]);
|
||||
dataBuilder.addValue((String) array[1]);
|
||||
});
|
||||
builder.addData(dataBuilder.build());
|
||||
String strVal = (String) array[1];
|
||||
if (strVal != null) {
|
||||
hasData = true;
|
||||
dataBuilder.addValue(strVal);
|
||||
}
|
||||
}
|
||||
if (hasData) {
|
||||
builder.addData(dataBuilder.build());
|
||||
}
|
||||
});
|
||||
|
||||
ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg(
|
||||
|
||||
@ -215,7 +215,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
|
||||
} else {
|
||||
historyFuture = Futures.immediateFuture(ctx);
|
||||
}
|
||||
Futures.addCallback(historyFuture, new FutureCallback<TbEntityDataSubCtx>() {
|
||||
Futures.addCallback(historyFuture, new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable TbEntityDataSubCtx theCtx) {
|
||||
if (cmd.getLatestCmd() != null) {
|
||||
@ -278,7 +278,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
|
||||
wsService.sendWsMsg(ctx.getSessionId(), update);
|
||||
} else {
|
||||
ctx.fetchAlarms();
|
||||
ctx.createSubscriptions(cmd.getQuery().getLatestValues(), true);
|
||||
ctx.createLatestValuesSubscriptions(cmd.getQuery().getLatestValues());
|
||||
if (adq.getPageLink().getTimeWindow() > 0) {
|
||||
TbAlarmDataSubCtx finalCtx = ctx;
|
||||
ScheduledFuture<?> task = scheduler.scheduleWithFixedDelay(
|
||||
@ -419,7 +419,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
|
||||
}
|
||||
wsService.sendWsMsg(ctx.getSessionId(), update);
|
||||
if (subscribe) {
|
||||
ctx.createSubscriptions(keys.stream().map(key -> new EntityKey(EntityKeyType.TIME_SERIES, key)).collect(Collectors.toList()), false);
|
||||
ctx.createTimeseriesSubscriptions(keys.stream().map(key -> new EntityKey(EntityKeyType.TIME_SERIES, key)).collect(Collectors.toList()), cmd.getStartTs(), cmd.getEndTs());
|
||||
}
|
||||
ctx.getData().getData().forEach(ed -> ed.getTimeseries().clear());
|
||||
return ctx;
|
||||
@ -468,7 +468,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
|
||||
update = new EntityDataUpdate(ctx.getCmdId(), null, ctx.getData().getData(), ctx.getMaxEntitiesPerDataSubscription());
|
||||
}
|
||||
wsService.sendWsMsg(ctx.getSessionId(), update);
|
||||
ctx.createSubscriptions(latestCmd.getKeys(), true);
|
||||
ctx.createLatestValuesSubscriptions(latestCmd.getKeys());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -484,7 +484,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
|
||||
wsService.sendWsMsg(ctx.getSessionId(), update);
|
||||
ctx.setInitialDataSent(true);
|
||||
}
|
||||
ctx.createSubscriptions(latestCmd.getKeys(), true);
|
||||
ctx.createLatestValuesSubscriptions(latestCmd.getKeys());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -115,10 +115,18 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
|
||||
}
|
||||
}
|
||||
|
||||
public void createSubscriptions(List<EntityKey> keys, boolean resultToLatestValues) {
|
||||
public void createLatestValuesSubscriptions(List<EntityKey> keys) {
|
||||
createSubscriptions(keys, true, 0, 0);
|
||||
}
|
||||
|
||||
public void createTimeseriesSubscriptions(List<EntityKey> keys, long startTs, long endTs) {
|
||||
createSubscriptions(keys, false, startTs, endTs);
|
||||
}
|
||||
|
||||
private void createSubscriptions(List<EntityKey> keys, boolean latestValues, long startTs, long endTs) {
|
||||
Map<EntityKeyType, List<EntityKey>> keysByType = getEntityKeyByTypeMap(keys);
|
||||
for (EntityData entityData : data.getData()) {
|
||||
List<TbSubscription> entitySubscriptions = addSubscriptions(entityData, keysByType, resultToLatestValues);
|
||||
List<TbSubscription> entitySubscriptions = addSubscriptions(entityData, keysByType, latestValues, startTs, endTs);
|
||||
entitySubscriptions.forEach(localSubscriptionService::addSubscription);
|
||||
}
|
||||
}
|
||||
@ -129,14 +137,14 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
|
||||
return keysByType;
|
||||
}
|
||||
|
||||
protected List<TbSubscription> addSubscriptions(EntityData entityData, Map<EntityKeyType, List<EntityKey>> keysByType, boolean resultToLatestValues) {
|
||||
protected List<TbSubscription> addSubscriptions(EntityData entityData, Map<EntityKeyType, List<EntityKey>> keysByType, boolean latestValues, long startTs, long endTs) {
|
||||
List<TbSubscription> subscriptionList = new ArrayList<>();
|
||||
keysByType.forEach((keysType, keysList) -> {
|
||||
int subIdx = sessionRef.getSessionSubIdSeq().incrementAndGet();
|
||||
subToEntityIdMap.put(subIdx, entityData.getEntityId());
|
||||
switch (keysType) {
|
||||
case TIME_SERIES:
|
||||
subscriptionList.add(createTsSub(entityData, subIdx, keysList, resultToLatestValues));
|
||||
subscriptionList.add(createTsSub(entityData, subIdx, keysList, latestValues, startTs, endTs));
|
||||
break;
|
||||
case CLIENT_ATTRIBUTE:
|
||||
subscriptionList.add(createAttrSub(entityData, subIdx, keysType, TbAttributeSubscriptionScope.CLIENT_SCOPE, keysList));
|
||||
@ -171,9 +179,9 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
|
||||
.build();
|
||||
}
|
||||
|
||||
private TbSubscription createTsSub(EntityData entityData, int subIdx, List<EntityKey> subKeys, boolean resultToLatestValues) {
|
||||
private TbSubscription createTsSub(EntityData entityData, int subIdx, List<EntityKey> subKeys, boolean latestValues, long startTs, long endTs) {
|
||||
Map<String, Long> keyStates = buildKeyStats(entityData, EntityKeyType.TIME_SERIES, subKeys);
|
||||
if (entityData.getTimeseries() != null) {
|
||||
if (!latestValues && entityData.getTimeseries() != null) {
|
||||
entityData.getTimeseries().forEach((k, v) -> {
|
||||
long ts = Arrays.stream(v).map(TsValue::getTs).max(Long::compareTo).orElse(0L);
|
||||
log.trace("[{}][{}] Updating key: {} with ts: {}", serviceId, cmdId, k, ts);
|
||||
@ -187,9 +195,12 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
|
||||
.subscriptionId(subIdx)
|
||||
.tenantId(sessionRef.getSecurityCtx().getTenantId())
|
||||
.entityId(entityData.getEntityId())
|
||||
.updateConsumer((sessionId, subscriptionUpdate) -> sendWsMsg(sessionId, subscriptionUpdate, EntityKeyType.TIME_SERIES, resultToLatestValues))
|
||||
.updateConsumer((sessionId, subscriptionUpdate) -> sendWsMsg(sessionId, subscriptionUpdate, EntityKeyType.TIME_SERIES, latestValues))
|
||||
.allKeys(false)
|
||||
.keyStates(keyStates)
|
||||
.latestValues(latestValues)
|
||||
.startTime(startTs)
|
||||
.endTime(endTs)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@ -132,8 +132,8 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx<AlarmDataQuery> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSubscriptions(List<EntityKey> keys, boolean resultToLatestValues) {
|
||||
super.createSubscriptions(keys, resultToLatestValues);
|
||||
public void createLatestValuesSubscriptions(List<EntityKey> keys) {
|
||||
super.createLatestValuesSubscriptions(keys);
|
||||
createAlarmSubscriptions();
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx<AlarmDataQuery> {
|
||||
newSubsList.forEach(
|
||||
entity -> {
|
||||
log.trace("[{}][{}] Found new subscription for entity: {}", sessionRef.getSessionId(), cmdId, entity.getEntityId());
|
||||
subsToAdd.addAll(addSubscriptions(entity, keysByType, true));
|
||||
subsToAdd.addAll(addSubscriptions(entity, keysByType, true, 0, 0));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -48,9 +48,6 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class TbEntityDataSubCtx extends TbAbstractDataSubCtx<EntityDataQuery> {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private TimeSeriesCmd tsCmd;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean initialDataSent;
|
||||
@ -137,7 +134,8 @@ public class TbEntityDataSubCtx extends TbAbstractDataSubCtx<EntityDataQuery> {
|
||||
for (TsValue update : new ArrayList<>(updateList)) {
|
||||
if (update.getTs() < v.getTs()) {
|
||||
log.trace("[{}][{}][{}] Removed stale update for key: {} and ts: {}", sessionId, cmdId, subscriptionUpdate.getSubscriptionId(), k, update.getTs());
|
||||
updateList.remove(update);
|
||||
// Looks like this is redundant feature and our UI is ready to merge the updates.
|
||||
//updateList.remove(update);
|
||||
} else if ((update.getTs() == v.getTs() && update.getValue().equals(v.getValue()))) {
|
||||
log.trace("[{}][{}][{}] Removed duplicate update for key: {} and ts: {}", sessionId, cmdId, subscriptionUpdate.getSubscriptionId(), k, update.getTs());
|
||||
updateList.remove(update);
|
||||
@ -182,25 +180,18 @@ public class TbEntityDataSubCtx extends TbAbstractDataSubCtx<EntityDataQuery> {
|
||||
subIdsToCancel.forEach(subToEntityIdMap::remove);
|
||||
List<EntityData> newSubsList = newDataMap.entrySet().stream().filter(entry -> !currentSubs.contains(entry.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
|
||||
if (!newSubsList.isEmpty()) {
|
||||
boolean resultToLatestValues;
|
||||
List<EntityKey> keys = null;
|
||||
if (curTsCmd != null) {
|
||||
resultToLatestValues = false;
|
||||
keys = curTsCmd.getKeys().stream().map(key -> new EntityKey(EntityKeyType.TIME_SERIES, key)).collect(Collectors.toList());
|
||||
} else if (latestValueCmd != null) {
|
||||
resultToLatestValues = true;
|
||||
keys = latestValueCmd.getKeys();
|
||||
} else {
|
||||
resultToLatestValues = true;
|
||||
}
|
||||
if (keys != null && !keys.isEmpty()) {
|
||||
Map<EntityKeyType, List<EntityKey>> keysByType = getEntityKeyByTypeMap(keys);
|
||||
newSubsList.forEach(
|
||||
entity -> {
|
||||
log.trace("[{}][{}] Found new subscription for entity: {}", sessionRef.getSessionId(), cmdId, entity.getEntityId());
|
||||
subsToAdd.addAll(addSubscriptions(entity, keysByType, resultToLatestValues));
|
||||
}
|
||||
);
|
||||
// NOTE: We ignore the TS subscriptions for new entities here, because widgets will re-init it's content and will create new subscriptions.
|
||||
if (curTsCmd == null && latestValueCmd != null) {
|
||||
List<EntityKey> keys = latestValueCmd.getKeys();
|
||||
if (keys != null && !keys.isEmpty()) {
|
||||
Map<EntityKeyType, List<EntityKey>> keysByType = getEntityKeyByTypeMap(keys);
|
||||
newSubsList.forEach(
|
||||
entity -> {
|
||||
log.trace("[{}][{}] Found new subscription for entity: {}", sessionRef.getSessionId(), cmdId, entity.getEntityId());
|
||||
subsToAdd.addAll(addSubscriptions(entity, keysByType, true, 0, 0));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
wsService.sendWsMsg(sessionRef.getSessionId(), new EntityDataUpdate(cmdId, data, null, maxEntitiesPerDataSubscription));
|
||||
|
||||
@ -83,6 +83,7 @@ public class TbSubscriptionUtils {
|
||||
TbSubscriptionKetStateProto.newBuilder().setKey(key).setTs(value).build()));
|
||||
tSubProto.setStartTime(tSub.getStartTime());
|
||||
tSubProto.setEndTime(tSub.getEndTime());
|
||||
tSubProto.setLatestValues(tSub.isLatestValues());
|
||||
msgBuilder.setTelemetrySub(tSubProto.build());
|
||||
break;
|
||||
case ATTRIBUTES:
|
||||
@ -146,6 +147,7 @@ public class TbSubscriptionUtils {
|
||||
telemetrySub.getKeyStatesList().forEach(ksProto -> keyStates.put(ksProto.getKey(), ksProto.getTs()));
|
||||
builder.startTime(telemetrySub.getStartTime());
|
||||
builder.endTime(telemetrySub.getEndTime());
|
||||
builder.latestValues(telemetrySub.getLatestValues());
|
||||
builder.keyStates(keyStates);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@ -34,16 +34,19 @@ public class TbTimeseriesSubscription extends TbSubscription<TelemetrySubscripti
|
||||
private final long startTime;
|
||||
@Getter
|
||||
private final long endTime;
|
||||
@Getter
|
||||
private final boolean latestValues;
|
||||
|
||||
@Builder
|
||||
public TbTimeseriesSubscription(String serviceId, String sessionId, int subscriptionId, TenantId tenantId, EntityId entityId,
|
||||
BiConsumer<String, TelemetrySubscriptionUpdate> updateConsumer,
|
||||
boolean allKeys, Map<String, Long> keyStates, long startTime, long endTime) {
|
||||
boolean allKeys, Map<String, Long> keyStates, long startTime, long endTime, boolean latestValues) {
|
||||
super(serviceId, sessionId, subscriptionId, tenantId, entityId, TbSubscriptionType.TIMESERIES, updateConsumer);
|
||||
this.allKeys = allKeys;
|
||||
this.keyStates = keyStates;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.latestValues = latestValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -22,9 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.common.util.ThingsBoardThreadFactory;
|
||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmQuery;
|
||||
@ -35,43 +33,22 @@ import org.thingsboard.server.common.data.id.AlarmId;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.LongDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.query.AlarmData;
|
||||
import org.thingsboard.server.common.data.query.AlarmDataPageLink;
|
||||
import org.thingsboard.server.common.data.query.AlarmDataQuery;
|
||||
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
||||
import org.thingsboard.server.dao.alarm.AlarmOperationResult;
|
||||
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
|
||||
import org.thingsboard.server.queue.discovery.PartitionService;
|
||||
import org.thingsboard.server.service.queue.TbClusterService;
|
||||
import org.thingsboard.server.service.subscription.SubscriptionManagerService;
|
||||
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
|
||||
import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Created by ashvayka on 27.03.18.
|
||||
@ -124,9 +101,15 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs) {
|
||||
ListenableFuture<AlarmOperationResult> result = clearAlarmForResult(tenantId, alarmId, details, clearTs);
|
||||
return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<AlarmOperationResult> clearAlarmForResult(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs) {
|
||||
ListenableFuture<AlarmOperationResult> result = alarmService.clearAlarm(tenantId, alarmId, details, clearTs);
|
||||
Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor);
|
||||
return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -110,7 +110,7 @@ security:
|
||||
# Enable/disable claiming devices, if false -> the device's [claimingAllowed] SERVER_SCOPE attribute must be set to [true] to allow claiming specific device
|
||||
allowClaimingByDefault: "${SECURITY_CLAIM_ALLOW_CLAIMING_BY_DEFAULT:true}"
|
||||
# Time allowed to claim the device in milliseconds
|
||||
duration: "${SECURITY_CLAIM_DURATION:60000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value
|
||||
duration: "${SECURITY_CLAIM_DURATION:86400000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value
|
||||
basic:
|
||||
enabled: "${SECURITY_BASIC_ENABLED:false}"
|
||||
oauth2:
|
||||
@ -348,8 +348,8 @@ caffeine:
|
||||
timeToLiveInMinutes: 1440
|
||||
maxSize: 0
|
||||
claimDevices:
|
||||
timeToLiveInMinutes: 1
|
||||
maxSize: 0
|
||||
timeToLiveInMinutes: 1440
|
||||
maxSize: 1000
|
||||
securitySettings:
|
||||
timeToLiveInMinutes: 1440
|
||||
maxSize: 0
|
||||
@ -625,11 +625,11 @@ queue:
|
||||
security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
|
||||
other:
|
||||
topic-properties:
|
||||
rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
|
||||
core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
|
||||
transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
|
||||
notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
|
||||
js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}"
|
||||
rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
|
||||
core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
|
||||
transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
|
||||
notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
|
||||
js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}"
|
||||
consumer-stats:
|
||||
enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}"
|
||||
print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}"
|
||||
|
||||
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.DeviceProfile;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.DeviceProfileType;
|
||||
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.controller.AbstractControllerTest;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractTransportIntegrationTest extends AbstractControllerTest {
|
||||
|
||||
protected static final String MQTT_URL = "tcp://localhost:1883";
|
||||
protected static final String COAP_BASE_URL = "coap://localhost:5683/api/v1/";
|
||||
|
||||
protected static final AtomicInteger atomicInteger = new AtomicInteger(2);
|
||||
|
||||
protected static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostTelemetry {\n" +
|
||||
" string key1 = 1;\n" +
|
||||
" bool key2 = 2;\n" +
|
||||
" double key3 = 3;\n" +
|
||||
" int32 key4 = 4;\n" +
|
||||
" JsonObject key5 = 5;\n" +
|
||||
"\n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 6;\n" +
|
||||
" repeated int32 someArray = 7;\n" +
|
||||
" NestedJsonObject someNestedObject = 8;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 9;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
protected static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostAttributes {\n" +
|
||||
" string key1 = 1;\n" +
|
||||
" bool key2 = 2;\n" +
|
||||
" double key3 = 3;\n" +
|
||||
" int32 key4 = 4;\n" +
|
||||
" JsonObject key5 = 5;\n" +
|
||||
"\n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 6;\n" +
|
||||
" repeated int32 someArray = 7;\n" +
|
||||
" NestedJsonObject someNestedObject = 8;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 9;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
protected Tenant savedTenant;
|
||||
protected User tenantAdmin;
|
||||
|
||||
protected Device savedDevice;
|
||||
protected String accessToken;
|
||||
|
||||
protected DeviceProfile deviceProfile;
|
||||
|
||||
protected void processAfterTest() throws Exception {
|
||||
loginSysAdmin();
|
||||
if (savedTenant != null) {
|
||||
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
|
||||
protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
|
||||
List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
|
||||
TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V);
|
||||
TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V);
|
||||
TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "3.0", TransportProtos.KeyValueType.DOUBLE_V);
|
||||
TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "4", TransportProtos.KeyValueType.LONG_V);
|
||||
TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V);
|
||||
keyValueProtos.add(strKeyValueProto);
|
||||
keyValueProtos.add(boolKeyValueProto);
|
||||
keyValueProtos.add(dblKeyValueProto);
|
||||
keyValueProtos.add(longKeyValueProto);
|
||||
keyValueProtos.add(jsonKeyValueProto);
|
||||
return keyValueProtos;
|
||||
}
|
||||
|
||||
protected TransportProtos.KeyValueProto getKeyValueProto(String key, String strValue, TransportProtos.KeyValueType type) {
|
||||
TransportProtos.KeyValueProto.Builder keyValueProtoBuilder = TransportProtos.KeyValueProto.newBuilder();
|
||||
keyValueProtoBuilder.setKey(key);
|
||||
keyValueProtoBuilder.setType(type);
|
||||
switch (type) {
|
||||
case BOOLEAN_V:
|
||||
keyValueProtoBuilder.setBoolV(Boolean.parseBoolean(strValue));
|
||||
break;
|
||||
case LONG_V:
|
||||
keyValueProtoBuilder.setLongV(Long.parseLong(strValue));
|
||||
break;
|
||||
case DOUBLE_V:
|
||||
keyValueProtoBuilder.setDoubleV(Double.parseDouble(strValue));
|
||||
break;
|
||||
case STRING_V:
|
||||
keyValueProtoBuilder.setStringV(strValue);
|
||||
break;
|
||||
case JSON_V:
|
||||
keyValueProtoBuilder.setJsonV(strValue);
|
||||
break;
|
||||
}
|
||||
return keyValueProtoBuilder.build();
|
||||
}
|
||||
|
||||
protected <T> T doExecuteWithRetriesAndInterval(SupplierWithThrowable<T> supplier, int retries, int intervalMs) throws Exception {
|
||||
int count = 0;
|
||||
T result = null;
|
||||
Throwable lastException = null;
|
||||
while (count < retries) {
|
||||
try {
|
||||
result = supplier.get();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
lastException = e;
|
||||
}
|
||||
count++;
|
||||
if (count < retries) {
|
||||
Thread.sleep(intervalMs);
|
||||
}
|
||||
}
|
||||
if (lastException != null) {
|
||||
throw new RuntimeException(lastException);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SupplierWithThrowable<T> {
|
||||
T get() throws Throwable;
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt;
|
||||
package org.thingsboard.server.transport;
|
||||
|
||||
import org.cassandraunit.dataset.cql.ClassPathCQLDataSet;
|
||||
import org.junit.BeforeClass;
|
||||
@ -28,8 +28,8 @@ import java.util.Arrays;
|
||||
|
||||
@RunWith(ClasspathSuite.class)
|
||||
@ClasspathSuite.ClassnameFilters({
|
||||
"org.thingsboard.server.mqtt.*.nosql.*Test"})
|
||||
public class MqttNoSqlTestSuite {
|
||||
"org.thingsboard.server.transport.*.telemetry.timeseries.nosql.*Test"})
|
||||
public class TransportNoSqlTestSuite {
|
||||
|
||||
@ClassRule
|
||||
public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt;
|
||||
package org.thingsboard.server.transport;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
@ -26,15 +26,15 @@ import java.util.Arrays;
|
||||
|
||||
@RunWith(ClasspathSuite.class)
|
||||
@ClasspathSuite.ClassnameFilters({
|
||||
"org.thingsboard.server.mqtt.rpc.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.telemetry.timeseries.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.telemetry.attributes.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.attributes.updates.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.attributes.request.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.claim.sql.*Test",
|
||||
"org.thingsboard.server.mqtt.provision.sql.*Test"
|
||||
"org.thingsboard.server.transport.*.rpc.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.attributes.updates.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.attributes.request.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.claim.sql.*Test",
|
||||
"org.thingsboard.server.transport.*.provision.sql.*Test"
|
||||
})
|
||||
public class MqttSqlTestSuite {
|
||||
public class TransportSqlTestSuite {
|
||||
|
||||
@ClassRule
|
||||
public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
|
||||
@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.DeviceProfile;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.DeviceProfileType;
|
||||
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
|
||||
|
||||
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
|
||||
this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, DeviceProfileProvisionType.DISABLED, null, null);
|
||||
}
|
||||
|
||||
protected void processBeforeTest(String deviceName,
|
||||
CoapDeviceType coapDeviceType,
|
||||
TransportPayloadType payloadType,
|
||||
String telemetryProtoSchema,
|
||||
String attributesProtoSchema,
|
||||
DeviceProfileProvisionType provisionType,
|
||||
String provisionKey, String provisionSecret
|
||||
) throws Exception {
|
||||
loginSysAdmin();
|
||||
|
||||
Tenant tenant = new Tenant();
|
||||
tenant.setTitle("My tenant");
|
||||
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
|
||||
Assert.assertNotNull(savedTenant);
|
||||
|
||||
tenantAdmin = new User();
|
||||
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
|
||||
tenantAdmin.setTenantId(savedTenant.getId());
|
||||
tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org");
|
||||
tenantAdmin.setFirstName("Joe");
|
||||
tenantAdmin.setLastName("Downs");
|
||||
|
||||
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
|
||||
|
||||
Device device = new Device();
|
||||
device.setName(deviceName);
|
||||
device.setType("default");
|
||||
|
||||
if (coapDeviceType != null) {
|
||||
DeviceProfile coapDeviceProfile = createCoapDeviceProfile(payloadType, coapDeviceType, attributesProtoSchema, provisionType, provisionKey, provisionSecret, telemetryProtoSchema);
|
||||
deviceProfile = doPost("/api/deviceProfile", coapDeviceProfile, DeviceProfile.class);
|
||||
device.setType(deviceProfile.getName());
|
||||
device.setDeviceProfileId(deviceProfile.getId());
|
||||
}
|
||||
|
||||
savedDevice = doPost("/api/device", device, Device.class);
|
||||
|
||||
DeviceCredentials deviceCredentials =
|
||||
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
|
||||
|
||||
assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
|
||||
accessToken = deviceCredentials.getCredentialsId();
|
||||
assertNotNull(accessToken);
|
||||
|
||||
}
|
||||
|
||||
protected DeviceProfile createCoapDeviceProfile(TransportPayloadType transportPayloadType, CoapDeviceType coapDeviceType,
|
||||
String attributesProtoSchema, DeviceProfileProvisionType provisionType,
|
||||
String provisionKey, String provisionSecret, String telemetryProtoSchema) {
|
||||
DeviceProfile deviceProfile = new DeviceProfile();
|
||||
deviceProfile.setName(transportPayloadType.name());
|
||||
deviceProfile.setType(DeviceProfileType.DEFAULT);
|
||||
deviceProfile.setProvisionType(provisionType);
|
||||
deviceProfile.setProvisionDeviceKey(provisionKey);
|
||||
deviceProfile.setDescription(transportPayloadType.name() + " Test");
|
||||
DeviceProfileData deviceProfileData = new DeviceProfileData();
|
||||
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
|
||||
deviceProfile.setTransportType(DeviceTransportType.COAP);
|
||||
CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = new CoapDeviceProfileTransportConfiguration();
|
||||
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration;
|
||||
if (CoapDeviceType.DEFAULT.equals(coapDeviceType)) {
|
||||
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = new DefaultCoapDeviceTypeConfiguration();
|
||||
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
|
||||
if (TransportPayloadType.PROTOBUF.equals(transportPayloadType)) {
|
||||
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
|
||||
if (StringUtils.isEmpty(telemetryProtoSchema)) {
|
||||
telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA;
|
||||
}
|
||||
if (StringUtils.isEmpty(attributesProtoSchema)) {
|
||||
attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
|
||||
}
|
||||
protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
|
||||
protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
|
||||
transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
|
||||
} else {
|
||||
transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
|
||||
}
|
||||
defaultCoapDeviceTypeConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
|
||||
coapDeviceTypeConfiguration = defaultCoapDeviceTypeConfiguration;
|
||||
} else {
|
||||
coapDeviceTypeConfiguration = new EfentoCoapDeviceTypeConfiguration();
|
||||
}
|
||||
coapDeviceProfileTransportConfiguration.setCoapDeviceTypeConfiguration(coapDeviceTypeConfiguration);
|
||||
deviceProfileData.setTransportConfiguration(coapDeviceProfileTransportConfiguration);
|
||||
DeviceProfileProvisionConfiguration provisionConfiguration;
|
||||
switch (provisionType) {
|
||||
case ALLOW_CREATE_NEW_DEVICES:
|
||||
provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(provisionSecret);
|
||||
break;
|
||||
case CHECK_PRE_PROVISIONED_DEVICES:
|
||||
provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(provisionSecret);
|
||||
break;
|
||||
case DISABLED:
|
||||
default:
|
||||
provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
|
||||
break;
|
||||
}
|
||||
deviceProfileData.setProvisionConfiguration(provisionConfiguration);
|
||||
deviceProfileData.setConfiguration(configuration);
|
||||
deviceProfile.setProfileData(deviceProfileData);
|
||||
deviceProfile.setDefault(false);
|
||||
deviceProfile.setDefaultRuleChainId(null);
|
||||
return deviceProfile;
|
||||
}
|
||||
|
||||
protected CoapClient getCoapClient(FeatureType featureType) {
|
||||
return new CoapClient(getFeatureTokenUrl(accessToken, featureType));
|
||||
}
|
||||
|
||||
protected CoapClient getCoapClient(String featureTokenUrl) {
|
||||
return new CoapClient(featureTokenUrl);
|
||||
}
|
||||
|
||||
protected String getFeatureTokenUrl(String token, FeatureType featureType) {
|
||||
return COAP_BASE_URL + token + "/" + featureType.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," +
|
||||
"\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}";
|
||||
|
||||
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
|
||||
super.processBeforeTest(deviceName, coapDeviceType, payloadType);
|
||||
}
|
||||
|
||||
protected void processAfterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
protected List<TransportProtos.TsKvProto> getTsKvProtoList() {
|
||||
TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("attribute1", "value1", TransportProtos.KeyValueType.STRING_V);
|
||||
TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("attribute2", "true", TransportProtos.KeyValueType.BOOLEAN_V);
|
||||
TransportProtos.TsKvProto tsKvProtoAttribute3 = getTsKvProto("attribute3", "42.0", TransportProtos.KeyValueType.DOUBLE_V);
|
||||
TransportProtos.TsKvProto tsKvProtoAttribute4 = getTsKvProto("attribute4", "73", TransportProtos.KeyValueType.LONG_V);
|
||||
TransportProtos.TsKvProto tsKvProtoAttribute5 = getTsKvProto("attribute5", "{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", TransportProtos.KeyValueType.JSON_V);
|
||||
List<TransportProtos.TsKvProto> tsKvProtoList = new ArrayList<>();
|
||||
tsKvProtoList.add(tsKvProtoAttribute1);
|
||||
tsKvProtoList.add(tsKvProtoAttribute2);
|
||||
tsKvProtoList.add(tsKvProtoAttribute3);
|
||||
tsKvProtoList.add(tsKvProtoAttribute4);
|
||||
tsKvProtoList.add(tsKvProtoAttribute5);
|
||||
return tsKvProtoList;
|
||||
}
|
||||
|
||||
protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) {
|
||||
TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder();
|
||||
TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType);
|
||||
tsKvProtoBuilder.setKv(keyValueProto);
|
||||
return tsKvProtoBuilder.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesRequestIntegrationTest extends AbstractCoapAttributesIntegrationTest {
|
||||
|
||||
protected static final long CLIENT_REQUEST_TIMEOUT = 60000L;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Request attribute values from the server", null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestAttributesValuesFromTheServer() throws Exception {
|
||||
processTestRequestAttributesValuesFromTheServer();
|
||||
}
|
||||
|
||||
protected void processTestRequestAttributesValuesFromTheServer() throws Exception {
|
||||
postAttributes();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
long end = System.currentTimeMillis() + 5000;
|
||||
|
||||
List<String> savedAttributeKeys = null;
|
||||
while (start <= end) {
|
||||
savedAttributeKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {});
|
||||
if (savedAttributeKeys.size() == 5) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
start += 100;
|
||||
}
|
||||
assertNotNull(savedAttributeKeys);
|
||||
|
||||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
|
||||
String featureTokenUrl = getFeatureTokenUrl(accessToken, FeatureType.ATTRIBUTES) + "?clientKeys=" + keys + "&sharedKeys=" + keys;
|
||||
CoapClient client = getCoapClient(featureTokenUrl);
|
||||
|
||||
CoapResponse getAttributesResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).get();
|
||||
validateResponse(getAttributesResponse);
|
||||
}
|
||||
|
||||
protected void postAttributes() throws Exception {
|
||||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
|
||||
CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
|
||||
CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(POST_ATTRIBUTES_PAYLOAD.getBytes(), MediaTypeRegistry.APPLICATION_JSON);
|
||||
assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
|
||||
}
|
||||
|
||||
protected void validateResponse(CoapResponse getAttributesResponse) throws InvalidProtocolBufferException {
|
||||
assertEquals(CoAP.ResponseCode.CONTENT, getAttributesResponse.getCode());
|
||||
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\"}}}}";
|
||||
assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(getAttributesResponse.getPayload(), StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesRequestJsonIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Request attribute values from the server json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestAttributesValuesFromTheServer() throws Exception {
|
||||
super.testRequestAttributesValuesFromTheServer();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request;
|
||||
|
||||
import com.github.os72.protobuf.dynamic.DynamicSchema;
|
||||
import com.google.protobuf.Descriptors;
|
||||
import com.google.protobuf.DynamicMessage;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.squareup.wire.schema.internal.parser.ProtoFileElement;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
|
||||
|
||||
public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostAttributes {\n" +
|
||||
" string attribute1 = 1;\n" +
|
||||
" bool attribute2 = 2;\n" +
|
||||
" double attribute3 = 3;\n" +
|
||||
" int32 attribute4 = 4;\n" +
|
||||
" JsonObject attribute5 = 5;\n" +
|
||||
"\n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 6;\n" +
|
||||
" repeated int32 someArray = 7;\n" +
|
||||
" NestedJsonObject someNestedObject = 8;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 9;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestAttributesValuesFromTheServer() throws Exception {
|
||||
super.processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT,
|
||||
TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
|
||||
processTestRequestAttributesValuesFromTheServer();
|
||||
}
|
||||
|
||||
protected void postAttributes() throws Exception {
|
||||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
|
||||
DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
|
||||
assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
|
||||
CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
|
||||
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration();
|
||||
assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
|
||||
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
|
||||
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
|
||||
assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
|
||||
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
|
||||
ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
|
||||
DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
|
||||
|
||||
DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
|
||||
Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(nestedJsonObjectBuilderDescriptor);
|
||||
DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
|
||||
|
||||
DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
|
||||
Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(jsonObjectBuilderDescriptor);
|
||||
DynamicMessage jsonObject = jsonObjectBuilder
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
|
||||
.build();
|
||||
|
||||
DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
|
||||
Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
|
||||
assertNotNull(postAttributesMsgDescriptor);
|
||||
DynamicMessage postAttributesMsg = postAttributesBuilder
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
|
||||
.build();
|
||||
byte[] payload = postAttributesMsg.toByteArray();
|
||||
CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
|
||||
CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
|
||||
}
|
||||
|
||||
protected void validateResponse(CoapResponse getAttributesResponse) throws InvalidProtocolBufferException {
|
||||
TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg();
|
||||
TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(getAttributesResponse.getPayload());
|
||||
assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId());
|
||||
List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
|
||||
assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
|
||||
}
|
||||
|
||||
private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() {
|
||||
TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder();
|
||||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
|
||||
result.addAllClientAttributeList(tsKvProtoList);
|
||||
result.addAllSharedAttributeList(tsKvProtoList);
|
||||
result.setRequestId(0);
|
||||
return result.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesRequestJsonSqlIntegrationTest extends AbstractCoapAttributesRequestJsonIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesRequestProtoSqlIntegrationTest extends AbstractCoapAttributesRequestProtoIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.request.AbstractCoapAttributesRequestIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesRequestSqlIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapHandler;
|
||||
import org.eclipse.californium.core.CoapObserveRelation;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.Request;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesUpdatesIntegrationTest extends AbstractCoapAttributesIntegrationTest {
|
||||
|
||||
private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}";
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Subscribe to attribute updates", null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
|
||||
processTestSubscribeToAttributesUpdates();
|
||||
}
|
||||
|
||||
protected void processTestSubscribeToAttributesUpdates() throws Exception {
|
||||
|
||||
CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
TestCoapCallback testCoapCallback = new TestCoapCallback(latch);
|
||||
|
||||
Request request = Request.newGet().setObserve();
|
||||
request.setType(CoAP.Type.CON);
|
||||
CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
|
||||
validateUpdateAttributesResponse(testCoapCallback);
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
|
||||
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class);
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
|
||||
validateDeleteAttributesResponse(testCoapCallback);
|
||||
|
||||
observeRelation.proactiveCancel();
|
||||
assertTrue(observeRelation.isCanceled());
|
||||
}
|
||||
|
||||
protected void validateUpdateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
|
||||
assertNotNull(callback.getPayloadBytes());
|
||||
assertNotNull(callback.getObserve());
|
||||
assertEquals(0, callback.getObserve().intValue());
|
||||
String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
|
||||
assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response));
|
||||
}
|
||||
|
||||
protected void validateDeleteAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
|
||||
assertNotNull(callback.getPayloadBytes());
|
||||
assertNotNull(callback.getObserve());
|
||||
assertEquals(1, callback.getObserve().intValue());
|
||||
String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
|
||||
assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response));
|
||||
}
|
||||
|
||||
protected static class TestCoapCallback implements CoapHandler {
|
||||
|
||||
private final CountDownLatch latch;
|
||||
|
||||
private Integer observe;
|
||||
private byte[] payloadBytes;
|
||||
|
||||
public byte[] getPayloadBytes() {
|
||||
return payloadBytes;
|
||||
}
|
||||
|
||||
public Integer getObserve() {
|
||||
return observe;
|
||||
}
|
||||
|
||||
private TestCoapCallback(CountDownLatch latch) {
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(CoapResponse response) {
|
||||
assertNotNull(response.getPayload());
|
||||
assertEquals(response.getCode(), CoAP.ResponseCode.CONTENT);
|
||||
observe = response.getOptions().getObserve();
|
||||
payloadBytes = response.getPayload();
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
log.warn("Command Response Ack Error, No connect");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesUpdatesJsonIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
|
||||
super.testSubscribeToAttributesUpdatesFromTheServer();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception {
|
||||
processTestSubscribeToAttributesUpdates();
|
||||
}
|
||||
|
||||
protected void validateUpdateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
|
||||
assertNotNull(callback.getPayloadBytes());
|
||||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
|
||||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList();
|
||||
attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
|
||||
|
||||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
|
||||
TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
|
||||
|
||||
List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList());
|
||||
|
||||
assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size());
|
||||
assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList));
|
||||
|
||||
}
|
||||
|
||||
protected void validateDeleteAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
|
||||
assertNotNull(callback.getPayloadBytes());
|
||||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
|
||||
attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5");
|
||||
|
||||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build();
|
||||
TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes());
|
||||
|
||||
assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size());
|
||||
assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesUpdatesSqlIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesUpdatesSqlJsonIntegrationTest extends AbstractCoapAttributesUpdatesJsonIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.attributes.updates.AbstractCoapAttributesUpdatesProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesUpdatesSqlProtoIntegrationTest extends AbstractCoapAttributesUpdatesProtoIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.ClaimRequest;
|
||||
import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.dao.device.claim.ClaimResponse;
|
||||
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!";
|
||||
|
||||
protected User customerAdmin;
|
||||
protected Customer savedCustomer;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
super.processBeforeTest("Test Claim device", null, null);
|
||||
createCustomerAndUser();
|
||||
}
|
||||
|
||||
protected void createCustomerAndUser() throws Exception {
|
||||
Customer customer = new Customer();
|
||||
customer.setTenantId(savedTenant.getId());
|
||||
customer.setTitle("Test Claiming Customer");
|
||||
savedCustomer = doPost("/api/customer", customer, Customer.class);
|
||||
assertNotNull(savedCustomer);
|
||||
assertEquals(savedTenant.getId(), savedCustomer.getTenantId());
|
||||
|
||||
User user = new User();
|
||||
user.setAuthority(Authority.CUSTOMER_USER);
|
||||
user.setTenantId(savedTenant.getId());
|
||||
user.setCustomerId(savedCustomer.getId());
|
||||
user.setEmail("customer@thingsboard.org");
|
||||
|
||||
customerAdmin = createUser(user, CUSTOMER_USER_PASSWORD);
|
||||
assertNotNull(customerAdmin);
|
||||
assertEquals(customerAdmin.getCustomerId(), savedCustomer.getId());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimingDevice() throws Exception {
|
||||
processTestClaimingDevice(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
|
||||
processTestClaimingDevice(true);
|
||||
}
|
||||
|
||||
protected void processTestClaimingDevice(boolean emptyPayload) throws Exception {
|
||||
log.warn("[testClaimingDevice] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
|
||||
CoapClient client = getCoapClient(FeatureType.CLAIM);
|
||||
byte[] payloadBytes;
|
||||
byte[] failurePayloadBytes;
|
||||
if (emptyPayload) {
|
||||
payloadBytes = "{}".getBytes();
|
||||
failurePayloadBytes = "{\"durationMs\":1}".getBytes();
|
||||
} else {
|
||||
payloadBytes = "{\"secretKey\":\"value\", \"durationMs\":60000}".getBytes();
|
||||
failurePayloadBytes = "{\"secretKey\":\"value\", \"durationMs\":1}".getBytes();
|
||||
}
|
||||
validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes);
|
||||
}
|
||||
|
||||
protected void validateClaimResponse(boolean emptyPayload, CoapClient client, byte[] payloadBytes, byte[] failurePayloadBytes) throws Exception {
|
||||
postClaimRequest(client, failurePayloadBytes);
|
||||
|
||||
loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD);
|
||||
ClaimRequest claimRequest;
|
||||
if (!emptyPayload) {
|
||||
claimRequest = new ClaimRequest("value");
|
||||
} else {
|
||||
claimRequest = new ClaimRequest(null);
|
||||
}
|
||||
|
||||
ClaimResponse claimResponse = doExecuteWithRetriesAndInterval(
|
||||
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()),
|
||||
20,
|
||||
100
|
||||
);
|
||||
|
||||
assertEquals(claimResponse, ClaimResponse.FAILURE);
|
||||
|
||||
postClaimRequest(client, payloadBytes);
|
||||
|
||||
ClaimResult claimResult = doExecuteWithRetriesAndInterval(
|
||||
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResult.class, status().isOk()),
|
||||
20,
|
||||
100
|
||||
);
|
||||
assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS);
|
||||
Device claimedDevice = claimResult.getDevice();
|
||||
assertNotNull(claimedDevice);
|
||||
assertNotNull(claimedDevice.getCustomerId());
|
||||
assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId());
|
||||
|
||||
claimResponse = doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest());
|
||||
assertEquals(claimResponse, ClaimResponse.CLAIMED);
|
||||
}
|
||||
|
||||
private void postClaimRequest(CoapClient client, byte[] payload) throws IOException, ConnectorException {
|
||||
CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapClaimJsonDeviceTest extends AbstractCoapClaimDeviceTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
super.processBeforeTest("Test Claim device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
createCustomerAndUser();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.afterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimingDevice() throws Exception {
|
||||
super.testClaimingDevice();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
|
||||
super.testClaimingDeviceWithoutSecretAndDuration();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.gen.transport.TransportApiProtos;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapClaimProtoDeviceTest extends AbstractCoapClaimDeviceTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Claim device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
|
||||
createCustomerAndUser();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception { super.afterTest(); }
|
||||
|
||||
@Test
|
||||
public void testClaimingDevice() throws Exception {
|
||||
processTestClaimingDevice(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception {
|
||||
processTestClaimingDevice(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processTestClaimingDevice(boolean emptyPayload) throws Exception {
|
||||
CoapClient client = getCoapClient(FeatureType.CLAIM);
|
||||
byte[] payloadBytes;
|
||||
if (emptyPayload) {
|
||||
TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(0, emptyPayload);
|
||||
payloadBytes = claimDevice.toByteArray();
|
||||
} else {
|
||||
TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(60000, emptyPayload);
|
||||
payloadBytes = claimDevice.toByteArray();
|
||||
}
|
||||
TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(1, emptyPayload);
|
||||
byte[] failurePayloadBytes = claimDevice.toByteArray();
|
||||
validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes);
|
||||
}
|
||||
|
||||
private TransportApiProtos.ClaimDevice getClaimDevice(long duration, boolean emptyPayload) {
|
||||
TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder();
|
||||
if (!emptyPayload) {
|
||||
claimDeviceBuilder.setSecretKey("value");
|
||||
}
|
||||
if (duration > 0) {
|
||||
claimDeviceBuilder.setSecretKey("value");
|
||||
claimDeviceBuilder.setDurationMs(duration);
|
||||
} else {
|
||||
claimDeviceBuilder.setDurationMs(0);
|
||||
}
|
||||
return claimDeviceBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
|
||||
package org.thingsboard.server.transport.coap.claim.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
|
||||
import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimJsonDeviceTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoNoSqlTest
|
||||
public class MqttAttributesNoSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest {
|
||||
@DaoSqlTest
|
||||
public class CoapClaimDeviceJsonSqlTest extends AbstractCoapClaimJsonDeviceTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.claim.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimProtoDeviceTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapClaimDeviceProtoSqlTest extends AbstractCoapClaimProtoDeviceTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.claim.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.claim.AbstractCoapClaimDeviceTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapClaimDeviceSqlTest extends AbstractCoapClaimDeviceTest {
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.provision;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.common.transport.util.JsonUtils;
|
||||
import org.thingsboard.server.dao.device.DeviceCredentialsService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
DeviceCredentialsService deviceCredentialsService;
|
||||
|
||||
@Autowired
|
||||
DeviceService deviceService;
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningDisabledDevice() throws Exception {
|
||||
processTestProvisioningDisabledDevice();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCheckPreProvisionedDevice() throws Exception {
|
||||
processTestProvisioningCheckPreProvisionedDevice();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithoutCredentials();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithAccessToken();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithCert() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithCert();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningWithBadKeyDevice() throws Exception {
|
||||
processTestProvisioningWithBadKeyDevice();
|
||||
}
|
||||
|
||||
|
||||
private void processTestProvisioningDisabledDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null);
|
||||
byte[] result = createCoapClientAndPublish().getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
byte[] result = createCoapClientAndPublish().getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
|
||||
byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN");
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
|
||||
byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE");
|
||||
|
||||
String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
|
||||
String sha3Hash = EncryptionUtil.getSha3Hash(cert);
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
byte[] result = createCoapClientAndPublish().getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningWithBadKeyDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
|
||||
byte[] result = createCoapClientAndPublish().getPayload();
|
||||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
|
||||
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
|
||||
}
|
||||
|
||||
private CoapResponse createCoapClientAndPublish() throws Exception {
|
||||
return createCoapClientAndPublish("");
|
||||
}
|
||||
|
||||
private CoapResponse createCoapClientAndPublish(String deviceCredentials) throws Exception {
|
||||
String provisionRequestMsg = createTestProvisionMessage(deviceCredentials);
|
||||
CoapClient client = getCoapClient(FeatureType.PROVISION);
|
||||
return postProvision(client, provisionRequestMsg.getBytes());
|
||||
}
|
||||
|
||||
|
||||
private CoapResponse postProvision(CoapClient client, byte[] payload) throws IOException, ConnectorException {
|
||||
return client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
private String createTestProvisionMessage(String deviceCredentials) {
|
||||
return "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials + "}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.provision;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
import org.thingsboard.server.dao.device.DeviceCredentialsService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.CredentialsDataProto;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.CredentialsType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceCredentialsMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
DeviceCredentialsService deviceCredentialsService;
|
||||
|
||||
@Autowired
|
||||
DeviceService deviceService;
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningDisabledDevice() throws Exception {
|
||||
processTestProvisioningDisabledDevice();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCheckPreProvisionedDevice() throws Exception {
|
||||
processTestProvisioningCheckPreProvisionedDevice();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithoutCredentials();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithAccessToken();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningCreateNewDeviceWithCert() throws Exception {
|
||||
processTestProvisioningCreateNewDeviceWithCert();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningWithBadKeyDevice() throws Exception {
|
||||
processTestProvisioningWithBadKeyDevice();
|
||||
}
|
||||
|
||||
|
||||
private void processTestProvisioningDisabledDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null);
|
||||
ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
|
||||
|
||||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayload());
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN);
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
|
||||
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
|
||||
|
||||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayload());
|
||||
|
||||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
|
||||
|
||||
Assert.assertNotNull(createdDevice);
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE);
|
||||
|
||||
String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
|
||||
String sha3Hash = EncryptionUtil.getSha3Hash(cert);
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
|
||||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
|
||||
|
||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
|
||||
|
||||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
|
||||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
|
||||
}
|
||||
|
||||
private void processTestProvisioningWithBadKeyDevice() throws Exception {
|
||||
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
|
||||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
|
||||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
|
||||
}
|
||||
|
||||
private CoapResponse createCoapClientAndPublish() throws Exception {
|
||||
byte[] provisionRequestMsg = createTestProvisionMessage();
|
||||
return createCoapClientAndPublish(provisionRequestMsg);
|
||||
}
|
||||
|
||||
private CoapResponse createCoapClientAndPublish(byte[] provisionRequestMsg) throws Exception {
|
||||
CoapClient client = getCoapClient(FeatureType.PROVISION);
|
||||
return postProvision(client, provisionRequestMsg);
|
||||
}
|
||||
|
||||
private CoapResponse postProvision(CoapClient client, byte[] payload) throws IOException, ConnectorException {
|
||||
return client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
private byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData) throws Exception {
|
||||
return ProvisionDeviceRequestMsg.newBuilder()
|
||||
.setDeviceName("Test Provision device")
|
||||
.setCredentialsType(credentialsType != null ? credentialsType : CredentialsType.ACCESS_TOKEN)
|
||||
.setCredentialsDataProto(credentialsData != null ? credentialsData: CredentialsDataProto.newBuilder().build())
|
||||
.setProvisionDeviceCredentialsMsg(
|
||||
ProvisionDeviceCredentialsMsg.newBuilder()
|
||||
.setProvisionDeviceKey("testProvisionKey")
|
||||
.setProvisionDeviceSecret("testProvisionSecret")
|
||||
).build()
|
||||
.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
private byte[] createTestProvisionMessage() throws Exception {
|
||||
return createTestsProvisionMessage(null, null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.provision.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.provision.AbstractCoapProvisionJsonDeviceTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapProvisionDeviceJsonSqlTest extends AbstractCoapProvisionJsonDeviceTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.provision.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.provision.AbstractCoapProvisionProtoDeviceTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapProvisionDeviceProtoSqlTest extends AbstractCoapProvisionProtoDeviceTest {
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc;
|
||||
|
||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.service.security.AccessValidator;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("RPC test device", null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapOneWayRpcDeviceOffline() throws Exception {
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}";
|
||||
String deviceId = savedDevice.getId().getId().toString();
|
||||
|
||||
doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409),
|
||||
asyncContextTimeoutToUseRpcPlugin);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapOneWayRpcDeviceDoesNotExist() throws Exception {
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}";
|
||||
String nonExistentDeviceId = Uuids.timeBased().toString();
|
||||
|
||||
String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class,
|
||||
status().isNotFound());
|
||||
Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapTwoWayRpcDeviceOffline() throws Exception {
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}";
|
||||
String deviceId = savedDevice.getId().getId().toString();
|
||||
|
||||
doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409),
|
||||
asyncContextTimeoutToUseRpcPlugin);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapTwoWayRpcDeviceDoesNotExist() throws Exception {
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}";
|
||||
String nonExistentDeviceId = Uuids.timeBased().toString();
|
||||
|
||||
String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class,
|
||||
status().isNotFound());
|
||||
Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapOneWayRpc() throws Exception {
|
||||
processOneWayRpcTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerCoapTwoWayRpc() throws Exception {
|
||||
processTwoWayRpcTest();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapHandler;
|
||||
import org.eclipse.californium.core.CoapObserveRelation;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.core.coap.Request;
|
||||
import org.junit.Assert;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
|
||||
|
||||
protected Long asyncContextTimeoutToUseRpcPlugin;
|
||||
|
||||
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
|
||||
super.processBeforeTest(deviceName, coapDeviceType, payloadType);
|
||||
asyncContextTimeoutToUseRpcPlugin = 10000L;
|
||||
}
|
||||
|
||||
protected void processOneWayRpcTest() throws Exception {
|
||||
CoapClient client = getCoapClient(FeatureType.RPC);
|
||||
client.useCONs();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
TestCoapCallback testCoapCallback = new TestCoapCallback(client, latch, true);
|
||||
|
||||
Request request = Request.newGet().setObserve();
|
||||
CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
|
||||
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
|
||||
String deviceId = savedDevice.getId().getId().toString();
|
||||
String result = doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
|
||||
Assert.assertTrue(StringUtils.isEmpty(result));
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
assertEquals(0, testCoapCallback.getObserve().intValue());
|
||||
observeRelation.proactiveCancel();
|
||||
assertTrue(observeRelation.isCanceled());
|
||||
}
|
||||
|
||||
protected void processTwoWayRpcTest() throws Exception {
|
||||
CoapClient client = getCoapClient(FeatureType.RPC);
|
||||
client.useCONs();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
TestCoapCallback testCoapCallback = new TestCoapCallback(client, latch, false);
|
||||
|
||||
Request request = Request.newGet().setObserve();
|
||||
request.setType(CoAP.Type.CON);
|
||||
CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
|
||||
|
||||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
|
||||
String deviceId = savedDevice.getId().getId().toString();
|
||||
|
||||
String expected = "{\"value1\":\"A\",\"value2\":\"B\"}";
|
||||
|
||||
String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(expected, result);
|
||||
assertEquals(0, testCoapCallback.getObserve().intValue());
|
||||
observeRelation.proactiveCancel();
|
||||
assertTrue(observeRelation.isCanceled());
|
||||
|
||||
// // TODO: 3/11/21 Fix test to validate next RPC
|
||||
// latch = new CountDownLatch(1);
|
||||
//
|
||||
// result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
|
||||
// latch.await(3, TimeUnit.SECONDS);
|
||||
//
|
||||
// assertEquals(expected, result);
|
||||
// assertEquals(1, testCoapCallback.getObserve().intValue());
|
||||
}
|
||||
|
||||
protected void processOnLoadResponse(CoapResponse response, CoapClient client, Integer observe, CountDownLatch latch) {
|
||||
client.setURI(getRpcResponseFeatureTokenUrl(accessToken, observe));
|
||||
client.post(new CoapHandler() {
|
||||
@Override
|
||||
public void onLoad(CoapResponse response) {
|
||||
log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
log.warn("Command Response Ack Error, No connect");
|
||||
}
|
||||
}, DEVICE_RESPONSE, MediaTypeRegistry.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
protected String getRpcResponseFeatureTokenUrl(String token, int requestId) {
|
||||
return COAP_BASE_URL + token + "/" + FeatureType.RPC.name().toLowerCase() + "/" + requestId;
|
||||
}
|
||||
|
||||
private class TestCoapCallback implements CoapHandler {
|
||||
|
||||
private final CoapClient client;
|
||||
private final CountDownLatch latch;
|
||||
private final boolean isOneWayRpc;
|
||||
|
||||
public Integer getObserve() {
|
||||
return observe;
|
||||
}
|
||||
|
||||
private Integer observe;
|
||||
|
||||
private TestCoapCallback(CoapClient client, CountDownLatch latch, boolean isOneWayRpc) {
|
||||
this.client = client;
|
||||
this.latch = latch;
|
||||
this.isOneWayRpc = isOneWayRpc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(CoapResponse response) {
|
||||
log.warn("coap response: {}, {}", response, response.getCode());
|
||||
assertNotNull(response.getPayload());
|
||||
assertEquals(response.getCode(), CoAP.ResponseCode.CONTENT);
|
||||
observe = response.getOptions().getObserve();
|
||||
if (!isOneWayRpc) {
|
||||
processOnLoadResponse(response, client, observe, latch);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
log.warn("Command Response Ack Error, No connect");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapServerSideRpcJsonIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerMqttOneWayRpc() throws Exception {
|
||||
processOneWayRpcTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerMqttTwoWayRpc() throws Exception {
|
||||
processTwoWayRpcTest();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapHandler;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
super.processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerMqttOneWayRpc() throws Exception {
|
||||
processOneWayRpcTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerMqttTwoWayRpc() throws Exception {
|
||||
processTwoWayRpcTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processOnLoadResponse(CoapResponse response, CoapClient client, Integer observe, CountDownLatch latch) {
|
||||
client.setURI(getRpcResponseFeatureTokenUrl(accessToken, observe));
|
||||
TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
|
||||
.setPayload(DEVICE_RESPONSE)
|
||||
.setRequestId(observe)
|
||||
.build();
|
||||
client.post(new CoapHandler() {
|
||||
@Override
|
||||
public void onLoad(CoapResponse response) {
|
||||
log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
log.warn("Command Response Ack Error, No connect");
|
||||
}
|
||||
}, toDeviceRpcResponseMsg.toByteArray(), MediaTypeRegistry.APPLICATION_JSON);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapServerSideRpcJsonSqlIntegrationTest extends AbstractCoapServerSideRpcJsonIntegrationTest {
|
||||
}
|
||||
@ -13,19 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt;
|
||||
package org.thingsboard.server.transport.coap.rpc.sql;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by ashvayka on 11.05.18.
|
||||
*/
|
||||
public class DbConfigurationTestRule implements TestRule {
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return null;
|
||||
}
|
||||
@DaoSqlTest
|
||||
public class CoapServerSideRpcProtoSqlIntegrationTest extends AbstractCoapServerSideRpcProtoIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.rpc.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcDefaultIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class CoapServerSideRpcSqlIntegrationTest extends AbstractCoapServerSideRpcDefaultIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
private static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
|
||||
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Post Attributes device", null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushAttributes() throws Exception {
|
||||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
|
||||
processAttributesTest(expectedKeys, PAYLOAD_VALUES_STR.getBytes());
|
||||
}
|
||||
|
||||
protected void processAttributesTest(List<String> expectedKeys, byte[] payload) throws Exception {
|
||||
log.warn("[testPushAttributes] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
|
||||
CoapClient client = getCoapClient(FeatureType.ATTRIBUTES);
|
||||
|
||||
postAttributes(client, payload);
|
||||
|
||||
DeviceId deviceId = savedDevice.getId();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
long end = System.currentTimeMillis() + 5000;
|
||||
|
||||
List<String> actualKeys = null;
|
||||
while (start <= end) {
|
||||
actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {});
|
||||
if (actualKeys.size() == expectedKeys.size()) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
start += 100;
|
||||
}
|
||||
assertNotNull(actualKeys);
|
||||
|
||||
Set<String> actualKeySet = new HashSet<>(actualKeys);
|
||||
|
||||
Set<String> expectedKeySet = new HashSet<>(expectedKeys);
|
||||
|
||||
assertEquals(expectedKeySet, actualKeySet);
|
||||
|
||||
String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet);
|
||||
List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {});
|
||||
assertAttributesValues(values, expectedKeySet);
|
||||
String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
|
||||
doDelete(deleteAttributesUrl);
|
||||
}
|
||||
|
||||
private void postAttributes(CoapClient client, byte[] payload) throws IOException, ConnectorException {
|
||||
if (payload == null) {
|
||||
payload = PAYLOAD_VALUES_STR.getBytes();
|
||||
}
|
||||
CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException {
|
||||
for (Map<String, Object> map : deviceValues) {
|
||||
String key = (String) map.get("key");
|
||||
Object value = map.get("value");
|
||||
assertTrue(expectedKeySet.contains(key));
|
||||
switch (key) {
|
||||
case "key1":
|
||||
assertEquals("value1", value);
|
||||
break;
|
||||
case "key2":
|
||||
assertEquals(true, value);
|
||||
break;
|
||||
case "key3":
|
||||
assertEquals(3.0, value);
|
||||
break;
|
||||
case "key4":
|
||||
assertEquals(4, value);
|
||||
break;
|
||||
case "key5":
|
||||
assertNotNull(value);
|
||||
assertEquals(3, ((LinkedHashMap) value).size());
|
||||
assertEquals(42, ((LinkedHashMap) value).get("someNumber"));
|
||||
assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray"));
|
||||
LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject");
|
||||
assertEquals("value", someNestedObject.get("key"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) {
|
||||
return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesJsonIntegrationTest extends AbstractCoapAttributesIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Post Attributes device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushAttributes() throws Exception {
|
||||
super.testPushAttributes();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes;
|
||||
|
||||
import com.github.os72.protobuf.dynamic.DynamicSchema;
|
||||
import com.google.protobuf.Descriptors;
|
||||
import com.google.protobuf.DynamicMessage;
|
||||
import com.squareup.wire.schema.internal.parser.ProtoFileElement;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapAttributesProtoIntegrationTest extends AbstractCoapAttributesIntegrationTest {
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushAttributes() throws Exception {
|
||||
super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
|
||||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
|
||||
DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
|
||||
assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
|
||||
CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
|
||||
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration();
|
||||
assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
|
||||
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
|
||||
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
|
||||
assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
|
||||
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
|
||||
ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA);
|
||||
DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
|
||||
|
||||
DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
|
||||
Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(nestedJsonObjectBuilderDescriptor);
|
||||
DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
|
||||
|
||||
DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
|
||||
Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(jsonObjectBuilderDescriptor);
|
||||
DynamicMessage jsonObject = jsonObjectBuilder
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
|
||||
.build();
|
||||
|
||||
DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
|
||||
Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
|
||||
assertNotNull(postAttributesMsgDescriptor);
|
||||
DynamicMessage postAttributesMsg = postAttributesBuilder
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("key1"), "value1")
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("key2"), true)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("key3"), 3.0)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4)
|
||||
.setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject)
|
||||
.build();
|
||||
processAttributesTest(expectedKeys, postAttributesMsg.toByteArray());
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,14 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.rpc.nosql;
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||
import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcDefaultIntegrationTest;
|
||||
import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoNoSqlTest
|
||||
public class MqttServerSideRpcNoSqlIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest {
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesSqlIntegrationTest extends AbstractCoapAttributesIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesSqlJsonIntegrationTest extends AbstractCoapAttributesJsonIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.attributes.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.attributes.AbstractCoapAttributesProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoSqlTest
|
||||
public class CoapAttributesSqlProtoIntegrationTest extends AbstractCoapAttributesProtoIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.californium.core.CoapClient;
|
||||
import org.eclipse.californium.core.CoapResponse;
|
||||
import org.eclipse.californium.core.coap.CoAP;
|
||||
import org.eclipse.californium.core.coap.MediaTypeRegistry;
|
||||
import org.eclipse.californium.elements.exception.ConnectorException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
|
||||
import org.thingsboard.server.common.msg.session.FeatureType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoapIntegrationTest {
|
||||
|
||||
private static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
|
||||
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Post Telemetry device", null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushTelemetry() throws Exception {
|
||||
processTestPostTelemetry(null, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushTelemetryWithTs() throws Exception {
|
||||
String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}";
|
||||
processTestPostTelemetry(payloadStr.getBytes(), true);
|
||||
}
|
||||
|
||||
protected void processTestPostTelemetry(byte[] payloadBytes, boolean withTs) throws Exception {
|
||||
log.warn("[testPushTelemetry] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType());
|
||||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
|
||||
CoapClient coapClient = getCoapClient(FeatureType.TELEMETRY);
|
||||
postTelemetry(coapClient, payloadBytes);
|
||||
|
||||
String deviceId = savedDevice.getId().getId().toString();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
long end = System.currentTimeMillis() + 5000;
|
||||
|
||||
List<String> actualKeys = null;
|
||||
while (start <= end) {
|
||||
actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() {});
|
||||
if (actualKeys.size() == expectedKeys.size()) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
start += 100;
|
||||
}
|
||||
assertNotNull(actualKeys);
|
||||
|
||||
Set<String> actualKeySet = new HashSet<>(actualKeys);
|
||||
Set<String> expectedKeySet = new HashSet<>(expectedKeys);
|
||||
|
||||
assertEquals(expectedKeySet, actualKeySet);
|
||||
|
||||
String getTelemetryValuesUrl;
|
||||
if (withTs) {
|
||||
getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=15000&keys=" + String.join(",", actualKeySet);
|
||||
} else {
|
||||
getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet);
|
||||
}
|
||||
start = System.currentTimeMillis();
|
||||
end = System.currentTimeMillis() + 5000;
|
||||
Map<String, List<Map<String, Object>>> values = null;
|
||||
while (start <= end) {
|
||||
values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() {});
|
||||
boolean valid = values.size() == expectedKeys.size();
|
||||
if (valid) {
|
||||
for (String key : expectedKeys) {
|
||||
List<Map<String, Object>> tsValues = values.get(key);
|
||||
if (tsValues != null && tsValues.size() > 0) {
|
||||
Object ts = tsValues.get(0).get("ts");
|
||||
if (ts == null) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
start += 100;
|
||||
}
|
||||
assertNotNull(values);
|
||||
|
||||
if (withTs) {
|
||||
assertTs(values, expectedKeys, 10000, 0);
|
||||
}
|
||||
assertValues(values, 0);
|
||||
}
|
||||
|
||||
private void postTelemetry(CoapClient client, byte[] payload) throws IOException, ConnectorException {
|
||||
if (payload == null) {
|
||||
payload = PAYLOAD_VALUES_STR.getBytes();
|
||||
}
|
||||
CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON);
|
||||
assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode());
|
||||
}
|
||||
|
||||
private void assertTs(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) {
|
||||
assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts"));
|
||||
assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts"));
|
||||
assertEquals(ts, deviceValues.get(expectedKeys.get(2)).get(arrayIndex).get("ts"));
|
||||
assertEquals(ts, deviceValues.get(expectedKeys.get(3)).get(arrayIndex).get("ts"));
|
||||
assertEquals(ts, deviceValues.get(expectedKeys.get(4)).get(arrayIndex).get("ts"));
|
||||
}
|
||||
|
||||
private void assertValues(Map<String, List<Map<String, Object>>> deviceValues, int arrayIndex) {
|
||||
for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
List<Map<String, Object>> tsKv = entry.getValue();
|
||||
String value = (String) tsKv.get(arrayIndex).get("value");
|
||||
switch (key) {
|
||||
case "key1":
|
||||
assertEquals("value1", value);
|
||||
break;
|
||||
case "key2":
|
||||
assertEquals("true", value);
|
||||
break;
|
||||
case "key3":
|
||||
assertEquals("3.0", value);
|
||||
break;
|
||||
case "key4":
|
||||
assertEquals("4", value);
|
||||
break;
|
||||
case "key5":
|
||||
assertEquals("{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapTimeseriesJsonIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
processBeforeTest("Test Post Telemetry device json payload", CoapDeviceType.DEFAULT, TransportPayloadType.JSON);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPushTelemetry() throws Exception {
|
||||
super.testPushTelemetry();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushTelemetryWithTs() throws Exception {
|
||||
super.testPushTelemetryWithTs();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries;
|
||||
|
||||
import com.github.os72.protobuf.dynamic.DynamicSchema;
|
||||
import com.google.protobuf.Descriptors;
|
||||
import com.google.protobuf.DynamicMessage;
|
||||
import com.squareup.wire.schema.internal.parser.ProtoFileElement;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.CoapDeviceType;
|
||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
processAfterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushTelemetry() throws Exception {
|
||||
super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
|
||||
DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
|
||||
assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
|
||||
CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
|
||||
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
|
||||
assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
|
||||
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
|
||||
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
|
||||
assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
|
||||
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
|
||||
ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA);
|
||||
DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
|
||||
|
||||
DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
|
||||
Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(nestedJsonObjectBuilderDescriptor);
|
||||
DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
|
||||
|
||||
DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
|
||||
Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(jsonObjectBuilderDescriptor);
|
||||
DynamicMessage jsonObject = jsonObjectBuilder
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
|
||||
.build();
|
||||
|
||||
DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
|
||||
Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
|
||||
assertNotNull(postTelemetryMsgDescriptor);
|
||||
DynamicMessage postTelemetryMsg = postTelemetryBuilder
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "value1")
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("key2"), true)
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 3.0)
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4)
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject)
|
||||
.build();
|
||||
processTestPostTelemetry(postTelemetryMsg.toByteArray(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushTelemetryWithTs() throws Exception {
|
||||
String schemaStr = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostTelemetry {\n" +
|
||||
" int64 ts = 1;\n" +
|
||||
" Values values = 2;\n" +
|
||||
" \n" +
|
||||
" message Values {\n" +
|
||||
" string key1 = 3;\n" +
|
||||
" bool key2 = 4;\n" +
|
||||
" double key3 = 5;\n" +
|
||||
" int32 key4 = 6;\n" +
|
||||
" JsonObject key5 = 7;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 8;\n" +
|
||||
" repeated int32 someArray = 9;\n" +
|
||||
" NestedJsonObject someNestedObject = 10;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 11;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
|
||||
DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
|
||||
assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
|
||||
CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
|
||||
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
|
||||
assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
|
||||
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
|
||||
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
|
||||
assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
|
||||
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
|
||||
ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr);
|
||||
DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
|
||||
|
||||
DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
|
||||
Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(nestedJsonObjectBuilderDescriptor);
|
||||
DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
|
||||
|
||||
DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
|
||||
Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
|
||||
assertNotNull(jsonObjectBuilderDescriptor);
|
||||
DynamicMessage jsonObject = jsonObjectBuilder
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
|
||||
.addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
|
||||
.setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
|
||||
.build();
|
||||
|
||||
|
||||
DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values");
|
||||
Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType();
|
||||
assertNotNull(valuesDescriptor);
|
||||
|
||||
DynamicMessage valuesMsg = valuesBuilder
|
||||
.setField(valuesDescriptor.findFieldByName("key1"), "value1")
|
||||
.setField(valuesDescriptor.findFieldByName("key2"), true)
|
||||
.setField(valuesDescriptor.findFieldByName("key3"), 3.0)
|
||||
.setField(valuesDescriptor.findFieldByName("key4"), 4)
|
||||
.setField(valuesDescriptor.findFieldByName("key5"), jsonObject)
|
||||
.build();
|
||||
|
||||
DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
|
||||
Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
|
||||
assertNotNull(postTelemetryMsgDescriptor);
|
||||
DynamicMessage postTelemetryMsg = postTelemetryBuilder
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L)
|
||||
.setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg)
|
||||
.build();
|
||||
|
||||
processTestPostTelemetry(postTelemetryMsg.toByteArray(), true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,12 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request.nosql;
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
|
||||
|
||||
|
||||
@DaoNoSqlTest
|
||||
public class MqttAttributesRequestNoSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
|
||||
public class CoapTimeseriesNoSqlIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
|
||||
}
|
||||
@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
|
||||
@DaoNoSqlTest
|
||||
public class MqttAttributesNoSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest {
|
||||
public class CoapTimeseriesNoSqlJsonIntegrationTest extends AbstractCoapTimeseriesJsonIntegrationTest {
|
||||
}
|
||||
@ -13,12 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates.nosql;
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.nosql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
|
||||
|
||||
|
||||
@DaoNoSqlTest
|
||||
public class MqttAttributesUpdatesNoSqlIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
|
||||
public class CoapTimeseriesNoSqlProtoIntegrationTest extends AbstractCoapTimeseriesProtoIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoSqlTest
|
||||
public class CoapTimeseriesSqlIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesJsonIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoSqlTest
|
||||
public class CoapTimeseriesSqlJsonIntegrationTest extends AbstractCoapTimeseriesJsonIntegrationTest {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.transport.coap.telemetry.timeseries.sql;
|
||||
|
||||
import org.thingsboard.server.transport.coap.telemetry.timeseries.AbstractCoapTimeseriesProtoIntegrationTest;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
/**
|
||||
* Created by Valerii Sosliuk on 8/22/2017.
|
||||
*/
|
||||
@DaoSqlTest
|
||||
public class CoapTimeseriesSqlProtoIntegrationTest extends AbstractCoapTimeseriesProtoIntegrationTest {
|
||||
}
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt;
|
||||
package org.thingsboard.server.transport.mqtt;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -44,71 +44,17 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.controller.AbstractControllerTest;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest {
|
||||
|
||||
protected static final String MQTT_URL = "tcp://localhost:1883";
|
||||
|
||||
private static final AtomicInteger atomicInteger = new AtomicInteger(2);
|
||||
|
||||
public static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostTelemetry {\n" +
|
||||
" string key1 = 1;\n" +
|
||||
" bool key2 = 2;\n" +
|
||||
" double key3 = 3;\n" +
|
||||
" int32 key4 = 4;\n" +
|
||||
" JsonObject key5 = 5;\n" +
|
||||
"\n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 6;\n" +
|
||||
" repeated int32 someArray = 7;\n" +
|
||||
" NestedJsonObject someNestedObject = 8;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 9;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
public static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
|
||||
"\n" +
|
||||
"package test;\n" +
|
||||
"\n" +
|
||||
"message PostAttributes {\n" +
|
||||
" string key1 = 1;\n" +
|
||||
" bool key2 = 2;\n" +
|
||||
" double key3 = 3;\n" +
|
||||
" int32 key4 = 4;\n" +
|
||||
" JsonObject key5 = 5;\n" +
|
||||
"\n" +
|
||||
" message JsonObject {\n" +
|
||||
" int32 someNumber = 6;\n" +
|
||||
" repeated int32 someArray = 7;\n" +
|
||||
" NestedJsonObject someNestedObject = 8;\n" +
|
||||
" message NestedJsonObject {\n" +
|
||||
" string key = 9;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
protected Tenant savedTenant;
|
||||
protected User tenantAdmin;
|
||||
|
||||
protected Device savedDevice;
|
||||
protected String accessToken;
|
||||
public abstract class AbstractMqttIntegrationTest extends AbstractTransportIntegrationTest {
|
||||
|
||||
protected Device savedGateway;
|
||||
protected String gatewayAccessToken;
|
||||
@ -208,45 +154,6 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
|
||||
client.publish(topic, message);
|
||||
}
|
||||
|
||||
protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
|
||||
List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
|
||||
TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V);
|
||||
TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V);
|
||||
TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "3.0", TransportProtos.KeyValueType.DOUBLE_V);
|
||||
TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "4", TransportProtos.KeyValueType.LONG_V);
|
||||
TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V);
|
||||
keyValueProtos.add(strKeyValueProto);
|
||||
keyValueProtos.add(boolKeyValueProto);
|
||||
keyValueProtos.add(dblKeyValueProto);
|
||||
keyValueProtos.add(longKeyValueProto);
|
||||
keyValueProtos.add(jsonKeyValueProto);
|
||||
return keyValueProtos;
|
||||
}
|
||||
|
||||
protected TransportProtos.KeyValueProto getKeyValueProto(String key, String strValue, TransportProtos.KeyValueType type) {
|
||||
TransportProtos.KeyValueProto.Builder keyValueProtoBuilder = TransportProtos.KeyValueProto.newBuilder();
|
||||
keyValueProtoBuilder.setKey(key);
|
||||
keyValueProtoBuilder.setType(type);
|
||||
switch (type) {
|
||||
case BOOLEAN_V:
|
||||
keyValueProtoBuilder.setBoolV(Boolean.parseBoolean(strValue));
|
||||
break;
|
||||
case LONG_V:
|
||||
keyValueProtoBuilder.setLongV(Long.parseLong(strValue));
|
||||
break;
|
||||
case DOUBLE_V:
|
||||
keyValueProtoBuilder.setDoubleV(Double.parseDouble(strValue));
|
||||
break;
|
||||
case STRING_V:
|
||||
keyValueProtoBuilder.setStringV(strValue);
|
||||
break;
|
||||
case JSON_V:
|
||||
keyValueProtoBuilder.setJsonV(strValue);
|
||||
break;
|
||||
}
|
||||
return keyValueProtoBuilder.build();
|
||||
}
|
||||
|
||||
protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
|
||||
String telemetryTopic, String attributesTopic,
|
||||
String telemetryProtoSchema, String attributesProtoSchema,
|
||||
@ -312,34 +219,4 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
|
||||
builder.addAllKv(kvProtos);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected <T> T doExecuteWithRetriesAndInterval(SupplierWithThrowable<T> supplier, int retries, int intervalMs) throws Exception {
|
||||
int count = 0;
|
||||
T result = null;
|
||||
Throwable lastException = null;
|
||||
while (count < retries) {
|
||||
try {
|
||||
result = supplier.get();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
lastException = e;
|
||||
}
|
||||
count++;
|
||||
if (count < retries) {
|
||||
Thread.sleep(intervalMs);
|
||||
}
|
||||
}
|
||||
if (lastException != null) {
|
||||
throw new RuntimeException(lastException);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SupplierWithThrowable<T> {
|
||||
T get() throws Throwable;
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes;
|
||||
package org.thingsboard.server.transport.mqtt.attributes;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
@ -21,7 +21,7 @@ import org.eclipse.paho.client.mqttv3.MqttCallback;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
@ -27,7 +27,7 @@ import org.junit.Test;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.device.profile.MqttTopics;
|
||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||
import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request;
|
||||
|
||||
import com.github.os72.protobuf.dynamic.DynamicSchema;
|
||||
import com.google.protobuf.Descriptors;
|
||||
@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
|
||||
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
|
||||
import org.thingsboard.server.gen.transport.TransportApiProtos;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -93,7 +94,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
|
||||
}
|
||||
|
||||
protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception {
|
||||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
|
||||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", AbstractMqttAttributesIntegrationTest.POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
|
||||
DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
|
||||
assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
|
||||
MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
|
||||
@ -148,7 +149,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
|
||||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes));
|
||||
}
|
||||
|
||||
protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
|
||||
TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder();
|
||||
attributesRequestBuilder.setClientKeys(keys);
|
||||
@ -170,7 +171,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
|
||||
assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
|
||||
}
|
||||
|
||||
protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
protected void validateClientResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
|
||||
TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true);
|
||||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
|
||||
@ -189,7 +190,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
|
||||
assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos));
|
||||
}
|
||||
|
||||
protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
protected void validateSharedResponseGateway(MqttAsyncClient client, AbstractMqttAttributesIntegrationTest.TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException {
|
||||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";
|
||||
TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false);
|
||||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray()));
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesRequestJsonSqlIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesRequestProtoSqlIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.request.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.request.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesRequestSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.TransportPayloadType;
|
||||
import org.thingsboard.server.common.data.device.profile.MqttTopics;
|
||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||
import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesUpdatesSqlIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesUpdatesSqlJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.attributes.updates.sql;
|
||||
package org.thingsboard.server.transport.mqtt.attributes.updates.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttAttributesUpdatesSqlProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest {
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim;
|
||||
package org.thingsboard.server.transport.mqtt.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.dao.device.claim.ClaimResponse;
|
||||
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
||||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim;
|
||||
package org.thingsboard.server.transport.mqtt.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.After;
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim;
|
||||
package org.thingsboard.server.transport.mqtt.claim;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim.sql;
|
||||
package org.thingsboard.server.transport.mqtt.claim.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
|
||||
import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttClaimDeviceJsonSqlTest extends AbstractMqttClaimJsonDeviceTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim.sql;
|
||||
package org.thingsboard.server.transport.mqtt.claim.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
|
||||
import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttClaimDeviceProtoSqlTest extends AbstractMqttClaimProtoDeviceTest {
|
||||
@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.claim.sql;
|
||||
package org.thingsboard.server.transport.mqtt.claim.sql;
|
||||
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest;
|
||||
import org.thingsboard.server.transport.mqtt.claim.AbstractMqttClaimDeviceTest;
|
||||
|
||||
@DaoSqlTest
|
||||
public class MqttClaimDeviceSqlTest extends AbstractMqttClaimDeviceTest {
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.mqtt.provision;
|
||||
package org.thingsboard.server.transport.mqtt.provision;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
@ -38,7 +38,7 @@ import org.thingsboard.server.dao.device.DeviceCredentialsService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
|
||||
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
|
||||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
|
||||
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user