Commit 0d62b2890c03ae469ef8ae6c3cb3a41859745a90

Authored by Yevhen Bondarenko
Committed by GitHub
1 parent 7ea6c716

[3.3] added tests for resources (#4282)

* added TbResourceService test

* fix ResourceService test

* created TbResourceControllerSqlTest

* fixed BaseTbResourceServiceTest
Showing 20 changed files with 851 additions and 77 deletions
... ... @@ -16,6 +16,10 @@
16 16 package org.thingsboard.server.controller;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.core.io.ByteArrayResource;
  20 +import org.springframework.http.HttpHeaders;
  21 +import org.springframework.http.MediaType;
  22 +import org.springframework.http.ResponseEntity;
19 23 import org.springframework.security.access.prepost.PreAuthorize;
20 24 import org.springframework.web.bind.annotation.PathVariable;
21 25 import org.springframework.web.bind.annotation.RequestBody;
... ... @@ -31,11 +35,13 @@ import org.thingsboard.server.common.data.id.TbResourceId;
31 35 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
32 36 import org.thingsboard.server.common.data.page.PageData;
33 37 import org.thingsboard.server.common.data.page.PageLink;
  38 +import org.thingsboard.server.common.data.security.Authority;
34 39 import org.thingsboard.server.dao.resource.TbResourceService;
35 40 import org.thingsboard.server.queue.util.TbCoreComponent;
36 41 import org.thingsboard.server.service.security.permission.Operation;
37 42 import org.thingsboard.server.service.security.permission.Resource;
38 43
  44 +import java.util.Base64;
39 45 import java.util.List;
40 46
41 47 @Slf4j
... ... @@ -53,6 +59,27 @@ public class TbResourceController extends BaseController {
53 59 }
54 60
55 61 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  62 + @RequestMapping(value = "/resource/{resourceId}/download", method = RequestMethod.GET)
  63 + @ResponseBody
  64 + public ResponseEntity<org.springframework.core.io.Resource> downloadResource(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
  65 + checkParameter(RESOURCE_ID, strResourceId);
  66 + try {
  67 + TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
  68 + TbResource tbResource = checkResourceId(resourceId, Operation.READ);
  69 +
  70 + ByteArrayResource resource = new ByteArrayResource(Base64.getDecoder().decode(tbResource.getData().getBytes()));
  71 + return ResponseEntity.ok()
  72 + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + tbResource.getFileName())
  73 + .header("x-filename", tbResource.getFileName())
  74 + .contentLength(resource.contentLength())
  75 + .contentType(MediaType.APPLICATION_OCTET_STREAM)
  76 + .body(resource);
  77 + } catch (Exception e) {
  78 + throw handleException(e);
  79 + }
  80 + }
  81 +
  82 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
