Feature horizontal scalability (#305)

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Dennis Melzer
2016-11-03 15:53:53 +01:00
committed by Kai Zimmermann
parent 07cb62a3dd
commit 866bc72114
287 changed files with 4219 additions and 5046 deletions

View File

@@ -1,27 +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.cache;
/**
* Cache Constants.
*
*
*
*/
public final class CacheConstants {
/**
* Constant for download cache id.
*/
public static final String DOWNLOAD_ID_CACHE = "DowonloadIdCache";
private CacheConstants() {
}
}

View File

@@ -0,0 +1,57 @@
/**
* 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.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
/**
* A default implementation of the {@link DownloadIdCache} which uses the
* {@link CacheManager} implementation to store the download-ids.
*/
public class DefaultDownloadIdCache implements DownloadIdCache {
static final String DOWNLOAD_ID_CACHE = "DowonloadIdCache";
private final CacheManager cacheManager;
/**
* @param cacheManager
* the underlying cache-manager to store the download-ids
*/
@Autowired
public DefaultDownloadIdCache(final CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public void put(final String downloadId, final DownloadArtifactCache object) {
getCache().put(downloadId, object);
}
@Override
public DownloadArtifactCache get(final String downloadId) {
final ValueWrapper valueWrapper = getCache().get(downloadId);
return (valueWrapper == null) ? null : (DownloadArtifactCache) valueWrapper.get();
}
@Override
public void evict(final String downloadId) {
getCache().evict(downloadId);
}
private Cache getCache() {
if (cacheManager instanceof TenancyCacheManager) {
return ((TenancyCacheManager) cacheManager).getDirectCache(DOWNLOAD_ID_CACHE);
}
return cacheManager.getCache(DOWNLOAD_ID_CACHE);
}
}

View File

@@ -9,10 +9,7 @@
package org.eclipse.hawkbit.cache;
/**
* Cache Object for download a Artifact.
*
*
*
* Cache Object for downloading an artifact.
*/
public class DownloadArtifactCache {
@@ -21,7 +18,7 @@ public class DownloadArtifactCache {
/**
* Constructor.
*
*
* @param downloadType
* the type for searching the artifact.
* @param id

View File

@@ -0,0 +1,57 @@
/**
* 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.cache;
/**
* A interface declaration of the download-id-cache which allows to store
* volatile generated download-IDs used to have a single unique download-request
* e.g. for distributed download-server.
*
* A valid download-id is created during a successful download-authorization
* request e.g. from a download-server. In the DMF response a unique
* download-URL containing a generated download-id which can be used to download
* the artifact using this single download-url.
*
* The {@link DownloadIdCache} handles storing this unique download-id from the
* DMF authorization request until the actual artifact download-request via HTTP
* with the unique ID is performed.
*
*/
public interface DownloadIdCache {
/**
* Puts a given artifact cache object with the given downloadId key into the
* cache.
*
* @param downloadId
* the ID to store the cache object to look it up later on
* @param downloadArtifactCacheObject
* the object to store into the cache
*/
void put(final String downloadId, final DownloadArtifactCache downloadArtifactCacheObject);
/**
* Retrieves a {@link DownloadArtifactCache} by a given downloadId.
*
* @param downloadId
* the ID to retrieve the artifact cache object
* @return the found {@link DownloadArtifactCache} or {@code null} if none
* exists for the given ID
*/
DownloadArtifactCache get(final String downloadId);
/**
* Evicts a {@link DownloadArtifactCache} for the given downloadId
*
* @param downloadId
* the ID to be evicted
*/
void evict(String downloadId);
}

View File

@@ -10,9 +10,6 @@ package org.eclipse.hawkbit.cache;
/**
* The type of the id which is saved.
*
*
*
*/
public enum DownloadType {
BY_SHA1

View File

@@ -12,7 +12,6 @@ import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
/**
*
* A cache interface which handles multi tenancy.
*/
public interface TenancyCacheManager extends CacheManager {
@@ -21,7 +20,7 @@ public interface TenancyCacheManager extends CacheManager {
* A direct access for retrieving the cache without including the current
* tenant key. This is necessary e.g. for retrieving caches not for the
* current tenant.
*
*
* @param name
* the name of the cache to retrieve directly
* @return the cache associated with the name without tenancy separation
@@ -31,10 +30,9 @@ public interface TenancyCacheManager extends CacheManager {
/**
* Evicts all caches for a given tenant. All caches under a certain tenant
* gets evicted.
*
*
* @param tenant
* the tenant to evict caches
*/
void evictCaches(final String tenant);
}

View File

@@ -8,8 +8,9 @@
*/
package org.eclipse.hawkbit.cache;
import static java.util.Collections.emptyList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -25,10 +26,6 @@ import org.springframework.cache.CacheManager;
*
* Additionally it also provide functionality to retrieve all caches overall
* tenants at once, for monitoring and system access.
*
*
*
*
*/
public class TenantAwareCacheManager implements TenancyCacheManager {
@@ -39,47 +36,45 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
private final TenantAware tenantAware;
/**
* Constructor.
*
* @param delegate
* the {@link CacheManager} to delegate to.
* @param tenantAware
* the tenant aware to retrieve the current tenant
*/
public TenantAwareCacheManager(final CacheManager delegate, final TenantAware tenantAware) {
this.delegate = delegate;
this.tenantAware = tenantAware;
this.delegate = delegate;
}
@Override
public Cache getCache(final String name) {
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
if (isTenantInvalid(currentTenant)) {
return null;
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return null;
}
return delegate.getCache(currentTenant + TENANT_CACHE_DELIMITER + name);
return delegate.getCache(buildKey(currentTenant, name));
}
@Override
public Collection<String> getCacheNames() {
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
return Collections.emptyList();
if (isTenantInvalid(currentTenant)) {
return emptyList();
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return Collections.emptyList();
}
return getCacheNames(currentTenant);
}
/**
* A direct access for retrieving all cache names overall tenants.
*
*
* @return all cache names without tenant check
*/
public Collection<String> getDirectCacheNames() {
@@ -91,17 +86,17 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
return delegate.getCache(name);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.cache.TenancyCacheManager#evictCaches(java.
* lang. String)
*/
@Override
public void evictCaches(final String tenant) {
getCacheNames(tenant)
.forEach(cachename -> delegate.getCache(tenant + TENANT_CACHE_DELIMITER + cachename).clear());
getCacheNames(tenant).forEach(cachename -> delegate.getCache(buildKey(tenant, cachename)).clear());
}
private boolean isTenantInvalid(final String tenant) {
return tenant == null || tenant.contains(TENANT_CACHE_DELIMITER);
}
private String buildKey(final String tenant, final String cacheName) {
return tenant + TENANT_CACHE_DELIMITER + cacheName;
}
private Collection<String> getCacheNames(final String tenant) {

View File

@@ -1,40 +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.eventbus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.Subscribe;
/**
* Catches all dead events by means of events with no fitting subscriber on the
* bus.
*
*
*
*/
@EventSubscriber
@Service
public class DeadEventListener {
private static final Logger LOG = LoggerFactory.getLogger(DeadEventListener.class);
/**
* Listens for dead vents and prints them into LOG.
*
* @param event
* to print
*/
@Subscribe
public void listen(final DeadEvent event) {
LOG.info("DeadEvent on bus! {}", event.getEvent());
}
}

View File

@@ -1,88 +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.eventbus;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* An {@link BeanPostProcessor} implementation which registers all beans as a
* event bus subscriber if the classes are annotated with
* {@link EventSubscriber} and have at least one method annotated with the
* guava's {@link Subscribe} annoation.
*
*
*/
public class EventBusSubscriberProcessor implements BeanPostProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(EventBusSubscriberProcessor.class);
@Autowired
private EventBus eventBus;
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#
* postProcessBeforeInitialization (java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) {
return bean;
}
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#
* postProcessAfterInitialization( java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) {
final Class<? extends Object> beanClass = bean.getClass();
final EventSubscriber eventSubscriber = beanClass.getAnnotation(EventSubscriber.class);
if (eventSubscriber != null) {
LOGGER.trace("Found bean {} with {} annotation ", bean.getClass().getName(),
EventSubscriber.class.getSimpleName());
final Method[] declaredMethods = beanClass.getDeclaredMethods();
for (final Method method : declaredMethods) {
final Subscribe subscriber = method.getAnnotation(Subscribe.class);
if (subscriber != null) {
LOGGER.trace("Found method {} for bean {} with {} annotation", method.getName(),
bean.getClass().getName(), Subscribe.class.getSimpleName());
eventBus.register(bean);
return bean;
}
}
}
if (eventSubscriber != null) {
LOGGER.debug("Found bean {} with {} annotation but without any method with necessary {} annotation",
bean.getClass().getName(), EventSubscriber.class.getSimpleName(), Subscribe.class.getSimpleName());
}
return bean;
}
/**
* package private setter for testing purposes.
*
* @param eventBus
* the event bus
*/
void setEventBus(final EventBus eventBus) {
this.eventBus = eventBus;
}
}

View File

@@ -1,39 +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.eventbus;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Marks an class as an event subscriber to listen on event on the event bus
* without explicit register this class to the event bus.
*
* <pre>
* &#064;EventSubscriber
* public class MySubscriber {
* &#064;Subscribe
* public void listen(MyEvent event) {
* System.out.println(&quot;event received: &quot; + event);
* }
* }
* </pre>
*
*
*
*
*/
@Target({ TYPE })
@Retention(RUNTIME)
public @interface EventSubscriber {
}

View File

@@ -1,105 +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.eventbus.event;
/**
* An abstract class of the {@link DistributedEvent} implementation which holds
* all the necessary information of distributing events to other nodes.
*
*
*
*
*/
public abstract class AbstractDistributedEvent implements DistributedEvent {
private static final long serialVersionUID = 1L;
private final long revision;
private String originNodeId;
private String nodeId;
private final String tenant;
/**
*
* @param revision
* the revision of this event
* @param tenant
* the tenant for this event
*/
protected AbstractDistributedEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setOriginNodeId(java.
* lang. String)
*/
@Override
public void setOriginNodeId(final String originNodeId) {
this.originNodeId = originNodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setNodeId(java.lang.
* String)
*/
@Override
public void setNodeId(final String nodeId) {
this.nodeId = nodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#getOriginNodeId()
*/
@Override
public String getOriginNodeId() {
return this.originNodeId;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.NodeAware#getNodeId()
*/
@Override
public String getNodeId() {
return this.nodeId;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.Event#getRevision()
*/
@Override
public long getRevision() {
return revision;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
*/
@Override
public String getTenant() {
return tenant;
}
}

View File

@@ -1,24 +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.eventbus.event;
/**
* Events to be published to refresh data on UI.
*
*
*
*
*/
public enum CustomEvents {
TARGETS_CREATED_EVENT,
DISTRIBUTION_CREATED_EVENT
}

View File

@@ -1,44 +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.eventbus.event;
/**
* Abstract event definition class which holds the necessary revsion and tenant
* information which every event needs.
*
* @see AbstractDistributedEvent for events which should be distributed to other
* cluster nodes
*/
public class DefaultEvent implements Event {
private final long revision;
private final String tenant;
/**
* @param revision
* the revision number of the event
* @param tenant
* the tenant of the event
*/
protected DefaultEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}
@Override
public long getRevision() {
return revision;
}
@Override
public String getTenant() {
return tenant;
}
}

View File

@@ -1,23 +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.eventbus.event;
import java.io.Serializable;
/**
* Marks an event to as an distributed event which will be distributed to other
* nodes.
*
*
*
*
*/
public interface DistributedEvent extends Event, NodeAware, Serializable {
}

View File

@@ -1,48 +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.eventbus.event;
/**
* An event interface which declares event types that an entity has been
* changed. {@link EntityEvent}s should not implement {@link DistributedEvent}
* due all {@link EntityEvent}s will be distributed to other nodes.
*
* Retrieving an {@link EntityEvent} on a different node the entity will be load
* lazy.
*
*
*
*
*/
public interface EntityEvent extends Event, NodeAware {
/**
* A typesafe way to retrieve the entity from the event, which might be
* loaded lazy in case the event has been distributed from another node.
*
* @param entityClass
* the class of the entity to retrieve
* @return the entity might be lazy loaded. Might be {@code null} in case
* the entity e.g. is queried lazy on a different node and has been
* already deleted from the database
* @throws ClassCastException
* in case a wrong entity class is given for this event
*/
<E> E getEntity(Class<E> entityClass);
/**
* An unsafe way to retrieve the entity from this event which might be
* loaded lazy in case the event has been distributed from another node.
*
* @return the entity might be lazy loaded. Might be {@code null} in case
* the entity e.g. is queried lazy on a different node and has been
* already deleted from the database
*/
Object getEntity();
}

View File

@@ -1,32 +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.eventbus.event;
/**
* An event declaration which holds an revision for each event so consumers have
* the chance to know if they might already retrieved an newer event.
*
*
*
*
*/
public interface Event {
/**
* @return the revision of this event which should be increment or each new
* event in case the event have a causalität. Might be {@code -1} in
* case the events does not provide any revision.
*/
long getRevision();
/**
* @return the tenant of the entity.
*/
String getTenant();
}

View File

@@ -1,52 +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.eventbus.event;
/**
* Interface to be implemented by events which are distributed to other nodes
* where it's necessary to know which node sent an event and which nodes
* retrieved the event from which node. Using the EventDistributor the
* implementation only needs to contain the necessary node IDs, setting and
* retrieving the node IDs is transparent by the EventDistributor so the event
* distributor does not hang in an endless loop of distributing the events which
* self posted.
*
*
*
*
*/
public interface NodeAware {
/**
* @return the origin node ID in case the event has been forwarded to other
* nodes or {@code null} if the event has not been forwarded to
* other nodes
*/
String getOriginNodeId();
/**
* @param originNodeId
* the origin node ID where this event has been sent originally
*/
void setOriginNodeId(String originNodeId);
/**
* @return the node ID which is processing this event locally, set by the
* EventDistributor so he can determine if this event has been
* received by another node and is processing on the current node.
*/
String getNodeId();
/**
* @param nodeId
* the ID of the node this event is processing.
*/
void setNodeId(String nodeId);
}

View File

@@ -0,0 +1,124 @@
/**
* 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.cache;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cache")
@Stories("Download ID Cache")
@RunWith(MockitoJUnitRunner.class)
public class DefaultDownloadIdCacheTest {
@Mock
private CacheManager cacheManagerMock;
@Mock
private TenancyCacheManager tenancyCacheManagerMock;
@Mock
private Cache cacheMock;
@Captor
private ArgumentCaptor<String> cacheManagerKeyCaptor;
@Captor
private ArgumentCaptor<DownloadArtifactCache> cacheManagerValueCaptor;
private DefaultDownloadIdCache underTest;
private final String knownKey = "12345";
@Before
public void before() {
underTest = new DefaultDownloadIdCache(cacheManagerMock);
when(cacheManagerMock.getCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE)).thenReturn(cacheMock);
when(tenancyCacheManagerMock.getDirectCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE)).thenReturn(cacheMock);
}
@Test
@Description("Verifies that putting key and value is delegated to the CacheManager implementation")
public void putKeyAndValueIsDelegatedToCacheManager() {
final DownloadArtifactCache value = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
underTest.put(knownKey, value);
verify(cacheMock).put(cacheManagerKeyCaptor.capture(), cacheManagerValueCaptor.capture());
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
assertThat(cacheManagerValueCaptor.getValue()).isEqualTo(value);
}
@Test
@Description("Verifies that evicting a key is delegated to the CacheManager implementation")
public void evictKeyIsDelegatedToCacheManager() {
underTest.evict(knownKey);
verify(cacheMock).evict(cacheManagerKeyCaptor.capture());
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
}
@Test
@Description("Verifies that retrieving a value for a specific key is delegated to the CacheManager implementation")
public void getValueReturnsTheAssociatedValueForKey() {
final String knownKey = "12345";
final DownloadArtifactCache knownValue = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
when(cacheMock.get(knownKey)).thenReturn(new SimpleValueWrapper(knownValue));
final DownloadArtifactCache downloadArtifactCache = underTest.get(knownKey);
assertThat(downloadArtifactCache).isEqualTo(knownValue);
}
@Test
@Description("Verifies that retrieving a null value for a specific key is delegated to the CacheManager implementation")
public void getValueReturnsNullIfNoKeyIsAssociated() {
when(cacheMock.get(knownKey)).thenReturn(new SimpleValueWrapper(null));
final DownloadArtifactCache downloadArtifactCache = underTest.get(knownKey);
assertThat(downloadArtifactCache).isNull();
}
@Test
@Description("Verifies that TenancyCacheManager is using direct cache because download-ids are global unique and don't need to run as tenant aware")
public void tenancyCacheManagerIsUsingDirectCache() {
underTest = new DefaultDownloadIdCache(tenancyCacheManagerMock);
final DownloadArtifactCache value = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
underTest.put(knownKey, value);
verify(cacheMock).put(cacheManagerKeyCaptor.capture(), cacheManagerValueCaptor.capture());
verify(tenancyCacheManagerMock).getDirectCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE);
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
assertThat(cacheManagerValueCaptor.getValue()).isEqualTo(value);
}
}

View File

@@ -1,75 +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.eventbus;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Event Bus")
@Stories("EventBus Subscriber Processor Test")
@RunWith(MockitoJUnitRunner.class)
// TODO: create description annotations
public class EventBusSubscriberProcessorTest {
@Mock
private EventBus eventBusMock;
private final EventBusSubscriberProcessor postProcessorUnderTest = new EventBusSubscriberProcessor();
@Before
public void before() {
reset(eventBusMock);
postProcessorUnderTest.setEventBus(eventBusMock);
}
@Test
public void correctAnnotatedClassAndMethodIsRegistered() {
final TestEventSubscriberClass testEventSubscriberClass = new TestEventSubscriberClass();
postProcessorUnderTest.postProcessAfterInitialization(testEventSubscriberClass, "correctEventSubscriber");
verify(eventBusMock, times(1)).register(testEventSubscriberClass);
}
@Test
public void eventSubscriberWithoutMethodAnnotationIsNotRegistered() {
final TestWrongEventSubscriberClass testEventSubscriberClass = new TestWrongEventSubscriberClass();
postProcessorUnderTest.postProcessAfterInitialization(testEventSubscriberClass, "correctEventSubscriber");
verify(eventBusMock, times(0)).register(testEventSubscriberClass);
}
@EventSubscriber
@Service
private class TestEventSubscriberClass {
@Subscribe
public void subscribe(final String s) {
}
}
@EventSubscriber
@Service
private class TestWrongEventSubscriberClass {
public void methodWithoutAnnotation(final String s) {
}
}
}