Initial check in accordance with Parallel IP

This commit is contained in:
Kai Zimmermann
2016-01-21 13:18:55 +01:00
parent c5e4f1139f
commit 7497ab61ed
763 changed files with 114508 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
# 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.

View File

@@ -0,0 +1,83 @@
<!--
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>
<version>0.1.0-SNAPSHOT</version>
<artifactId>hawkbit-parent</artifactId>
</parent>
<artifactId>hawkbit-artifact-repository-mongo</artifactId>
<name>hawkBit :: Artifact Repository Mongo</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,280 @@
/**
* 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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClientException;
import com.mongodb.MongoException;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;
/**
* The file management which looks up all the file in the filestore.
*
*
*
*
*/
public class ArtifactStore implements ArtifactRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactStore.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.
*/
private static final String FILENAME = "filename";
/**
* The mongoDB field which automatically calculated by the mongoDB.
*/
private static final String MD5 = "md5";
/**
* The mongoDB field which holds the SHA1 hash, stored in the metadata
* object.
*/
private static final String SHA1 = "sha1";
private static final String ID = "_id";
@Autowired
private GridFsOperations gridFs;
MongoTemplate mongoTemplate;
/**
* Retrieves a {@link GridFSDBFile} from the store by it's SHA1 hash.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param sha1Hash
* the sha1-hash of the file to lookup.
* @return The gridfs file object or {@code null} if no file exists.
*/
@Override
public DbArtifact getArtifactBySha1(final String sha1Hash) {
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash))));
}
/**
* Retrieves a {@link GridFSDBFile} from the store by it's MD5 hash.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param md5Hash
* the md5-hash of the file to lookup.
* @return The gridfs file object or {@code null} if no file exists.
*/
public DbArtifact getArtifactByMd5(final String md5Hash) {
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(MD5).is(md5Hash))));
}
/**
* Retrieves a {@link GridFSDBFile} from the store by it's object id.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param id
* the id of the file to lookup.
* @return The gridfs file object or {@code null} if no file exists.
*/
@Override
public DbArtifact getArtifactById(final String id) {
return map(gridFs.findOne(new Query().addCriteria(Criteria.where(ID).is(id))));
}
@Override
public DbArtifact store(final InputStream content, final String filename, final String contentType) {
return store(content, filename, contentType, null);
}
@Override
public DbArtifact store(final InputStream content, final String filename, final String contentType,
final DbArtifactHash hash) {
File tempFile = null;
try {
LOGGER.debug("storing file {} of content {}", filename, contentType);
tempFile = File.createTempFile("uploadFile", null);
try (final FileOutputStream os = new FileOutputStream(tempFile)) {
return store(content, contentType, os, tempFile, hash);
}
} catch (final IOException | MongoException e1) {
throw new ArtifactStoreException(e1.getMessage(), e1);
} finally {
if (tempFile != null && !tempFile.delete()) {
LOGGER.error("Could not delete temporary file: {}", tempFile);
}
}
}
@Override
public void deleteById(final String artifactId) {
try {
deleteArtifact(gridFs.findOne(new Query().addCriteria(Criteria.where(ID).is(artifactId))));
} catch (final MongoException e) {
throw new ArtifactStoreException(e.getMessage(), e);
}
}
@Override
public void deleteBySha1(final String sha1Hash) {
try {
deleteArtifact(gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash))));
} catch (final MongoException e) {
throw new ArtifactStoreException(e.getMessage(), e);
}
}
private void deleteArtifact(final GridFSDBFile dbFile) {
if (dbFile != null) {
try {
gridFs.delete(new Query().addCriteria(Criteria.where(ID).is(dbFile.getId())));
} catch (final MongoClientException e) {
throw new ArtifactStoreException(e.getMessage(), e);
}
}
}
private DbArtifact store(final InputStream content, final String contentType, final FileOutputStream os,
final File tempFile, final DbArtifactHash hash) {
final GridFsArtifact storedArtifact;
try {
final String sha1Hash = computeSHA1Hash(content, os, hash != null ? hash.getSha1() : null);
// upload if it does not exist already, check if file exists, not
// tenant specific.
final GridFSDBFile result = gridFs.findOne(new Query().addCriteria(Criteria.where(FILENAME).is(sha1Hash)));
if (null == result) {
try (FileInputStream inputStream = new FileInputStream(tempFile)) {
final BasicDBObject metadata = new BasicDBObject();
metadata.put(SHA1, sha1Hash);
storedArtifact = map(gridFs.store(inputStream, sha1Hash, contentType, metadata));
}
} else {
LOGGER.info("file with sha1 hash {} already exists in database, increase reference counter", sha1Hash);
result.save();
storedArtifact = map(result);
}
} catch (final NoSuchAlgorithmException | IOException e) {
throw new ArtifactStoreException(e.getMessage(), e);
}
if (hash != null && hash.getMd5() != null && !storedArtifact.getHashes().getMd5().equals(hash.getMd5())) {
throw new HashNotMatchException("The given md5 hash " + hash.getMd5()
+ " not matching the calculated md5 hash " + storedArtifact.getHashes().getMd5(),
HashNotMatchException.MD5);
}
return storedArtifact;
}
private String computeSHA1Hash(final InputStream stream, final FileOutputStream os, final String providedSHA1Sum)
throws NoSuchAlgorithmException, IOException {
String sha1Hash;
// compute digest
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final DigestOutputStream dos = new DigestOutputStream(os, md);
ByteStreams.copy(stream, dos);
dos.close();
sha1Hash = BaseEncoding.base16().lowerCase().encode(md.digest());
if (providedSHA1Sum != null && !providedSHA1Sum.equalsIgnoreCase(sha1Hash)) {
throw new HashNotMatchException(
"The given sha1 hash " + providedSHA1Sum + " not matching the calculated sha1 hash " + sha1Hash,
HashNotMatchException.SHA1);
}
return sha1Hash;
}
/**
* Maps a list of {@link GridFSDBFile} to paged list of {@link DbArtifact}s.
*
* @param tenant
* the tenant
* @param dbFiles
* the list of mongoDB gridFs files.
* @return a paged list of artifacts mapped from the given dbFiles
*/
private List<DbArtifact> map(final List<GridFSDBFile> dbFiles) {
final List<DbArtifact> collect = dbFiles.stream().map(dbFile -> map(dbFile)).collect(Collectors.toList());
return collect;
}
/**
* Retrieves a list of {@link GridFSDBFile} from the store by all SHA1
* hashes.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param sha1Hashes
* the sha1-hashes of the files to lookup.
* @return list of artfiacts
*/
public List<DbArtifact> getArtifactsBySha1(final List<String> sha1Hashes) {
return map(gridFs.find(new Query().addCriteria(Criteria.where(SHA1).in(sha1Hashes))));
}
/**
* Retrieves a list of {@link GridFSDBFile} from the store by all ids.
*
* @param tenant
* the tenant to retrieve the artifacts from, ignore case.
* @param ids
* the ids of the files to lookup.
* @return list of artfiacts
*/
public List<DbArtifact> getArtifactsByIds(final List<String> ids) {
return map(gridFs.find(new Query().addCriteria(Criteria.where(ID).in(ids))));
}
/**
* Maps a single {@link GridFSFile} to {@link DbArtifact}.
*
* @param tenant
* the tenant
* @param dbFile
* the mongoDB gridFs file.
* @return a mapped artifact from the given dbFile
*/
private GridFsArtifact map(final GridFSFile fsFile) {
if (fsFile == null) {
return null;
}
final GridFsArtifact artifact = new GridFsArtifact(fsFile);
artifact.setArtifactId(fsFile.getId().toString());
artifact.setSize(fsFile.getLength());
artifact.setContentType(fsFile.getContentType());
artifact.setHashes(new DbArtifactHash(fsFile.getFilename(), fsFile.getMD5()));
return artifact;
}
}

