Browse Source

improved downloading ota in deviceTransportAPi

pull/7062/head
AnastasiiaKomar 4 years ago
parent
commit
17705dec08
  1. 12
      application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java
  2. 42
      application/src/main/java/org/thingsboard/server/service/ota/TbMultipartFileImp.java
  3. 20
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  4. 44
      application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
  5. 16
      common/cache/src/main/java/org/thingsboard/server/cache/ota/files/TemporaryFileCleaner.java
  6. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java
  7. 15
      common/dao-api/src/main/java/org/thingsboard/server/dao/ota/TbMultipartFile.java
  8. 29
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  9. 23
      dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
  10. 19
      dao/src/main/java/org/thingsboard/server/dao/service/validator/AbstractHasOtaPackageValidator.java
  11. 43
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java
  12. 57
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java
  13. 90
      dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java
  14. 45
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java
  15. 1
      dao/src/test/java/org/thingsboard/server/dao/service/sql/OtaPackageServiceSqlTest.java

12
application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java

@ -19,7 +19,12 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.OtaPackageId;
@ -29,6 +34,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.ota.util.ChecksumUtil;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.ota.TbMultipartFileImp;
import java.io.IOException;
@ -61,7 +67,7 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
@Override
public OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm,
MultipartFile file, User user) throws ThingsboardException {
MultipartFile file, User user) {
TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId();
try {
@ -83,7 +89,7 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
otaPackage.setContentType(file.getContentType());
otaPackage.setData(file.getInputStream());
otaPackage.setDataSize(file.getSize());
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage, new TbMultipartFileImp(file));
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackage.getId(),
savedOtaPackage, user, ActionType.UPDATED, true, null);
return savedOtaPackage;

42
application/src/main/java/org/thingsboard/server/service/ota/TbMultipartFileImp.java

@ -0,0 +1,42 @@
package org.thingsboard.server.service.ota;
import lombok.RequiredArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
@RequiredArgsConstructor
public class TbMultipartFileImp implements TbMultipartFile {
@NotNull
private final MultipartFile file;
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}

20
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -101,6 +101,7 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.resource.TbResourceService;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
@ -599,16 +600,17 @@ public class DefaultTransportApiService implements TransportApiService {
builder.setType(otaPackageInfo.getType().name());
builder.setTitle(otaPackageInfo.getTitle());
builder.setVersion(otaPackageInfo.getVersion());
builder.setFileName(otaPackageInfo.getFileName());
File file = otaPackageService.getOtaDataFile(otaPackageInfo.getTenantId(), otaPackageId);
builder.setFileName(file.getAbsolutePath());
builder.setContentType(otaPackageInfo.getContentType());
if (!otaPackageDataCache.has(otaPackageId.toString())) {
OtaPackage otaPackage = otaPackageService.findOtaPackageById(tenantId, otaPackageId);
try {
otaPackageDataCache.put(otaPackageId.toString(), otaPackage.getData().readAllBytes());
} catch (IOException e) {
log.error("Failed to cache ota package with id {}",otaPackage.getId(), e);
}
}
// if (!otaPackageDataCache.has(otaPackageId.toString())) {
// OtaPackage otaPackage = otaPackageService.findOtaPackageById(tenantId, otaPackageId);
// try {
// otaPackageDataCache.put(otaPackageId.toString(), otaPackage.getData().readAllBytes());
// } catch (IOException e) {
// log.error("Failed to cache ota package with id {}",otaPackage.getId(), e);
// }
// }
}
}

44
application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java

