/** * Copyright © 2016-2017 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.controller; import static org.hamcrest.Matchers.containsString; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.model.ModelConstants; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.core.type.TypeReference; public class DeviceControllerTest extends AbstractControllerTest { private IdComparator<Device> idComparator = new IdComparator<>(); private Tenant savedTenant; private User tenantAdmin; @Before public void beforeTest() 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("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); } @After public void afterTest() throws Exception { loginSysAdmin(); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testSaveDevice() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); Assert.assertNotNull(savedDevice); Assert.assertNotNull(savedDevice.getId()); Assert.assertTrue(savedDevice.getCreatedTime() > 0); Assert.assertEquals(savedTenant.getId(), savedDevice.getTenantId()); Assert.assertNotNull(savedDevice.getCustomerId()); Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId()); Assert.assertEquals(device.getName(), savedDevice.getName()); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertNotNull(deviceCredentials); Assert.assertNotNull(deviceCredentials.getId()); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType()); Assert.assertNotNull(deviceCredentials.getCredentialsId()); Assert.assertEquals(20, deviceCredentials.getCredentialsId().length()); savedDevice.setName("My new device"); doPost("/api/device", savedDevice, Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); } @Test public void testFindDeviceById() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertNotNull(foundDevice); Assert.assertEquals(savedDevice, foundDevice); } @Test public void testDeleteDevice() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); doDelete("/api/device/"+savedDevice.getId().getId().toString()) .andExpect(status().isOk()); doGet("/api/device/"+savedDevice.getId().getId().toString()) .andExpect(status().isNotFound()); } @Test public void testSaveDeviceWithEmptyName() throws Exception { Device device = new Device(); doPost("/api/device", device) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Device name should be specified"))); } @Test public void testAssignUnassignDeviceToCustomer() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); Customer customer = new Customer(); customer.setTitle("My customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); Device unassignedDevice = doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId()); } @Test public void testAssignDeviceToNonExistentCustomer() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); doPost("/api/customer/" + UUIDs.timeBased().toString() + "/device/" + savedDevice.getId().getId().toString()) .andExpect(status().isNotFound()); } @Test public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { loginSysAdmin(); Tenant tenant2 = new Tenant(); tenant2.setTitle("Different tenant"); Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); Assert.assertNotNull(savedTenant2); User tenantAdmin2 = new User(); tenantAdmin2.setAuthority(Authority.TENANT_ADMIN); tenantAdmin2.setTenantId(savedTenant2.getId()); tenantAdmin2.setEmail("tenant3@thingsboard.org"); tenantAdmin2.setFirstName("Joe"); tenantAdmin2.setLastName("Downs"); tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); Customer customer = new Customer(); customer.setTitle("Different customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); login(tenantAdmin.getEmail(), "testPassword1"); Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString()) .andExpect(status().isForbidden()); loginSysAdmin(); doDelete("/api/tenant/"+savedTenant2.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testFindDeviceCredentialsByDeviceId() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); } @Test public void testSaveDeviceCredentials() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); deviceCredentials.setCredentialsId("access_token"); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isOk()); DeviceCredentials foundDeviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertEquals(deviceCredentials, foundDeviceCredentials); } @Test public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception { DeviceCredentials deviceCredentials = new DeviceCredentials(); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isBadRequest()); } @Test public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); deviceCredentials.setCredentialsType(null); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Device credentials type should be specified"))); } @Test public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); deviceCredentials.setCredentialsId(null); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Device credentials id should be specified"))); } @Test public void testSaveNonExistentDeviceCredentials() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(UUIDs.timeBased())); newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime()); newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId()); newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); doPost("/api/device/credentials", newDeviceCredentials) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Unable to update non-existent device credentials"))); } @Test public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); deviceCredentials.setDeviceId(new DeviceId(UUIDs.timeBased())); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isNotFound()); } @Test public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception { Device device = new Device(); device.setName("My device"); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials deviceCredentials = doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(21)); doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Incorrect access token length"))); } @Test public void testFindTenantDevices() throws Exception { List<Device> devices = new ArrayList<>(); for (int i=0;i<178;i++) { Device device = new Device(); device.setName("Device"+i); devices.add(doPost("/api/device", device, Device.class)); } List<Device> loadedDevices = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(23); TextPageData<Device> pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevices.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devices, idComparator); Collections.sort(loadedDevices, idComparator); Assert.assertEquals(devices, loadedDevices); } @Test public void testFindTenantDevicesByName() throws Exception { String title1 = "Device title 1"; List<Device> devicesTitle1 = new ArrayList<>(); for (int i=0;i<143;i++) { Device device = new Device(); String suffix = RandomStringUtils.randomAlphanumeric(15); String name = title1+suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); devicesTitle1.add(doPost("/api/device", device, Device.class)); } String title2 = "Device title 2"; List<Device> devicesTitle2 = new ArrayList<>(); for (int i=0;i<75;i++) { Device device = new Device(); String suffix = RandomStringUtils.randomAlphanumeric(15); String name = title2+suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); devicesTitle2.add(doPost("/api/device", device, Device.class)); } List<Device> loadedDevicesTitle1 = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(15, title1); TextPageData<Device> pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevicesTitle1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devicesTitle1, idComparator); Collections.sort(loadedDevicesTitle1, idComparator); Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); List<Device> loadedDevicesTitle2 = new ArrayList<>(); pageLink = new TextPageLink(4, title2); do { pageData = doGetTypedWithPageLink("/api/tenant/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevicesTitle2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devicesTitle2, idComparator); Collections.sort(loadedDevicesTitle2, idComparator); Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); for (Device device : loadedDevicesTitle1) { doDelete("/api/device/"+device.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, title1); pageData = doGetTypedWithPageLink("/api/tenant/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (Device device : loadedDevicesTitle2) { doDelete("/api/device/"+device.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, title2); pageData = doGetTypedWithPageLink("/api/tenant/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); } @Test public void testFindCustomerDevices() throws Exception { Customer customer = new Customer(); customer.setTitle("Test customer"); customer = doPost("/api/customer", customer, Customer.class); CustomerId customerId = customer.getId(); List<Device> devices = new ArrayList<>(); for (int i=0;i<128;i++) { Device device = new Device(); device.setName("Device"+i); device = doPost("/api/device", device, Device.class); devices.add(doPost("/api/customer/" + customerId.getId().toString() + "/device/" + device.getId().getId().toString(), Device.class)); } List<Device> loadedDevices = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(23); TextPageData<Device> pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevices.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devices, idComparator); Collections.sort(loadedDevices, idComparator); Assert.assertEquals(devices, loadedDevices); } @Test public void testFindCustomerDevicesByName() throws Exception { Customer customer = new Customer(); customer.setTitle("Test customer"); customer = doPost("/api/customer", customer, Customer.class); CustomerId customerId = customer.getId(); String title1 = "Device title 1"; List<Device> devicesTitle1 = new ArrayList<>(); for (int i=0;i<125;i++) { Device device = new Device(); String suffix = RandomStringUtils.randomAlphanumeric(15); String name = title1+suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device = doPost("/api/device", device, Device.class); devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() + "/device/" + device.getId().getId().toString(), Device.class)); } String title2 = "Device title 2"; List<Device> devicesTitle2 = new ArrayList<>(); for (int i=0;i<143;i++) { Device device = new Device(); String suffix = RandomStringUtils.randomAlphanumeric(15); String name = title2+suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device = doPost("/api/device", device, Device.class); devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() + "/device/" + device.getId().getId().toString(), Device.class)); } List<Device> loadedDevicesTitle1 = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(15, title1); TextPageData<Device> pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevicesTitle1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devicesTitle1, idComparator); Collections.sort(loadedDevicesTitle1, idComparator); Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); List<Device> loadedDevicesTitle2 = new ArrayList<>(); pageLink = new TextPageLink(4, title2); do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); loadedDevicesTitle2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(devicesTitle2, idComparator); Collections.sort(loadedDevicesTitle2, idComparator); Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); for (Device device : loadedDevicesTitle1) { doDelete("/api/customer/device/" + device.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, title1); pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (Device device : loadedDevicesTitle2) { doDelete("/api/customer/device/" + device.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, title2); pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", new TypeReference<TextPageData<Device>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); } }