View File

@@ -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.artifact.repository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Auto configuration for the {@link ArtifactStore}.
*
*
*
*/
@Configuration
@ComponentScan
@ConditionalOnMissingBean(value = ArtifactRepository.class)
@Import(value = MongoConfiguration.class)
public class ArtifactStoreAutoConfiguration {
/**
* @return Default {@link ArtifactRepository} implementation.
*/
@Bean
public ArtifactRepository artifactRepository() {
return new ArtifactStore();
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.InputStream;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;
/**
* A wrapper object for the {@link DbArtifact} object which returns the
* {@link InputStream} directly from {@link GridFSDBFile#getInputStream()} which
* retrieves when calling {@link #getFileInputStream()} always a new
* {@link InputStream} and not the same.
*
*
*
*/
public class GridFsArtifact extends DbArtifact {
private final GridFSFile dbFile;
/**
* @param dbFile
*/
public GridFsArtifact(final GridFSFile dbFile) {
this.dbFile = dbFile;
}
@Override
public InputStream getFileInputStream() {
if (dbFile instanceof GridFSDBFile) {
return ((GridFSDBFile) dbFile).getInputStream();
}
return null;
}
}

View File

@@ -0,0 +1,117 @@
/**
* 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.net.UnknownHostException;
import java.util.Arrays;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import com.mongodb.MongoClientURI;
import com.mongodb.ServerAddress;
/**
* {@link AbstractMongoConfiguration} that uses {@link MongoClientURI} even when
* port is configured for NON {@link Cloud} use cases.
*
*/
@Configuration
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnClass(Mongo.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
@Profile({ "!cloud" })
public class MongoConfiguration extends AbstractMongoConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MongoConfiguration.class);
@Autowired
private MongoProperties properties;
@Autowired(required = false)
private MongoClientOptions options;
private Mongo mongo;
@Override
public String getDatabaseName() {
return properties.getMongoClientDatabase();
}
/**
* Closes mongo client when destroyd.
*/
@PreDestroy
public void close() {
if (this.mongo != null) {
this.mongo.close();
}
}
@Override
@Bean
@ConditionalOnMissingBean
public Mongo mongo() throws UnknownHostException {
final MongoClientURI uri = new MongoClientURI(properties.getUri(), createBuilderOutOfOptions(options));
if (properties.getPort() != null) {
LOG.debug("Create mongo by properties (host: {}, port: {})", uri.getHosts().get(0), properties.getPort());
this.mongo = new MongoClient(Arrays.asList(new ServerAddress(uri.getHosts().get(0), properties.getPort())),
uri.getOptions());
} else {
LOG.debug("Create mongo by URI : {}", uri);
this.mongo = new MongoClient(uri);
}
return this.mongo;
}
/*
* Creates {@link MongoClientOptions} builder out of existing options as the
* {@link MongoClientURI} expects a builder.
*
* Based on MongoProperties#builder method.
*/
private Builder createBuilderOutOfOptions(final MongoClientOptions options) {
final Builder builder = MongoClientOptions.builder();
if (options != null) {
builder.alwaysUseMBeans(options.isAlwaysUseMBeans());
builder.connectionsPerHost(options.getConnectionsPerHost());
builder.connectTimeout(options.getConnectTimeout());
builder.cursorFinalizerEnabled(options.isCursorFinalizerEnabled());
builder.dbDecoderFactory(options.getDbDecoderFactory());
builder.dbEncoderFactory(options.getDbEncoderFactory());
builder.description(options.getDescription());
builder.maxWaitTime(options.getMaxWaitTime());
builder.readPreference(options.getReadPreference());
builder.serverSelectionTimeout(options.getServerSelectionTimeout());
builder.socketFactory(options.getSocketFactory());
builder.socketKeepAlive(options.isSocketKeepAlive());
builder.socketTimeout(options.getSocketTimeout());
builder.threadsAllowedToBlockForConnectionMultiplier(options
.getThreadsAllowedToBlockForConnectionMultiplier());
builder.writeConcern(options.getWriteConcern());
}
return builder;
}
}

View File

@@ -0,0 +1,3 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.eclipse.hawkbit.artifact.repository.ArtifactStoreAutoConfiguration

View File

@@ -0,0 +1,75 @@
/**
* 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;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
/**
*
*
*/
public class FreePortFileWriter {
private final String filePortPath;
private final int from;
private final int to;
/**
* @param from
* @param to
*/
public FreePortFileWriter(final int from, final int to, final String filePortPath) {
this.from = from;
this.to = to;
this.filePortPath = filePortPath;
}
public int getPort() {
return findFree();
}
protected int findFree() {
for (int i = from; i <= to; i++) {
if (isFree(i)) {
return i;
}
}
throw new RuntimeException("No free port in range " + from + ":" + to);
}
boolean isFree(final int port) {
try {
final File portFile = new File(filePortPath + File.separator + port + ".port");
portFile.getParentFile().mkdirs();
if (portFile.exists()) {
return false;
} else {
boolean isFree = false;
final ServerSocket sock = new ServerSocket();
sock.setReuseAddress(true);
sock.bind(new InetSocketAddress(port));
if (portFile.createNewFile()) {
portFile.deleteOnExit();
isFree = true;
}
sock.close();
// is free:
return isFree;
// We rely on an exception thrown to determine availability or
// not availability.
}
} catch (final Exception e) {
// not free.
return false;
}
}
}

View File

@@ -0,0 +1,115 @@
/**
* 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;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.UUID;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.flapdoodle.embed.mongo.Command;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.ArtifactStoreBuilder;
import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder;
import de.flapdoodle.embed.mongo.config.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
import de.flapdoodle.embed.process.runtime.Network;
/**
*
*
*/
public class MongoDBTestRule implements TestRule {
private static final Logger LOG = LoggerFactory.getLogger(MongoDBTestRule.class);
private static volatile MongodExecutable mongodExecutable = null;
private static volatile MongodProcess mongod;
private final String id = UUID.randomUUID().toString();
@Override
public Statement apply(final Statement base, final Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before(base, description);
try {
base.evaluate();
} finally {
after();
}
}
};
}
private void after() {
if (mongodExecutable != null) {
LOG.info("Stop MongoDB...");
mongodExecutable.stop();
mongodExecutable = null;
if (mongod != null) {
mongod.stop();
mongod = null;
}
LOG.info("MongoDB stopped... {}", id);
}
}
private void before(final Statement base, final Description description) throws UnknownHostException, IOException {
final Command command = Command.MongoD;
final RuntimeConfigBuilder runtimeConfig = new RuntimeConfigBuilder().defaults(command);
int port = -1;
if (System.getProperty("spring.data.mongodb.port") != null) {
port = Integer.parseInt(System.getProperty("spring.data.mongodb.port"));
} else {
port = new FreePortFileWriter(27017, 27100, "./target/freeports").getPort();
System.setProperty("spring.data.mongodb.port", String.valueOf(port));
}
Version version = Version.V3_1_0;
if (System.getProperty("inf.mongodb.version") != null) {
version = Version.valueOf("V" + System.getProperty("inf.mongodb.version").trim().replaceAll("\\.", "_"));
}
if (System.getProperty("http.proxyHost") != null) {
runtimeConfig.artifactStore(new ArtifactStoreBuilder().defaults(command)
.download(new DownloadConfigBuilder().defaultsForCommand(command)
.proxyFactory(new HttpProxyFactory(System.getProperty("http.proxyHost").trim(),
Integer.valueOf(System.getProperty("http.proxyPort"))))));
}
final IMongodConfig mongodConfig = new MongodConfigBuilder().version(version)
.net(new Net("127.0.0.1", port, Network.localhostIsIPv6())).build();
final MongodStarter starter = MongodStarter.getInstance(runtimeConfig.build());
mongodExecutable = starter.prepare(mongodConfig);
LOG.info("Start MongoDB...");
mongod = mongodExecutable.start();
final Net net = mongod.getConfig().net();
LOG.info("MongoDB started id {} on bind ip :{} Port:{} and version {}", id, net.getBindIp(), net.getPort(),
mongodConfig.version().toString());
}
}