@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration;
@ -71,17 +72,23 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.BaseOtaPackageServiceTest;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.service.sync.vc.data.SimpleEntitiesExportCtx;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@ -171,8 +178,9 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
otaPackage.setChecksumAlgorithm(ChecksumAlgorithm.SHA256);
otaPackage.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
otaPackage.setDataSize(1L);
otaPackage.setData(ByteBuffer.wrap(new byte[]{(int) 1}));
return otaPackageService.saveOtaPackage(otaPackage);
otaPackage.setData(new ByteArrayInputStream(new byte[]{1}));
MockMultipartFile file = new MockMultipartFile("filename.txt", new byte[]{1});
return otaPackageService.saveOtaPackage(otaPackage, new TestTbMultipartFile(file));
}
protected void checkImportedDeviceData(Device initialDevice, Device importedDevice) {
@ -449,4 +457,36 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
return new SecurityUser(user, true, new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()));
}
private class TestTbMultipartFile implements TbMultipartFile {
private final MockMultipartFile file;
private TestTbMultipartFile(MockMultipartFile file) {
this.file = file;
}
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}
}

16
common/cache/src/main/java/org/thingsboard/server/cache/ota/files/TemporaryFileCleaner.java

@ -43,6 +43,7 @@ import java.util.stream.Collectors;
public class TemporaryFileCleaner {
@Value("${files.temporary_files_directory}/ota/")
private String PATH;
private final static String FILE_NAME_TEMPLATE = "%s%s.tmp";
private final static long TEMPORARY_FILE_INACTIVITY_TIME = 900_000;
private final ConcurrentMap<OtaPackageId, Long> lastActivityTimes = new ConcurrentHashMap<>();
@ -51,19 +52,24 @@ public class TemporaryFileCleaner {
}
@EventListener(ApplicationReadyEvent.class)
public void createScheduledTaskToClear() {
public void cleanDirectoryWithTemporaryFiles() {
createTempDirectoryIfNotExist();
cleanDirectoryWithTemporaryFiles();
cleanDirectory();
log.info("Directory {} with temporary ota files cleaned", PATH);
}
private void createTempDirectoryIfNotExist() {
File directory = new File(PATH);
if (!directory.exists()) {
directory.mkdir();
try{
FileUtils.forceMkdir(directory);
} catch(IOException e){
log.error("Failed to create directory for temporary files ", e);
}
}
}
private void cleanDirectoryWithTemporaryFiles() {
private void cleanDirectory() {
File directory = new File(PATH);
if (directory.isDirectory()) {
File[] files = directory.listFiles();
@ -100,7 +106,7 @@ public class TemporaryFileCleaner {
}
private synchronized void deleteFile(String otaId) {
String fileName = PATH + otaId;
String fileName = String.format(FILE_NAME_TEMPLATE, PATH, otaId);
File file = new File(fileName);
try (FileChannel channel = FileChannel.open(Path.of(URI.create(file.getPath())), StandardOpenOption.APPEND)) {
FileLock lock = channel.lock();

3
common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.ota;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -32,7 +33,7 @@ public interface OtaPackageService {
OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl);
OtaPackage saveOtaPackage(OtaPackage otaPackage);
OtaPackage saveOtaPackage(OtaPackage otaPackage, TbMultipartFile file);
OtaPackage findOtaPackageById(TenantId tenantId, OtaPackageId otaPackageId);

15
common/dao-api/src/main/java/org/thingsboard/server/dao/ota/TbMultipartFile.java

@ -0,0 +1,15 @@
package org.thingsboard.server.dao.ota;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
public interface TbMultipartFile {
Optional<InputStream> getInputStream();
String getFileName();
long getFileSize();
String getContentType();
}

29
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -20,10 +20,13 @@ import com.google.gson.JsonParser;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -65,6 +68,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseM
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@ -505,15 +510,25 @@ public class DeviceApiController implements TbTransportService {
}
@Override
@SneakyThrows
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg otaPackageResponseMsg) {
if (!TransportProtos.ResponseStatus.SUCCESS.equals(otaPackageResponseMsg.getResponseStatus())) {
responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_FOUND));
} else if (title.equals(otaPackageResponseMsg.getTitle()) && version.equals(otaPackageResponseMsg.getVersion())) {
String otaPackageId = new UUID(otaPackageResponseMsg.getOtaPackageIdMSB(), otaPackageResponseMsg.getOtaPackageIdLSB()).toString();
ByteArrayResource resource = new ByteArrayResource(transportContext.getOtaPackageDataCache().get(otaPackageId, chuckSize, chuck));
ResponseEntity<ByteArrayResource> response = ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackageResponseMsg.getFileName())
.header("x-filename", otaPackageResponseMsg.getFileName())
// String otaPackageId = new UUID(otaPackageResponseMsg.getOtaPackageIdMSB(), otaPackageResponseMsg.getOtaPackageIdLSB()).toString();
File file = new File(otaPackageResponseMsg.getFileName());
Resource resource = null;
if(chuckSize!=0){
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = new byte[chuckSize];
fileInputStream.read(bytes, chuck, chuckSize);
resource = new ByteArrayResource(bytes);
} else {
resource= new FileSystemResource(file);
}
ResponseEntity<Resource> response = ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + getFileName(otaPackageResponseMsg.getFileName()))
.header("x-filename", getFileName(otaPackageResponseMsg.getFileName()))
.contentLength(resource.contentLength())
.contentType(parseMediaType(otaPackageResponseMsg.getContentType()))
.body(resource);
@ -523,6 +538,10 @@ public class DeviceApiController implements TbTransportService {
}
}
private String getFileName(String fileName) {
return new File(fileName).getName();
}
@Override
public void onError(Throwable e) {
log.warn("Failed to process request", e);

23
dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java

@ -38,10 +38,7 @@ import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import javax.transaction.Transactional;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ -98,25 +95,23 @@ public class BaseOtaPackageService extends AbstractCachedEntityService<OtaPackag
}
@Override
@Transactional
public OtaPackage saveOtaPackage(OtaPackage otaPackage) {
public OtaPackage saveOtaPackage(OtaPackage otaPackage, TbMultipartFile file) {
log.trace("Executing saveOtaPackage [{}]", otaPackage);
try {
File tempFile = baseFileCacheService.saveDataTemporaryFile(otaPackage.getData());
otaPackage.setData(new FileInputStream(tempFile));
otaPackageValidator.validate(otaPackage, OtaPackageInfo::getTenantId);
BufferedInputStream stream = new BufferedInputStream(new FileInputStream(tempFile));
Optional<InputStream> optionalStream = file.getInputStream();
if(optionalStream.isEmpty()){
log.error("Failed to get input stream from file {}", file.getFileName());
throw new RuntimeException("Failed to save ota package file");
}
BufferedInputStream stream = new BufferedInputStream(optionalStream.get());
stream.mark(0);
otaPackage.setData(stream);
OtaPackageId otaPackageId = otaPackage.getId();
if (otaPackageId != null) {
publishEvictEvent(new OtaPackageCacheEvictEvent(otaPackageId));
}
OtaPackage savedOtaPackage = otaPackageDao.save(otaPackage.getTenantId(), otaPackage);
return savedOtaPackage;
} catch (FileNotFoundException e) {
log.error("Failed to save data of ota package {} to file", otaPackage.getId(), e);
throw new RuntimeException(e);
return otaPackageDao.save(otaPackage.getTenantId(), otaPackage);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) {

19
dao/src/main/java/org/thingsboard/server/dao/service/validator/AbstractHasOtaPackageValidator.java

@ -20,6 +20,7 @@ import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasOtaPackage;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
@ -35,29 +36,29 @@ public abstract class AbstractHasOtaPackageValidator<D extends BaseData<?>> exte
protected <T extends HasOtaPackage> void validateOtaPackage(TenantId tenantId, T entity, DeviceProfileId deviceProfileId) {
if (entity.getFirmwareId() != null) {
OtaPackage firmware = otaPackageService.findOtaPackageById(tenantId, entity.getFirmwareId());
OtaPackageInfo firmware = otaPackageService.findOtaPackageInfoById(tenantId, entity.getFirmwareId());
validateOtaPackage(tenantId, OtaPackageType.FIRMWARE, deviceProfileId, firmware);
}
if (entity.getSoftwareId() != null) {
OtaPackage software = otaPackageService.findOtaPackageById(tenantId, entity.getSoftwareId());
OtaPackageInfo software = otaPackageService.findOtaPackageInfoById(tenantId, entity.getSoftwareId());
validateOtaPackage(tenantId, OtaPackageType.SOFTWARE, deviceProfileId, software);
}
}
private void validateOtaPackage(TenantId tenantId, OtaPackageType type, DeviceProfileId deviceProfileId, OtaPackage otaPackage) {
if (otaPackage == null) {
private void validateOtaPackage(TenantId tenantId, OtaPackageType type, DeviceProfileId deviceProfileId, OtaPackageInfo otaPackageInfo) {
if (otaPackageInfo == null) {
throw new DataValidationException(prepareMsg("Can't assign non-existent %s!", type));
}
if (!otaPackage.getTenantId().equals(tenantId)) {
if (!otaPackageInfo.getTenantId().equals(tenantId)) {
throw new DataValidationException(prepareMsg("Can't assign %s from different tenant!", type));
}
if (!otaPackage.getType().equals(type)) {
throw new DataValidationException(prepareMsg("Can't assign %s with type: " + otaPackage.getType(), type));
if (!otaPackageInfo.getType().equals(type)) {
throw new DataValidationException(prepareMsg("Can't assign %s with type: " + otaPackageInfo.getType(), type));
}
if (otaPackage.getData() == null && !otaPackage.hasUrl()) {
if (otaPackageInfo.getDataSize() == 0 && !otaPackageInfo.hasUrl()) {
throw new DataValidationException(prepareMsg("Can't assign %s with empty data!", type));
}
if (!otaPackage.getDeviceProfileId().equals(deviceProfileId)) {
if (!otaPackageInfo.getDeviceProfileId().equals(deviceProfileId)) {
throw new DataValidationException(prepareMsg("Can't assign %s with different deviceProfile!", type));
}
}

43
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

@ -25,6 +25,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.mock.web.MockMultipartFile;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
@ -37,12 +38,16 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -115,7 +120,8 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest {
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(new ByteArrayInputStream(new byte[]{1}));
firmware.setDataSize(1L);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile("test.txt", new byte[]{1});
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
deviceProfile.setFirmwareId(savedFirmware.getId());
@ -261,7 +267,8 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest {
DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
OtaPackage otaPackage = constructDefaultOtaPackage(tenantId, deviceProfile.getId());
otaPackage = otaPackageService.saveOtaPackage(otaPackage);
MockMultipartFile file = new MockMultipartFile("filename.txt", new byte[]{1});
otaPackage = otaPackageService.saveOtaPackage(otaPackage, new TestTbMultipartFile(file));
assertThat(deviceProfileService.findDeviceProfileById(tenantId, deviceProfile.getId())).isNotNull();
assertThat(otaPackageService.findOtaPackageById(tenantId, otaPackage.getId())).isNotNull();
@ -372,4 +379,36 @@ public abstract class BaseDeviceProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(1, pageData.getTotalElements());
}
private class TestTbMultipartFile implements TbMultipartFile {
private final MockMultipartFile file;
private TestTbMultipartFile(MockMultipartFile file) {
this.file = file;
}
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}
}

57
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java

@ -17,13 +17,13 @@ package org.thingsboard.server.dao.service;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.apache.commons.lang3.RandomStringUtils;
import org.hibernate.engine.jdbc.BlobProxy;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.mock.web.MockMultipartFile;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
@ -41,12 +41,15 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -204,7 +207,8 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(new ByteArrayInputStream(new byte[]{1}));
firmware.setDataSize(1L);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile("test.txt", new byte[]{1});
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
savedDevice.setFirmwareId(savedFirmware.getId());
@ -239,7 +243,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(new ByteArrayInputStream(new byte[]{1}));
firmware.setDataSize(1L);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile("test.txt", new byte[]{1});
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
savedDevice.setFirmwareId(savedFirmware.getId());
@ -848,8 +854,8 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
deviceInfosWithLabel.stream()
.anyMatch(
d -> d.getId().equals(savedDevice.getId())
&& d.getTenantId().equals(tenantId)
&& d.getLabel().equals(savedDevice.getLabel())
&& d.getTenantId().equals(tenantId)
&& d.getLabel().equals(savedDevice.getLabel())
)
);
@ -907,9 +913,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
deviceInfosWithLabel.stream()
.anyMatch(
d -> d.getId().equals(savedDevice.getId())
&& d.getTenantId().equals(tenantId)
&& d.getDeviceProfileName().equals(savedDevice.getType())
&& d.getLabel().equals(savedDevice.getLabel())
&& d.getTenantId().equals(tenantId)
&& d.getDeviceProfileName().equals(savedDevice.getType())
&& d.getLabel().equals(savedDevice.getLabel())
)
);
@ -975,4 +981,37 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
)
);
}
private class TestTbMultipartFile implements TbMultipartFile {
private final MockMultipartFile file;
private TestTbMultipartFile(MockMultipartFile file) {
this.file = file;
}
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}
}

90
dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java

@ -23,6 +23,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.mock.web.MockMultipartFile;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
@ -37,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import org.thingsboard.server.dao.ota.util.ChecksumUtil;
import javax.validation.ValidationException;
@ -45,8 +47,10 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.FILE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
@ -140,7 +144,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM);
firmware.setData(DATA);
firmware.setDataSize(DATA_SIZE);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
Assert.assertNotNull(savedFirmware);
Assert.assertNotNull(savedFirmware.getId());
@ -152,7 +157,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
Assert.assertEquals(firmware.getData(), savedFirmware.getData());
savedFirmware.setAdditionalInfo(JacksonUtil.newObjectNode());
otaPackageService.saveOtaPackage(savedFirmware);
otaPackageService.saveOtaPackage(savedFirmware, new TestTbMultipartFile(file));
OtaPackage foundFirmware = otaPackageService.findOtaPackageById(tenantId, savedFirmware.getId());
Assert.assertEquals(foundFirmware.getTitle(), savedFirmware.getTitle());
@ -219,7 +224,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setData(DATA);
firmware.setDataSize(DATA_SIZE);
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
savedFirmwareInfo = otaPackageService.findOtaPackageInfoById(tenantId, savedFirmwareInfo.getId());
savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode());
@ -249,7 +255,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage should be assigned to tenant!");
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
}
@Test
@ -267,7 +274,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("Type should be specified!");
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
}
@Test
@ -285,7 +293,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage title should be specified!");
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
}
@Test
@ -303,8 +312,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage file name should be specified!");
otaPackageService.saveOtaPackage(firmware);
}
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file)); }
@Test
public void testSaveFirmwareWithEmptyContentType() {
@ -321,8 +330,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage content type should be specified!");
otaPackageService.saveOtaPackage(firmware);
}
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file)); }
@Test
public void testSaveFirmwareWithEmptyData() {
@ -339,8 +348,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage data should be specified!");
otaPackageService.saveOtaPackage(firmware);
}
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file)); }
@Test
public void testSaveFirmwareWithInvalidTenant() {
@ -358,8 +367,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage is referencing to non-existent tenant!");
otaPackageService.saveOtaPackage(firmware);
}
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file)); }
@Test
public void testSaveFirmwareWithInvalidDeviceProfileId() {
@ -377,7 +386,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage is referencing to non-existent device profile!");
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
}
@Test
@ -395,7 +405,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("OtaPackage checksum should be specified!");
otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
}
@Test
@ -457,7 +468,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
thrown.expect(DataValidationException.class);
thrown.expectMessage("Updating otaPackage deviceProfile is prohibited!");
savedFirmware.setDeviceProfileId(null);
otaPackageService.saveOtaPackage(savedFirmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
otaPackageService.saveOtaPackage(savedFirmware, new TestTbMultipartFile(file));
} finally {
otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId());
}
@ -480,7 +492,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM);
firmware.setData(DATA);
firmware.setDataSize(DATA_SIZE);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware, new TestTbMultipartFile(file));
savedDeviceProfile.setFirmwareId(savedFirmware.getId());
deviceProfileService.saveDeviceProfile(savedDeviceProfile);
@ -581,8 +594,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
@Test
public void testFindTenantFirmwaresByTenantIdAndHasData() {
List<OtaPackageInfo> firmwares = new ArrayList<>();
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
for (int i = 0; i < 165; i++) {
firmwares.add(new OtaPackageInfo(otaPackageService.saveOtaPackage(createAndSaveFirmware(tenantId, VERSION + i))));
firmwares.add(new OtaPackageInfo(otaPackageService.saveOtaPackage(createAndSaveFirmware(tenantId, VERSION + i), new TestTbMultipartFile(file))));
}
OtaPackageInfo firmwareWithUrl = new OtaPackageInfo();
@ -700,7 +714,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
@Test
public void testGettingCorrectFileWithOtaData() {
OtaPackage firmware = createFirmware(tenantId, "24687846");
OtaPackage firmware = createFirmware(tenantId, "24687846", deviceProfileId);
File file = otaPackageService.getOtaDataFile(tenantId, firmware.getId());
try {
assertEquals(firmware.getChecksum(), ChecksumUtil.generateChecksum(CHECKSUM_ALGORITHM, new FileInputStream(file)));
@ -710,7 +724,8 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
}
private OtaPackage createAndSaveFirmware(TenantId tenantId, String version) {
return otaPackageService.saveOtaPackage(createFirmware(tenantId, version, deviceProfileId));
MockMultipartFile file = new MockMultipartFile(FILE_NAME, new byte[]{1});
return otaPackageService.saveOtaPackage(createFirmware(tenantId, version, deviceProfileId), new TestTbMultipartFile(file));
}
public static OtaPackage createFirmware(
@ -732,4 +747,37 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setDataSize(DATA_SIZE);
return firmware;
}
private class TestTbMultipartFile implements TbMultipartFile {
private final MockMultipartFile file;
private TestTbMultipartFile(MockMultipartFile file) {
this.file = file;
}
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}
}

45
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java

@ -21,6 +21,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.mock.web.MockMultipartFile;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cache.TbTransactionalCache;
import org.thingsboard.server.common.data.Customer;
@ -56,12 +57,12 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.ota.TbMultipartFile;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -584,9 +585,10 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
}
private OtaPackage createAndSaveOtaPackageFor(Tenant tenant, DeviceProfile deviceProfile) {
MockMultipartFile file = new MockMultipartFile("filename.txt", new byte[]{1});
return otaPackageService.saveOtaPackage(
BaseOtaPackageServiceTest.createFirmware(
tenant.getId(), "2", deviceProfile.getId())
tenant.getId(), "2", deviceProfile.getId()), new TestTbMultipartFile(file)
);
}
@ -695,4 +697,37 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
tenantProfile.setName("Test tenant profile");
return tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
}
private class TestTbMultipartFile implements TbMultipartFile {
private final MockMultipartFile file;
private TestTbMultipartFile(MockMultipartFile file) {
this.file = file;
}
@Override
public Optional<InputStream> getInputStream() {
try {
return Optional.of(file.getInputStream());
} catch (IOException e) {
return Optional.empty();
}
}
@Override
public String getFileName() {
return file.getName();
}
@Override
public long getFileSize() {
return file.getSize();
}
@Override
public String getContentType() {
return file.getContentType();
}
}
}

1
dao/src/test/java/org/thingsboard/server/dao/service/sql/OtaPackageServiceSqlTest.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.service.sql;
import org.thingsboard.server.dao.service.BaseOtaPackageServiceTest;
import org.thingsboard.server.dao.service.DaoSqlTest;

Loading…
Cancel
Save