Add filesystem artifact repository implementation (#336)
Signed-off-by: Michael Hirsch <michael.hirsch@bosch-si.com>
This commit is contained in:
committed by
Kai Zimmermann
parent
9b42c8cf57
commit
8be49a1184
1
examples/hawkbit-example-app/.gitignore
vendored
1
examples/hawkbit-example-app/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/target/
|
||||
/artifactrepo/*
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Eclipse.IoT hawkBit - Artifact Repository MongoDB
|
||||
HawkBit Artifact Repository is a library for storing binary artifacts and metadata into MongoDB.
|
||||
|
||||
|
||||
## Using Artifact Repository MongoDB Extension
|
||||
The module contains a spring-boot autoconfiguration for easily integration into spring-boot projects.
|
||||
For using this extension in the hawkbit-example-application you just need to add the maven dependency.
|
||||
```
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-extension-artifact-repository-mongo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
If you do not have a mongoDB running you can use the the flapdoodle project to download and start an mongoDB on demand
|
||||
```
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<version>${flapdoodle.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
@@ -16,7 +16,7 @@
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<artifactId>hawkbit-parent</artifactId>
|
||||
</parent>
|
||||
<artifactId>hawkbit-artifact-repository-mongo</artifactId>
|
||||
<artifactId>hawkbit-extension-artifact-repository-mongo</artifactId>
|
||||
<name>hawkBit :: Artifact Repository Mongo</name>
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Mockito -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
@@ -44,13 +44,14 @@ import com.mongodb.gridfs.GridFSFile;
|
||||
* The file management which looks up all the file in the file tore.
|
||||
*
|
||||
*/
|
||||
public class ArtifactStore implements ArtifactRepository {
|
||||
public class MongoDBArtifactStore implements ArtifactRepository {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactStore.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MongoDBArtifactStore.class);
|
||||
|
||||
/**
|
||||
* The mongoDB field which holds the filename of the file to download. SP
|
||||
* Server uses the SHA hash as a filename and lookup in the mongoDB.
|
||||
* The mongoDB field which holds the filename of the file to download.
|
||||
* hawkBit update-server uses the SHA hash as a filename and lookup in the
|
||||
* mongoDB.
|
||||
*/
|
||||
private static final String FILENAME = "filename";
|
||||
|
||||
@@ -206,7 +207,7 @@ public class ArtifactStore implements ArtifactRepository {
|
||||
* @return a paged list of artifacts mapped from the given dbFiles
|
||||
*/
|
||||
private List<DbArtifact> map(final List<GridFSDBFile> dbFiles) {
|
||||
return dbFiles.stream().map(ArtifactStore::map).collect(Collectors.toList());
|
||||
return dbFiles.stream().map(MongoDBArtifactStore::map).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -13,17 +13,16 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Auto configuration for the {@link ArtifactStore}.
|
||||
* Auto configuration for the {@link MongoDBArtifactStore}.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(value = ArtifactRepository.class)
|
||||
public class ArtifactStoreAutoConfiguration {
|
||||
public class MongoDBArtifactStoreAutoConfiguration {
|
||||
|
||||
/**
|
||||
* @return Default {@link ArtifactRepository} implementation.
|
||||
*/
|
||||
@Bean
|
||||
public ArtifactRepository artifactRepository() {
|
||||
return new ArtifactStore();
|
||||
return new MongoDBArtifactStore();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.eclipse.hawkbit.artifact.repository.ArtifactStoreAutoConfiguration
|
||||
org.eclipse.hawkbit.artifact.repository.MongoDBArtifactStoreAutoConfiguration
|
||||
@@ -34,12 +34,12 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Artifact Store MongoDB")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = { ArtifactStoreAutoConfiguration.class, TestConfiguration.class })
|
||||
@SpringApplicationConfiguration(classes = { MongoDBArtifactStoreAutoConfiguration.class, TestConfiguration.class })
|
||||
@TestPropertySource(properties = { "spring.data.mongodb.port=0", "spring.mongodb.embedded.version=3.2.7" })
|
||||
public class ArtifactStoreTest {
|
||||
public class MongoDBArtifactStoreTest {
|
||||
|
||||
@Autowired
|
||||
private ArtifactStore artifactStoreUnderTest;
|
||||
private MongoDBArtifactStore artifactStoreUnderTest;
|
||||
|
||||
@Autowired
|
||||
private GridFsOperations gridFs;
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
<modules>
|
||||
<module>hawkbit-extension-uaa</module>
|
||||
<module>hawkbit-extension-artifact-repository-mongo</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
1
hawkbit-artifact-repository-filesystem/.gitignore
vendored
Normal file
1
hawkbit-artifact-repository-filesystem/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/artifactrepo/*
|
||||
17
hawkbit-artifact-repository-filesystem/README.md
Normal file
17
hawkbit-artifact-repository-filesystem/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Eclipse.IoT hawkBit - Artifact Repository File System
|
||||
|
||||
This module contains the implementation of the `ArtifactRepository` based on the file-system.
|
||||
It's a very convenient and easy implementation of storing the artifact binaries into the file-system based on the SHA-1 hash naming.
|
||||
|
||||
Due the limit of many file-systems of files within one directory, the files
|
||||
are stored in different sub-directories based on the last four digits of the
|
||||
SHA1-hash `/basepath/[two digit sha1]/[two digit sha1/sha1-hash-filename]`.
|
||||
|
||||
# Compile
|
||||
|
||||
#### Build hawkbit-artifact-repository-filesystem
|
||||
|
||||
```
|
||||
$ cd hawkbit/hawkbit-artifact-repository-filesystem
|
||||
$ mvn clean install
|
||||
```
|
||||
69
hawkbit-artifact-repository-filesystem/pom.xml
Normal file
69
hawkbit-artifact-repository-filesystem/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<!--
|
||||
|
||||
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
which accompanies this distribution, and is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easytesting</groupId>
|
||||
<artifactId>fest-assert-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easytesting</groupId>
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.yandex.qatools.allure</groupId>
|
||||
<artifactId>allure-junit-adaptor</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.artifact.repository;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
/**
|
||||
* A {@link DbArtifact} implementation which dynamically creates a
|
||||
* {@link FileInputStream} on calling {@link #getFileInputStream()}.
|
||||
*/
|
||||
public class ArtifactFilesystem extends DbArtifact {
|
||||
|
||||
private final File file;
|
||||
|
||||
ArtifactFilesystem(final File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
// suppress warning, this InputStream needs to be closed by the caller, this
|
||||
// cannot be closed in this method
|
||||
@SuppressWarnings("squid:S2095")
|
||||
public InputStream getFileInputStream() {
|
||||
try {
|
||||
return new BufferedInputStream(new FileInputStream(file));
|
||||
} catch (final FileNotFoundException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.artifact.repository;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for the file-system repository, e.g. the base-path
|
||||
* to store the files.
|
||||
*/
|
||||
@ConfigurationProperties("org.eclipse.hawkbit.repository.file")
|
||||
public class ArtifactFilesystemProperties {
|
||||
|
||||
/**
|
||||
* The base-path of the directory to store the artifacts.
|
||||
*/
|
||||
private String path = "./artifactrepo";
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(final String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.artifact.repository;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link ArtifactRepository} to store artifacts on the
|
||||
* file-system. The files are stored by their SHA1 hash of the artifact binary.
|
||||
* Duplicate files with the same SHA1 hash will only stored once.
|
||||
*
|
||||
* All files are stored flat in one base directory configured in the
|
||||
* {@link ArtifactFilesystemProperties#getPath()}.
|
||||
*
|
||||
* Due the limit of many file-systems of files within one directory, the files
|
||||
* are stored in different sub-directories based on the last four digits of the
|
||||
* SHA1-hash {@code (/basepath/[two digit sha1]/[two digit sha1])}.
|
||||
*/
|
||||
public class ArtifactFilesystemRepository implements ArtifactRepository {
|
||||
|
||||
private static final String TEMP_FILE_PREFIX = "tmp";
|
||||
private static final String TEMP_FILE_SUFFIX = "artifactrepo";
|
||||
private final ArtifactFilesystemProperties artifactResourceProperties;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param artifactResourceProperties
|
||||
* the properties which holds the necessary configuration for the
|
||||
* file-system repository
|
||||
*/
|
||||
public ArtifactFilesystemRepository(final ArtifactFilesystemProperties artifactResourceProperties) {
|
||||
this.artifactResourceProperties = artifactResourceProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactFilesystem store(final InputStream content, final String filename, final String contentType) {
|
||||
return store(content, filename, contentType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
// suppress warning, of not strong enough hashing algorithm, SHA-1 and MD5
|
||||
// is not used security related
|
||||
@SuppressWarnings("squid:S2070")
|
||||
public ArtifactFilesystem store(final InputStream content, final String filename, final String contentType,
|
||||
final DbArtifactHash hash) {
|
||||
|
||||
final MessageDigest mdSHA1;
|
||||
final MessageDigest mdMD5;
|
||||
try {
|
||||
mdSHA1 = MessageDigest.getInstance("SHA1");
|
||||
mdMD5 = MessageDigest.getInstance("MD5");
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new ArtifactStoreException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
final File file = createTempFile();
|
||||
final DbArtifact artifact = store(content, contentType, hash, mdSHA1, mdMD5, file);
|
||||
return renameFileToSHA1Naming(file, artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBySha1(final String sha1Hash) {
|
||||
FileUtils.deleteQuietly(getFile(sha1Hash));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactFilesystem getArtifactBySha1(final String sha1) {
|
||||
final File file = getFile(sha1);
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
final ArtifactFilesystem artifact = new ArtifactFilesystem(file);
|
||||
artifact.setArtifactId(sha1);
|
||||
artifact.setHashes(new DbArtifactHash(sha1, null));
|
||||
artifact.setSize(file.length());
|
||||
return artifact;
|
||||
}
|
||||
|
||||
private DbArtifact store(final InputStream content, final String contentType, final DbArtifactHash hash,
|
||||
final MessageDigest mdSHA1, final MessageDigest mdMD5, final File file) {
|
||||
final DbArtifact artifact = new DbArtifact();
|
||||
try (final DigestOutputStream outputstream = openFileOutputStream(file, mdSHA1, mdMD5)) {
|
||||
final long artifactSize = ByteStreams.copy(content, outputstream);
|
||||
outputstream.flush();
|
||||
final String sha1Hash = BaseEncoding.base16().lowerCase().encode(mdSHA1.digest());
|
||||
final String md5Hash = BaseEncoding.base16().lowerCase().encode(mdMD5.digest());
|
||||
artifact.setArtifactId(sha1Hash);
|
||||
artifact.setSize(artifactSize);
|
||||
artifact.setContentType(contentType);
|
||||
artifact.setHashes(new DbArtifactHash(sha1Hash, md5Hash));
|
||||
checkHashes(artifact, hash);
|
||||
} catch (final IOException e) {
|
||||
throw new ArtifactStoreException(e.getMessage(), e);
|
||||
} catch (final HashNotMatchException e) {
|
||||
file.delete();
|
||||
throw e;
|
||||
}
|
||||
return artifact;
|
||||
}
|
||||
|
||||
private ArtifactFilesystem renameFileToSHA1Naming(final File file, final DbArtifact artifact) {
|
||||
final File fileSHA1Naming = getFile(artifact.getHashes().getSha1());
|
||||
final ArtifactFilesystem fileSystemArtifact = new ArtifactFilesystem(fileSHA1Naming);
|
||||
if (fileSHA1Naming.exists()) {
|
||||
FileUtils.deleteQuietly(file);
|
||||
} else if (!file.renameTo(fileSHA1Naming)) {
|
||||
throw new ArtifactStoreException("Could not store the file " + fileSHA1Naming);
|
||||
}
|
||||
|
||||
file.delete();
|
||||
fileSystemArtifact.setArtifactId(artifact.getArtifactId());
|
||||
fileSystemArtifact.setContentType(artifact.getContentType());
|
||||
fileSystemArtifact.setHashes(artifact.getHashes());
|
||||
fileSystemArtifact.setSize(artifact.getSize());
|
||||
return fileSystemArtifact;
|
||||
}
|
||||
|
||||
private DbArtifact checkHashes(final DbArtifact artifact, final DbArtifactHash hash) {
|
||||
if (hash == null) {
|
||||
return artifact;
|
||||
}
|
||||
if (hash.getSha1() != null && !artifact.getHashes().getSha1().equals(hash.getSha1())) {
|
||||
throw new HashNotMatchException("The given sh1 hash " + hash.getSha1()
|
||||
+ " does not match with the calcualted sha1 hash " + artifact.getHashes().getSha1(),
|
||||
HashNotMatchException.SHA1);
|
||||
}
|
||||
if (hash.getMd5() != null && !artifact.getHashes().getMd5().equals(hash.getMd5())) {
|
||||
throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
|
||||
+ " does not match with the calcualted md5 hash " + artifact.getHashes().getMd5(),
|
||||
HashNotMatchException.MD5);
|
||||
}
|
||||
return artifact;
|
||||
}
|
||||
|
||||
private File createTempFile() {
|
||||
try {
|
||||
return File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);
|
||||
} catch (final IOException e) {
|
||||
throw new ArtifactStoreException("Cannot create tempfile", e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getFile(final String sha1) {
|
||||
final File aritfactDirectory = getSha1DirectoryPath(sha1).toFile();
|
||||
aritfactDirectory.mkdirs();
|
||||
return new File(aritfactDirectory, sha1);
|
||||
}
|
||||
|
||||
private Path getSha1DirectoryPath(final String sha1) {
|
||||
final int length = sha1.length();
|
||||
final List<String> folders = Splitter.fixedLength(2).splitToList(sha1.substring(length - 4, length));
|
||||
final String folder1 = folders.get(0);
|
||||
final String folder2 = folders.get(1);
|
||||
return Paths.get(artifactResourceProperties.getPath(), folder1, folder2);
|
||||
}
|
||||
|
||||
private DigestOutputStream openFileOutputStream(final File file, final MessageDigest mdSHA1,
|
||||
final MessageDigest mdMD5) throws FileNotFoundException {
|
||||
return new DigestOutputStream(
|
||||
new DigestOutputStream(new BufferedOutputStream(new FileOutputStream(file)), mdMD5), mdSHA1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.artifact.repository;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.fest.assertions.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Unit Tests - Artifact File System Repository")
|
||||
@Stories("Test storing artifact binaries in the file-system")
|
||||
public class ArtifactFilesystemRepositoryTest {
|
||||
|
||||
private final ArtifactFilesystemProperties artifactResourceProperties = new ArtifactFilesystemProperties();
|
||||
|
||||
private final ArtifactFilesystemRepository artifactFilesystemRepository = new ArtifactFilesystemRepository(
|
||||
artifactResourceProperties);
|
||||
|
||||
@Test
|
||||
@Description("Verfies that an artifact can be successfully stored in the file-system repository")
|
||||
public void storeSuccessfully() throws IOException {
|
||||
final byte[] fileContent = randomBytes();
|
||||
final ArtifactFilesystem artifact = storeRandomArtifact(fileContent);
|
||||
|
||||
final byte[] readContent = new byte[fileContent.length];
|
||||
IOUtils.read(artifact.getFileInputStream(), readContent);
|
||||
|
||||
assertThat(readContent).isEqualTo(fileContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that an artifact can be successfully stored in the file-system repository")
|
||||
public void getStoredArtifactBasedOnSHA1Hash() {
|
||||
|
||||
final byte[] fileContent = randomBytes();
|
||||
final ArtifactFilesystem artifact = storeRandomArtifact(fileContent);
|
||||
|
||||
final DbArtifact artifactBySha1 = artifactFilesystemRepository
|
||||
.getArtifactBySha1(artifact.getHashes().getSha1());
|
||||
assertThat(artifactBySha1).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that an artifact can be deleted in the file-system repository")
|
||||
public void deleteStoredArtifactBySHA1Hash() {
|
||||
final ArtifactFilesystem artifact = storeRandomArtifact(randomBytes());
|
||||
|
||||
artifactFilesystemRepository.deleteBySha1(artifact.getHashes().getSha1());
|
||||
|
||||
assertThat(artifactFilesystemRepository.getArtifactBySha1(artifact.getHashes().getSha1())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that an artifact which does not exists is deleted quietly in the file-system repository")
|
||||
public void deleteArtifactWhichDoesNotExistsBySHA1HashWithoutException() {
|
||||
try {
|
||||
artifactFilesystemRepository.deleteBySha1("sha1HashWhichDoesNotExists");
|
||||
} catch (final Exception e) {
|
||||
Assertions.fail("did not expect an exception while deleting a file which does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
private ArtifactFilesystem storeRandomArtifact(final byte[] fileContent) {
|
||||
final String fileName = "filename.tmp";
|
||||
final ByteArrayInputStream inputStream = new ByteArrayInputStream(fileContent);
|
||||
final ArtifactFilesystem store = artifactFilesystemRepository.store(inputStream, fileName, "application/txt");
|
||||
return store;
|
||||
}
|
||||
|
||||
private static byte[] randomBytes() {
|
||||
final byte[] randomBytes = new byte[20];
|
||||
final Random ran = new Random();
|
||||
ran.nextBytes(randomBytes);
|
||||
return randomBytes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.artifact.repository;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.fest.assertions.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Unit Tests - Artifact File System Repository")
|
||||
@Stories("Test storing artifact binaries in the file-system")
|
||||
public class ArtifactFilesystemTest {
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an exception is thrown on opening an InputStream when file does not exists")
|
||||
public void getInputStreamOfNonExistingFileThrowsException() {
|
||||
final File file = new File("fileWhichTotalDoesNotExists");
|
||||
final ArtifactFilesystem underTest = new ArtifactFilesystem(file);
|
||||
try {
|
||||
underTest.getFileInputStream();
|
||||
Assertions.fail("Expected a FileNotFoundException because file does not exists");
|
||||
} catch (final RuntimeException e) {
|
||||
assertThat(e.getCause()).isInstanceOf(FileNotFoundException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an InputStream can be opened if file exists")
|
||||
public void getInputStreamOfExistingFile() throws IOException {
|
||||
final File createTempFile = File.createTempFile(ArtifactFilesystemTest.class.getSimpleName(), "");
|
||||
createTempFile.deleteOnExit();
|
||||
|
||||
final ArtifactFilesystem underTest = new ArtifactFilesystem(createTempFile);
|
||||
final byte[] buffer = new byte[1024];
|
||||
IOUtils.read(underTest.getFileInputStream(), buffer);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# HawkBit Artifact Repositoy
|
||||
HawkBit Artifact Repository is library for storing binary artifacts and metadata into MongoDB.
|
||||
It has an spring-boot autoconfiguration for easily integration into spring-boot projects.
|
||||
@@ -8,8 +8,7 @@
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
@@ -68,7 +67,13 @@
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.autoconfigure.repository;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactFilesystemProperties;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactFilesystemRepository;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Auto configuration for the {@link ArtifactFilesystemRepository}.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(ArtifactRepository.class)
|
||||
@EnableConfigurationProperties(ArtifactFilesystemProperties.class)
|
||||
public class ArtifactStoreAutoConfiguration {
|
||||
|
||||
/**
|
||||
* @param artifactFilesystemProperties
|
||||
* the artifact file system properties
|
||||
* @return Default {@link ArtifactRepository} implementation.
|
||||
*/
|
||||
@Bean
|
||||
public ArtifactRepository artifactRepository(final ArtifactFilesystemProperties artifactFilesystemProperties) {
|
||||
return new ArtifactFilesystemRepository(artifactFilesystemProperties);
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,5 @@ org.eclipse.hawkbit.autoconfigure.event.EventPublisherAutoConfiguration,\
|
||||
org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\
|
||||
org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
|
||||
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration,\
|
||||
org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration
|
||||
org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration,\
|
||||
org.eclipse.hawkbit.autoconfigure.repository.ArtifactStoreAutoConfiguration
|
||||
|
||||
@@ -133,11 +133,6 @@
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.yandex.qatools.allure</groupId>
|
||||
<artifactId>allure-junit-adaptor</artifactId>
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
@@ -62,7 +62,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
@Features("Component Tests - Direct Device Integration API")
|
||||
@Stories("Artifact Download Resource")
|
||||
@SpringApplicationConfiguration(classes = DownloadTestConfiguration.class)
|
||||
public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
public class DdiArtifactDownloadTest extends AbstractRestIntegrationTest {
|
||||
|
||||
private static final int ARTIFACT_SIZE = 5 * 1024 * 1024;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.fest.assertions.core.Condition;
|
||||
@@ -59,7 +59,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
*/
|
||||
@Features("Component Tests - Direct Device Integration API")
|
||||
@Stories("Deployment Action Resource")
|
||||
public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
public class DdiDeploymentBaseTest extends AbstractRestIntegrationTest {
|
||||
|
||||
private static final String HTTP_LOCALHOST = "http://localhost:8080/";
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
@@ -57,7 +57,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
*/
|
||||
@Features("Component Tests - Direct Device Integration API")
|
||||
@Stories("Root Poll Resource")
|
||||
public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
public class DdiRootControllerTest extends AbstractRestIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private HawkbitSecurityProperties securityProperties;
|
||||
|
||||
@@ -137,11 +137,6 @@
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
|
||||
@@ -131,11 +131,6 @@
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.yandex.qatools.allure</groupId>
|
||||
<artifactId>allure-junit-adaptor</artifactId>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
@@ -82,8 +83,8 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi {
|
||||
artifactCache.getId(), artifactCache.getDownloadType());
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
try {
|
||||
ByteStreams.copy(artifact.getFileInputStream(),
|
||||
try (InputStream inputstream = artifact.getFileInputStream()) {
|
||||
ByteStreams.copy(inputstream,
|
||||
requestResponseContextHolder.getHttpServletResponse().getOutputStream());
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error("Cannot copy streams", e);
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -30,7 +30,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Management API")
|
||||
@Stories("Download Resource")
|
||||
public class MgmtDownloadResourceTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
public class MgmtDownloadResourceTest extends AbstractRestIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private DownloadIdCache downloadIdCache;
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -43,7 +44,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
@@ -70,7 +71,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
*/
|
||||
@Features("Component Tests - Management API")
|
||||
@Stories("Software Module Resource")
|
||||
public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void assertPreparationOfRepo() {
|
||||
@@ -165,12 +166,12 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
|
||||
assertThat(artifactManagement.countArtifactsAll()).as("Wrong artifact size").isEqualTo(1);
|
||||
|
||||
// binary
|
||||
assertTrue("Wrong artifact content",
|
||||
IOUtils.contentEquals(new ByteArrayInputStream(random),
|
||||
artifactManagement
|
||||
.loadArtifactBinary(
|
||||
softwareManagement.findSoftwareModuleById(sm.getId()).getArtifacts().get(0))
|
||||
.getFileInputStream()));
|
||||
try (InputStream fileInputStream = artifactManagement
|
||||
.loadArtifactBinary(softwareManagement.findSoftwareModuleById(sm.getId()).getArtifacts().get(0))
|
||||
.getFileInputStream()) {
|
||||
assertTrue("Wrong artifact content",
|
||||
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
||||
}
|
||||
|
||||
// hashes
|
||||
assertThat(artifactManagement.findArtifactByFilename("origFilename").get(0).getSha1Hash()).as("Wrong sha1 hash")
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
/**
|
||||
* Tests {@link MgmtSoftwareModuleResource} in case of missing MongoDB
|
||||
* connection.
|
||||
*
|
||||
*/
|
||||
@Features("Component Tests - Management API")
|
||||
@Stories("Download Resource")
|
||||
public class SMRessourceMisingMongoDbConnectionTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the correct error code is returned in case MongoDB unavailable.")
|
||||
public void missingMongoDbConnectionResultsInErrorAtUpload() throws Exception {
|
||||
mongodExecutable.stop();
|
||||
|
||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||
assertThat(artifactManagement.countArtifactsAll()).isEqualTo(0);
|
||||
SoftwareModule sm = entityFactory.generateSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"),
|
||||
"name 1", "version 1", null, null);
|
||||
sm = softwareManagement.createSoftwareModule(sm);
|
||||
assertThat(artifactManagement.countArtifactsAll()).isEqualTo(0);
|
||||
|
||||
// create test file
|
||||
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
|
||||
final MockMultipartFile file = new MockMultipartFile("file", "origFilename", null, random);
|
||||
|
||||
// upload
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isInternalServerError()).andReturn();
|
||||
|
||||
// check error result
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_ARTIFACT_UPLOAD_FAILED.getKey());
|
||||
assertThat(exceptionInfo.getMessage()).isEqualTo(SpServerError.SP_ARTIFACT_UPLOAD_FAILED.getMessage());
|
||||
|
||||
// ensure that the JPA transaction was rolled back
|
||||
assertThat(artifactManagement.countArtifactsAll()).isEqualTo(0);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void cleanCurrentCollection() {
|
||||
// not needed, mongodb is stopped already
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-artifact-repository-mongo</artifactId>
|
||||
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -20,12 +20,10 @@ import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
import com.mongodb.gridfs.GridFS;
|
||||
import com.mongodb.gridfs.GridFSFile;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link LocalArtifact}.
|
||||
*
|
||||
@@ -73,9 +71,9 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
||||
* Constructs artifact.
|
||||
*
|
||||
* @param gridFsFileName
|
||||
* that is the link to the {@link GridFS} entity.
|
||||
* that is the link to the {@link DbArtifact} entity.
|
||||
* @param filename
|
||||
* that is used by {@link GridFSFile} store.
|
||||
* that is used by {@link DbArtifact} store.
|
||||
* @param softwareModule
|
||||
* of this artifact
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,6 @@ import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.data.mongodb.gridfs.GridFsOperations;
|
||||
|
||||
@SpringApplicationConfiguration(classes = { org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
|
||||
public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest {
|
||||
@@ -62,9 +61,6 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
@Autowired
|
||||
protected TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
protected GridFsOperations operations;
|
||||
|
||||
@Autowired
|
||||
protected RolloutGroupRepository rolloutGroupRepository;
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
|
||||
@SpringApplicationConfiguration(classes = { org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
|
||||
public abstract class AbstractJpaIntegrationTestWithMongoDB extends AbstractIntegrationTest {
|
||||
|
||||
@PersistenceContext
|
||||
protected EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
protected TargetRepository targetRepository;
|
||||
|
||||
@Autowired
|
||||
protected ActionRepository actionRepository;
|
||||
|
||||
@Autowired
|
||||
protected DistributionSetRepository distributionSetRepository;
|
||||
|
||||
@Autowired
|
||||
protected SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
@Autowired
|
||||
protected TenantMetaDataRepository tenantMetaDataRepository;
|
||||
|
||||
@Autowired
|
||||
protected DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
|
||||
@Autowired
|
||||
protected SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
|
||||
@Autowired
|
||||
protected TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
protected DistributionSetTagRepository distributionSetTagRepository;
|
||||
|
||||
@Autowired
|
||||
protected SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
|
||||
@Autowired
|
||||
protected ActionStatusRepository actionStatusRepository;
|
||||
|
||||
@Autowired
|
||||
protected LocalArtifactRepository artifactRepository;
|
||||
|
||||
@Autowired
|
||||
protected TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
protected RolloutGroupRepository rolloutGroupRepository;
|
||||
|
||||
@Autowired
|
||||
protected RolloutRepository rolloutRepository;
|
||||
|
||||
@Autowired
|
||||
protected TenantAwareCacheManager cacheManager;
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Artifact Management")
|
||||
public class ArtifactManagementFailedMongoDBTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||
|
||||
@Test
|
||||
@Description("Trys and fails to delete or create local artifact with a down mongodb and checks if expected ArtifactDeleteFailedException is thrown.")
|
||||
public void deleteArtifactsWithNoMongoDb() throws UnknownHostException, IOException {
|
||||
// ensure baseline
|
||||
assertThat(artifactRepository.findAll()).isEmpty();
|
||||
|
||||
// prepare test
|
||||
JpaSoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1",
|
||||
"version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
|
||||
final Artifact result = artifactManagement.createArtifact(new RandomGeneratedInputStream(5 * 1024), sm.getId(),
|
||||
"file1", false);
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(1);
|
||||
|
||||
mongodExecutable.stop();
|
||||
try {
|
||||
artifactManagement.deleteArtifact(result.getId());
|
||||
fail("deletion should have failed");
|
||||
} catch (final ArtifactDeleteFailedException e) {
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
artifactManagement.createArtifact(new RandomGeneratedInputStream(5 * 1024), sm.getId(), "file2", false);
|
||||
fail("Should not have worked with MongoDb down.");
|
||||
} catch (final ArtifactUploadFailedException e) {
|
||||
|
||||
}
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(1);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void cleanCurrentCollection() {
|
||||
// no need to clean, is stopped already
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -28,8 +29,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
@@ -44,7 +43,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
*/
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Artifact Management")
|
||||
public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||
public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
@@ -151,25 +150,17 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getGridFsFileName())
|
||||
.isNotEqualTo(((JpaArtifact) result2).getGridFsFileName());
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result2).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNotNull();
|
||||
|
||||
artifactManagement.deleteArtifact(result.getId());
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNull();
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result2).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNotNull();
|
||||
|
||||
artifactManagement.deleteArtifact(result2.getId());
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result2).getGridFsFileName()))))
|
||||
.isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNull();
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
}
|
||||
@@ -198,18 +189,12 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getGridFsFileName()).isEqualTo(((JpaArtifact) result2).getGridFsFileName());
|
||||
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
||||
artifactManagement.deleteArtifact(result.getId());
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
||||
|
||||
artifactManagement.deleteArtifact(result2.getId());
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,8 +238,10 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
final Artifact result = artifactManagement.createArtifact(new ByteArrayInputStream(random), sm.getId(), "file1",
|
||||
false);
|
||||
|
||||
assertTrue("The stored binary matches the given binary", IOUtils.contentEquals(new ByteArrayInputStream(random),
|
||||
artifactManagement.loadArtifactBinary(result).getFileInputStream()));
|
||||
try (InputStream fileInputStream = artifactManagement.loadArtifactBinary(result).getFileInputStream()) {
|
||||
assertTrue("The stored binary matches the given binary",
|
||||
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -45,8 +45,6 @@ import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -57,7 +55,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Software Management")
|
||||
public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||
public class SoftwareManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Try to update non updatable fields results in repository doing nothing.")
|
||||
@@ -387,7 +385,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Deletes an artifact, which is assigned to a Distribution Set")
|
||||
@Description("Deletes an artifact, which is assigned to a DistributionSet")
|
||||
public void softDeleteOfAssignedArtifact() {
|
||||
|
||||
// Init DistributionSet
|
||||
@@ -464,12 +462,9 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Delete an softwaremodule with an artifact, which is also used by another softwaremodule.")
|
||||
@Description("Delete an softwaremodule with an artifact, which is alsoused by another softwaremodule.")
|
||||
public void deleteSoftwareModulesWithSharedArtifact() throws IOException {
|
||||
|
||||
// Precondition: Make sure MongoDB is Empty
|
||||
assertThat(operations.find(new Query())).hasSize(0);
|
||||
|
||||
// Init artifact binary data, target and DistributionSets
|
||||
final byte[] source = RandomUtils.nextBytes(1024);
|
||||
|
||||
@@ -489,9 +484,6 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
moduleY = softwareManagement.findSoftwareModuleById(moduleY.getId());
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
// verify: that only one entry was created in mongoDB
|
||||
assertThat(operations.find(new Query())).hasSize(1);
|
||||
|
||||
// [STEP5]: Delete SoftwareModuleX
|
||||
softwareManagement.deleteSoftwareModule(moduleX.getId());
|
||||
|
||||
@@ -515,9 +507,6 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
@Description("Delete two assigned softwaremodules which share an artifact.")
|
||||
public void deleteMultipleSoftwareModulesWhichShareAnArtifact() throws IOException {
|
||||
|
||||
// Precondition: Make sure MongoDB is Empty
|
||||
assertThat(operations.find(new Query())).hasSize(0);
|
||||
|
||||
// Init artifact binary data, target and DistributionSets
|
||||
final byte[] source = RandomUtils.nextBytes(1024);
|
||||
final Target target = targetManagement.createTarget(new JpaTarget("test123"));
|
||||
@@ -540,9 +529,6 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
moduleY = softwareManagement.findSoftwareModuleById(moduleY.getId());
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
// verify: that only one entry was created in mongoDB
|
||||
assertThat(operations.find(new Query())).hasSize(1);
|
||||
|
||||
// [STEP3]: Assign SoftwareModuleX to DistributionSetX and to target
|
||||
distributionSetManagement.assignSoftwareModules(disSetX, Sets.newHashSet(moduleX));
|
||||
deploymentManagement.assignDistributionSet(disSetX, Lists.newArrayList(target));
|
||||
@@ -611,17 +597,14 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
|
||||
assertThat(artifactRepository.findAll()).hasSize(results.length);
|
||||
for (final Artifact result : results) {
|
||||
assertThat(result.getId()).isNotNull();
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName()))
|
||||
.isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertArtfiactNull(final Artifact... results) {
|
||||
for (final Artifact result : results) {
|
||||
assertThat(operations.findOne(
|
||||
new Query().addCriteria(Criteria.where("filename").is(((JpaArtifact) result).getGridFsFileName()))))
|
||||
.isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("System Management")
|
||||
public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||
public class SystemManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Ensures that findTenants returns all tenants and not only restricted to the tenant which currently is logged in")
|
||||
|
||||
@@ -30,7 +30,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Tenant Configuration Management")
|
||||
public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||
public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Tests that tenant specific configuration can be persisted and in case the tenant does not have specific configuration the default from environment is used instead.")
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-artifact-repository-mongo</artifactId>
|
||||
<artifactId>hawkbit-artifact-repository-filesystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -43,8 +43,8 @@
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net._01001111</groupId>
|
||||
|
||||
@@ -13,6 +13,9 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties;
|
||||
import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactFilesystemProperties;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactFilesystemRepository;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.cache.DefaultDownloadIdCache;
|
||||
import org.eclipse.hawkbit.cache.DownloadIdCache;
|
||||
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||
@@ -53,7 +56,6 @@ import org.springframework.security.concurrent.DelegatingSecurityContextExecutor
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import com.mongodb.MongoClientOptions;
|
||||
|
||||
/**
|
||||
* Spring context configuration required for Dev.Environment.
|
||||
@@ -64,10 +66,16 @@ import com.mongodb.MongoClientOptions;
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.PROXY, proxyTargetClass = false, securedEnabled = true)
|
||||
@EnableConfigurationProperties({ HawkbitServerProperties.class, DdiSecurityProperties.class,
|
||||
ArtifactUrlHandlerProperties.class })
|
||||
ArtifactUrlHandlerProperties.class, ArtifactFilesystemProperties.class })
|
||||
@Profile("test")
|
||||
@EnableAutoConfiguration
|
||||
public class TestConfiguration implements AsyncConfigurer {
|
||||
|
||||
@Bean
|
||||
public ArtifactRepository artifactRepository(final ArtifactFilesystemProperties artifactFilesystemProperties) {
|
||||
return new ArtifactFilesystemRepository(artifactFilesystemProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestRepositoryManagement testRepositoryManagement(final SystemSecurityContext systemSecurityContext,
|
||||
final SystemManagement systemManagement) {
|
||||
@@ -85,13 +93,6 @@ public class TestConfiguration implements AsyncConfigurer {
|
||||
return new PropertyBasedArtifactUrlHandler(urlHandlerProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MongoClientOptions options() {
|
||||
return MongoClientOptions.builder().connectTimeout(500).maxWaitTime(500).connectionsPerHost(2)
|
||||
.serverSelectionTimeout(500).build();
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TenantAware tenantAware() {
|
||||
return new SecurityContextTenantAware();
|
||||
|
||||
@@ -12,8 +12,15 @@ import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpre
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.SYSTEM_ROLE;
|
||||
import static org.junit.rules.RuleChain.outerRule;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
|
||||
import org.eclipse.hawkbit.TestConfiguration;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactFilesystemProperties;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
@@ -54,13 +61,10 @@ import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.gridfs.GridFsOperations;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -68,8 +72,6 @@ import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import de.flapdoodle.embed.mongo.MongodExecutable;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ActiveProfiles({ "test" })
|
||||
@@ -80,7 +82,6 @@ import de.flapdoodle.embed.mongo.MongodExecutable;
|
||||
// refreshed we e.g. get two instances of CacheManager which leads to very
|
||||
// strange test failures.
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||
@TestPropertySource(properties = { "spring.data.mongodb.port=0", "spring.mongodb.embedded.version=3.2.7" })
|
||||
public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(AbstractIntegrationTest.class);
|
||||
|
||||
@@ -154,6 +155,15 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
@Autowired
|
||||
protected SystemSecurityContext systemSecurityContext;
|
||||
|
||||
@Autowired
|
||||
private ArtifactFilesystemProperties artifactFilesystemProperties;
|
||||
|
||||
@Autowired
|
||||
protected ArtifactRepository binaryArtifactRepository;
|
||||
|
||||
@Autowired
|
||||
protected TenantAwareCacheManager cacheManager;
|
||||
|
||||
protected MockMvc mvc;
|
||||
|
||||
protected SoftwareModuleType osType;
|
||||
@@ -165,12 +175,6 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
@Autowired
|
||||
protected TestdataFactory testdataFactory;
|
||||
|
||||
@Autowired
|
||||
protected GridFsOperations operations;
|
||||
|
||||
@Autowired
|
||||
protected MongodExecutable mongodExecutable;
|
||||
|
||||
@Autowired
|
||||
protected ServiceMatcher serviceMatcher;
|
||||
|
||||
@@ -232,8 +236,8 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanCurrentCollection() {
|
||||
operations.delete(new Query());
|
||||
public void cleanCurrentCollection() throws IOException {
|
||||
FileUtils.deleteDirectory(new File(artifactFilesystemProperties.getPath()));
|
||||
}
|
||||
|
||||
protected DefaultMockMvcBuilder createMvcWebAppContext() {
|
||||
|
||||
@@ -180,9 +180,9 @@ public final class RestResourceConversionHelper {
|
||||
response.setHeader(CONTENT_RANGE, "bytes " + r.getStart() + "-" + r.getEnd() + "/" + r.getTotal());
|
||||
response.setHeader(CONTENT_LENGTH, String.valueOf(r.getLength()));
|
||||
|
||||
try {
|
||||
copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId,
|
||||
r.getStart(), r.getLength());
|
||||
try (InputStream inputStream = file.getFileInputStream()) {
|
||||
copyStreams(inputStream, response.getOutputStream(), controllerManagement, statusId, r.getStart(),
|
||||
r.getLength());
|
||||
} catch (final IOException e) {
|
||||
LOG.error("fullfileRequest of file ({}) failed!", artifact.getFilename(), e);
|
||||
throw new FileSteamingFailedException(artifact.getFilename());
|
||||
@@ -246,8 +246,9 @@ public final class RestResourceConversionHelper {
|
||||
response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY);
|
||||
response.setStatus(SC_PARTIAL_CONTENT);
|
||||
|
||||
try {
|
||||
for (final ByteRange r : ranges) {
|
||||
for (final ByteRange r : ranges) {
|
||||
try (InputStream inputStream = file.getFileInputStream()) {
|
||||
|
||||
// Add multipart boundary and header fields for every range.
|
||||
response.getOutputStream().println();
|
||||
response.getOutputStream().println("--" + MULTIPART_BOUNDARY);
|
||||
@@ -255,19 +256,26 @@ public final class RestResourceConversionHelper {
|
||||
.println("Content-Range: bytes " + r.getStart() + "-" + r.getEnd() + "/" + r.getTotal());
|
||||
|
||||
// Copy single part range of multi part range.
|
||||
copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId,
|
||||
r.getStart(), r.getLength());
|
||||
copyStreams(inputStream, response.getOutputStream(), controllerManagement, statusId, r.getStart(),
|
||||
r.getLength());
|
||||
} catch (final IOException e) {
|
||||
throwFileStreamingFailedException(artifact, e);
|
||||
}
|
||||
|
||||
}
|
||||
try {
|
||||
// End with final multipart boundary.
|
||||
response.getOutputStream().println();
|
||||
response.getOutputStream().print("--" + MULTIPART_BOUNDARY + "--");
|
||||
} catch (final IOException e) {
|
||||
LOG.error("multipartRangeRequest of file ({}) failed!", artifact.getFilename(), e);
|
||||
throw new FileSteamingFailedException(artifact.getFilename());
|
||||
throwFileStreamingFailedException(artifact, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwFileStreamingFailedException(final Artifact artifact, final IOException e) {
|
||||
LOG.error("multipartRangeRequest of file ({}) failed!", artifact.getFilename(), e);
|
||||
throw new FileSteamingFailedException(artifact.getFilename());
|
||||
}
|
||||
|
||||
private static void handleStandardRangeRequest(final Artifact artifact, final HttpServletResponse response,
|
||||
final DbArtifact file, final ControllerManagement controllerManagement, final Long statusId,
|
||||
final List<ByteRange> ranges) {
|
||||
@@ -276,9 +284,9 @@ public final class RestResourceConversionHelper {
|
||||
response.setHeader(CONTENT_LENGTH, String.valueOf(r.getLength()));
|
||||
response.setStatus(SC_PARTIAL_CONTENT);
|
||||
|
||||
try {
|
||||
copyStreams(file.getFileInputStream(), response.getOutputStream(), controllerManagement, statusId,
|
||||
r.getStart(), r.getLength());
|
||||
try (InputStream inputStream = file.getFileInputStream()) {
|
||||
copyStreams(inputStream, response.getOutputStream(), controllerManagement, statusId, r.getStart(),
|
||||
r.getLength());
|
||||
} catch (final IOException e) {
|
||||
LOG.error("standardRangeRequest of file ({}) failed!", artifact.getFilename(), e);
|
||||
throw new FileSteamingFailedException(artifact.getFilename());
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest;
|
||||
|
||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.configuration.RestConfiguration;
|
||||
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
|
||||
/**
|
||||
* Abstract Test for Rest tests.
|
||||
*/
|
||||
@SpringApplicationConfiguration(classes = { RestConfiguration.class,
|
||||
org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
|
||||
public abstract class AbstractRestIntegrationTestWithMongoDB extends AbstractIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private FilterHttpResponse filterHttpResponse;
|
||||
|
||||
@Override
|
||||
protected DefaultMockMvcBuilder createMvcWebAppContext() {
|
||||
final DefaultMockMvcBuilder createMvcWebAppContext = super.createMvcWebAppContext();
|
||||
return createMvcWebAppContext.addFilter(filterHttpResponse);
|
||||
}
|
||||
}
|
||||
@@ -271,11 +271,6 @@
|
||||
<artifactId>fest-assert</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.yandex.qatools.allure</groupId>
|
||||
<artifactId>allure-junit-adaptor</artifactId>
|
||||
|
||||
7
pom.xml
7
pom.xml
@@ -38,7 +38,7 @@
|
||||
<module>hawkbit-security-integration</module>
|
||||
<module>hawkbit-http-security</module>
|
||||
<module>hawkbit-ui</module>
|
||||
<module>hawkbit-artifact-repository-mongo</module>
|
||||
<module>hawkbit-artifact-repository-filesystem</module>
|
||||
<module>hawkbit-autoconfigure</module>
|
||||
<module>hawkbit-test-report</module>
|
||||
<module>examples</module>
|
||||
@@ -670,11 +670,6 @@
|
||||
<artifactId>json</artifactId>
|
||||
<version>${json.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<version>${embedded-mongo.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easytesting</groupId>
|
||||
<artifactId>fest-assert</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user