View File

@@ -0,0 +1,17 @@
/**
* 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;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class TestConfiguration {
}

View File

@@ -0,0 +1,132 @@
/**
* 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.api.Assertions.assertThat;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import org.apache.commons.io.IOUtils;
import org.eclipse.hawkbit.artifact.MongoDBTestRule;
import org.eclipse.hawkbit.artifact.TestConfiguration;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.google.common.io.BaseEncoding;
import com.mongodb.gridfs.GridFSDBFile;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { ArtifactStoreAutoConfiguration.class, TestConfiguration.class })
public class ArtifactStoreTest {
@ClassRule
public static final MongoDBTestRule mongoDBRule = new MongoDBTestRule();
@Autowired
private ArtifactStore artifactStoreUnderTest;
@Autowired
private GridFsOperations gridFs;
@Test
public void storeArtifactInMongoDB() {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";
final DbArtifact storedFile = artifactStoreUnderTest.store(generateInputStream(filelengthBytes), filename,
contentType);
assertThat(storedFile).isNotNull();
assertThat(artifactStoreUnderTest.getArtifactById(storedFile.getArtifactId())).isNotNull();
}
@Test
public void findArtifactBySHA1Hash() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "SHA-1");
artifactStoreUnderTest.store(digestInputStream, filename, contentType);
assertThat(artifactStoreUnderTest.getArtifactBySha1(
BaseEncoding.base16().lowerCase().encode(digestInputStream.getMessageDigest().digest()))).isNotNull();
}
@Test
public void findArtifactByMD5Hash() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "MD5");
artifactStoreUnderTest.store(digestInputStream, filename, contentType);
assertThat(artifactStoreUnderTest.getArtifactByMd5(
BaseEncoding.base16().lowerCase().encode(digestInputStream.getMessageDigest().digest()))).isNotNull();
}
@Test
public void getInputStreamFromArtifact() throws IOException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";
final ByteArrayInputStream inputStream = generateInputStream(filelengthBytes);
final DbArtifact artifact = artifactStoreUnderTest
.getArtifactById(artifactStoreUnderTest.store(inputStream, filename, contentType).getArtifactId());
inputStream.reset();
final byte[] artifactBytes = new byte[filelengthBytes];
final byte[] artifactStoredBytes = new byte[filelengthBytes];
IOUtils.readFully(inputStream, artifactBytes);
IOUtils.readFully(artifact.getFileInputStream(), artifactStoredBytes);
assertThat(artifactBytes).isEqualTo(artifactStoredBytes);
}
@Test
public void deleteArtifactWithOnlyOneTenantLast() throws NoSuchAlgorithmException {
final int filelengthBytes = 128;
final String filename = "testfile.json";
final String contentType = "application/json";
final DigestInputStream digestInputStream = digestInputStream(generateInputStream(filelengthBytes), "SHA-1");
final DbArtifact store = artifactStoreUnderTest.store(digestInputStream, filename, contentType);
artifactStoreUnderTest.deleteById(store.getArtifactId());
final GridFSDBFile findOne = gridFs
.findOne(new Query().addCriteria(Criteria.where("_id").is(store.getArtifactId())));
assertThat(findOne).isNull();
}
private static ByteArrayInputStream generateInputStream(final int length) {
final byte[] bytes = new byte[length];
new Random().nextBytes(bytes);
return new ByteArrayInputStream(bytes);
}
private static DigestInputStream digestInputStream(final ByteArrayInputStream stream, final String digest)
throws NoSuchAlgorithmException {
return new DigestInputStream(stream, MessageDigest.getInstance(digest));
}
}