Skip to content

Commit

Permalink
Merge pull request #968 from hashmapinc/Tempus-898-Dynamic-device-cre…
Browse files Browse the repository at this point in the history
…ation

Tempus 898 dynamic device creation
  • Loading branch information
VikashSingh94 committed Jan 14, 2019
2 parents 2eb188f + 0d17024 commit 8387ead
Show file tree
Hide file tree
Showing 12 changed files with 411 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"com.hashmapinc.server.controller.sql.*SqlTest",
"com.hashmapinc.server.mqtt.rpc.sql.*Test",
"com.hashmapinc.server.mqtt.telemetry.sql.*Test",
"com.hashmapinc.server.mqtt.attribute.sql.*Test",
"com.hashmapinc.server.system.sql.*SqlTest"
})
public class SqlIntegrationTestSuite {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.hashmapinc.server.common.data.DataConstants.*;
import static com.hashmapinc.server.dao.model.ModelConstants.NULL_UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
Expand Down Expand Up @@ -853,4 +855,31 @@ protected void deleteDevice(DeviceId deviceId) throws Exception {
doDelete("/api/device/"+deviceId.getId().toString())
.andExpect(status().isOk());
}

protected DataModelObject createDataModelObjectWithParentDMOId(DataModel dataModel , String name , String type , DataModelObjectId parentId) throws Exception {
DataModelObject dataModelObject = new DataModelObject();
dataModelObject.setName(name);
dataModelObject.setDataModelId(dataModel.getId());
dataModelObject.setType(type);
dataModelObject.setParentId(parentId);
DataModelObject savedDataModelObject = doPost("/api/data-model/" + dataModel.getId().toString() + "/objects", dataModelObject, DataModelObject.class);
assertNotNull(savedDataModelObject);
assertNotNull(savedDataModelObject.getId());
Assert.assertTrue(savedDataModelObject.getCreatedTime() > 0);
assertNotNull(savedDataModelObject.getCustomerId());
assertEquals(dataModelObject.getName(), savedDataModelObject.getName());
return savedDataModelObject;
}

protected Device createGatewayDevice(String name , String deviceType , DataModelObjectId dataModelObjectId , CustomerId customerId ) throws Exception{
Device gatewayDevice = new Device();
gatewayDevice.setName(name);
gatewayDevice.setType(deviceType);
gatewayDevice.setDataModelObjectId(dataModelObjectId);
gatewayDevice.setCustomerId(customerId);
ObjectMapper mapper = new ObjectMapper();
JsonNode additionalInfo = mapper.readTree("{\"gateway\":true}");
gatewayDevice.setAdditionalInfo(additionalInfo);
return doPost("/api/device", gatewayDevice, Device.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/**
* Copyright © 2016-2018 The Thingsboard Authors
* Modifications © 2017-2018 Hashmap, Inc
*
* 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 com.hashmapinc.server.mqtt.attribute;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hashmapinc.server.common.data.Customer;
import com.hashmapinc.server.common.data.CustomerGroup;
import com.hashmapinc.server.common.data.Device;
import com.hashmapinc.server.common.data.asset.Asset;
import com.hashmapinc.server.common.data.datamodel.DataModel;
import com.hashmapinc.server.common.data.datamodel.DataModelObject;
import com.hashmapinc.server.common.data.id.CustomerId;
import com.hashmapinc.server.common.data.id.DataModelId;
import com.hashmapinc.server.common.data.id.DataModelObjectId;
import com.hashmapinc.server.common.data.id.TenantId;
import com.hashmapinc.server.common.data.relation.EntityRelationInfo;
import com.hashmapinc.server.common.data.security.DeviceCredentials;
import com.hashmapinc.server.controller.AbstractControllerTest;
import com.hashmapinc.server.dao.asset.AssetService;
import com.hashmapinc.server.dao.datamodel.DataModelObjectService;
import com.hashmapinc.server.dao.datamodel.DataModelService;
import com.hashmapinc.server.dao.device.DeviceService;
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.MqttMessage;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;

import static com.hashmapinc.server.dao.model.ModelConstants.NULL_UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@Slf4j
public abstract class AbstractMqttAttributeIntegrationTest extends AbstractControllerTest {

private static final String MQTT_URL = "tcp://localhost:1883";

private Device savedGatewayDevice;
private String gatewayAccessToken;
private CustomerId customerId;
private DataModel dataModel;
private DataModelObject dataModelObjectOfTypeAsset;
private DataModelObject dataModelObjectOfTypeDevice;
private Asset asset;

@Autowired
private DeviceService deviceService;
@Autowired
private DataModelService dataModelService;
@Autowired
private DataModelObjectService dataModelObjectService;
@Autowired
private AssetService assetService;

@Before
public void beforeTest() throws Exception {
loginTenantAdmin();

dataModel = createDataModel();
dataModelObjectOfTypeAsset = createDataModelObjectWithParentDMOId(dataModel , "well", "Asset", null);
dataModelObjectOfTypeDevice = createDataModelObjectWithParentDMOId(dataModel, "Temperature_Device", "Device", dataModelObjectOfTypeAsset.getId());

customerId = createCustomer("My customer", dataModel.getId(),tenantId).getId();

asset = createAsset(dataModelObjectOfTypeAsset.getId(), customerId, "well123");

savedGatewayDevice = createGatewayDevice("Device Gateway", "gateway", dataModelObjectOfTypeDevice.getId(),customerId);

DeviceCredentials gatewayDeviceCredentials =
doGet("/api/device/" + savedGatewayDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);

assertEquals(savedGatewayDevice.getId(), gatewayDeviceCredentials.getDeviceId());
gatewayAccessToken = gatewayDeviceCredentials.getCredentialsId();
assertNotNull(gatewayAccessToken);
}


@Test
public void testPushMqttDeviceAttribute() throws Exception {
String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);

MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(gatewayAccessToken);
client.connect(options);
Thread.sleep(3000); //NOSONAR
MqttMessage message = new MqttMessage();
message.setPayload("{\"DeviceA\":{\"attribute1\":\"value1\", \"attribute2\": 42 , \"parent_asset\": \"well123\"}, \"DeviceB\":{\"attribute1\":\"value1\", \"attribute2\": 42 }}".getBytes());

client.publish("v1/gateway/attributes", message);
Thread.sleep(1000); //NOSONAR Added for test

Device savedDeviceA = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceA");
Device savedDeviceB = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceB");

assertNotNull(savedDeviceA);
assertNotNull(savedDeviceB);

List<EntityRelationInfo> entityRelationInfos = doGetTyped("/api/relations/info?fromId="+savedDeviceA.getId().getId().toString()+"&fromType=DEVICE",new TypeReference<List<EntityRelationInfo>>() {});

assertEquals("DeviceA",savedDeviceA.getName());
assertEquals(customerId,savedDeviceA.getCustomerId());
assertEquals(dataModelObjectOfTypeDevice.getId(),savedDeviceA.getDataModelObjectId());

assertNotNull(entityRelationInfos);
assertEquals(1,entityRelationInfos.size());
assertEquals("well123",entityRelationInfos.get(0).getToName());
}


@Test
public void testPushMqttDeviceAttributeWithInvalidParentAsset() throws Exception {
String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);

MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(gatewayAccessToken);
client.connect(options);
Thread.sleep(3000); //NOSONAR
MqttMessage message = new MqttMessage();
message.setPayload("{\"DeviceA\":{\"attribute1\":\"value1\", \"attribute2\": 42 , \"parent_asset\": \"well1234\"}, \"DeviceB\":{\"attribute1\":\"value1\", \"attribute2\": 42 }}".getBytes());

client.publish("v1/gateway/attributes", message);
Thread.sleep(1000); //NOSONAR Added for test

Device savedDeviceA = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceA");
Device savedDeviceB = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceB");

assertNotNull(savedDeviceA);
assertNotNull(savedDeviceB);

List<EntityRelationInfo> entityRelationInfos = doGetTyped("/api/relations/info?fromId="+savedDeviceA.getId().getId().toString()+"&fromType=DEVICE",new TypeReference<List<EntityRelationInfo>>() {});

assertEquals("DeviceA",savedDeviceA.getName());
assertEquals(customerId,savedDeviceA.getCustomerId());
assertEquals(dataModelObjectOfTypeDevice.getId(),savedDeviceA.getDataModelObjectId());

assertNotNull(entityRelationInfos);
assertEquals(0,entityRelationInfos.size());
}

@Test
public void testPushMqttDeviceAttributeWithEmptyParentAsset() throws Exception {
String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);

MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(gatewayAccessToken);
client.connect(options);
Thread.sleep(3000); //NOSONAR
MqttMessage message = new MqttMessage();
message.setPayload("{\"DeviceA\":{\"attribute1\":\"value1\", \"attribute2\": 42 , \"parent_asset\": \" \"}, \"DeviceB\":{\"attribute1\":\"value1\", \"attribute2\": 42 }}".getBytes());

client.publish("v1/gateway/attributes", message);
Thread.sleep(1000); //NOSONAR Added for test

Device savedDeviceA = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceA");
Device savedDeviceB = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceB");

assertNotNull(savedDeviceA);
assertNotNull(savedDeviceB);

List<EntityRelationInfo> entityRelationInfos = doGetTyped("/api/relations/info?fromId="+savedDeviceA.getId().getId().toString()+"&fromType=DEVICE",new TypeReference<List<EntityRelationInfo>>() {});

assertEquals("DeviceA",savedDeviceA.getName());
assertEquals(customerId,savedDeviceA.getCustomerId());
assertEquals(dataModelObjectOfTypeDevice.getId(),savedDeviceA.getDataModelObjectId());

assertNotNull(entityRelationInfos);
assertEquals(0,entityRelationInfos.size());
}

@Test
public void testPushMqttDeviceAttributeWithoutParentAsset() throws Exception {
String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);

MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(gatewayAccessToken);
client.connect(options);
Thread.sleep(3000); //NOSONAR
MqttMessage message = new MqttMessage();
message.setPayload("{\"DeviceA\":{\"attribute1\":\"value1\", \"attribute2\": 42 }, \"DeviceB\":{\"attribute1\":\"value1\", \"attribute2\": 42 }}".getBytes());

client.publish("v1/gateway/attributes", message);
Thread.sleep(1000); //NOSONAR Added for test

Device savedDeviceA = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceA");
Device savedDeviceB = deviceService.findDeviceByTenantIdAndName(tenantId,"DeviceB");

assertNotNull(savedDeviceA);
assertNotNull(savedDeviceB);

List<EntityRelationInfo> entityRelationInfos = doGetTyped("/api/relations/info?fromId="+savedDeviceA.getId().getId().toString()+"&fromType=DEVICE",new TypeReference<List<EntityRelationInfo>>() {});

assertEquals("DeviceA",savedDeviceA.getName());
assertEquals(customerId,savedDeviceA.getCustomerId());
assertEquals(dataModelObjectOfTypeDevice.getId(),savedDeviceA.getDataModelObjectId());

assertNotNull(entityRelationInfos);
assertEquals(0,entityRelationInfos.size());
}

private Customer createCustomer(String title, DataModelId dataModelId, TenantId tenantId) throws Exception{
Customer customer = new Customer();
customer.setTitle(title);
customer.setDataModelId(dataModelId);
customer.setTenantId(tenantId);
return doPost("/api/customer", customer, Customer.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright © 2016-2018 The Thingsboard Authors
* Modifications © 2017-2018 Hashmap, Inc
*
* 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 com.hashmapinc.server.mqtt.attribute.nosql;

import com.hashmapinc.server.dao.service.DaoNoSqlTest;
import com.hashmapinc.server.mqtt.attribute.AbstractMqttAttributeIntegrationTest;
import org.junit.Ignore;


@DaoNoSqlTest
public class MqttAttributeNoSqlIntegrationTest extends AbstractMqttAttributeIntegrationTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright © 2016-2018 The Thingsboard Authors
* Modifications © 2017-2018 Hashmap, Inc
*
* 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 com.hashmapinc.server.mqtt.attribute.sql;

import com.hashmapinc.server.dao.service.DaoSqlTest;
import com.hashmapinc.server.mqtt.attribute.AbstractMqttAttributeIntegrationTest;
import org.junit.Ignore;


@DaoSqlTest
public class MqttAttributeSqlIntegrationTest extends AbstractMqttAttributeIntegrationTest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void testPushMqttWithMetaDataJson() throws Exception {
String getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + java.lang.String.join(",", actualKeySet);
Map<String, List<Map<String, String>>> values = doGetAsync(getTelemetryValuesUrl, Map.class);

assertEquals("15.616", values.get("humidity").get(0).get("value"));
assertEquals("0.15616", values.get("humidity").get(0).get("value"));
assertEquals("0.158", values.get("viscosity").get(0).get("value"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.hashmapinc.server.common.data.Dashboard;
import com.hashmapinc.server.common.data.DashboardType;
import com.hashmapinc.server.common.data.Device;
import com.hashmapinc.server.common.data.asset.Asset;
import com.hashmapinc.server.common.data.datamodel.AttributeDefinition;
import com.hashmapinc.server.common.data.datamodel.DataModel;
Expand All @@ -27,6 +28,7 @@
import com.hashmapinc.server.common.data.kv.DataType;
import com.hashmapinc.server.dao.asset.AssetDao;
import com.hashmapinc.server.dao.dashboard.DashboardService;
import com.hashmapinc.server.dao.device.DeviceService;
import com.hashmapinc.server.dao.exception.DataValidationException;
import com.hashmapinc.server.dao.service.DataValidator;
import com.hashmapinc.server.dao.service.Validator;
Expand Down Expand Up @@ -67,6 +69,9 @@ public class DataModelObjectServiceImp implements DataModelObjectService {
@Autowired
DashboardService dashboardService;

@Autowired
DeviceService deviceService;

@Override
public DataModelObject save(DataModelObject dataModelObject) {
log.trace("Executing save for DataModel Object {}", dataModelObject);
Expand Down Expand Up @@ -143,11 +148,13 @@ public void removeById(DataModelObjectId dataModelObjectId) {
List<Asset> assets = assetDao.findAssetsByDataModelObjectId(dataModelObject.getId().getId());
if (!assets.isEmpty())
throw new DataValidationException("Cannot delete dataModelObject because one or more assets are associated with it");
else {
removeAttributeDefinitions(dataModelObject);
removeAssetLandingDashboard(dataModelObjectId);
dataModelObjectDao.removeById(dataModelObjectId.getId());
}
List<Device> devices = deviceService.findDeviceByDataModelObjectId(dataModelObjectId);
if(!devices.isEmpty())
throw new DataValidationException("Cannot delete dataModelObject because one or more devices are associated with it");

removeAttributeDefinitions(dataModelObject);
removeAssetLandingDashboard(dataModelObjectId);
dataModelObjectDao.removeById(dataModelObjectId.getId());
}
}

Expand Down
Loading

0 comments on commit 8387ead

Please sign in to comment.