56 83 @RequestMapping(value = "/resource/info/{resourceId}", method = RequestMethod.GET)
57 84 @ResponseBody
58 85 public TbResourceInfo getResourceInfoById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
... ... @@ -103,7 +130,11 @@ public class TbResourceController extends BaseController {
103 130 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
104 131 try {
105 132 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
106   - return checkNotNull(resourceService.findResourcesByTenantId(getTenantId(), pageLink));
  133 + if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
  134 + return checkNotNull(resourceService.findTenantResourcesByTenantId(getTenantId(), pageLink));
  135 + } else {
  136 + return checkNotNull(resourceService.findAllTenantResourcesByTenantId(getTenantId(), pageLink));
  137 + }
107 138 } catch (Exception e) {
108 139 throw handleException(e);
109 140 }
... ...
... ... @@ -205,6 +205,7 @@ public class InstallScripts {
205 205 try {
206 206 byte[] fileBytes = Files.readAllBytes(path);
207 207 TbResource resource = new TbResource();
  208 + resource.setFileName(path.getFileName().toString());
208 209 resource.setTenantId(TenantId.SYS_TENANT_ID);
209 210 resource.setResourceType(ResourceType.LWM2M_MODEL);
210 211 resource.setData(Base64.getEncoder().encodeToString(fileBytes));
... ...
... ... @@ -458,6 +458,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
458 458 "resource_type varchar(32) NOT NULL, " +
459 459 "resource_key varchar(255) NOT NULL, " +
460 460 "search_text varchar(255), " +
  461 + "file_name varchar(255) NOT NULL, " +
461 462 "data varchar, " +
462 463 "CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)" +
463 464 ");");
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import com.fasterxml.jackson.core.type.TypeReference;
  19 +import org.junit.After;
  20 +import org.junit.Assert;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.thingsboard.server.common.data.ResourceType;
  24 +import org.thingsboard.server.common.data.TbResource;
  25 +import org.thingsboard.server.common.data.TbResourceInfo;
  26 +import org.thingsboard.server.common.data.Tenant;
  27 +import org.thingsboard.server.common.data.User;
  28 +import org.thingsboard.server.common.data.page.PageData;
  29 +import org.thingsboard.server.common.data.page.PageLink;
  30 +import org.thingsboard.server.common.data.security.Authority;
  31 +
  32 +import java.util.ArrayList;
  33 +import java.util.Collections;
  34 +import java.util.List;
  35 +
  36 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  37 +
  38 +public abstract class BaseTbResourceControllerTest extends AbstractControllerTest {
  39 +
  40 + private IdComparator<TbResourceInfo> idComparator = new IdComparator<>();
  41 +
  42 + private static final String DEFAULT_FILE_NAME = "test.jks";
  43 +
  44 + private Tenant savedTenant;
  45 + private User tenantAdmin;
  46 +
  47 + @Before
  48 + public void beforeTest() throws Exception {
  49 + loginSysAdmin();
  50 +
  51 + Tenant tenant = new Tenant();
  52 + tenant.setTitle("My tenant");
  53 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  54 + Assert.assertNotNull(savedTenant);
  55 +
  56 + tenantAdmin = new User();
  57 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  58 + tenantAdmin.setTenantId(savedTenant.getId());
  59 + tenantAdmin.setEmail("tenant2@thingsboard.org");
  60 + tenantAdmin.setFirstName("Joe");
  61 + tenantAdmin.setLastName("Downs");
  62 +
  63 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  64 + }
  65 +
  66 + @After
  67 + public void afterTest() throws Exception {
  68 + loginSysAdmin();
  69 +
  70 + doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
  71 + .andExpect(status().isOk());
  72 + }
  73 +
  74 + @Test
  75 + public void testSaveTbResource() throws Exception {
  76 + TbResource resource = new TbResource();
  77 + resource.setResourceType(ResourceType.JKS);
  78 + resource.setTitle("My first resource");
  79 + resource.setFileName(DEFAULT_FILE_NAME);
  80 + resource.setData("Test Data");
  81 +
  82 + TbResource savedResource = doPost("/api/resource", resource, TbResource.class);
  83 +
  84 + Assert.assertNotNull(savedResource);
  85 + Assert.assertNotNull(savedResource.getId());
  86 + Assert.assertTrue(savedResource.getCreatedTime() > 0);
  87 + Assert.assertEquals(savedTenant.getId(), savedResource.getTenantId());
  88 + Assert.assertEquals(resource.getTitle(), savedResource.getTitle());
  89 + Assert.assertEquals(DEFAULT_FILE_NAME, savedResource.getFileName());
  90 + Assert.assertEquals(DEFAULT_FILE_NAME, savedResource.getResourceKey());
  91 + Assert.assertEquals(resource.getData(), savedResource.getData());
  92 +
  93 + savedResource.setTitle("My new resource");
  94 +
  95 + doPost("/api/resource", savedResource, TbResource.class);
  96 +
  97 + TbResource foundResource = doGet("/api/resource/" + savedResource.getId().getId().toString(), TbResource.class);
  98 + Assert.assertEquals(foundResource.getTitle(), savedResource.getTitle());
  99 + }
  100 +
  101 + @Test
  102 + public void testUpdateTbResourceFromDifferentTenant() throws Exception {
  103 + TbResource resource = new TbResource();
  104 + resource.setResourceType(ResourceType.JKS);
  105 + resource.setTitle("My first resource");
  106 + resource.setFileName(DEFAULT_FILE_NAME);
  107 + resource.setData("Test Data");
  108 +
  109 + TbResource savedResource = doPost("/api/resource", resource, TbResource.class);
  110 +
  111 + loginDifferentTenant();
  112 + doPost("/api/resource", savedResource, TbResource.class, status().isForbidden());
  113 + deleteDifferentTenant();
  114 + }
  115 +
  116 + @Test
  117 + public void testFindTbResourceById() throws Exception {
  118 + TbResource resource = new TbResource();
  119 + resource.setResourceType(ResourceType.JKS);
  120 + resource.setTitle("My first resource");
  121 + resource.setFileName(DEFAULT_FILE_NAME);
  122 + resource.setData("Test Data");
  123 +
  124 + TbResource savedResource = doPost("/api/resource", resource, TbResource.class);
  125 +
  126 + TbResource foundResource = doGet("/api/resource/" + savedResource.getId().getId().toString(), TbResource.class);
  127 + Assert.assertNotNull(foundResource);
  128 + Assert.assertEquals(savedResource, foundResource);
  129 + }
  130 +
  131 + @Test
  132 + public void testDeleteTbResource() throws Exception {
  133 + TbResource resource = new TbResource();
  134 + resource.setResourceType(ResourceType.JKS);
  135 + resource.setTitle("My first resource");
  136 + resource.setFileName(DEFAULT_FILE_NAME);
  137 + resource.setData("Test Data");
  138 +
  139 + TbResource savedResource = doPost("/api/resource", resource, TbResource.class);
  140 +
  141 + doDelete("/api/resource/" + savedResource.getId().getId().toString())
  142 + .andExpect(status().isOk());
  143 +
  144 + doGet("/api/resource/" + savedResource.getId().getId().toString())
  145 + .andExpect(status().isNotFound());
  146 + }
  147 +
  148 + @Test
  149 + public void testFindTenantTbResources() throws Exception {
  150 + List<TbResourceInfo> resources = new ArrayList<>();
  151 + for (int i = 0; i < 173; i++) {
  152 + TbResource resource = new TbResource();
  153 + resource.setTitle("Resource" + i);
  154 + resource.setResourceType(ResourceType.JKS);
  155 + resource.setFileName(i + DEFAULT_FILE_NAME);
  156 + resource.setData("Test Data");
  157 + resources.add(new TbResourceInfo(doPost("/api/resource", resource, TbResource.class)));
  158 + }
  159 + List<TbResourceInfo> loadedResources = new ArrayList<>();
  160 + PageLink pageLink = new PageLink(24);
  161 + PageData<TbResourceInfo> pageData;
  162 + do {
  163 + pageData = doGetTypedWithPageLink("/api/resource?",
  164 + new TypeReference<PageData<TbResourceInfo>>() {
  165 + }, pageLink);
  166 + loadedResources.addAll(pageData.getData());
  167 + if (pageData.hasNext()) {
  168 + pageLink = pageLink.nextPageLink();
  169 + }
  170 + } while (pageData.hasNext());
  171 +
  172 + Collections.sort(resources, idComparator);
  173 + Collections.sort(loadedResources, idComparator);
  174 +
  175 + Assert.assertEquals(resources, loadedResources);
  176 + }
  177 +
  178 + @Test
  179 + public void testFindSystemTbResources() throws Exception {
  180 + loginSysAdmin();
  181 +
  182 + List<TbResourceInfo> resources = new ArrayList<>();
  183 + for (int i = 0; i < 173; i++) {
  184 + TbResource resource = new TbResource();
  185 + resource.setTitle("Resource" + i);
  186 + resource.setResourceType(ResourceType.JKS);
  187 + resource.setFileName(i + DEFAULT_FILE_NAME);
  188 + resource.setData("Test Data");
  189 + resources.add(new TbResourceInfo(doPost("/api/resource", resource, TbResource.class)));
  190 + }
  191 + List<TbResourceInfo> loadedResources = new ArrayList<>();
  192 + PageLink pageLink = new PageLink(24);
  193 + PageData<TbResourceInfo> pageData;
  194 + do {
  195 + pageData = doGetTypedWithPageLink("/api/resource?",
  196 + new TypeReference<PageData<TbResourceInfo>>() {
  197 + }, pageLink);
  198 + loadedResources.addAll(pageData.getData());
  199 + if (pageData.hasNext()) {
  200 + pageLink = pageLink.nextPageLink();
  201 + }
  202 + } while (pageData.hasNext());
  203 +
  204 + Collections.sort(resources, idComparator);
  205 + Collections.sort(loadedResources, idComparator);
  206 +
  207 + Assert.assertEquals(resources, loadedResources);
  208 +
  209 + for (TbResourceInfo resource : resources) {
  210 + doDelete("/api/resource/" + resource.getId().getId().toString())
  211 + .andExpect(status().isOk());
  212 + }
  213 +
  214 + pageLink = new PageLink(27);
  215 + loadedResources.clear();
  216 + do {
  217 + pageData = doGetTypedWithPageLink("/api/resource?",
  218 + new TypeReference<PageData<TbResourceInfo>>() {
  219 + }, pageLink);
  220 + loadedResources.addAll(pageData.getData());
  221 + if (pageData.hasNext()) {
  222 + pageLink = pageLink.nextPageLink();
  223 + }
  224 + } while (pageData.hasNext());
  225 +
  226 + Assert.assertTrue(loadedResources.isEmpty());
  227 + }
  228 +
  229 + @Test
  230 + public void testFindSystemAndTenantTbResources() throws Exception {
  231 + List<TbResourceInfo> systemResources = new ArrayList<>();
  232 + List<TbResourceInfo> expectedResources = new ArrayList<>();
  233 + for (int i = 0; i < 73; i++) {
  234 + TbResource resource = new TbResource();
  235 + resource.setTitle("Resource" + i);
  236 + resource.setResourceType(ResourceType.JKS);
  237 + resource.setFileName(i + DEFAULT_FILE_NAME);
  238 + resource.setData("Test Data");
  239 + expectedResources.add(new TbResourceInfo(doPost("/api/resource", resource, TbResource.class)));
  240 + }
  241 +
  242 + loginSysAdmin();
  243 +
  244 + for (int i = 0; i < 173; i++) {
  245 + TbResource resource = new TbResource();
  246 + resource.setTitle("Resource" + i);
  247 + resource.setResourceType(ResourceType.JKS);
  248 + resource.setFileName(i + DEFAULT_FILE_NAME);
  249 + resource.setData("Test Data");
  250 + TbResourceInfo savedResource = new TbResourceInfo(doPost("/api/resource", resource, TbResource.class));
  251 + systemResources.add(savedResource);
  252 + if (i >= 73) {
  253 + expectedResources.add(savedResource);
  254 + }
  255 + }
  256 +
  257 + login(tenantAdmin.getEmail(), "testPassword1");
  258 +
  259 + List<TbResourceInfo> loadedResources = new ArrayList<>();
  260 + PageLink pageLink = new PageLink(24);
  261 + PageData<TbResourceInfo> pageData;
  262 + do {
  263 + pageData = doGetTypedWithPageLink("/api/resource?",
  264 + new TypeReference<PageData<TbResourceInfo>>() {
  265 + }, pageLink);
  266 + loadedResources.addAll(pageData.getData());
  267 + if (pageData.hasNext()) {
  268 + pageLink = pageLink.nextPageLink();
  269 + }
  270 + } while (pageData.hasNext());
  271 +
  272 + Collections.sort(expectedResources, idComparator);
  273 + Collections.sort(loadedResources, idComparator);
  274 +
  275 + Assert.assertEquals(expectedResources, loadedResources);
  276 +
  277 + loginSysAdmin();
  278 +
  279 + for (TbResourceInfo resource : systemResources) {
  280 + doDelete("/api/resource/" + resource.getId().getId().toString())
  281 + .andExpect(status().isOk());
  282 + }
  283 + }
  284 +}
... ...
application/src/test/java/org/thingsboard/server/controller/sql/TbResourceControllerSqlTest.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/resource/Resource.java
... ... @@ -13,25 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.resource;
  16 +package org.thingsboard.server.controller.sql;
17 17
18   -import lombok.Data;
19   -import org.thingsboard.server.common.data.HasTenantId;
20   -import org.thingsboard.server.common.data.id.TenantId;
  18 +import org.thingsboard.server.controller.BaseTbResourceControllerTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
21 20
22   -@Data
23   -public class Resource implements HasTenantId {
24   - private TenantId tenantId;
25   - private ResourceType resourceType;
26   - private String resourceId;
27   - private String value;
28   -
29   - @Override
30   - public String toString() {
31   - return "Resource{" +
32   - "tenantId=" + tenantId +
33   - ", resourceType=" + resourceType +
34   - ", resourceId='" + resourceId + '\'' +
35   - '}';
36   - }
  21 +@DaoSqlTest
  22 +public class TbResourceControllerSqlTest extends BaseTbResourceControllerTest {
37 23 }
... ...
... ... @@ -38,7 +38,9 @@ public interface TbResourceService {
38 38
39 39 TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId);
40 40
41   - PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  41 + PageData<TbResourceInfo> findAllTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  42 +
  43 + PageData<TbResourceInfo> findTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink);
42 44
43 45 List<LwM2mObject> findLwM2mObject(TenantId tenantId,
44 46 String sortOrder,
... ...
... ... @@ -27,6 +27,8 @@ public class TbResource extends TbResourceInfo {
27 27
28 28 private static final long serialVersionUID = 7379609705527272306L;
29 29
  30 + private String fileName;
  31 +
30 32 private String data;
31 33
32 34 public TbResource() {
... ... @@ -61,6 +63,8 @@ public class TbResource extends TbResourceInfo {
61 63 builder.append(getResourceType());
62 64 builder.append(", resourceKey=");
63 65 builder.append(getResourceKey());
  66 + builder.append(", fileName=");
  67 + builder.append(fileName);
64 68 builder.append(", data=");
65 69 builder.append(data);
66 70 builder.append("]");
... ...
... ... @@ -45,12 +45,13 @@ public class TbResourceInfo extends SearchTextBased<TbResourceId> implements Has
45 45 this.tenantId = resourceInfo.getTenantId();
46 46 this.title = resourceInfo.getTitle();
47 47 this.resourceType = resourceInfo.getResourceType();
48   - this.resourceKey = resourceInfo.resourceKey;
  48 + this.resourceKey = resourceInfo.getResourceKey();
  49 + this.searchText = resourceInfo.getSearchText();
49 50 }
50 51
51 52 @Override
52 53 public String getSearchText() {
53   - return searchText;
  54 + return searchText != null ? searchText : title;
54 55 }
55 56
56 57 @Override
... ...
... ... @@ -464,6 +464,7 @@ public class ModelConstants {
464 464 public static final String RESOURCE_TYPE_COLUMN = "resource_type";
465 465 public static final String RESOURCE_KEY_COLUMN = "resource_key";
466 466 public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY;
  467 + public static final String RESOURCE_FILE_NAME_COLUMN = "file_name";
467 468 public static final String RESOURCE_DATA_COLUMN = "data";
468 469
469 470 /**
... ...
... ... @@ -30,6 +30,7 @@ import javax.persistence.Table;
30 30 import java.util.UUID;
31 31
32 32 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLUMN;
  33 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_FILE_NAME_COLUMN;
33 34 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
34 35 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
35 36 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
... ... @@ -58,6 +59,9 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements Searc
58 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 60 private String searchText;
60 61
  62 + @Column(name = RESOURCE_FILE_NAME_COLUMN)
  63 + private String fileName;
  64 +
61 65 @Column(name = RESOURCE_DATA_COLUMN)
62 66 private String data;
63 67
... ... @@ -65,32 +69,37 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements Searc
65 69 }
66 70
67 71 public TbResourceEntity(TbResource resource) {
68   - this.id = resource.getUuidId();
  72 + if (resource.getId() != null) {
  73 + this.id = resource.getId().getId();
  74 + }
69 75 this.createdTime = resource.getCreatedTime();
70   - this.tenantId = resource.getTenantId().getId();
  76 + if (resource.getTenantId() != null) {
  77 + this.tenantId = resource.getTenantId().getId();
  78 + }
71 79 this.title = resource.getTitle();
72 80 this.resourceType = resource.getResourceType().name();
73 81 this.resourceKey = resource.getResourceKey();
74 82 this.searchText = resource.getSearchText();
  83 + this.fileName = resource.getFileName();
75 84 this.data = resource.getData();
76 85 }
77 86
78 87 @Override
79 88 public TbResource toData() {
80   - TbResource resource = new TbResource();
81   - resource.setId(new TbResourceId(id));
  89 + TbResource resource = new TbResource(new TbResourceId(id));
82 90 resource.setCreatedTime(createdTime);
83 91 resource.setTenantId(new TenantId(tenantId));
84 92 resource.setTitle(title);
85 93 resource.setResourceType(ResourceType.valueOf(resourceType));
86 94 resource.setResourceKey(resourceKey);
87 95 resource.setSearchText(searchText);
  96 + resource.setFileName(fileName);
88 97 resource.setData(data);
89 98 return resource;
90 99 }
91 100
92 101 @Override
93 102 public String getSearchTextSource() {
94   - return title;
  103 + return this.searchText;
95 104 }
96 105 }
... ...
... ... @@ -61,8 +61,10 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
61 61 }
62 62
63 63 public TbResourceInfoEntity(TbResourceInfo resource) {
64   - this.setUuid(resource.getId().getId());
65   - this.setCreatedTime(resource.getCreatedTime());
  64 + if (resource.getId() != null) {
  65 + this.id = resource.getId().getId();
  66 + }
  67 + this.createdTime = resource.getCreatedTime();
66 68 this.tenantId = resource.getTenantId().getId();
67 69 this.title = resource.getTitle();
68 70 this.resourceType = resource.getResourceType().name();
... ... @@ -72,8 +74,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
72 74
73 75 @Override
74 76 public TbResourceInfo toData() {
75   - TbResourceInfo resource = new TbResourceInfo();
76   - resource.setId(new TbResourceId(id));
  77 + TbResourceInfo resource = new TbResourceInfo(new TbResourceId(id));
77 78 resource.setCreatedTime(createdTime);
78 79 resource.setTenantId(new TenantId(tenantId));
79 80 resource.setTitle(title);
... ...
... ... @@ -16,14 +16,17 @@
16 16 package org.thingsboard.server.dao.resource;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
19 20 import org.eclipse.leshan.core.model.DDFFileParser;
20 21 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
21 22 import org.eclipse.leshan.core.model.InvalidDDFFileException;
22 23 import org.eclipse.leshan.core.model.ObjectModel;
  24 +import org.hibernate.exception.ConstraintViolationException;
23 25 import org.springframework.stereotype.Service;
24 26 import org.thingsboard.server.common.data.ResourceType;
25 27 import org.thingsboard.server.common.data.TbResource;
26 28 import org.thingsboard.server.common.data.TbResourceInfo;
  29 +import org.thingsboard.server.common.data.Tenant;
27 30 import org.thingsboard.server.common.data.id.TbResourceId;
28 31 import org.thingsboard.server.common.data.id.TenantId;
29 32 import org.thingsboard.server.common.data.lwm2m.LwM2mInstance;
... ... @@ -32,8 +35,11 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mResource;
32 35 import org.thingsboard.server.common.data.page.PageData;
33 36 import org.thingsboard.server.common.data.page.PageLink;
34 37 import org.thingsboard.server.dao.exception.DataValidationException;
  38 +import org.thingsboard.server.dao.model.ModelConstants;
  39 +import org.thingsboard.server.dao.service.DataValidator;
35 40 import org.thingsboard.server.dao.service.PaginatedRemover;
36 41 import org.thingsboard.server.dao.service.Validator;
  42 +import org.thingsboard.server.dao.tenant.TenantDao;
37 43
38 44 import java.io.ByteArrayInputStream;
39 45 import java.io.IOException;
... ... @@ -41,6 +47,7 @@ import java.util.ArrayList;
41 47 import java.util.Base64;
42 48 import java.util.Comparator;
43 49 import java.util.List;
  50 +import java.util.Optional;
44 51 import java.util.stream.Collectors;
45 52
46 53 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
... ... @@ -55,39 +62,59 @@ public class BaseTbResourceService implements TbResourceService {
55 62 public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId ";
56 63 private final TbResourceDao resourceDao;
57 64 private final TbResourceInfoDao resourceInfoDao;
  65 + private final TenantDao tenantDao;
58 66 private final DDFFileParser ddfFileParser;
59 67
60   - public BaseTbResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao) {
  68 + public BaseTbResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao, TenantDao tenantDao) {
61 69 this.resourceDao = resourceDao;
62 70 this.resourceInfoDao = resourceInfoDao;
  71 + this.tenantDao = tenantDao;
63 72 this.ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
64 73 }
65 74
66 75 @Override
67   - public TbResource saveResource(TbResource tbResource) throws InvalidDDFFileException, IOException {
68   - log.trace("Executing saveResource [{}]", tbResource);
69   - if (ResourceType.LWM2M_MODEL.equals(tbResource.getResourceType())) {
  76 + public TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException {
  77 + log.trace("Executing saveResource [{}]", resource);
  78 + if (StringUtils.isEmpty(resource.getData())) {
  79 + throw new DataValidationException("Resource data should be specified!");
  80 + }
  81 + if (ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
70 82 List<ObjectModel> objectModels =
71   - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(tbResource.getData())), tbResource.getSearchText());
  83 + ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
72 84 if (!objectModels.isEmpty()) {
73 85 ObjectModel objectModel = objectModels.get(0);
  86 +
74 87 String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion();
75 88 String name = objectModel.name;
76   - tbResource.setResourceKey(resourceKey);
77   - tbResource.setTitle(name);
78   - tbResource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
  89 + resource.setResourceKey(resourceKey);
  90 + resource.setTitle(name);
  91 + resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
  92 + } else {
  93 + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
  94 + }
  95 + } else {
  96 + resource.setResourceKey(resource.getFileName());
  97 + }
  98 +
  99 + resourceValidator.validate(resource, TbResourceInfo::getTenantId);
  100 +
  101 + try {
  102 + return resourceDao.save(resource.getTenantId(), resource);
  103 + } catch (Exception t) {
  104 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  105 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) {
  106 + String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName";
  107 + throw new DataValidationException("Resource with such " + field + " already exists!");
79 108 } else {
80   - throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", tbResource.getSearchText()));
  109 + throw t;
81 110 }
82 111 }
83   - validate(tbResource);
84   - return resourceDao.save(tbResource.getTenantId(), tbResource);
  112 +
85 113 }
86 114
87 115 @Override
88 116 public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
89 117 log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceKey);
90   - validate(tenantId, resourceType, resourceKey);
91 118 return resourceDao.getResource(tenantId, resourceType, resourceKey);
92 119 }
93 120
... ... @@ -113,10 +140,17 @@ public class BaseTbResourceService implements TbResourceService {
113 140 }
114 141
115 142 @Override
116   - public PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
117   - log.trace("Executing findByTenantId [{}]", tenantId);
  143 + public PageData<TbResourceInfo> findAllTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
  144 + log.trace("Executing findAllTenantResourcesByTenantId [{}]", tenantId);
  145 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  146 + return resourceInfoDao.findAllTenantResourcesByTenantId(tenantId.getId(), pageLink);
  147 + }
  148 +
  149 + @Override
  150 + public PageData<TbResourceInfo> findTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
  151 + log.trace("Executing findTenantResourcesByTenantId [{}]", tenantId);
118 152 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
119   - return resourceInfoDao.findTbResourcesByTenantId(tenantId.getId(), pageLink);
  153 + return resourceInfoDao.findTenantResourcesByTenantId(tenantId.getId(), pageLink);
120 154 }
121 155
122 156 @Override
... ... @@ -154,26 +188,6 @@ public class BaseTbResourceService implements TbResourceService {
154 188 tenantResourcesRemover.removeEntities(tenantId, tenantId);
155 189 }
156 190
157   - protected void validate(TbResource resource) {
158   - if (resource == null) {
159   - throw new DataValidationException("Resource should be specified!");
160   - }
161   - if (resource.getData() == null) {
162   - throw new DataValidationException("Resource value should be specified!");
163   - }
164   - validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey());
165   - }
166   -
167   - protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) {
168   - if (resourceType == null) {
169   - throw new DataValidationException("Resource type should be specified!");
170   - }
171   - if (resourceId == null) {
172   - throw new DataValidationException("Resource id should be specified!");
173   - }
174   - validateId(tenantId, "Incorrect tenantId ");
175   - }
176   -
177 191 private LwM2mObject toLwM2mObject(TbResource resource) {
178 192 try {
179 193 DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
... ... @@ -218,6 +232,37 @@ public class BaseTbResourceService implements TbResourceService {
218 232 return "DESC".equals(sortOrder) ? comparator.reversed() : comparator;
219 233 }
220 234
  235 + private DataValidator<TbResource> resourceValidator = new DataValidator<>() {
  236 +
  237 + @Override
  238 + protected void validateDataImpl(TenantId tenantId, TbResource resource) {
  239 + if (StringUtils.isEmpty(resource.getTitle())) {
  240 + throw new DataValidationException("Resource title should be specified!");
  241 + }
  242 + if (resource.getResourceType() == null) {
  243 + throw new DataValidationException("Resource type should be specified!");
  244 + }
  245 + if (StringUtils.isEmpty(resource.getFileName())) {
  246 + throw new DataValidationException("Resource file name should be specified!");
  247 + }
  248 + if (StringUtils.isEmpty(resource.getResourceKey())) {
  249 + throw new DataValidationException("Resource key should be specified!");
  250 + }
  251 + if (resource.getTenantId() == null) {
  252 + resource.setTenantId(new TenantId(ModelConstants.NULL_UUID));
  253 + }
  254 + if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
  255 + Tenant tenant = tenantDao.findById(tenantId, resource.getTenantId().getId());
  256 + if (tenant == null) {
  257 + throw new DataValidationException("Resource is referencing to non-existent tenant!");
  258 + }
  259 + }
  260 + if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && toLwM2mObject(resource) == null) {
  261 + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
  262 + }
  263 + }
  264 + };
  265 +
221 266 private PaginatedRemover<TenantId, TbResource> tenantResourcesRemover =
222 267 new PaginatedRemover<>() {
223 268
... ... @@ -231,4 +276,14 @@ public class BaseTbResourceService implements TbResourceService {
231 276 deleteResource(tenantId, new TbResourceId(entity.getUuidId()));
232 277 }
233 278 };
  279 +
  280 + protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {
  281 + if (t instanceof ConstraintViolationException) {
  282 + return Optional.of((ConstraintViolationException) t);
  283 + } else if (t.getCause() instanceof ConstraintViolationException) {
  284 + return Optional.of((ConstraintViolationException) (t.getCause()));
  285 + } else {
  286 + return Optional.empty();
  287 + }
  288 + }
234 289 }
... ...
... ... @@ -24,6 +24,8 @@ import java.util.UUID;
24 24
25 25 public interface TbResourceInfoDao extends Dao<TbResourceInfo> {
26 26
27   - PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink);
  27 + PageData<TbResourceInfo> findAllTenantResourcesByTenantId(UUID tenantId, PageLink pageLink);
  28 +
  29 + PageData<TbResourceInfo> findTenantResourcesByTenantId(UUID tenantId, PageLink pageLink);
28 30
29 31 }
... ...
... ... @@ -49,11 +49,21 @@ public class JpaTbResourceInfoDao extends JpaAbstractSearchTextDao<TbResourceInf
49 49 }
50 50
51 51 @Override
52   - public PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink) {
  52 + public PageData<TbResourceInfo> findAllTenantResourcesByTenantId(UUID tenantId, PageLink pageLink) {
53 53 return DaoUtil.toPageData(resourceInfoRepository
54   - .findByTenantId(
  54 + .findAllTenantResourcesByTenantId(
55 55 tenantId,
56 56 TenantId.NULL_UUID,
57 57 Objects.toString(pageLink.getTextSearch(), ""),
58   - DaoUtil.toPageable(pageLink))); }
  58 + DaoUtil.toPageable(pageLink)));
  59 + }
  60 +
  61 + @Override
  62 + public PageData<TbResourceInfo> findTenantResourcesByTenantId(UUID tenantId, PageLink pageLink) {
  63 + return DaoUtil.toPageData(resourceInfoRepository
  64 + .findTenantResourcesByTenantId(
  65 + tenantId,
  66 + Objects.toString(pageLink.getTextSearch(), ""),
  67 + DaoUtil.toPageable(pageLink)));
  68 + }
59 69 }
... ...
... ... @@ -26,8 +26,8 @@ import java.util.UUID;
26 26
27 27 public interface TbResourceInfoRepository extends CrudRepository<TbResourceInfoEntity, UUID> {
28 28
29   - @Query("SELECT tr FROM TbResourceInfoEntity tr WHERE tr.tenantId = :tenantId " +
30   - "AND LOWER(tr.searchText) LIKE LOWER(CONCAT(:searchText, '%'))" +
  29 + @Query("SELECT tr FROM TbResourceInfoEntity tr WHERE " +
  30 + "LOWER(tr.searchText) LIKE LOWER(CONCAT(:searchText, '%'))" +
31 31 "AND (tr.tenantId = :tenantId " +
32 32 "OR (tr.tenantId = :systemAdminId " +
33 33 "AND NOT EXISTS " +
... ... @@ -35,8 +35,15 @@ public interface TbResourceInfoRepository extends CrudRepository<TbResourceInfoE
35 35 "WHERE sr.tenantId = :tenantId " +
36 36 "AND tr.resourceType = sr.resourceType " +
37 37 "AND tr.resourceKey = sr.resourceKey)))")
38   - Page<TbResourceInfoEntity> findByTenantId(@Param("tenantId") UUID tenantId,
39   - @Param("systemAdminId") UUID sysadminId,
40   - @Param("searchText") String searchText,
41   - Pageable pageable);
  38 + Page<TbResourceInfoEntity> findAllTenantResourcesByTenantId(@Param("tenantId") UUID tenantId,
  39 + @Param("systemAdminId") UUID sysadminId,
  40 + @Param("searchText") String searchText,
  41 + Pageable pageable);
  42 +
  43 + @Query("SELECT ri FROM TbResourceInfoEntity ri WHERE " +
  44 + "ri.tenantId = :tenantId " +
  45 + "AND LOWER(ri.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
  46 + Page<TbResourceInfoEntity> findTenantResourcesByTenantId(@Param("tenantId") UUID tenantId,
  47 + @Param("searchText") String searchText,
  48 + Pageable pageable);
42 49 }
... ...
... ... @@ -433,6 +433,7 @@ CREATE TABLE IF NOT EXISTS resource (
433 433 resource_type varchar(32) NOT NULL,
434 434 resource_key varchar(255) NOT NULL,
435 435 search_text varchar(255),
  436 + file_name varchar(255) NOT NULL,
436 437 data varchar,
437 438 CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
438 439 );
... ...
... ... @@ -459,6 +459,7 @@ CREATE TABLE IF NOT EXISTS resource (
459 459 resource_type varchar(32) NOT NULL,
460 460 resource_key varchar(255) NOT NULL,
461 461 search_text varchar(255),
  462 + file_name varchar(255) NOT NULL,
462 463 data varchar,
463 464 CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
464 465 );
... ...
... ... @@ -52,6 +52,7 @@ import org.thingsboard.server.dao.entity.EntityService;
52 52 import org.thingsboard.server.dao.entityview.EntityViewService;
53 53 import org.thingsboard.server.dao.event.EventService;
54 54 import org.thingsboard.server.dao.relation.RelationService;
  55 +import org.thingsboard.server.dao.resource.TbResourceService;
55 56 import org.thingsboard.server.dao.rule.RuleChainService;
56 57 import org.thingsboard.server.dao.settings.AdminSettingsService;
57 58 import org.thingsboard.server.dao.tenant.TenantProfileService;
... ... @@ -142,6 +143,9 @@ public abstract class AbstractServiceTest {
142 143 @Autowired
143 144 protected DeviceProfileService deviceProfileService;
144 145
  146 + @Autowired
  147 + protected TbResourceService resourceService;
  148 +
145 149 class IdComparator<D extends HasId> implements Comparator<D> {
146 150 @Override
147 151 public int compare(D o1, D o2) {
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.service;
  17 +
  18 +import com.datastax.oss.driver.api.core.uuid.Uuids;
  19 +import org.junit.After;
  20 +import org.junit.Assert;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.thingsboard.server.common.data.ResourceType;
  24 +import org.thingsboard.server.common.data.TbResource;
  25 +import org.thingsboard.server.common.data.TbResourceInfo;
  26 +import org.thingsboard.server.common.data.Tenant;
  27 +import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.common.data.page.PageData;
  29 +import org.thingsboard.server.common.data.page.PageLink;
  30 +import org.thingsboard.server.dao.exception.DataValidationException;
  31 +
  32 +import java.util.ArrayList;
  33 +import java.util.Base64;
  34 +import java.util.Collections;
  35 +import java.util.List;
  36 +
  37 +public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
  38 +
  39 + private static final String LWM2M_TEST_MODEL = "<LWM2M xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd\">\n" +
  40 + "<Object ObjectType=\"MODefinition\">\n" +
  41 + "<Name>My first resource</Name>\n" +
  42 + "<Description1></Description1>\n" +
  43 + "<ObjectID>0</ObjectID>\n" +
  44 + "<ObjectURN></ObjectURN>\n" +
  45 + "<ObjectVersion>1.0</ObjectVersion>\n" +
  46 + "<MultipleInstances>Multiple</MultipleInstances>\n" +
  47 + "<Mandatory>Mandatory</Mandatory>\n" +
  48 + "<Resources>\n" +
  49 + "<Item ID=\"0\">\n" +
  50 + "<Name>LWM2M</Name>\n" +
  51 + "<Operations></Operations>\n" +
  52 + "<MultipleInstances>Single</MultipleInstances>\n" +
  53 + "<Mandatory>Mandatory</Mandatory>\n" +
  54 + "<Type>String</Type>\n" +
  55 + "<RangeEnumeration>0..255</RangeEnumeration>\n" +
  56 + "<Units></Units>\n" +
  57 + "<Description></Description>\n" +
  58 + "</Item>\n" +
  59 + "</Resources>\n" +
  60 + "<Description2></Description2>\n" +
  61 + "</Object>\n" +
  62 + "</LWM2M>";
  63 +
  64 + private static final String DEFAULT_FILE_NAME = "test.jks";
  65 +
  66 + private IdComparator<TbResourceInfo> idComparator = new IdComparator<>();
  67 +
  68 + private TenantId tenantId;
  69 +
  70 + @Before
  71 + public void before() {
  72 + Tenant tenant = new Tenant();
  73 + tenant.setTitle("My tenant");
  74 + Tenant savedTenant = tenantService.saveTenant(tenant);
  75 + Assert.assertNotNull(savedTenant);
  76 + tenantId = savedTenant.getId();
  77 + }
  78 +
  79 + @After
  80 + public void after() {
  81 + tenantService.deleteTenant(tenantId);
  82 + }
  83 +
  84 + @Test
  85 + public void testSaveTbResource() throws Exception {
  86 + TbResource resource = new TbResource();
  87 + resource.setTenantId(tenantId);
  88 + resource.setResourceType(ResourceType.JKS);
  89 + resource.setTitle("My first resource");
  90 + resource.setFileName(DEFAULT_FILE_NAME);
  91 + resource.setData("Test Data");
  92 +
  93 + TbResource savedResource = resourceService.saveResource(resource);
  94 +
  95 + Assert.assertNotNull(savedResource);
  96 + Assert.assertNotNull(savedResource.getId());
  97 + Assert.assertTrue(savedResource.getCreatedTime() > 0);
  98 + Assert.assertEquals(resource.getTenantId(), savedResource.getTenantId());
  99 + Assert.assertEquals(resource.getTitle(), savedResource.getTitle());
  100 + Assert.assertEquals(resource.getResourceKey(), savedResource.getResourceKey());
  101 + Assert.assertEquals(resource.getData(), savedResource.getData());
  102 +
  103 + savedResource.setTitle("My new resource");
  104 +
  105 + resourceService.saveResource(savedResource);
  106 + TbResource foundResource = resourceService.findResourceById(tenantId, savedResource.getId());
  107 + Assert.assertEquals(foundResource.getTitle(), savedResource.getTitle());
  108 +
  109 + resourceService.deleteResource(tenantId, savedResource.getId());
  110 + }
  111 +
  112 + @Test
  113 + public void testSaveLwm2mTbResource() throws Exception {
  114 + TbResource resource = new TbResource();
  115 + resource.setTenantId(tenantId);
  116 + resource.setResourceType(ResourceType.LWM2M_MODEL);
  117 + resource.setFileName("test_model.xml");
  118 + resource.setData(Base64.getEncoder().encodeToString(LWM2M_TEST_MODEL.getBytes()));
  119 +
  120 + TbResource savedResource = resourceService.saveResource(resource);
  121 +
  122 + Assert.assertNotNull(savedResource);
  123 + Assert.assertNotNull(savedResource.getId());
  124 + Assert.assertTrue(savedResource.getCreatedTime() > 0);
  125 + Assert.assertEquals(resource.getTenantId(), savedResource.getTenantId());
  126 + Assert.assertEquals("My first resource", savedResource.getTitle());
  127 + Assert.assertEquals("0_1.0", savedResource.getResourceKey());
  128 + Assert.assertEquals(resource.getData(), savedResource.getData());
  129 +
  130 + resourceService.deleteResource(tenantId, savedResource.getId());
  131 + }
  132 +
  133 + @Test
  134 + public void testSaveTbResourceWithEmptyTenant() throws Exception {
  135 + TbResource resource = new TbResource();
  136 + resource.setResourceType(ResourceType.JKS);
  137 + resource.setTitle("My resource");
  138 + resource.setFileName(DEFAULT_FILE_NAME);
  139 + resource.setData("Test Data");
  140 + TbResource savedResource = resourceService.saveResource(resource);
  141 +
  142 + Assert.assertEquals(TenantId.SYS_TENANT_ID, savedResource.getTenantId());
  143 +
  144 + resourceService.deleteResource(tenantId, savedResource.getId());
  145 + }
  146 +
  147 + @Test(expected = DataValidationException.class)
  148 + public void testSaveTbResourceWithExistsFileName() throws Exception {
  149 + TbResource resource = new TbResource();
  150 + resource.setTenantId(tenantId);
  151 + resource.setResourceType(ResourceType.JKS);
  152 + resource.setTitle("My resource");
  153 + resource.setFileName(DEFAULT_FILE_NAME);
  154 + resource.setData("Test Data");
  155 +
  156 + TbResource savedResource = resourceService.saveResource(resource);
  157 +
  158 + TbResource resource2 = new TbResource();
  159 + resource.setTenantId(tenantId);
  160 + resource.setResourceType(ResourceType.JKS);
  161 + resource.setTitle("My resource");
  162 + resource.setFileName(DEFAULT_FILE_NAME);
  163 + resource.setData("Test Data");
  164 +
  165 + try {
  166 + resourceService.saveResource(resource2);
  167 + } finally {
  168 + resourceService.deleteResource(tenantId, savedResource.getId());
  169 + }
  170 + }
  171 +
  172 + @Test(expected = DataValidationException.class)
  173 + public void testSaveTbResourceWithEmptyTitle() throws Exception {
  174 + TbResource resource = new TbResource();
  175 + resource.setTenantId(tenantId);
  176 + resource.setResourceType(ResourceType.JKS);
  177 + resource.setFileName(DEFAULT_FILE_NAME);
  178 + resource.setData("Test Data");
  179 + resourceService.saveResource(resource);
  180 + }
  181 +
  182 + @Test(expected = DataValidationException.class)
  183 + public void testSaveTbResourceWithInvalidTenant() throws Exception {
  184 + TbResource resource = new TbResource();
  185 + resource.setTenantId(new TenantId(Uuids.timeBased()));
  186 + resource.setResourceType(ResourceType.JKS);
  187 + resource.setTitle("My resource");
  188 + resource.setFileName(DEFAULT_FILE_NAME);
  189 + resource.setData("Test Data");
  190 + resourceService.saveResource(resource);
  191 + }
  192 +
  193 + @Test
  194 + public void testFindResourceById() throws Exception {
  195 + TbResource resource = new TbResource();
  196 + resource.setResourceType(ResourceType.JKS);
  197 + resource.setTitle("My resource");
  198 + resource.setFileName(DEFAULT_FILE_NAME);
  199 + resource.setData("Test Data");
  200 + TbResource savedResource = resourceService.saveResource(resource);
  201 +
  202 + TbResource foundResource = resourceService.findResourceById(tenantId, savedResource.getId());
  203 + Assert.assertNotNull(foundResource);
  204 + Assert.assertEquals(savedResource, foundResource);
  205 + resourceService.deleteResource(tenantId, savedResource.getId());
  206 + }
  207 +
  208 + @Test
  209 + public void testFindResourceByTenantIdAndResourceTypeAndResourceKey() throws Exception {
  210 + TbResource resource = new TbResource();
  211 + resource.setResourceType(ResourceType.JKS);
  212 + resource.setTenantId(tenantId);
  213 + resource.setTitle("My resource");
  214 + resource.setFileName(DEFAULT_FILE_NAME);
  215 + resource.setData("Test Data");
  216 + TbResource savedResource = resourceService.saveResource(resource);
  217 +
  218 + TbResource foundResource = resourceService.getResource(tenantId, savedResource.getResourceType(), savedResource.getResourceKey());
  219 + Assert.assertNotNull(foundResource);
  220 + Assert.assertEquals(savedResource, foundResource);
  221 + resourceService.deleteResource(tenantId, savedResource.getId());
  222 + }
  223 +
  224 + @Test
  225 + public void testDeleteResource() throws Exception {
  226 + TbResource resource = new TbResource();
  227 + resource.setResourceType(ResourceType.JKS);
  228 + resource.setTitle("My resource");
  229 + resource.setFileName(DEFAULT_FILE_NAME);
  230 + resource.setData("Test Data");
  231 + TbResource savedResource = resourceService.saveResource(resource);
  232 +
  233 + TbResource foundResource = resourceService.findResourceById(tenantId, savedResource.getId());
  234 + Assert.assertNotNull(foundResource);
  235 + resourceService.deleteResource(tenantId, savedResource.getId());
  236 + foundResource = resourceService.findResourceById(tenantId, savedResource.getId());
  237 + Assert.assertNull(foundResource);
  238 + }
  239 +
  240 + @Test
  241 + public void testFindTenantResourcesByTenantId() throws Exception {
  242 + Tenant tenant = new Tenant();
  243 + tenant.setTitle("Test tenant");
  244 + tenant = tenantService.saveTenant(tenant);
  245 +
  246 + TenantId tenantId = tenant.getId();
  247 +
  248 + List<TbResourceInfo> resources = new ArrayList<>();
  249 + for (int i = 0; i < 165; i++) {
  250 + TbResource resource = new TbResource();
  251 + resource.setTenantId(tenantId);
  252 + resource.setTitle("Resource" + i);
  253 + resource.setResourceType(ResourceType.JKS);
  254 + resource.setFileName(i + DEFAULT_FILE_NAME);
  255 + resource.setData("Test Data");
  256 + resources.add(new TbResourceInfo(resourceService.saveResource(resource)));
  257 + }
  258 +
  259 + List<TbResourceInfo> loadedResources = new ArrayList<>();
  260 + PageLink pageLink = new PageLink(16);
  261 + PageData<TbResourceInfo> pageData;
  262 + do {
  263 + pageData = resourceService.findTenantResourcesByTenantId(tenantId, pageLink);
  264 + loadedResources.addAll(pageData.getData());
  265 + if (pageData.hasNext()) {
  266 + pageLink = pageLink.nextPageLink();
  267 + }
  268 + } while (pageData.hasNext());
  269 +
  270 + Collections.sort(resources, idComparator);
  271 + Collections.sort(loadedResources, idComparator);
  272 +
  273 + Assert.assertEquals(resources, loadedResources);
  274 +
  275 + resourceService.deleteResourcesByTenantId(tenantId);
  276 +
  277 + pageLink = new PageLink(31);
  278 + pageData = resourceService.findTenantResourcesByTenantId(tenantId, pageLink);
  279 + Assert.assertFalse(pageData.hasNext());
  280 + Assert.assertTrue(pageData.getData().isEmpty());
  281 +
  282 + tenantService.deleteTenant(tenantId);
  283 + }
  284 +
  285 + @Test
  286 + public void testFindAllTenantResourcesByTenantId() throws Exception {
  287 + Tenant tenant = new Tenant();
  288 + tenant.setTitle("Test tenant");
  289 + tenant = tenantService.saveTenant(tenant);
  290 +
  291 + TenantId tenantId = tenant.getId();
  292 +
  293 + List<TbResourceInfo> resources = new ArrayList<>();
  294 + for (int i = 0; i < 100; i++) {
  295 + TbResource resource = new TbResource();
  296 + resource.setTenantId(TenantId.SYS_TENANT_ID);
  297 + resource.setTitle("System Resource" + i);
  298 + resource.setResourceType(ResourceType.JKS);
  299 + resource.setFileName(i + DEFAULT_FILE_NAME);
  300 + resource.setData("Test Data");
  301 + TbResourceInfo tbResourceInfo = new TbResourceInfo(resourceService.saveResource(resource));
  302 + if (i >= 50) {
  303 + resources.add(tbResourceInfo);
  304 + }
  305 + }
  306 +
  307 + for (int i = 0; i < 50; i++) {
  308 + TbResource resource = new TbResource();
  309 + resource.setTenantId(tenantId);
  310 + resource.setTitle("Tenant Resource" + i);
  311 + resource.setResourceType(ResourceType.JKS);
  312 + resource.setFileName(i + DEFAULT_FILE_NAME);
  313 + resource.setData("Test Data");
  314 + resources.add(new TbResourceInfo(resourceService.saveResource(resource)));
  315 + }
  316 +
  317 + List<TbResourceInfo> loadedResources = new ArrayList<>();
  318 + PageLink pageLink = new PageLink(10);
  319 + PageData<TbResourceInfo> pageData;
  320 + do {
  321 + pageData = resourceService.findAllTenantResourcesByTenantId(tenantId, pageLink);
  322 + loadedResources.addAll(pageData.getData());
  323 + if (pageData.hasNext()) {
  324 + pageLink = pageLink.nextPageLink();
  325 + }
  326 + } while (pageData.hasNext());
  327 +
  328 + Collections.sort(resources, idComparator);
  329 + Collections.sort(loadedResources, idComparator);
  330 +
  331 + Assert.assertEquals(resources, loadedResources);
  332 +
  333 + resourceService.deleteResourcesByTenantId(tenantId);
  334 +
  335 + pageLink = new PageLink(100);
  336 + pageData = resourceService.findAllTenantResourcesByTenantId(tenantId, pageLink);
  337 + Assert.assertFalse(pageData.hasNext());
  338 + Assert.assertEquals(pageData.getData().size(), 100);
  339 +
  340 + resourceService.deleteResourcesByTenantId(TenantId.SYS_TENANT_ID);
  341 +
  342 + pageLink = new PageLink(100);
  343 + pageData = resourceService.findAllTenantResourcesByTenantId(TenantId.SYS_TENANT_ID, pageLink);
  344 + Assert.assertFalse(pageData.hasNext());
  345 + Assert.assertTrue(pageData.getData().isEmpty());
  346 +
  347 + tenantService.deleteTenant(tenantId);
  348 + }
  349 +
  350 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.service.sql;
  17 +
  18 +import org.thingsboard.server.dao.service.BaseTbResourceServiceTest;
  19 +import org.thingsboard.server.dao.service.DaoSqlTest;
  20 +
  21 +@DaoSqlTest
  22 +public class TbResourceServiceSqlTest extends BaseTbResourceServiceTest {
  23 +}
... ...