348 changed files with 10163 additions and 2586 deletions
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
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,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. |
|||
-- |
|||
|
|||
ALTER TABLE widget_type |
|||
ADD COLUMN IF NOT EXISTS image varchar (1000000), |
|||
ADD COLUMN IF NOT EXISTS description varchar (255); |
|||
|
|||
ALTER TABLE widgets_bundle |
|||
ADD COLUMN IF NOT EXISTS image varchar (1000000), |
|||
ADD COLUMN IF NOT EXISTS description varchar (255); |
|||
@ -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 |
|||
$$; |
|||
@ -1,26 +0,0 @@ |
|||
/** |
|||
* 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.mqtt.rpc.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcDefaultIntegrationTest; |
|||
|
|||
/** |
|||
* Created by Valerii Sosliuk on 8/22/2017. |
|||
*/ |
|||
@DaoNoSqlTest |
|||
public class MqttServerSideRpcNoSqlIntegrationTest extends AbstractMqttServerSideRpcDefaultIntegrationTest { |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
/** |
|||
* 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.mqtt.telemetry.attributes.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesNoSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
/** |
|||
* 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.mqtt.telemetry.attributes.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesNoSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest { |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
|
|||
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.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
|
|||
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(); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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.AbstractCoapClaimJsonDeviceTest; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
|
|||
@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 { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* 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.AbstractCoapServerSideRpcProtoIntegrationTest; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
|
|||
|
|||
@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()); |
|||
} |
|||
|
|||
} |
|||
@ -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.AbstractCoapAttributesIntegrationTest; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
|
|||
/** |
|||
* Created by Valerii Sosliuk on 8/22/2017. |
|||
*/ |
|||
@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); |
|||
} |
|||
|
|||
} |
|||
@ -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 { |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue